diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 14cb2568c1ae3..ed3a7cf62df40 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -32,7 +32,7 @@ "*.yml": "azure-pipelines" }, // ms-dotnettools.csharp settings - "omnisharp.defaultLaunchSolution": "Compilers.sln", + "omnisharp.defaultLaunchSolution": "Roslyn.sln", "omnisharp.disableMSBuildDiagnosticWarning": true, "omnisharp.enableEditorConfigSupport": true, "omnisharp.enableImportCompletion": true, diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 942a2b624491e..44258d64c59ea 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -30,10 +30,19 @@ src/Interactive/ @dotnet/roslyn-interactive src/NuGet/ @dotnet/roslyn-infrastructure src/Scripting/ @dotnet/roslyn-interactive src/Setup/ @dotnet/roslyn-infrastructure -src/Tools/ @dotnet/roslyn-infrastructure +src/Tools/AnalyzerRunner @dotnet/roslyn-ide +src/Tools/BuildActionTelemetryTable @dotnet/roslyn-infrastructure +src/Tools/BuildBoss @dotnet/roslyn-infrastructure +src/Tools/BuildValidator @dotnet/roslyn-infrastructure +src/Tools/dotnet-format @dotnet/roslyn-infrastructure +src/Tools/ExternalAccess @dotnet/roslyn-ide +src/Tools/IdeBenchmarks @dotnet/roslyn-ide +src/Tools/IdeCoreBenchmarks @dotnet/roslyn-ide +src/Tools/ManifestGenerator @dotnet/roslyn-infrastructure +src/Tools/PrepareTests @dotnet/roslyn-infrastructure src/Tools/Source/CompilerGeneratorTools/ @dotnet/roslyn-compiler +src/Tools/Source/RunTests @dotnet/roslyn-infrastructure src/VisualStudio/ @dotnet/roslyn-ide -src/VisualStudio/LiveShare @dotnet/roslyn-ide @daytonellwanger @srivatsn @aletsdelarosa src/Workspaces/ @dotnet/roslyn-ide src/Compilers/**/PublicAPI.Unshipped.txt @dotnet/roslyn-api-owners diff --git a/.github/ISSUE_TEMPLATE/localization-suggestion.md b/.github/ISSUE_TEMPLATE/localization-suggestion.md new file mode 100644 index 0000000000000..89242dc038103 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/localization-suggestion.md @@ -0,0 +1,46 @@ +--- +name: Localization suggestion +about: Suggest a change to a localized string. +labels: [Area-Infrastructure, Tenet-Localization] +--- + +## Repo URL where the string lives + +https://github.com/dotnet/roslyn + +## File Name + + + +## Resource ID + + + +## English String + + + +## Current Translation + + + +## Suggested Translation + + + +## Language + + + +## Why Fix is needed + + + + + + +--- + +A Roslyn team member will file a bug through https://aka.ms/ceLocBug which the translation team will consider. + +Internal Tracking Issue: {Update with tracking issue URL.} \ No newline at end of file diff --git a/.github/fabricbot.json b/.github/fabricbot.json new file mode 100644 index 0000000000000..66c0f5f021449 --- /dev/null +++ b/.github/fabricbot.json @@ -0,0 +1,1122 @@ +{ + "version": "1.0", + "tasks": [ + { + "taskType": "trigger", + "capabilityId": "AutoMerge", + "subCapability": "AutoMerge", + "version": "1.0", + "config": { + "taskName": "Automatically merge PR once CI passes", + "label": "auto-merge", + "minMinutesOpen": "12", + "mergeType": "merge", + "deleteBranches": true, + "requireAllStatuses": false, + "minimumNumberOfCheckRuns": 0, + "removeLabelOnPush": true, + "silentMode": true, + "conditionalMergeTypes": [ + { + "condition": { + "placeholder": "" + } + } + ], + "requireAllStatuses_exemptList": [ + "codecov", + "msftbot", + "dependabot", + "DotNet Maestro", + "DotNet Maestro - Int", + ".NET Helix (Int)" + ], + "requireSpecificCheckRuns": true, + "requireSpecificCheckRunsList": [ + "roslyn-CI" + ] + }, + "disabled": false + }, + { + "taskType": "trigger", + "capabilityId": "IssueResponder", + "subCapability": "PullRequestResponder", + "version": "1.0", + "config": { + "conditions": { + "operator": "and", + "operands": [ + { + "name": "labelAdded", + "parameters": { + "label": "auto-merge" + } + }, + { + "operator": "or", + "operands": [ + { + "name": "activitySenderHasPermissions", + "parameters": { + "permissions": "admin" + } + }, + { + "name": "isActivitySender", + "parameters": { + "permissions": "write", + "user": "dotnet-bot" + } + } + ] + } + ] + }, + "eventType": "pull_request", + "eventNames": [ + "pull_request", + "issues", + "project_card" + ], + "taskName": "Auto-approve auto-merge PRs", + "actions": [ + { + "name": "approvePullRequest", + "parameters": { + "comment": "Auto-approval" + } + } + ] + } + }, + { + "taskType": "trigger", + "capabilityId": "IssueResponder", + "subCapability": "PullRequestResponder", + "version": "1.0", + "config": { + "conditions": { + "operator": "and", + "operands": [ + { + "name": "isActivitySender", + "parameters": { + "user": "dotnet-maestro[bot]" + } + }, + { + "name": "isAction", + "parameters": { + "action": "opened" + } + }, + { + "operator": "not", + "operands": [ + { + "name": "bodyContains", + "parameters": { + "bodyPattern": "Updates sdk.version" + } + } + ] + } + ] + }, + "eventType": "pull_request", + "eventNames": [ + "pull_request", + "issues", + "project_card" + ], + "taskName": "Auto-approve maestro PRs", + "actions": [ + { + "name": "approvePullRequest", + "parameters": { + "comment": "Auto-approve" + } + } + ] + } + }, + { + "taskType": "trigger", + "capabilityId": "IssueResponder", + "subCapability": "PullRequestResponder", + "version": "1.0", + "config": { + "conditions": { + "operator": "and", + "operands": [ + { + "operator": "or", + "operands": [ + { + "name": "prTargetsBranch", + "parameters": { + "branchName": "main" + } + }, + { + "name": "prTargetsBranch", + "parameters": { + "branchName": "main-vs-deps" + } + } + ] + }, + { + "name": "isAction", + "parameters": { + "action": "merged" + } + } + ] + }, + "eventType": "pull_request", + "eventNames": [ + "pull_request", + "issues", + "project_card" + ], + "taskName": "Milestone tracking", + "actions": [ + { + "name": "addMilestone", + "parameters": { + "milestoneName": "Next" + } + } + ], + "dangerZone": { + "respondToBotActions": true, + "acceptRespondToBotActions": true + } + } + }, + { + "taskType": "trigger", + "capabilityId": "IssueResponder", + "subCapability": "PullRequestResponder", + "version": "1.0", + "config": { + "conditions": { + "operator": "and", + "operands": [ + { + "name": "isActivitySender", + "parameters": { + "user": "dotnet-maestro[bot]" + } + }, + { + "name": "isAction", + "parameters": { + "action": "opened" + } + }, + { + "name": "bodyContains", + "parameters": { + "bodyPattern": "Updates sdk.version" + } + } + ] + }, + "eventType": "pull_request", + "eventNames": [ + "pull_request", + "issues", + "project_card" + ], + "actions": [ + { + "name": "requestChangesPullRequest", + "parameters": { + "comment": "This PR changes the .NET SDK version. Review required from @dotnet/roslyn-infrastructure before merging.\nTasks:\n- [ ] Getting Started Documentation has been updated\n- [ ] NuGet dependency version updated to match version shipping in SDK" + } + } + ], + "taskName": "Require PR approval before merging SDK change" + } + }, + { + "taskType": "trigger", + "capabilityId": "IssueResponder", + "subCapability": "IssuesOnlyResponder", + "version": "1.0", + "config": { + "conditions": { + "operator": "and", + "operands": [ + { + "name": "isActivitySender", + "parameters": { + "user": "dotnet-bot" + } + }, + { + "name": "titleContains", + "parameters": { + "titlePattern": "Localized file check-in" + } + }, + { + "name": "isAction", + "parameters": { + "action": "opened" + } + } + ] + }, + "eventType": "issue", + "eventNames": [ + "issues", + "project_card" + ], + "actions": [ + { + "name": "addLabel", + "parameters": { + "label": "auto-merge" + } + } + ], + "taskName": "Auto-approve OneLoc PRs" + } + }, + { + "taskType": "scheduled", + "capabilityId": "ScheduledSearch", + "subCapability": "ScheduledSearch", + "version": "1.1", + "config": { + "frequency": [ + { + "weekDay": 0, + "hours": [ + 1, + 4, + 7, + 10, + 13, + 16, + 19, + 22 + ], + "timezoneOffset": -7 + }, + { + "weekDay": 1, + "hours": [ + 1, + 4, + 7, + 10, + 13, + 16, + 19, + 22 + ], + "timezoneOffset": -7 + }, + { + "weekDay": 2, + "hours": [ + 1, + 4, + 7, + 10, + 13, + 16, + 19, + 22 + ], + "timezoneOffset": -7 + }, + { + "weekDay": 3, + "hours": [ + 1, + 4, + 7, + 10, + 13, + 16, + 19, + 22 + ], + "timezoneOffset": -7 + }, + { + "weekDay": 4, + "hours": [ + 1, + 4, + 7, + 10, + 13, + 16, + 19, + 22 + ], + "timezoneOffset": -7 + }, + { + "weekDay": 5, + "hours": [ + 1, + 4, + 7, + 10, + 13, + 16, + 19, + 22 + ], + "timezoneOffset": -7 + }, + { + "weekDay": 6, + "hours": [ + 1, + 4, + 7, + 10, + 13, + 16, + 19, + 22 + ], + "timezoneOffset": -7 + } + ], + "searchTerms": [ + { + "name": "isOpen", + "parameters": {} + }, + { + "name": "isIssue", + "parameters": {} + }, + { + "name": "hasLabel", + "parameters": { + "label": "Need More Info" + } + }, + { + "name": "noActivitySince", + "parameters": { + "days": 10 + } + } + ], + "taskName": "Close \"Need More Info\" Issues", + "actions": [ + { + "name": "closeIssue", + "parameters": {} + }, + { + "name": "addReply", + "parameters": { + "comment": "Closing this issue as we've seen no reply to the request for more information. If you are able to get the requested information, please add it to the issue and we will retriage it. " + } + } + ] + } + }, + { + "taskType": "trigger", + "capabilityId": "IssueResponder", + "subCapability": "IssueCommentResponder", + "version": "1.0", + "config": { + "conditions": { + "operator": "and", + "operands": [ + { + "name": "isOpen", + "parameters": {} + }, + { + "name": "hasLabel", + "parameters": { + "label": "Need More Info" + } + } + ] + }, + "eventType": "issue", + "eventNames": [ + "issue_comment" + ], + "taskName": "Remove \"Need More Info\" on comment", + "actions": [ + { + "name": "addLabel", + "parameters": { + "label": "untriaged" + } + }, + { + "name": "removeLabel", + "parameters": { + "label": "Need More Info" + } + } + ] + } + }, + { + "taskType": "trigger", + "capabilityId": "IssueResponder", + "subCapability": "PullRequestResponder", + "version": "1.0", + "config": { + "conditions": { + "operator": "and", + "operands": [ + { + "name": "isAction", + "parameters": { + "action": "opened" + } + }, + { + "operator": "and", + "operands": [ + { + "operator": "not", + "operands": [ + { + "name": "activitySenderHasPermissions", + "parameters": { + "permissions": "admin" + } + } + ] + }, + { + "operator": "not", + "operands": [ + { + "name": "activitySenderHasPermissions", + "parameters": { + "permissions": "write" + } + } + ] + }, + { + "operator": "not", + "operands": [ + { + "name": "isActivitySender", + "parameters": { + "user": "github-actions[bot]" + } + } + ] + }, + { + "operator": "not", + "operands": [ + { + "name": "isActivitySender", + "parameters": { + "user": "dotnet-maestro[bot]" + } + } + ] + }, + { + "operator": "not", + "operands": [ + { + "name": "isActivitySender", + "parameters": { + "user": "dotnet-maestro-bot[bot]" + } + } + ] + }, + { + "operator": "not", + "operands": [ + { + "name": "isActivitySender", + "parameters": { + "user": "dotnet-maestro-bot" + } + } + ] + }, + { + "operator": "not", + "operands": [ + { + "name": "isActivitySender", + "parameters": { + "user": "dotnet-maestro" + } + } + ] + }, + { + "operator": "not", + "operands": [ + { + "name": "isActivitySender", + "parameters": { + "user": "github-actions" + } + } + ] + } + ] + } + ] + }, + "eventType": "pull_request", + "eventNames": [ + "pull_request", + "issues", + "project_card" + ], + "taskName": "Label Community Pull Requests", + "actions": [ + { + "name": "addLabel", + "parameters": { + "label": "Community" + } + } + ] + } + }, + { + "taskType": "trigger", + "capabilityId": "IssueResponder", + "subCapability": "PullRequestResponder", + "version": "1.0", + "config": { + "conditions": { + "operator": "and", + "operands": [ + { + "name": "prMatchesPattern", + "parameters": { + "matchRegex": "[xX][aA][mM][lL]$" + } + }, + { + "operator": "and", + "operands": [ + { + "operator": "not", + "operands": [ + { + "name": "hasLabel", + "parameters": { + "label": "UX Review Requested" + } + } + ] + }, + { + "operator": "not", + "operands": [ + { + "name": "hasLabel", + "parameters": { + "label": "UX Review Complete" + } + } + ] + }, + { + "operator": "not", + "operands": [ + { + "name": "hasLabel", + "parameters": { + "label": "UX Review Not Required" + } + } + ] + }, + { + "operator": "not", + "operands": [ + { + "name": "hasLabel", + "parameters": { + "label": "Needs UX Triage" + } + } + ] + } + ] + }, + { + "operator": "or", + "operands": [ + { + "name": "isAction", + "parameters": { + "action": "opened" + } + }, + { + "name": "isAction", + "parameters": { + "action": "synchronize" + } + }, + { + "name": "isAction", + "parameters": { + "action": "merged" + } + } + ] + }, + { + "operator": "and", + "operands": [ + { + "operator": "not", + "operands": [ + { + "name": "isActivitySender", + "parameters": { + "user": "dotnet-bot" + } + } + ] + }, + { + "operator": "not", + "operands": [ + { + "name": "isActivitySender", + "parameters": { + "user": "dotnet-maestro[bot]" + } + } + ] + } + ] + }, + { + "operator": "not", + "operands": [ + { + "name": "titleContains", + "parameters": { + "isRegex": true, + "titlePattern": "^Merge .* to .*$" + } + } + ] + } + ] + }, + "eventType": "pull_request", + "eventNames": [ + "pull_request", + "issues", + "project_card" + ], + "actions": [ + { + "name": "addLabel", + "parameters": { + "label": "Needs UX Triage" + } + } + ], + "taskName": "Add \"Needs UX Triage\" on PRs" + } + }, + { + "taskType": "trigger", + "capabilityId": "IssueResponder", + "subCapability": "PullRequestResponder", + "version": "1.0", + "config": { + "conditions": { + "operator": "and", + "operands": [ + { + "operator": "or", + "operands": [ + { + "name": "prTargetsBranch", + "parameters": { + "branchName": "release/16.11-vs-deps" + } + }, + { + "name": "prTargetsBranch", + "parameters": { + "branchName": "release/17.0-vs-deps" + } + }, + { + "name": "prTargetsBranch", + "parameters": { + "branchName": "release/17.1" + } + }, + { + "name": "prTargetsBranch", + "parameters": { + "branchName": "release/17.1-vs-deps" + } + }, + { + "name": "prTargetsBranch", + "parameters": { + "branchName": "release/17.2" + } + }, + { + "name": "prTargetsBranch", + "parameters": { + "branchName": "release/17.3" + } + }, + { + "name": "prTargetsBranch", + "parameters": { + "branchName": "release/17.4" + } + }, + { + "name": "prTargetsBranch", + "parameters": { + "branchName": "release/17.5" + } + }, + { + "name": "prTargetsBranch", + "parameters": { + "branchName": "release/17.6" + } + }, + { + "name": "prTargetsBranch", + "parameters": { + "branchName": "release/17.7" + } + }, + { + "name": "prTargetsBranch", + "parameters": { + "branchName": "release/17.8" + } + } + ] + }, + { + "operator": "and", + "operands": [ + { + "operator": "not", + "operands": [ + { + "name": "isActivitySender", + "parameters": { + "user": "dotnet-bot" + } + } + ] + }, + { + "operator": "not", + "operands": [ + { + "name": "hasLabel", + "parameters": { + "label": "infraswat-approved" + } + } + ] + } + ] + } + ] + }, + "eventType": "pull_request", + "eventNames": [ + "pull_request", + "issues", + "project_card" + ], + "taskName": "Require InfraSwat approval on PRs to release branches", + "actions": [ + { + "name": "requestReviewer", + "parameters": { + "comment": "InfraSwat needs to sign off on PRs to release branches.", + "reRequest": true, + "reviewer": "@dotnet/roslyn-infrastructure" + } + }, + { + "name": "requestChangesPullRequest", + "parameters": { + "comment": "InfraSwat needs to sign off on PRs to release branches." + } + } + ] + }, + "disabled": true + }, + { + "taskType": "trigger", + "capabilityId": "IssueResponder", + "subCapability": "PullRequestResponder", + "version": "1.0", + "config": { + "conditions": { + "operator": "and", + "operands": [ + { + "name": "labelAdded", + "parameters": { + "label": "infraswat-approved" + } + }, + { + "operator": "or", + "operands": [ + { + "name": "prTargetsBranch", + "parameters": { + "branchName": "release/16.11-vs-deps" + } + }, + { + "name": "prTargetsBranch", + "parameters": { + "branchName": "release/17.0-vs-deps" + } + }, + { + "name": "prTargetsBranch", + "parameters": { + "branchName": "release/17.1" + } + }, + { + "name": "prTargetsBranch", + "parameters": { + "branchName": "release/17.1-vs-deps" + } + }, + { + "name": "prTargetsBranch", + "parameters": { + "branchName": "release/17.2" + } + }, + { + "name": "prTargetsBranch", + "parameters": { + "branchName": "release/17.3" + } + }, + { + "name": "prTargetsBranch", + "parameters": { + "branchName": "release/17.4" + } + }, + { + "name": "prTargetsBranch", + "parameters": { + "branchName": "release/17.5" + } + }, + { + "name": "prTargetsBranch", + "parameters": { + "branchName": "release/17.6" + } + }, + { + "name": "prTargetsBranch", + "parameters": { + "branchName": "release/17.7" + } + }, + { + "name": "prTargetsBranch", + "parameters": { + "branchName": "release/17.8" + } + } + ] + } + ] + }, + "eventType": "pull_request", + "eventNames": [ + "pull_request", + "issues", + "project_card" + ], + "actions": [ + { + "name": "approvePullRequest", + "parameters": { + "comment": "InfraSwat approved the PR." + } + } + ], + "taskName": "Approve PRs to release branches that are approved by InfraSwat" + }, + "disabled": true + }, + { + "taskType": "trigger", + "capabilityId": "IssueResponder", + "subCapability": "PullRequestResponder", + "version": "1.0", + "config": { + "conditions": { + "operator": "and", + "operands": [ + { + "name": "prMatchesPattern", + "parameters": { + "matchRegex": ".*/PublicAPI\\.(Shipped|Unshipped)\\.txt" + } + }, + { + "operator": "not", + "operands": [ + { + "name": "isActivitySender", + "parameters": { + "user": "dotnet-bot" + } + } + ] + }, + { + "operator": "or", + "operands": [ + { + "name": "isAction", + "parameters": { + "action": "opened" + } + }, + { + "name": "isAction", + "parameters": { + "action": "synchronize" + } + } + ] + }, + { + "operator": "and", + "operands": [ + { + "operator": "not", + "operands": [ + { + "name": "hasLabel", + "parameters": { + "label": "api-approved" + } + } + ] + }, + { + "operator": "not", + "operands": [ + { + "name": "hasLabel", + "parameters": { + "label": "Needs API Review" + } + } + ] + } + ] + } + ] + }, + "eventType": "pull_request", + "eventNames": [ + "pull_request", + "issues", + "project_card" + ], + "taskName": "Adds \"Needs API Review\" on PRs that touch public APIs", + "actions": [ + { + "name": "addLabel", + "parameters": { + "label": "Needs API Review" + } + }, + { + "name": "addReply", + "parameters": { + "comment": "This PR modifies public API files. Please follow the instructions at https://github.com/dotnet/roslyn/blob/main/docs/contributing/API%20Review%20Process.md for ensuring all public APIs are reviewed before merging." + } + } + ] + } + }, + { + "taskType": "trigger", + "capabilityId": "IssueResponder", + "subCapability": "IssuesOnlyResponder", + "version": "1.0", + "config": { + "conditions": { + "operator": "and", + "operands": [ + { + "name": "hasLabel", + "parameters": { + "label": "vs-insertion" + } + }, + { + "name": "titleContains", + "parameters": { + "titlePattern": "[Automated] PRs inserted in VS build" + } + } + ] + }, + "eventType": "issue", + "eventNames": [ + "issues", + "project_card" + ], + "taskName": "Close automatically generated PR tagger issues", + "actions": [ + { + "name": "closeIssue", + "parameters": {} + } + ] + } + } + ], + "userGroups": [] +} diff --git a/.vscode/settings.json b/.vscode/settings.json index 33f395601404b..626dc50731467 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -22,7 +22,7 @@ "*.yml": "azure-pipelines" }, // ms-dotnettools.csharp settings - "omnisharp.defaultLaunchSolution": "Compilers.sln", + "omnisharp.defaultLaunchSolution": "Roslyn.sln", "omnisharp.disableMSBuildDiagnosticWarning": true, "omnisharp.enableEditorConfigSupport": true, "omnisharp.enableImportCompletion": true, diff --git a/Compilers.sln b/Compilers.sln index c27f64deec044..44db2147d97a6 100644 --- a/Compilers.sln +++ b/Compilers.sln @@ -160,35 +160,9 @@ Project("{D954291E-2A0B-460D-934E-DC6B0785DB48}") = "VbcCommandLine", "src\Compi EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "vbc-arm64", "src\Compilers\VisualBasic\vbc\arm64\vbc-arm64.csproj", "{48C93F90-8776-4847-96D8-127B896D6C80}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.CodeAnalysis.CSharp.EndToEnd.UnitTests", "src\Compilers\CSharp\Test\EndToEnd\Microsoft.CodeAnalysis.CSharp.EndToEnd.UnitTests.csproj", "{F3D9264A-7CAE-4265-AF48-0C863301F51E}" +EndProject Global - GlobalSection(SharedMSBuildProjectFiles) = preSolution - 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\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\Compilers\VisualBasic\vbc\VbcCommandLine.projitems*{48c93f90-8776-4847-96d8-127b896d6c80}*SharedItemsImports = 5 - src\Compilers\CSharp\csc\CscCommandLine.projitems*{4b45ca0c-03a0-400f-b454-3d4bcb16af38}*SharedItemsImports = 5 - src\Compilers\CSharp\CSharpAnalyzerDriver\CSharpAnalyzerDriver.projitems*{54e08bf5-f819-404f-a18d-0ab9ea81ea04}*SharedItemsImports = 13 - src\Workspaces\SharedUtilitiesAndExtensions\Compiler\VisualBasic\VisualBasicCompilerExtensions.projitems*{57ca988d-f010-4bf2-9a2e-07d6dcd2ff2c}*SharedItemsImports = 5 - src\Workspaces\SharedUtilitiesAndExtensions\Workspace\VisualBasic\VisualBasicWorkspaceExtensions.projitems*{57ca988d-f010-4bf2-9a2e-07d6dcd2ff2c}*SharedItemsImports = 5 - src\Dependencies\Collections\Microsoft.CodeAnalysis.Collections.projitems*{5f8d2414-064a-4b3a-9b42-8e2a04246be5}*SharedItemsImports = 5 - src\Dependencies\PooledObjects\Microsoft.CodeAnalysis.PooledObjects.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\Compilers\Server\VBCSCompiler\VBCSCompilerCommandLine.projitems*{869e3b79-4e91-45fd-ba37-56dbd2f34721}*SharedItemsImports = 5 - src\Compilers\Server\VBCSCompiler\VBCSCompilerCommandLine.projitems*{9508f118-f62e-4c16-a6f4-7c3b56e166ad}*SharedItemsImports = 5 - src\Compilers\CSharp\CSharpAnalyzerDriver\CSharpAnalyzerDriver.projitems*{b501a547-c911-4a05-ac6e-274a50dff30e}*SharedItemsImports = 5 - src\Compilers\CSharp\csc\CscCommandLine.projitems*{b5a27411-77ff-4c43-b0e3-fe09fba5f887}*SharedItemsImports = 5 - src\Dependencies\PooledObjects\Microsoft.CodeAnalysis.PooledObjects.projitems*{c1930979-c824-496b-a630-70f5369a636f}*SharedItemsImports = 13 - src\Compilers\Core\AnalyzerDriver\AnalyzerDriver.projitems*{d0bc9be7-24f6-40ca-8dc6-fcb93bd44b34}*SharedItemsImports = 13 - src\Dependencies\CodeAnalysis.Debugging\Microsoft.CodeAnalysis.Debugging.projitems*{d73adf7d-2c1c-42ae-b2ab-edc9497e4b71}*SharedItemsImports = 13 - src\Compilers\VisualBasic\vbc\VbcCommandLine.projitems*{e58ee9d7-1239-4961-a0c1-f9ec3952c4c1}*SharedItemsImports = 5 - src\Compilers\VisualBasic\BasicAnalyzerDriver\BasicAnalyzerDriver.projitems*{e8f0baa5-7327-43d1-9a51-644e81ae55f1}*SharedItemsImports = 13 - src\Dependencies\Collections\Microsoft.CodeAnalysis.Collections.projitems*{e919dd77-34f8-4f57-8058-4d3ff4c2b241}*SharedItemsImports = 13 - EndGlobalSection GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU Release|Any CPU = Release|Any CPU @@ -438,6 +412,10 @@ Global {48C93F90-8776-4847-96D8-127B896D6C80}.Debug|Any CPU.Build.0 = Debug|Any CPU {48C93F90-8776-4847-96D8-127B896D6C80}.Release|Any CPU.ActiveCfg = Release|Any CPU {48C93F90-8776-4847-96D8-127B896D6C80}.Release|Any CPU.Build.0 = Release|Any CPU + {F3D9264A-7CAE-4265-AF48-0C863301F51E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {F3D9264A-7CAE-4265-AF48-0C863301F51E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {F3D9264A-7CAE-4265-AF48-0C863301F51E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {F3D9264A-7CAE-4265-AF48-0C863301F51E}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -512,8 +490,40 @@ Global {869E3B79-4E91-45FD-BA37-56DBD2F34721} = {E35DA3D1-16C0-4318-9187-6B664F12A870} {810B02AD-2EA5-4422-88AC-B71B8AB0DF0B} = {C65C6143-BED3-46E6-869E-9F0BE6E84C37} {48C93F90-8776-4847-96D8-127B896D6C80} = {C65C6143-BED3-46E6-869E-9F0BE6E84C37} + {F3D9264A-7CAE-4265-AF48-0C863301F51E} = {32A48625-F0AD-419D-828B-A50BDABA38EA} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {6F599E08-A9EA-4FAA-897F-5D824B0210E6} EndGlobalSection + GlobalSection(SharedMSBuildProjectFiles) = preSolution + 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\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\Compilers\VisualBasic\vbc\VbcCommandLine.projitems*{48c93f90-8776-4847-96d8-127b896d6c80}*SharedItemsImports = 5 + src\Compilers\CSharp\csc\CscCommandLine.projitems*{4b45ca0c-03a0-400f-b454-3d4bcb16af38}*SharedItemsImports = 5 + src\Compilers\CSharp\CSharpAnalyzerDriver\CSharpAnalyzerDriver.projitems*{54e08bf5-f819-404f-a18d-0ab9ea81ea04}*SharedItemsImports = 13 + src\Workspaces\SharedUtilitiesAndExtensions\Compiler\VisualBasic\VisualBasicCompilerExtensions.projitems*{57ca988d-f010-4bf2-9a2e-07d6dcd2ff2c}*SharedItemsImports = 5 + src\Workspaces\SharedUtilitiesAndExtensions\Workspace\VisualBasic\VisualBasicWorkspaceExtensions.projitems*{57ca988d-f010-4bf2-9a2e-07d6dcd2ff2c}*SharedItemsImports = 5 + src\Dependencies\Collections\Microsoft.CodeAnalysis.Collections.projitems*{5f8d2414-064a-4b3a-9b42-8e2a04246be5}*SharedItemsImports = 5 + src\Dependencies\PooledObjects\Microsoft.CodeAnalysis.PooledObjects.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\Compilers\VisualBasic\vbc\VbcCommandLine.projitems*{810b02ad-2ea5-4422-88ac-b71b8ab0df0b}*SharedItemsImports = 13 + src\Compilers\Server\VBCSCompiler\VBCSCompilerCommandLine.projitems*{869e3b79-4e91-45fd-ba37-56dbd2f34721}*SharedItemsImports = 5 + src\Compilers\Server\VBCSCompiler\VBCSCompilerCommandLine.projitems*{9508f118-f62e-4c16-a6f4-7c3b56e166ad}*SharedItemsImports = 5 + src\Compilers\CSharp\csc\CscCommandLine.projitems*{b021ccbc-b2af-4560-af28-ed055f0ed696}*SharedItemsImports = 13 + src\Compilers\CSharp\CSharpAnalyzerDriver\CSharpAnalyzerDriver.projitems*{b501a547-c911-4a05-ac6e-274a50dff30e}*SharedItemsImports = 5 + src\Compilers\CSharp\csc\CscCommandLine.projitems*{b5a27411-77ff-4c43-b0e3-fe09fba5f887}*SharedItemsImports = 5 + src\Dependencies\PooledObjects\Microsoft.CodeAnalysis.PooledObjects.projitems*{c1930979-c824-496b-a630-70f5369a636f}*SharedItemsImports = 13 + src\Compilers\Core\AnalyzerDriver\AnalyzerDriver.projitems*{d0bc9be7-24f6-40ca-8dc6-fcb93bd44b34}*SharedItemsImports = 13 + 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\Compilers\VisualBasic\vbc\VbcCommandLine.projitems*{e58ee9d7-1239-4961-a0c1-f9ec3952c4c1}*SharedItemsImports = 5 + src\Compilers\VisualBasic\BasicAnalyzerDriver\BasicAnalyzerDriver.projitems*{e8f0baa5-7327-43d1-9a51-644e81ae55f1}*SharedItemsImports = 13 + src\Dependencies\Collections\Microsoft.CodeAnalysis.Collections.projitems*{e919dd77-34f8-4f57-8058-4d3ff4c2b241}*SharedItemsImports = 13 + EndGlobalSection EndGlobal diff --git a/Compilers.slnf b/Compilers.slnf index f22d85e972676..26e6beb9d51ba 100644 --- a/Compilers.slnf +++ b/Compilers.slnf @@ -7,6 +7,7 @@ "src\\Compilers\\CSharp\\Test\\CommandLine\\Microsoft.CodeAnalysis.CSharp.CommandLine.UnitTests.csproj", "src\\Compilers\\CSharp\\Test\\Emit\\Microsoft.CodeAnalysis.CSharp.Emit.UnitTests.csproj", "src\\Compilers\\CSharp\\Test\\Emit2\\Microsoft.CodeAnalysis.CSharp.Emit2.UnitTests.csproj", + "src\\Compilers\\CSharp\\Test\\EndToEnd\\Microsoft.CodeAnalysis.CSharp.EndToEnd.UnitTests.csproj", "src\\Compilers\\CSharp\\Test\\IOperation\\Microsoft.CodeAnalysis.CSharp.IOperation.UnitTests.csproj", "src\\Compilers\\CSharp\\Test\\Semantic\\Microsoft.CodeAnalysis.CSharp.Semantic.UnitTests.csproj", "src\\Compilers\\CSharp\\Test\\Symbol\\Microsoft.CodeAnalysis.CSharp.Symbol.UnitTests.csproj", diff --git a/Roslyn.sln b/Roslyn.sln index 61c8682f2503f..7b3342cc3ad33 100644 --- a/Roslyn.sln +++ b/Roslyn.sln @@ -509,6 +509,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Net.Compilers.Too EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Net.Compilers.Toolset.Package.Arm64", "src\NuGet\Microsoft.Net.Compilers.Toolset\arm64\Microsoft.Net.Compilers.Toolset.Package.Arm64.csproj", "{A9A8ADE5-F123-4109-9FA4-4B92F1657043}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.CodeAnalysis.CSharp.EndToEnd.UnitTests", "src\Compilers\CSharp\Test\EndToEnd\Microsoft.CodeAnalysis.CSharp.EndToEnd.UnitTests.csproj", "{C247414A-8946-4BAB-BE1F-C82B90C63EF6}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -1235,6 +1237,10 @@ Global {A9A8ADE5-F123-4109-9FA4-4B92F1657043}.Debug|Any CPU.Build.0 = Debug|Any CPU {A9A8ADE5-F123-4109-9FA4-4B92F1657043}.Release|Any CPU.ActiveCfg = Release|Any CPU {A9A8ADE5-F123-4109-9FA4-4B92F1657043}.Release|Any CPU.Build.0 = Release|Any CPU + {C247414A-8946-4BAB-BE1F-C82B90C63EF6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C247414A-8946-4BAB-BE1F-C82B90C63EF6}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C247414A-8946-4BAB-BE1F-C82B90C63EF6}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C247414A-8946-4BAB-BE1F-C82B90C63EF6}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -1466,6 +1472,7 @@ Global {46429C41-0733-4568-9BA6-3F52CB47C4ED} = {BE25E872-1667-4649-9D19-96B83E75A44E} {6131713D-DFB4-49B5-8010-50071FED3E85} = {C52D8057-43AF-40E6-A01B-6CDBB7301985} {A9A8ADE5-F123-4109-9FA4-4B92F1657043} = {C52D8057-43AF-40E6-A01B-6CDBB7301985} + {C247414A-8946-4BAB-BE1F-C82B90C63EF6} = {32A48625-F0AD-419D-828B-A50BDABA38EA} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {604E6B91-7BC0-4126-AE07-D4D2FEFC3D29} @@ -1512,6 +1519,7 @@ Global 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\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\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\Compilers\VisualBasic\vbc\VbcCommandLine.projitems*{975cd834-45f4-4ea0-a395-cb60dbd0e214}*SharedItemsImports = 5 @@ -1527,6 +1535,7 @@ Global src\ExpressionEvaluator\Core\Source\ResultProvider\ResultProvider.projitems*{abdbac1e-350e-4dc3-bb45-3504404545ee}*SharedItemsImports = 5 src\Analyzers\CSharp\Tests\CSharpAnalyzers.UnitTests.projitems*{ac2bcefb-9298-4621-ac48-1ff5e639e48d}*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\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\ExpressionEvaluator\CSharp\Source\ResultProvider\CSharpResultProvider.projitems*{bf9dac1e-3a5e-4dc3-bb44-9a64e0d4e9d4}*SharedItemsImports = 5 @@ -1534,6 +1543,7 @@ Global 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\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\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 diff --git a/THIRD-PARTY-NOTICES.txt b/THIRD-PARTY-NOTICES.txt index 30ed202c8ebe0..e503d0dd40274 100644 --- a/THIRD-PARTY-NOTICES.txt +++ b/THIRD-PARTY-NOTICES.txt @@ -109,3 +109,17 @@ Permission is hereby granted, free of charge, to any person obtaining a copy of The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +MSBuild Structured Logging +------------------------------------- + +https://github.com/KirillOsenkov/MSBuildStructuredLog + +Copyright (c) 2016 Kirill Osenkov + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/azure-pipelines-integration-dartlab.yml b/azure-pipelines-integration-dartlab.yml index 18cb4a8407b4e..31805fb89834a 100644 --- a/azure-pipelines-integration-dartlab.yml +++ b/azure-pipelines-integration-dartlab.yml @@ -68,4 +68,4 @@ stages: configuration: $(_configuration) oop64bit: $(_oop64bit) lspEditor: false - shallowCheckout: false + skipCheckout: true diff --git a/azure-pipelines-integration-lsp.yml b/azure-pipelines-integration-lsp.yml index cbeb5d90e1016..3ef2baafb6722 100644 --- a/azure-pipelines-integration-lsp.yml +++ b/azure-pipelines-integration-lsp.yml @@ -37,12 +37,14 @@ pr: variables: - name: XUNIT_LOGS value: $(Build.SourcesDirectory)\artifacts\log\$(_configuration) +- name: queueName + value: windows.vs2022preview.amd64.open jobs: - job: VS_Integration_LSP pool: - name: NetCore-Svc-Public - demands: ImageOverride -equals windows.vs2022.amd64.open + name: NetCore-Public + demands: ImageOverride -equals $(queueName) timeoutInMinutes: 150 steps: diff --git a/azure-pipelines-integration.yml b/azure-pipelines-integration.yml index 587bdfee75708..c1ab876f20468 100644 --- a/azure-pipelines-integration.yml +++ b/azure-pipelines-integration.yml @@ -36,22 +36,41 @@ pr: - eng/config/PublishData.json - .vscode/* - .github/* - - .devcontainer/ + - .devcontainer/* - .git-blame-ignore-revs - .vsconfig - CODE-OF-CONDUCT.md - CONTRIBUTING.md - README.md + - src/Compilers/* variables: - name: poolName value: NetCore-Svc-Public - name: queueName - value: windows.vs2022.amd64.open + value: windows.vs2022preview.amd64.open -jobs: -- ${{ if ne(variables['Build.Reason'], 'PullRequest') }}: - - job: VS_Integration_Debug_32 +stages: +- stage: Debug_Integration + dependsOn: [] + jobs: + - ${{ if ne(variables['Build.Reason'], 'PullRequest') }}: + - job: VS_Integration_Debug_32 + pool: + name: $(poolName) + demands: ImageOverride -equals $(queueName) + timeoutInMinutes: 150 + variables: + - name: XUNIT_LOGS + value: $(Build.SourcesDirectory)\artifacts\log\Debug + steps: + - template: eng/pipelines/test-integration-job.yml + parameters: + configuration: Debug + oop64bit: false + lspEditor: false + + - job: VS_Integration_Debug_64 pool: name: $(poolName) demands: ImageOverride -equals $(queueName) @@ -63,41 +82,13 @@ jobs: - template: eng/pipelines/test-integration-job.yml parameters: configuration: Debug - oop64bit: false + oop64bit: true lspEditor: false -- job: VS_Integration_Debug_64 - pool: - name: $(poolName) - demands: ImageOverride -equals $(queueName) - timeoutInMinutes: 150 - variables: - - name: XUNIT_LOGS - value: $(Build.SourcesDirectory)\artifacts\log\Debug - steps: - - template: eng/pipelines/test-integration-job.yml - parameters: - configuration: Debug - oop64bit: true - lspEditor: false - -- job: VS_Integration_Release_32 - pool: - name: $(poolName) - demands: ImageOverride -equals $(queueName) - timeoutInMinutes: 150 - variables: - - name: XUNIT_LOGS - value: $(Build.SourcesDirectory)\artifacts\log\Release - steps: - - template: eng/pipelines/test-integration-job.yml - parameters: - configuration: Release - oop64bit: false - lspEditor: false - -- ${{ if ne(variables['Build.Reason'], 'PullRequest') }}: - - job: VS_Integration_Release_64 +- stage: Release_Integration + dependsOn: [] + jobs: + - job: VS_Integration_Release_32 pool: name: $(poolName) demands: ImageOverride -equals $(queueName) @@ -109,5 +100,21 @@ jobs: - template: eng/pipelines/test-integration-job.yml parameters: configuration: Release - oop64bit: true + oop64bit: false lspEditor: false + + - ${{ if ne(variables['Build.Reason'], 'PullRequest') }}: + - job: VS_Integration_Release_64 + pool: + name: $(poolName) + demands: ImageOverride -equals $(queueName) + timeoutInMinutes: 150 + variables: + - name: XUNIT_LOGS + value: $(Build.SourcesDirectory)\artifacts\log\Release + steps: + - template: eng/pipelines/test-integration-job.yml + parameters: + configuration: Release + oop64bit: true + lspEditor: false diff --git a/azure-pipelines-richnav.yml b/azure-pipelines-richnav.yml index 2c48aa5aeb865..242d4dfbce7a8 100644 --- a/azure-pipelines-richnav.yml +++ b/azure-pipelines-richnav.yml @@ -19,8 +19,8 @@ pr: none jobs: - job: RichCodeNav_Indexing pool: - name: NetCore-Svc-Public - demands: ImageOverride -equals windows.vs2022.amd64.open + name: NetCore-Public + demands: ImageOverride -equals windows.vs2022preview.amd64.open variables: EnableRichCodeNavigation: true timeoutInMinutes: 260 diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 02a354bd4b4e4..2e478f2487f2c 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -28,243 +28,327 @@ pr: - CONTRIBUTING.md - README.md -# Windows Build and Test Jobs -jobs: -- template: eng/pipelines/build-windows-job.yml - parameters: - jobName: Build_Windows_Debug - testArtifactName: Transport_Artifacts_Windows_Debug - configuration: Debug - queueName: windows.vs2022.amd64.open - -- template: eng/pipelines/build-windows-job.yml - parameters: - jobName: Build_Windows_Release - testArtifactName: Transport_Artifacts_Windows_Release - configuration: Release - queueName: windows.vs2022.amd64.open - -- ${{ if ne(variables['Build.Reason'], 'PullRequest') }}: - - template: eng/pipelines/test-windows-job.yml +stages: +- stage: Windows_Debug_Build + dependsOn: [] + jobs: + - template: eng/pipelines/build-windows-job.yml parameters: - testRunName: 'Test Windows Desktop Debug 32' - jobName: Test_Windows_Desktop_Debug_32 - buildJobName: Build_Windows_Debug + jobName: Build_Windows_Debug testArtifactName: Transport_Artifacts_Windows_Debug configuration: Debug - testArguments: -testDesktop -testArch x86 + queueName: windows.vs2022preview.amd64.open + restoreArguments: -msbuildEngine dotnet /p:UsingToolPdbConverter=false /p:UsingToolVSSDK=false /p:GenerateSatelliteAssemblies=false + buildArguments: -msbuildEngine dotnet /p:UsingToolPdbConverter=false /p:UsingToolVSSDK=false /p:GenerateSatelliteAssemblies=false /p:PublishReadyToRun=false + +- stage: Windows_Release_Build + dependsOn: [] + jobs: + - template: eng/pipelines/build-windows-job.yml + parameters: + jobName: Build_Windows_Release + testArtifactName: Transport_Artifacts_Windows_Release + configuration: Release + queueName: windows.vs2022preview.amd64.open + restoreArguments: -msbuildEngine dotnet /p:UsingToolPdbConverter=false /p:UsingToolVSSDK=false /p:GenerateSatelliteAssemblies=false + buildArguments: -msbuildEngine dotnet /p:UsingToolPdbConverter=false /p:UsingToolVSSDK=false /p:GenerateSatelliteAssemblies=false /p:PublishReadyToRun=false + +- stage: Unix_Build + dependsOn: [] + jobs: + - template: eng/pipelines/build-unix-job.yml + parameters: + jobName: Build_Unix_Debug + testArtifactName: Transport_Artifacts_Unix_Debug + configuration: Debug + queueName: Build.Ubuntu.1804.Amd64.Open + +- stage: Source_Build + dependsOn: [] + jobs: + - template: eng/common/templates/jobs/source-build.yml -- template: eng/pipelines/test-windows-job.yml - parameters: - testRunName: 'Test Windows Desktop Debug 64' - jobName: Test_Windows_Desktop_Debug_64 - buildJobName: Build_Windows_Debug - testArtifactName: Transport_Artifacts_Windows_Debug - configuration: Debug - testArguments: -testDesktop -testArch x64 - -- template: eng/pipelines/test-windows-job.yml - parameters: - testRunName: 'Test Windows CoreClr Debug' - jobName: Test_Windows_CoreClr_Debug - buildJobName: Build_Windows_Debug - testArtifactName: Transport_Artifacts_Windows_Debug - configuration: Debug - testArguments: -testCoreClr - -- ${{ if ne(variables['Build.Reason'], 'PullRequest') }}: - - template: eng/pipelines/test-windows-job-single-machine.yml +- stage: Windows_Debug_Desktop + dependsOn: Windows_Debug_Build + jobs: + - ${{ if ne(variables['Build.Reason'], 'PullRequest') }}: + - template: eng/pipelines/test-windows-job.yml + parameters: + testRunName: 'Test Windows Desktop Debug 32' + jobName: Test_Windows_Desktop_Debug_32 + testArtifactName: Transport_Artifacts_Windows_Debug + configuration: Debug + testArguments: -testDesktop -testArch x86 + + - template: eng/pipelines/test-windows-job.yml parameters: - testRunName: 'Test Windows CoreClr Debug Single Machine' - jobName: Test_Windows_CoreClr_Debug_Single_Machine - buildJobName: Build_Windows_Debug + testRunName: 'Test Windows Desktop Debug 64' + jobName: Test_Windows_Desktop_Debug_64 testArtifactName: Transport_Artifacts_Windows_Debug configuration: Debug - testArguments: -testCoreClr + testArguments: -testDesktop -testArch x64 -- template: eng/pipelines/test-windows-job.yml - parameters: - testRunName: 'Test Windows Desktop Release 32' - jobName: Test_Windows_Desktop_Release_32 - buildJobName: Build_Windows_Release - testArtifactName: Transport_Artifacts_Windows_Release - configuration: Release - testArguments: -testDesktop -testArch x86 - -- template: eng/pipelines/test-windows-job.yml - parameters: - testRunName: 'Test Windows Desktop Spanish Release 64' - jobName: Test_Windows_Desktop_Spanish_Release_64 - buildJobName: Build_Windows_Release - testArtifactName: Transport_Artifacts_Windows_Release - configuration: Release - testArguments: -testDesktop -testArch x64 -helixQueueName Windows.10.Amd64.Server2022.ES.Open - -- ${{ if ne(variables['Build.Reason'], 'PullRequest') }}: +- stage: Windows_Release_Desktop + dependsOn: Windows_Release_Build + jobs: - template: eng/pipelines/test-windows-job.yml parameters: - testRunName: 'Test Windows Desktop Release 64' - jobName: Test_Windows_Desktop_Release_64 - buildJobName: Build_Windows_Release + testRunName: 'Test Windows Desktop Release 32' + jobName: Test_Windows_Desktop_Release_32 testArtifactName: Transport_Artifacts_Windows_Release configuration: Release - testArguments: -testDesktop -testArch x64 + testArguments: -testDesktop -testArch x86 + + - ${{ if ne(variables['Build.Reason'], 'PullRequest') }}: + - template: eng/pipelines/test-windows-job.yml + parameters: + testRunName: 'Test Windows Desktop Release 64' + jobName: Test_Windows_Desktop_Release_64 + testArtifactName: Transport_Artifacts_Windows_Release + configuration: Release + testArguments: -testDesktop -testArch x64 -- template: eng/pipelines/test-windows-job.yml - parameters: - testRunName: 'Test Windows CoreClr Release' - jobName: Test_Windows_CoreClr_Release - buildJobName: Build_Windows_Release - testArtifactName: Transport_Artifacts_Windows_Release - configuration: Release - testArguments: -testCoreClr - -- template: eng/pipelines/test-windows-job.yml - parameters: - testRunName: 'Test Windows CoreCLR IOperation Debug' - jobName: Test_Windows_CoreClr_IOperation_Debug - buildJobName: Build_Windows_Debug - testArtifactName: Transport_Artifacts_Windows_Debug - configuration: Debug - testArguments: -testCoreClr -testIOperation -testCompilerOnly - -# This leg runs almost all the compiler tests supported on CoreCLR, but -# with additional validation for used assemblies and GetEmitDiagnostics -- template: eng/pipelines/test-windows-job.yml - parameters: - testRunName: 'Test Windows CoreCLR UsedAssemblies Debug' - jobName: Test_Windows_CoreClr_UsedAssemblies_Debug - buildJobName: Build_Windows_Debug - testArtifactName: Transport_Artifacts_Windows_Debug - configuration: Debug - testArguments: -testCoreClr -testUsedAssemblies -testCompilerOnly - -# Unix Build and Test Jobs -- template: eng/pipelines/build-unix-job.yml - parameters: - jobName: Build_Unix_Debug - testArtifactName: Transport_Artifacts_Unix_Debug - configuration: Debug - queueName: Build.Ubuntu.1804.Amd64.Open - -- template: eng/pipelines/test-unix-job.yml - parameters: - testRunName: 'Test Linux Debug' - jobName: Test_Linux_Debug - buildJobName: Build_Unix_Debug - testArtifactName: Transport_Artifacts_Unix_Debug - configuration: Debug - testArguments: --testCoreClr --helixQueueName Ubuntu.1804.Amd64.Open - -- ${{ if ne(variables['Build.Reason'], 'PullRequest') }}: - - template: eng/pipelines/test-unix-job-single-machine.yml + - template: eng/pipelines/test-windows-job.yml parameters: - testRunName: 'Test Linux Debug Single Machine' - jobName: Test_Linux_Debug_Single_Machine - buildJobName: Build_Unix_Debug - testArtifactName: Transport_Artifacts_Unix_Debug + testRunName: 'Test Windows Desktop Spanish Release 64' + jobName: Test_Windows_Desktop_Spanish_Release_64 + testArtifactName: Transport_Artifacts_Windows_Release + configuration: Release + testArguments: -testDesktop -testArch x64 -helixQueueName Windows.10.Amd64.Server2022.ES.Open + +- stage: Windows_Debug_CoreClr + dependsOn: Windows_Debug_Build + jobs: + - template: eng/pipelines/test-windows-job.yml + parameters: + testRunName: 'Test Windows CoreClr Debug' + jobName: Test_Windows_CoreClr_Debug + testArtifactName: Transport_Artifacts_Windows_Debug configuration: Debug - testArguments: --testCoreClr - queueName: Build.Ubuntu.1804.Amd64.Open + testArguments: -testCoreClr -- template: eng/pipelines/test-unix-job.yml - parameters: - testRunName: 'Test macOS Debug' - jobName: Test_macOS_Debug - buildJobName: Build_Unix_Debug - testArtifactName: Transport_Artifacts_Unix_Debug - configuration: Debug - testArguments: --testCoreClr --helixQueueName OSX.1015.Amd64.Open + - ${{ if ne(variables['Build.Reason'], 'PullRequest') }}: + - template: eng/pipelines/test-windows-job-single-machine.yml + parameters: + testRunName: 'Test Windows CoreClr Debug Single Machine' + jobName: Test_Windows_CoreClr_Debug_Single_Machine + testArtifactName: Transport_Artifacts_Windows_Debug + configuration: Debug + testArguments: -testCoreClr -- template: eng/common/templates/jobs/source-build.yml + - template: eng/pipelines/test-windows-job.yml + parameters: + testRunName: 'Test Windows CoreCLR IOperation Debug' + jobName: Test_Windows_CoreClr_IOperation_Debug + testArtifactName: Transport_Artifacts_Windows_Debug + configuration: Debug + testArguments: -testCoreClr -testIOperation -testCompilerOnly -# Build Correctness Jobs + # This leg runs almost all the compiler tests supported on CoreCLR, but + # with additional validation for used assemblies and GetEmitDiagnostics + - template: eng/pipelines/test-windows-job.yml + parameters: + testRunName: 'Test Windows CoreCLR UsedAssemblies Debug' + jobName: Test_Windows_CoreClr_UsedAssemblies_Debug + testArtifactName: Transport_Artifacts_Windows_Debug + configuration: Debug + testArguments: -testCoreClr -testUsedAssemblies -testCompilerOnly -- job: Correctness_Determinism - pool: - name: NetCore-Svc-Public - demands: ImageOverride -equals windows.vs2022.amd64.open - timeoutInMinutes: 90 - steps: - - template: eng/pipelines/checkout-windows-task.yml +- stage: Windows_Release_CoreClr + dependsOn: Windows_Release_Build + jobs: + - template: eng/pipelines/test-windows-job.yml + parameters: + testRunName: 'Test Windows CoreClr Release' + jobName: Test_Windows_CoreClr_Release + testArtifactName: Transport_Artifacts_Windows_Release + configuration: Release + testArguments: -testCoreClr - - script: eng/test-determinism.cmd -configuration Debug - displayName: Build - Validate determinism +- stage: Unix_Debug_CoreClr + dependsOn: Unix_Build + jobs: + - template: eng/pipelines/test-unix-job.yml + parameters: + testRunName: 'Test Linux Debug' + jobName: Test_Linux_Debug + testArtifactName: Transport_Artifacts_Unix_Debug + configuration: Debug + testArguments: --testCoreClr --helixQueueName Ubuntu.1804.Amd64.Open - - template: eng/pipelines/publish-logs.yml + - ${{ if ne(variables['Build.Reason'], 'PullRequest') }}: + - template: eng/pipelines/test-unix-job-single-machine.yml parameters: - jobName: Correctness_Determinism + testRunName: 'Test Linux Debug Single Machine' + jobName: Test_Linux_Debug_Single_Machine + testArtifactName: Transport_Artifacts_Unix_Debug configuration: Debug + testArguments: --testCoreClr + queueName: Build.Ubuntu.1804.Amd64.Open -- job: Correctness_Build - pool: - name: NetCore-Svc-Public - demands: ImageOverride -equals windows.vs2022.amd64.open - timeoutInMinutes: 90 - steps: - - template: eng/pipelines/checkout-windows-task.yml - - - script: eng/test-build-correctness.cmd -configuration Release -enableDumps - displayName: Build - Validate correctness - - - template: eng/pipelines/publish-logs.yml - parameters: - jobName: Correctness_Build - configuration: Release + - template: eng/pipelines/test-unix-job.yml + parameters: + testRunName: 'Test macOS Debug' + jobName: Test_macOS_Debug + testArtifactName: Transport_Artifacts_Unix_Debug + configuration: Debug + testArguments: --testCoreClr --helixQueueName OSX.1015.Amd64.Open - - task: PublishBuildArtifacts@1 - displayName: Publish Artifact Packages - inputs: - PathtoPublish: '$(Build.SourcesDirectory)\artifacts\packages\Release\PreRelease' - ArtifactName: 'Packages - PreRelease' - publishLocation: Container - condition: succeeded() - - - task: PublishBuildArtifacts@1 - displayName: Publish VSIX Packages - inputs: - PathtoPublish: '$(Build.SourcesDirectory)\artifacts\VSSetup\Release\Installer' - ArtifactName: 'VSIX - PreRelease' - publishLocation: Container - condition: succeeded() - -- job: Correctness_TodoCheck - pool: - vmImage: ubuntu-20.04 - timeoutInMinutes: 10 - steps: - - template: eng/pipelines/checkout-unix-task.yml - - - pwsh: eng/todo-check.ps1 - displayName: Validate TODO/PROTOTYPE comments are not present - -- job: Correctness_Rebuild - pool: - name: NetCore-Svc-Public - demands: ImageOverride -equals windows.vs2022.amd64.open - timeoutInMinutes: 90 - steps: - - template: eng/pipelines/checkout-windows-task.yml - - - task: PowerShell@2 - displayName: Restore - inputs: - filePath: eng/build.ps1 - arguments: -configuration Debug -prepareMachine -ci -restore -binaryLog - - - powershell: .\eng\test-rebuild.ps1 -ci -configuration Release - displayName: Run BuildValidator - - - task: PublishBuildArtifacts@1 - displayName: Publish BuildValidator debug outputs - inputs: - PathtoPublish: '$(Build.SourcesDirectory)/artifacts/BuildValidator' - ArtifactName: 'BuildValidator_DebugOut' - publishLocation: Container - continueOnError: true - condition: failed() - - - template: eng/pipelines/publish-logs.yml - parameters: - jobName: Correctness_Rebuild - configuration: Release +- stage: Correctness + dependsOn: [] + jobs: + - template: eng/pipelines/evaluate-changed-files.yml + parameters: + jobName: Determine_Changes + vmImageName: ubuntu-latest + paths: + - subset: compilers + include: + - src/Compilers/* + - src/Dependencies/* + + - job: Correctness_Build_Artifacts + dependsOn: Determine_Changes + pool: + name: NetCore-Public + demands: ImageOverride -equals windows.vs2022preview.amd64.open + timeoutInMinutes: 90 + variables: + compilerChange: $[dependencies.Determine_Changes.outputs['SetPathVars_compilers.containsChange']] + steps: + - template: eng/pipelines/checkout-windows-task.yml + + - task: PowerShell@2 + displayName: Restore + inputs: + filePath: eng/build.ps1 + arguments: -configuration Release -prepareMachine -ci -restore -binaryLog + + - task: PowerShell@2 + displayName: Build + inputs: + filePath: eng/build.ps1 + arguments: -configuration Release -prepareMachine -ci -build -pack -publish -sign -binaryLog + + - script: $(Build.SourcesDirectory)\artifacts\bin\BuildBoss\Release\net472\BuildBoss.exe -r "$(Build.SourcesDirectory)/" -c Release -p Roslyn.sln + displayName: Validate Build Artifacts + + - task: PowerShell@2 + displayName: Generate Syntax Files + inputs: + filePath: eng/generate-compiler-code.ps1 + arguments: -test -configuration Release + condition: or(ne(variables['Build.Reason'], 'PullRequest'), eq(variables['compilerChange'], 'true')) + + - script: $(Build.SourcesDirectory)\.dotnet\dotnet.exe tool run dotnet-format whitespace $(Build.SourcesDirectory)\src --folder --include-generated --include $(Build.SourcesDirectory)\src\Compilers\CSharp\Portable\Generated\ $(Build.SourcesDirectory)\src\Compilers\VisualBasic\Portable\Generated\ $(Build.SourcesDirectory)\src\ExpressionEvaluator\VisualBasic\Source\ResultProvider\Generated\ --verify-no-changes + displayName: Validate Generated Syntax Files + condition: or(ne(variables['Build.Reason'], 'PullRequest'), eq(variables['compilerChange'], 'true')) + + - template: eng/pipelines/publish-logs.yml + parameters: + jobName: Correctness_Build_Artifacts + configuration: Release + + - job: Correctness_Determinism + dependsOn: Determine_Changes + condition: or(ne(variables['Build.Reason'], 'PullRequest'), eq(dependencies.Determine_Changes.outputs['SetPathVars_compilers.containsChange'], 'true')) + pool: + name: NetCore-Public + demands: ImageOverride -equals windows.vs2022preview.amd64.open + timeoutInMinutes: 90 + steps: + - template: eng/pipelines/checkout-windows-task.yml + + - script: eng/test-determinism.cmd -configuration Debug + displayName: Build - Validate determinism + + - template: eng/pipelines/publish-logs.yml + parameters: + jobName: Correctness_Determinism + configuration: Debug + + - job: Correctness_Bootstrap_Build + dependsOn: Determine_Changes + condition: or(ne(variables['Build.Reason'], 'PullRequest'), eq(dependencies.Determine_Changes.outputs['SetPathVars_compilers.containsChange'], 'true')) + pool: + name: NetCore-Public + demands: ImageOverride -equals windows.vs2022preview.amd64.open + timeoutInMinutes: 90 + steps: + - template: eng/pipelines/checkout-windows-task.yml + + - script: eng/test-build-correctness.cmd -configuration Release -enableDumps + displayName: Build - Validate correctness + + - template: eng/pipelines/publish-logs.yml + parameters: + jobName: Correctness_Bootstrap_Build + configuration: Release + + - task: PublishBuildArtifacts@1 + displayName: Publish Artifact Packages + inputs: + PathtoPublish: '$(Build.SourcesDirectory)\artifacts\packages\Release\PreRelease' + ArtifactName: 'Bootstrap Packages - PreRelease' + publishLocation: Container + + - task: PublishBuildArtifacts@1 + displayName: Publish VSIX Packages + inputs: + PathtoPublish: '$(Build.SourcesDirectory)\artifacts\VSSetup\Release\Installer' + ArtifactName: 'Bootstrap VSIX - PreRelease' + publishLocation: Container + + - job: Correctness_TodoCheck + pool: + vmImage: ubuntu-20.04 + timeoutInMinutes: 10 + steps: + - template: eng/pipelines/checkout-unix-task.yml + + - pwsh: eng/todo-check.ps1 + displayName: Validate TODO/PROTOTYPE comments are not present + + - job: Correctness_Rebuild + dependsOn: Determine_Changes + condition: or(ne(variables['Build.Reason'], 'PullRequest'), eq(dependencies.Determine_Changes.outputs['SetPathVars_compilers.containsChange'], 'true')) + pool: + name: NetCore-Public + demands: ImageOverride -equals windows.vs2022preview.amd64.open + timeoutInMinutes: 90 + steps: + - template: eng/pipelines/checkout-windows-task.yml + + - task: PowerShell@2 + displayName: Restore + inputs: + filePath: eng/build.ps1 + arguments: -configuration Debug -prepareMachine -ci -restore -binaryLog + + - powershell: .\eng\test-rebuild.ps1 -ci -configuration Release + displayName: Run BuildValidator + + - task: PublishBuildArtifacts@1 + displayName: Publish BuildValidator debug outputs + inputs: + PathtoPublish: '$(Build.SourcesDirectory)/artifacts/BuildValidator' + ArtifactName: 'BuildValidator_DebugOut' + publishLocation: Container + continueOnError: true + condition: failed() + + - template: eng/pipelines/publish-logs.yml + parameters: + jobName: Correctness_Rebuild + configuration: Release + + - job: Correctness_Analyzers + pool: + name: NetCore-Public + demands: ImageOverride -equals Build.Ubuntu.1804.Amd64.Open + timeoutInMinutes: 35 + steps: + - template: eng/pipelines/checkout-unix-task.yml + + - script: ./eng/build.sh --solution Roslyn.sln --restore --build --configuration Debug --prepareMachine --ci --binaryLog --runanalyzers --warnaserror /p:RoslynEnforceCodeStyle=true + displayName: Build with analyzers diff --git a/build.sh b/build.sh index b115784de051d..afe6d28e8b413 100755 --- a/build.sh +++ b/build.sh @@ -13,4 +13,4 @@ while [[ -h $source ]]; do done scriptroot="$( cd -P "$( dirname "$source" )" && pwd )" -"$scriptroot/eng/build.sh" --build $@ \ No newline at end of file +"$scriptroot/eng/build.sh" --build --solution Roslyn.sln $@ \ No newline at end of file diff --git a/docs/Language Feature Status.md b/docs/Language Feature Status.md index dfe00e2ce1a66..a10a86fa325f7 100644 --- a/docs/Language Feature Status.md +++ b/docs/Language Feature Status.md @@ -10,6 +10,21 @@ efforts behind them. | Feature | Branch | State | Developer | Reviewer | LDM Champ | | ------- | ------ | ----- | --------- | -------- | --------- | +| [Semi-auto-properties](https://github.com/dotnet/csharplang/issues/140) | [semi-auto-props](https://github.com/dotnet/roslyn/tree/features/semi-auto-props) | [In Progress](https://github.com/dotnet/roslyn/issues/57012) | [Youssef1313](https://github.com/Youssef1313) | [333fred](https://github.com/333fred), [RikkiGibson](https://github.com/RikkiGibson) | [CyrusNajmabadi](https://github.com/CyrusNajmabadi) | +| [Top Level statement attribute specifiers](https://github.com/dotnet/csharplang/issues/5045) | [main-attributes](https://github.com/dotnet/roslyn/tree/features/main-attributes) | [In Progress](https://github.com/dotnet/roslyn/issues/57047) | [chsienki](https://github.com/chsienki) | [cston](https://github.com/cston), [333fred](https://github.com/333fred) | [jaredpar](https://github.com/jaredpar) | +| [Primary Constructors](https://github.com/dotnet/csharplang/issues/2691) | [primary-constructors](https://github.com/dotnet/roslyn/tree/features/primary-constructors) | [In Progress](https://github.com/dotnet/roslyn/issues/57048) | TBD | TBD | [MadsTorgersen](https://github.com/MadsTorgersen) | +| [Params Span\ + Stackalloc any array type](https://github.com/dotnet/csharplang/issues/1757) | [params-span](https://github.com/dotnet/roslyn/tree/features/params-span) | [In Progress](https://github.com/dotnet/roslyn/issues/57049) | [cston](https://github.com/cston) | TBD | [jaredpar](https://github.com/jaredpar) | +| [nameof accessing instance members](https://github.com/dotnet/roslyn/issues/40229) | main | [In Progress](https://github.com/dotnet/roslyn/pull/48754) | [YairHalberstadt ](https://github.com/YairHalberstadt) | [333fred](https://github.com/333fred), [AlekseyTs](https://github.com/AlekseyTs) | [333fred](https://github.com/333fred) | +| [Lambda default parameters](https://github.com/dotnet/csharplang/issues/6051) | [lambda-default-parameters](https://github.com/dotnet/roslyn/tree/features/lambda-default-parameters) | [In Progress](https://github.com/dotnet/roslyn/issues/62485) | [adamperlin](https://github.com/adamperlin) | [333fred](https://github.com/333fred), [cston](https://github.com/cston) | [captainsafia](https://github.com/captainsafia) | +| [Default in deconstruction](https://github.com/dotnet/roslyn/pull/25562) | [decon-default](https://github.com/dotnet/roslyn/tree/features/decon-default) | [In Progress](https://github.com/dotnet/roslyn/issues/25559) | [jcouv](https://github.com/jcouv) | [gafter](https://github.com/gafter) | [jcouv](https://github.com/jcouv) | + +# C# 11.0 + +| Feature | Branch | State | Developer | Reviewer | LDM Champ | +| ------- | ------ | ----- | --------- | -------- | --------- | +| [File-local types](https://github.com/dotnet/csharplang/issues/6011) | [file-types](https://github.com/dotnet/roslyn/tree/features/file-types) | [Merged into 17.4p1](https://github.com/dotnet/roslyn/issues/60819) | [RikkiGibson](https://github.com/RikkiGibson) | [jcouv](https://github.com/jcouv), [cston](https://github.com/cston) | [stephentoub](https://github.com/stephentoub) | +| [ref fields](https://github.com/dotnet/csharplang/blob/main/proposals/low-level-struct-improvements.md) | [ref-fields](https://github.com/dotnet/roslyn/tree/features/ref-fields) | [Merged into 17.3p3](https://github.com/dotnet/roslyn/issues/59194) | [cston](https://github.com/cston) | [RikkiGibson](https://github.com/RikkiGibson), [AlekseyTs](https://github.com/AlekseyTs) | [jaredpar](https://github.com/jaredpar) | +| [Required members](https://github.com/dotnet/csharplang/issues/3630) | main | [Merged into 17.3p2](https://github.com/dotnet/roslyn/issues/57046) | [333fred](https://github.com/333fred) | [jcouv](https://github.com/jcouv), [RikkiGibson](https://github.com/RikkiGibson) | [333fred](https://github.com/333fred) | | [DIM for Static Members](https://github.com/dotnet/csharplang/issues/4436) | [DefaultInterfaceImplementation](https://github.com/dotnet/roslyn/tree/features/DefaultInterfaceImplementation) | [Merged into 17.3p2](https://github.com/dotnet/roslyn/issues/60968) | [AlekseyTs](https://github.com/AlekseyTs) | [333fred](https://github.com/333fred), [jcouv](https://github.com/jcouv) | [MadsTorgersen](https://github.com/MadsTorgersen) | | [Numeric IntPtr](https://github.com/dotnet/csharplang/issues/6065) | [numeric-intptr](https://github.com/dotnet/roslyn/tree/features/numeric-intptr) | [Merged into 17.3p2](https://github.com/dotnet/roslyn/issues/60578) | [jcouv](https://github.com/jcouv) | [cston](https://github.com/cston), [333fred](https://github.com/333fred) | [jcouv](https://github.com/jcouv) | | [Unsigned Right Shift](https://github.com/dotnet/csharplang/issues/4682) | [UnsignedRightShift](https://github.com/dotnet/roslyn/tree/features/UnsignedRightShift) | [Merged into 17.3p1](https://github.com/dotnet/roslyn/issues/60433) | [AlekseyTs](https://github.com/AlekseyTs) | [333fred](https://github.com/333fred), [jcouv](https://github.com/jcouv) | [AlekseyTs](https://github.com/AlekseyTs) | @@ -23,17 +38,7 @@ efforts behind them. | [Cache delegates for static method group](https://github.com/dotnet/roslyn/issues/5835) | main | [Merged into 17.2](https://github.com/dotnet/roslyn/pull/58288) | [pawchen](https://github.com/pawchen) | [AlekseyTs](https://github.com/AlekseyTs), [jcouv](https://github.com/jcouv) | [AlekseyTs](https://github.com/AlekseyTs) | | [nameof(parameter)](https://github.com/dotnet/csharplang/issues/373) | main | [Merged into 17.3p2](https://github.com/dotnet/roslyn/issues/40524) | [jcouv](https://github.com/jcouv) | [AlekseyTs](https://github.com/AlekseyTs), [RikkiGibson](https://github.com/RikkiGibson) | [jcouv](https://github.com/jcouv) | | [Relaxing Shift Operator](https://github.com/dotnet/csharplang/issues/4666) | main | [Merged into 17.3p2](https://github.com/dotnet/roslyn/issues/60967) | [AlekseyTs](https://github.com/AlekseyTs) | [333fred](https://github.com/333fred), [jcouv](https://github.com/jcouv) | [MadsTorgersen](https://github.com/MadsTorgersen) | -| [Relax ordering of `ref` and `partial` modifiers](https://github.com/dotnet/csharplang/issues/946) | [ref-partial](https://github.com/dotnet/roslyn/tree/features/ref-partial) | In Progress | [alrz](https://github.com/alrz) | [gafter](https://github.com/gafter) | [jcouv](https://github.com/jcouv) | | [Generic attributes](https://github.com/dotnet/csharplang/issues/124) | [generic-attributes](https://github.com/dotnet/roslyn/tree/features/generic-attributes) | [Merged into 17.0p4 (preview langver)](https://github.com/dotnet/roslyn/issues/36285) | [AviAvni](https://github.com/AviAvni) | [RikkiGibson](https://github.com/RikkiGibson), [jcouv](https://github.com/jcouv) | [mattwar](https://github.com/mattwar) | -| [Default in deconstruction](https://github.com/dotnet/roslyn/pull/25562) | [decon-default](https://github.com/dotnet/roslyn/tree/features/decon-default) | [Implemented](https://github.com/dotnet/roslyn/issues/25559) | [jcouv](https://github.com/jcouv) | [gafter](https://github.com/gafter) | [jcouv](https://github.com/jcouv) | -| [Semi-auto-properties](https://github.com/dotnet/csharplang/issues/140) | [semi-auto-props](https://github.com/dotnet/roslyn/tree/features/semi-auto-props) | [In Progress](https://github.com/dotnet/roslyn/issues/57012) | [Youssef1313](https://github.com/Youssef1313) | [333fred](https://github.com/333fred), [RikkiGibson](https://github.com/RikkiGibson) | [CyrusNajmabadi](https://github.com/CyrusNajmabadi) | -| [Required members](https://github.com/dotnet/csharplang/issues/3630) | main | [Merged into 17.3p2](https://github.com/dotnet/roslyn/issues/57046) | [333fred](https://github.com/333fred) | [jcouv](https://github.com/jcouv), [RikkiGibson](https://github.com/RikkiGibson) | [333fred](https://github.com/333fred) | -| [Top Level statement attribute specifiers](https://github.com/dotnet/csharplang/issues/5045) | [main-attributes](https://github.com/dotnet/roslyn/tree/features/main-attributes) | [In Progress](https://github.com/dotnet/roslyn/issues/57047) | [chsienki](https://github.com/chsienki) | [cston](https://github.com/cston), [333fred](https://github.com/333fred) | [jaredpar](https://github.com/jaredpar) | -| [Primary Constructors](https://github.com/dotnet/csharplang/issues/2691) | [primary-constructors](https://github.com/dotnet/roslyn/tree/features/primary-constructors) | [In Progress](https://github.com/dotnet/roslyn/issues/57048) | TBD | TBD | [MadsTorgersen](https://github.com/MadsTorgersen) | -| [Params Span\ + Stackalloc any array type](https://github.com/dotnet/csharplang/issues/1757) | [params-span](https://github.com/dotnet/roslyn/tree/features/params-span) | [In Progress](https://github.com/dotnet/roslyn/issues/57049) | [cston](https://github.com/cston) | TBD | [jaredpar](https://github.com/jaredpar) | -| [nameof accessing instance members](https://github.com/dotnet/roslyn/issues/40229) | main | [In Progress](https://github.com/dotnet/roslyn/pull/48754) | [YairHalberstadt ](https://github.com/YairHalberstadt) | [333fred](https://github.com/333fred), [AlekseyTs](https://github.com/AlekseyTs) | [333fred](https://github.com/333fred) | -| [ref fields](https://github.com/dotnet/csharplang/blob/main/proposals/low-level-struct-improvements.md) | [ref-fields](https://github.com/dotnet/roslyn/tree/features/ref-fields) | [Merged into 17.3p3](https://github.com/dotnet/roslyn/issues/59194) | [cston](https://github.com/cston) | [RikkiGibson](https://github.com/RikkiGibson), [AlekseyTs](https://github.com/AlekseyTs) | [jaredpar](https://github.com/jaredpar) | -| [File types](https://github.com/dotnet/csharplang/issues/6011) | [file-types](https://github.com/dotnet/roslyn/tree/features/file-types) | [In Progress](https://github.com/dotnet/roslyn/issues/60819) | [RikkiGibson](https://github.com/RikkiGibson) | [jcouv](https://github.com/jcouv), [cston](https://github.com/cston) | [stephentoub](https://github.com/stephentoub) | # C# 10.0 diff --git a/docs/compilers/Bootstrap Builds.md b/docs/compilers/Bootstrap Builds.md new file mode 100644 index 0000000000000..6902c15d8fcbb --- /dev/null +++ b/docs/compilers/Bootstrap Builds.md @@ -0,0 +1,96 @@ +# Bootstrap Builds + +The build correctness leg ensures that the latest code in dotnet/roslyn can be used to build dotnet/roslyn. Essentially our compiler can bootstrap itself. + +## Why? + +The reason we go through so much effort is failures of this nature are incredibly hard to track down after the fact. The compiler is a complex tool and dotnet/roslyn is a large code base. It can take significant time to work out which of the ~300 commits since the last successful bootstrap is causing the current one to fail. + +In the past we used to run a bootstrap exercise roughly once a month. Every time there was a failure to build dotnet/roslyn with the latest compiler and it often took weeks for us to understand what change caused the failure. That resulted in a **lot** of wasted time and almost caused us to slip several releases. + +The build correctness jobs was introduced to solve this problem. The compiler verifies it can bootstrap on every change which means we find the failures immediately. + +## Process + +The build correctness job works by first building the Microsoft.Net.Compilers.Toolset package. This gives us a functioning compiler with the latest changes. This build occurs using the `/define:BOOTSTRAP` which allows the compiler to make failures more actionable. This is primarily leveraged in the following ways: + +- Inserts a [ExitingTraceListener](https://github.com/dotnet/roslyn/blob/main/src/Compilers/Shared/ExitingTraceListener.cs) into the process trace listeners. This means any `Debug.Assert` failure will result in the compilation failing with an actionable stack trace. +- Defines a [ValidateBootstrap](https://github.com/dotnet/roslyn/blob/main/src/Compilers/Core/MSBuildTask/ValidateBootstrap.cs). This lets us validate that the compiler used in the bootstrap build is actually the one we built vs. the default. This helps protect against build authoring changes which could inadvertently cause the default compiler to be used in a bootstrap build. + +The job then cleans out all of the artifacts from the build and starts a normal build of Roslyn.sln but specifies `/p:BootstrapBuildPath=...`. This causes two files to be loaded: + +- [Bootstrap.props](https://github.com/dotnet/roslyn/blob/main/eng/targets/Bootstrap.props): loads the bootstrap compiler over the default one +- [Bootstrap.targets](https://github.com/dotnet/roslyn/blob/main/eng/targets/Bootstrap.targets): verifies the bootstrap compiler was actually used + +This leg also ensures that the binary log and the build server log are captured in the set of published artifacts to allow for easy investigations. + +## Investigating + +The first step for investigating a correctness build failure is downloading the log files. These are available in the published artifacts + +![Published Artifacts](images/bootstrap-logs.png) + +The two most interesting files are: + +1. Build.Server.log: this is the text log of the compilation process. All stack traces and server error messages will be present in this file +1. Build.binlog: this is the binary log that results from building dotnet/roslyn with a bootstrap compiler. + +The build server log file will contain the reason why the particular request to the compiler failed. In most cases searching for one of two terms will take you straight to the failure. + +The first term to search for is `"Debug.Assert"` (no quotes). The most common cause of a bootstrap failure is a `Debug.Assert` call failing during compilation. This will result in an exception being added to the log with the full stack trace. For example: + +```txt +ID=VBCSCompiler TID=33: Debug.Assert failed with message: Fail: +Stack Trace + at Microsoft.CodeAnalysis.CommandLine.ExitingTraceListener.Exit(String originalMessage) + at Microsoft.CodeAnalysis.CommandLine.ExitingTraceListener.WriteLine(String message) + at System.Diagnostics.TraceInternal.Fail(String message) + at System.Diagnostics.Debug.Assert(Boolean condition) + at Microsoft.CodeAnalysis.GeneratorDriver..ctor(GeneratorDriverState state) + at Microsoft.CodeAnalysis.CSharp.CSharpGeneratorDriver..ctor(GeneratorDriverState state) + at Microsoft.CodeAnalysis.CSharp.CSharpGeneratorDriver.FromState(GeneratorDriverState state) + at Microsoft.CodeAnalysis.GeneratorDriver.RunGeneratorsAndUpdateCompilation(Compilation compilation, Compilation& outputCompilation, ImmutableArray`1& diagnostics, CancellationToken cancellationToken) + at Microsoft.CodeAnalysis.CommonCompiler.RunGenerators(Compilation input, ParseOptions parseOptions, ImmutableArray`1 generators, AnalyzerConfigOptionsProvider analyzerConfigOptionsProvider, ImmutableArray`1 additionalTexts, DiagnosticBag generatorDiagnostics) + at Microsoft.CodeAnalysis.CommonCompiler.CompileAndEmit(TouchedFileLogger touchedFilesLogger, Compilation& compilation, ImmutableArray`1 analyzers, ImmutableArray`1 generators, ImmutableArray`1 additionalTextFiles, AnalyzerConfigSet analyzerConfigSet, ImmutableArray`1 sourceFileAnalyzerConfigOptions, ImmutableArray`1 embeddedTexts, DiagnosticBag diagnostics, CancellationToken cancellationToken, CancellationTokenSource& analyzerCts, AnalyzerDriver& analyzerDriver, Nullable`1& generatorTimingInfo) + at Microsoft.CodeAnalysis.CommonCompiler.RunCore(TextWriter consoleOutput, ErrorLogger errorLogger, CancellationToken cancellationToken) + at Microsoft.CodeAnalysis.CommonCompiler.Run(TextWriter consoleOutput, CancellationToken cancellationToken) + at Microsoft.CodeAnalysis.CompilerServer.CompilerServerHost.RunCompilation(RunRequest& request, CancellationToken cancellationToken) + at Microsoft.CodeAnalysis.CompilerServer.CompilerServerHost.Microsoft.CodeAnalysis.CompilerServer.ICompilerServerHost.RunCompilation(RunRequest& request, CancellationToken cancellationToken) + at Microsoft.CodeAnalysis.CompilerServer.ClientConnectionHandler.<>c__DisplayClass8_0.b__1() + at System.Threading.Tasks.Task`1.InnerInvoke() + at System.Threading.Tasks.Task.Execute() + at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx) + at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx) + at System.Threading.Tasks.Task.ExecuteWithThreadLocal(Task& currentTaskSlot) + at System.Threading.Tasks.Task.ExecuteEntry(Boolean bPreventDoubleExecution) + at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx) + at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx) + at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state) + at System.Threading.ThreadHelper.ThreadStart(Object obj) + ``` + +These failures are almost always due to changes being tested. Essentially the change updated compiler logic in such a way that it caused an `Assert` to fail. On occasion this will also fail because an IDE change introduces a coding pattern that sets of a latent bug in the compiler or analyzer but this is certainly the rare case. + +The next term to search for is `"Error "` (no quotes but keep the space). This will be added to the log every the server hits an error and needs to shut down. + +```txt +ID=MSBuild 60300 TID=3: Error Error: 'EndOfStreamException' 'Reached end of stream before end of read.' occurred during 'Reading response for d2c3aeac-bd8a-4251-bde0-2e11bbc57d13' +Stack trace: + at Microsoft.CodeAnalysis.CommandLine.BuildProtocolConstants.d__4.MoveNext() in C:\Users\jaredpar\code\wt\ros2\src\Compilers\Core\CommandLine\BuildProtocol.cs:line 641 +--- End of stack trace from previous location where exception was thrown --- + at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) + at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) + at System.Runtime.CompilerServices.ConfiguredTaskAwaitable.ConfiguredTaskAwaiter.GetResult() + at Microsoft.CodeAnalysis.CommandLine.BuildResponse.d__5.MoveNext() in C:\Users\jaredpar\code\wt\ros2\src\Compilers\Core\CommandLine\BuildProtocol.cs:line 342 +--- End of stack trace from previous location where exception was thrown --- + at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) + at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) + at System.Runtime.CompilerServices.ConfiguredTaskAwaitable`1.ConfiguredTaskAwaiter.GetResult() + at Microsoft.CodeAnalysis.CommandLine.BuildServerConnection.<g__tryRunRequestAsync|7_1>d.MoveNext() in C:\Users\jaredpar\code\wt\ros2\src\Compilers\Shared\BuildServerConnection.cs:line 288 +``` + +These type of errors, when not paired with a `Debug.Assert` failure, are almost always bugs in the compiler server. Please contact the compiler team to help track down such failures. + +Note: when you encounter a case where the log file does not have an actionable description of why a build failed, strongly consider sending a PR that fixes this. This approach is why the log is such a valuable tool for tracking down bootstrap failures. + + diff --git a/docs/compilers/CSharp/Compiler Breaking Changes - DotNet 7.md b/docs/compilers/CSharp/Compiler Breaking Changes - DotNet 7.md index 85417b7843492..2ff8fa2172130 100644 --- a/docs/compilers/CSharp/Compiler Breaking Changes - DotNet 7.md +++ b/docs/compilers/CSharp/Compiler Breaking Changes - DotNet 7.md @@ -1,5 +1,46 @@ # This document lists known breaking changes in Roslyn after .NET 6 all the way to .NET 7. +## Unused results from ref local are dereferences. + +***Introduced in Visual Studio 2022 version 17.4*** + +When a `ref` local variable is referenced by value, but the result is not used (such as being assigned to a discard), the result was previously ignored. The compiler will now dereference that local, ensuring that any side effects are observed. + +```csharp +ref int local = Unsafe.NullRef(); +_ = local; // Will now produce a `NullReferenceException` +``` + +## Types cannot be named `scoped` + +***Introduced in Visual Studio 2022 version 17.4.*** Starting in C# 11, types cannot be named `scoped`. The compiler will report an error on all such type names. To work around this, the type name and all usages must be escaped with an `@`: + +```csharp +class scoped {} // Error CS9056 +class @scoped {} // No error +``` + +```csharp +ref scoped local; // Error +ref scoped.nested local; // Error +ref @scoped local2; // No error +``` + +This was done as `scoped` is now a modifier for variable declarations and reserved following `ref` in a ref type. + +## Types cannot be named `file` + +***Introduced in Visual Studio 2022 version 17.4.*** Starting in C# 11, types cannot be named `file`. The compiler will report an error on all such type names. To work around this, the type name and all usages must be escaped with an `@`: + +```csharp +class file {} // Error CS9056 +class @file {} // No error +``` + +This was done as `file` is now a modifier for type declarations. + +You can learn more about this change in the associated [csharplang issue](https://github.com/dotnet/csharplang/issues/6011). + ## Required spaces in #line span directives ***Introduced in .NET SDK 6.0.400, Visual Studio 2022 version 17.3.*** @@ -83,11 +124,6 @@ Possible workarounds are: 1. Rename the type parameter or parameter to avoid shadowing the name from outer scope. 1. Use a string literal instead of the `nameof` operator. -1. Downgrade the `` element to 9.0 or earlier. - -Note: The break will also apply to C# 10 and earlier when .NET 7 ships, but is -currently scoped down to users of LangVer=preview. -Tracked by https://github.com/dotnet/roslyn/issues/60640 ## Cannot return an out parameter by reference @@ -103,13 +139,58 @@ static ref T ReturnOutParamByRef(out T t) } ``` -A possible workaround is to change the method signature to pass the parameter by `ref` instead. +Possible workarounds are: +1. Use `System.Diagnostics.CodeAnalysis.UnscopedRefAttribute` to mark the reference as unscoped. + ```csharp + static ref T ReturnOutParamByRef([UnscopedRef] out T t) + { + t = default; + return ref t; // ok + } + ``` + +1. Change the method signature to pass the parameter by `ref`. + ```csharp + static ref T ReturnRefParamByRef(ref T t) + { + t = default; + return ref t; // ok + } + ``` + +## Instance method on ref struct may capture unscoped ref parameters + +***Introduced in .NET SDK 7.0.100, Visual Studio 2022 version 17.4.*** + +With language version C# 11 or later, or with .NET 7.0 or later, a `ref struct` instance method invocation is assumed to capture unscoped `ref` or `in` parameters. + +```csharp +R Use(R r) +{ + int i = 42; + r.MayCaptureArg(ref i); // error CS8350: may expose variables referenced by parameter 't' outside of their declaration scope + return r; +} + +ref struct R +{ + public void MayCaptureArg(ref T t) { } +} +``` + +A possible workaround, if the `ref` or `in` parameter is not captured in the `ref struct` instance method, is to declare the parameter as `scoped ref` or `scoped in`. ```csharp -static ref T ReturnRefParamByRef(ref T t) +R Use(R r) { - t = default; - return ref t; // ok + int i = 42; + r.CannotCaptureArg(ref i); // ok + return r; +} + +ref struct R +{ + public void CannotCaptureArg(scoped ref T t) { } } ``` @@ -154,6 +235,27 @@ static R Create() } ``` +## `ref` to `ref struct` argument considered unscoped in `__arglist` + +***Introduced in .NET SDK 7.0.100, Visual Studio 2022 version 17.4.*** + +With language version C# 11 or later, or with .NET 7.0 or later, a `ref` to a `ref struct` type is considered an unscoped reference when passed as an argument to `__arglist`. + +```csharp +ref struct R { } + +class Program +{ + static void MayCaptureRef(__arglist) { } + + static void Main() + { + var r = new R(); + MayCaptureRef(__arglist(ref r)); // error: may expose variables outside of their declaration scope + } +} +``` + ## Unsigned right shift operator ***Introduced in .NET SDK 6.0.400, Visual Studio 2022 version 17.3.*** diff --git a/docs/compilers/images/bootstrap-logs.png b/docs/compilers/images/bootstrap-logs.png new file mode 100644 index 0000000000000..aca2eb958faf1 Binary files /dev/null and b/docs/compilers/images/bootstrap-logs.png differ diff --git a/docs/contributing/Compiler Test Plan.md b/docs/contributing/Compiler Test Plan.md index f287fc02e3f49..a3d0b6b4f463a 100644 --- a/docs/contributing/Compiler Test Plan.md +++ b/docs/contributing/Compiler Test Plan.md @@ -38,6 +38,7 @@ This document provides guidance for thinking about language interactions and tes # Type and members - Access modifiers (public, protected, internal, protected internal, private protected, private), static, ref - type declarations (class, record class/struct with or without positional members, struct, interface, type parameter) +- file-local types - methods - fields (required and not) - properties (including get/set/init accessors, required and not) diff --git a/docs/features/incremental-generators.md b/docs/features/incremental-generators.md index 5009d395ef7a5..2e0a3004567a8 100644 --- a/docs/features/incremental-generators.md +++ b/docs/features/incremental-generators.md @@ -30,7 +30,7 @@ public class Generator : IIncrementalGenerator // define the execution pipeline here via a series of transformations: // find all additional files that end with .txt - IncrementalValuesProvider textFiles = context.AdditionalTextsProvider.Where(static file => file.Path.EndsWith(".txt")); + IncrementalValuesProvider textFiles = initContext.AdditionalTextsProvider.Where(static file => file.Path.EndsWith(".txt")); // read their contents and save their name IncrementalValuesProvider<(string name, string content)> namesAndContents = textFiles.Select((text, cancellationToken) => (name: Path.GetFileNameWithoutExtension(text.Path), content: text.GetText(cancellationToken)!.ToString())); @@ -89,7 +89,7 @@ single time for the lifetime of the host. Rather than a dedicated `Execute` method, an Incremental Generator instead defines an immutable execution pipeline as part of initialization. The `Initialize` method receives an instance of -`IncrementalGeneratorInitializationContext`which is used by the generator to +`IncrementalGeneratorInitializationContext` which is used by the generator to define a set of transformations. @@ -160,7 +160,7 @@ IValueProvider └─────────────┘ ``` -Instead, the generator supplies a set of transformations that ar to be applied to the +Instead, the generator supplies a set of transformations that are to be applied to the data contained within the provider, which in turn creates a new value provider. ### Select @@ -799,7 +799,7 @@ even though they referenced something in `file1.cs`. Because the first check is purely _syntactic_ we can be sure the results for `file2.cs` would be the same. While it may seem unfortunate that the driver must run the `transform` for all -selected syntax nodes, if it did not it could up producing incorrect data +selected syntax nodes, if it did not it could end up producing incorrect data due to cross file dependencies. Because the initial syntactic check allows the driver to substantially filter the number of nodes on which the semantic checks have to be re-run, significantly improved performance @@ -826,7 +826,7 @@ The set of output methods are **RegisterSourceOutput**: -RegisterSourceOutput allows a generator author to produce source files and +`RegisterSourceOutput` allows a generator author to produce source files and diagnostics that will be included in the users compilation. As input, it takes a `Value[s]Provider` and an `Action` that will be invoked for every value in the value provider. @@ -905,15 +905,15 @@ transformations are run, meaning that it will be visible as part of the rest of the regular execution pipeline, and an author may ask semantic questions about it. -It is particularly useful for adding attributes to the users source code. These -can then be added by the user their code, and the generator may find the -attributed code via the semantic model. +It is particularly useful for adding attribute definitions to the users' +source code. These can then be applied by the user in their code, and the +generator may find the attributed code via the semantic model. ## Handling Cancellation Incremental generators are designed to be used in interactive hosts such as an IDE. As such, it is critically important that generators respect and respond to -the passed in cancellation tokens. +the passed-in cancellation tokens. In general, it is likely that the amount of user computation performed per transformation is low, but often will be calling into Roslyn APIs that may have @@ -1033,7 +1033,7 @@ the driver knows there can be no work to be done when a `SyntaxTree` changes. ### Comparing Items -For a user provided result to be comparable across iterations, there needs to be +For a user-provided result to be comparable across iterations, there needs to be some concept of equivalence. By default the host will use `EqualityComparer` to determine equivalence. There are obviously times where this is insufficient, and there exists an extension method that allows the author to supply a comparer diff --git a/docs/ide/specs/semantic_snippets.md b/docs/ide/specs/semantic_snippets.md new file mode 100644 index 0000000000000..5cb4b2dabf1cf --- /dev/null +++ b/docs/ide/specs/semantic_snippets.md @@ -0,0 +1,465 @@ +# Semantic Snippets + +@jmarolf | Status: Draft + +Snippets as they exist today for C# developers only do text expansion (`cw -> Console.WriteLine`) and have lacked any significant improvements in the last 10+ years. We would like to iterate on this experience for .NET developers using Visual Studio. The hope is that typing (the thing developers do a lot) can also be the best way to discover how to and write code. + +## Table of Contents + +- [Requirements](#requirements) + - [Goals](#goals) + - [Non-Goals](#non-goals) +- [Scenarios and User Experience](#scenarios-and-user-experience) + - [User Experience: Snippet commit behavior](#user-experience-snippet-commit-behavior) + - [User Experience: Snippet behavior with existing options](#user-experience-snippet-behavior-with-existing-options) + - [Scenario 1: Add New Snippets](#scenario-1-add-new-snippets) + - [record snippet](#record-snippet) + - [record struct snippet](#record-struct-snippet) + - [Scenario 2: Snippets only show up where they are valid](#scenario-2-snippets-only-show-up-where-they-are-valid) + - [Existing Snippet Valid Insertion Locations](#existing-snippet-valid-insertion-locations) + - [New Snippet Valid Insertion Locations](#new-snippet-valid-insertion-locations) + - [Scenario 3: Snippet text is relevant to my code](#scenario-3-snippet-text-is-relevant-to-my-code) + - [`Console.WriteLine`](#consolewriteline) + - [MessageBox.Show](#messageboxshow) + - [Invoke an Event](#invoke-an-event) + - [Scenario 3: Ability to populate snippets replacement parameters from context](#scenario-3-ability-to-populate-snippets-replacement-parameters-from-context) + - [Boolean snippets](#boolean-snippets) + - [Loop snippets](#loop-snippets) + - [Scenario 4: Snippets are discoverable](#scenario-4-snippets-are-discoverable) + - [Snippets Synonyms](#snippets-synonyms) +- [Design](#design) + - [Snippet Completion Provider](#snippet-completion-provider) + - [Custom Completion Sorting Logic](#custom-completion-sorting-logic) + - [Complex Edits](#complex-edits) + - [LSP Considerations](#lsp-considerations) +- [Test Plan](#test-plan) + - [Ensuring we don't break muscle memory](#ensuring-we-dont-break-muscle-memory) + - [Ensuring out new feautures work](#ensuring-out-new-feautures-work) +- [Q & A](#q--a) + +## Requirements + +### Goals + +- Snippet functionality of more discoverable for all users +- Snippets are more targeted to what a user is trying to do +- We do not want existing users to have their flow interrupted + +### Non-Goals + +- We are not making a general-purpose extension API for snippets (yet) + - We may do this someday but for now we want to ensure that we can meet customers’ needs for the narrow case +- We are not changing the VB experience for snippets (yet) + - VB has a very different design than C#. +- We are not changing "Surround With" behavior +- we are not changing snippet menu behavior (Ctrl+K,X) + +## Scenarios and User Experience + +### User Experience: Snippet commit behavior + +- We should change the commit behavior of these new snippets to only require a single tab to complete +- If the user types `Tab ↹` twice (due to muscle memory) we will eat the second key press (similar to how automatic brace matching works) +- Two undo stacks will be created for each snippet that is commited (`Console.WriteLine()` -> `cw` -> ``) + +### User Experience: Snippet behavior with existing options + +There is also the snippet options under `Tools->Options->Text Editor->C# Intellisense`: + +![image](https://user-images.githubusercontent.com/9797472/137983382-f243e241-fc4a-4529-be08-18e3ee7d5174.png) + +"Always include snippets" is the default and this is what over 90% of user have set. + +1. If "Always include snippets" is on + - We need to preserve the muscle memory of users with this option while being allowed to change the visual presentation. + - Even though “cw” won’t appear in the completion list with our feature turned on it still “needs to work” from the users perspective so the following experience needs to be preserved: + - User types `cw` + - Nothing is pre-selected in the completion list such that cw is over-written + - Tab-Tab executed the console.writeline(); snippet +1. If "Never include snippets" is on + - If the user has decided to never include snippets in the completion list then we also want to preserve this behavior + - User types `cw` + - The completion list pre-selects an item from the list + - Tab commits this item from the list to the editor +1. If "Include snippets when ?-Tab is typed after an identifier" is on + - Might want to consider removing this option as its rather odd and cannot find any data to suggests that people use this. If we decided to include this then the behavior is + - No ?-Tab: behaves like 2 above + - ?-Tab: behaves like 1 above + +### Scenario 1: Add New Snippets + +*We should offer new snippets for new language constructs.* + +|Name |Description | +|-----|------------| +|`record` | Creates a record declaration. | +|`srecord` | Creates a record struct declaration. | + +#### record snippet + +```csharp +record MyRecord() // users cursor is placed inside the parenthesis +{ +} +``` + +#### record struct snippet + +```csharp +record struct MyRecord() // users cursor is placed inside the parenthesis +{ +} +``` + +### Scenario 2: Snippets only show up where they are valid + +*If a user types an existing snippet in a location where it is not valid (example `cw`) nothing will be shown and no snippet suggestions will be given to the user.* + +Below is a list of snippets that the contexts in which they should appear + +#### Existing Snippet Valid Insertion Locations + +|Name | Valid locations to insert snippet| +|-----|----------------------------------| +|`#if` | Anywhere. +|`#region` | Anywhere. +|`~` | Inside a class or record. +|`attribute` | Inside a namespace (including the global namespace), a class, record, struct record, or a struct. +|`checked` | Inside a method, an indexer, a property accessor, or an event accessor. +|`class` | Inside a namespace (including the global namespace), a class, record, struct record, or a struct. +|`ctor` | Inside a class or record. +|`cw` | Inside a method, an indexer, a property accessor, or an event accessor. +|`do` | Inside a method, an indexer, a property accessor, or an event accessor. +|`else` | Inside a method, an indexer, a property accessor, or an event accessor. +|`enum` | Inside a namespace (including the global namespace), a class, record, struct record, or a struct. +|`equals` | Inside a class, or a struct. +|`exception` | Inside a namespace (including the global namespace), a class, record, struct record, or a struct. +|`for` | Inside a method, an indexer, a property accessor, or an event accessor. +|`foreach` | Inside a method, an indexer, a property accessor, or an event accessor. +|`forr` | Inside a method, an indexer, a property accessor, or an event accessor. +|`if` | Inside a method, an indexer, a property accessor, or an event accessor. +|`indexer` | Inside a class, recordstruct record, or a struct. +|`interface` | Inside a namespace (including the global namespace), a class, record, struct record, or a struct. +|`invoke` | Inside a method, an indexer, a property accessor, or an event accessor. +|`iterator` | Inside a class, recordstruct record, or a struct. +|`iterindex` | Inside a class, recordstruct record, or a struct. +|`lock` | Inside a method, an indexer, a property accessor, or an event accessor. +|`mbox` | (If inside a winforms project) Inside a method, an indexer, a property accessor, or an event accessor. +|`namespace` | Inside a namespace (including the global namespace). +|`prop` | Inside a class, record ,or a struct. +|`propfull` | Inside a class, record, struct record, or a struct. +|`propg` | Inside a class, record, struct record, or a struct. +|`sim` | Inside a class, record, struct record, or a struct. +|`struct` | Inside a namespace (including the global namespace), a class, record, struct record, or a struct. +|`svm` | Inside a class, record, struct record, or a struct. +|`switch` | Inside a method, an indexer, a property accessor, or an event accessor. +|`try` | Inside a method, an indexer, a property accessor, or an event accessor. +|`tryf` | Inside a method, an indexer, a property accessor, or an event accessor. +|`unchecked` | Inside a method, an indexer, a property accessor, or an event accessor. +|`unsafe` | Inside a method, an indexer, a property accessor, or an event accessor. +|`using` | Inside a namespace (including the global namespace). +|`while` | Inside a method, an indexer, a property accessor, or an event accessor. + +#### New Snippet Valid Insertion Locations + +|Name | Valid locations to insert snippet| +|-----|----------------------------------| +|`record` | Inside a namespace (including the global namespace), a class, record, struct record, or a struct. +|`srecord` | Inside a namespace (including the global namespace), a class, record, struct record, or a struct. +|`elseif` | Inside a method, an indexer, a property accessor, or an event accessor. + +### Scenario 3: Snippet text is relevant to my code + +When possible, we want snippets to offer more fine-grained help to users writing code. There are two snippets where we want to change the code we complete dependeing on context. + +#### `Console.WriteLine` + +Today `cw` always expands to the text below: + +```csharp +Console.WriteLine(); // Users cursor is placed inside the parenthesis +``` + +This should remain the same for normal methods. + +```csharp +void M() +{ + Console.WriteLine(); // cursor is placed inside the parenthesis +} +``` + +however inside an `async` method we should complete to this instead + +```csharp +async Task M() +{ + await Console.Out.WriteLineAsync(); // cursor is placed inside the parenthesis +} +``` + +#### MessageBox.Show + +`mbox` always expands to the following text + +```csharp +System.Windows.Forms.MessageBox.Show("Test"); +``` + +This is a perfectly valid snippet but we only want it to show under the following circumstances: + +1. The user is in a .NET Framework project +1. The user is int a .NET Core project with `true` set + +#### Invoke an Event + +This snippet (`invoke`) was added to help with invoking events before the introduction of the `?.` operator. It always generates the following text: + +```csharp +[|EventHandler|] temp = [|MyEvent|]; // two tab stop groups denoted with [||] + // 1. first the user fills in the event type + // 2. then the user gives the identifier name of the event +if (temp != null) +{ + temp(); +} +``` + +If the user it targeting a version that is older than C# 6 (where `?.` was introduced) we should still generate something similar to what the original snippet did but with better help. + +```csharp +event System.Action MyEvent; + +void CallMyEvent() +{ + Action? temp = [|MyEvent|]; // Just one tab stop group where the user fills in the identifier of the event + // NOTE: we should also show a target-typed completion list here to help fill in the event + // Once the user types `Tab` to complete filling in the event identifier we will update the + // type of `temp` (if the user has non-var code style preferences). + if (temp != null) + { + temp([||]); // The second tab group is now here since most events require arguments, whole-method completion should be turned on for this line + } +} +``` + +If the user is doing this in a version of C# that is newer than version 5 things are significantly simpler. We will still offer a target-typed completion for events that are in scopt but we just generate this code: + +```csharp +event System.Action MyEvent; + +void CallMyEvent() +{ + MyEvent?.Invoke([||]); // The user was offered a list of event types in scope and upon selection the whole line was re-writted to this. + // As above, whole-line completion helps fill in the argument list here. +} +``` + +If the user selects an event that returns an awaitable type things get more complex. + +```csharp +event System.Func MyEvent; + +void CallMyEvent() +{ + Func? myEvent = [|MyEvent|]; // user chose an event that returns an awaitable type + if (myEvent != null) + { + Task eventTasks = Task.WhenAll(Array.ConvertAll( // we generate the code to ensure all the delegate results are awaited + myEvent.GetInvocationList(), + e => ((Func)e).Invoke([||]))); // As above, whole-line completion helps fill in the argument list here. + [|eventTasks.GetAwaiter().GetResult();|] // since the method is not async we offer a third group with the options + // 1. make method async + // 2. wait for all delegates to finish + } +} +``` + +If the user is inside of an `async` method _and_ they select an event that returns an awaitable we elide the third tab group. + +```csharp +event System.Func MyEvent; + +async Task CallMyEventAsync() +{ + Func? myEvent = [|MyEvent|]; // user chose an event that returns an awaitable type + if (myEvent != null) + { + await Task.WhenAll(Array.ConvertAll( + myEvent.GetInvocationList(), + e => ((Func)e).Invoke([||]))); // As above, whole-line completion helps fill in the argument list here. + } +} +``` + +### Scenario 3: Ability to populate snippets replacement parameters from context + +Note that is a snippet isn't called out here the expectation is that its behavior remanes the same. Meaning snippets like `tryf` expand to the same text. + +#### Boolean snippets + +- `do` +- `if` +- `while` +- `else` +- `elseif` + +These snippets create a block and have a place to but a boolean expression. The only additional work we want to do here is ensure the users are shown a target-typed list of members that are in scope + +Note that `else if` isn't a snippet today and in the past was handled by the user typing `else` Tab `if` Tab-Tab. Since we are changine this behavior a bit we should add an `elseif` snippet that completes the following + +```csharp +else if ([|true|]) // user is shown a target-typed list for bool members +{ + +} +``` + +#### Loop snippets + +- `for` +- `forr` +- `foreach` + +this is what `for` produces today: + +```csharp +for (int [|i|] = 0; i < [|length|]; i++) // user need to iterate through naming `i` then selecting what `length` should be +{ + +} +``` + +We can improve the process for filling in for loops here + +```csharp +for (int [|i|] = 0; i < [|length|]; i++) // we automatically choose a name for `i` so it does not conflict, + // show a list of in-scope variabled that have a Count or Length property and are indexable +{ + T [|temp|] = arrag[i]; // Once the uder commits the indexable member we generate a temp and let them name it. + // if the user is doing something that does not require reading from the indexable member esc undoes this +} +``` + +Today users are asked to fill in information on a foreach loop in the exact opposite order of what it should be: + +```csharp +foreach ([|var|] [|item|] in [|collection|]) // user needs to select `var` then `item` then `collection` +{ + +} +``` + +For foreach loops we will reverse the tab group ordering asking them to select the type the member they are iterating over first + +```csharp +foreach (var [|item|] in [|collection|]) // user selects`collection` first from list of IEnumerable variables then everything else is filled in based on preferenced. +{ // the user is allowed to override the chosen name by tabbing + // If the user preferes var then var is used for the variable type otherwise it is replaced with concrete type from the enumerable +} +``` + +By changing this order it also allows us to automatically deconstruct elements we are iterating over. + +```csharp +List<(int id, string name)> _students = new(); + +foreach ((int [|id|], string [|name|]) in [|_students|}) // user chose a type that can be decontructed so we do that automatically +{ // user can tab though the deconstructed names and change them if they want + +} +``` + +### Scenario 4: Snippets are discoverable + +Just typing what the user is trying to do snippets should show up and be obvious what they do. What also want to handle synonmyms. Below is a list of synonyms that should also filter to the snippet in the completion list. Note that the old trigger text for these snippets is included to ensure that typing the same keystrokes produces the same results. + +#### Snippets Synonyms + +|Name |Descriptive Text in Completion List | Valid synonyms | +|-----|------------|----------------------------------| +|`#if` | Create a #if directive and a #endif directive. | directive, pound, hashtag, #if +|`#region` | Create a #region directive and a #endregion directive. | region, pound, hashtag, #region +|`~` | Create a finalizer (destructor) for the containing class. | destruct, final, dispose, ~ +|`attribute` | Create a declaration for a class that derives from Attribute. | +|`checked` | Create a checked block. | +|`class` | Create a class declaration. | type, new +|`ctor` | Create a constructor for the containing class. | new +|`cw` | Write to the console. | write line, output, log, print, cw +|`do` | Create a do while loop. | +|`else` | Create an else block. | +|`enum` | Create an enum declaration. | new +|`equals` | Create a method declaration that overrides the Equals method defined in the Object class. | compare, equal, equals +|`exception` | Create a declaration for a class that derives from an exception (Exception by default). | +|`for` | Create a for loop. | +|`foreach` | Create a foreach loop. | +|`forr` | Create a for loop that decrements the loop variable after each iteration.| reverse, forr +|`if` | Create an if block. | +|`indexer` | Create an indexer declaration. | +|`interface` | Create an interface declaration. | +|`invoke` | Create a block that safely invokes an event. | event, invoke +|`iterator` | Create an iterator. | +|`iterindex` | Create a "named" iterator and indexer pair by using a nested class. | iterindex +|`lock` | Create a lock block. | +|`mbox` | Call System.Windows.Forms.MessageBox.Show. | popup, show, mbox +|`namespace` | Create a namespace declaration. | +|`prop` | Create an auto-implemented property declaration. | auto, prop +|`propfull` | Create a property declaration with get and set accessors. | full, propfull +|`propg` | Create a read-only auto-implemented property with a private set accessor. | propg +|`sim` | Create a static int Main method declaration | sim, entry, start +|`struct` | Create a struct declaration. | +|`svm` | Create a static void Main method declaration. | svm, entry, start +|`switch` | Create a switch block. | +|`try` | Create a try-catch block. | catch, handle +|`tryf` | Create a try-finally block. | finally, tryf +|`unchecked` | Create an unchecked block | +|`unsafe` | Create an unsafe block. | +|`using` | Create a using directive. | dispose +|`while` | Create a while loop. | +|`record` | Create a record declaration. | data, new +|`srecord` | Create a struct record declaration. | data, new + +## Design + +Essentially all of these new snippets can just be completion providers as the apis we have today should be enought to accmplish everything that is detailed here. There are a few adjusts that will need to be made to exising services to ensure these all fit in cleanly. + +### Snippet Completion Provider + +Work will need to be done [here](https://github.com/dotnet/roslyn/blob/1667bc61ac41e5e63ea672c2a39c1a0bebe5f8e9/src/Features/CSharp/Portable/Completion/CompletionProviders/SnippetCompletionProvider.cs#L146) and potentially [here](https://github.com/dotnet/roslyn/blob/main/src/VisualStudio/Core/Def/Implementation/Snippets/AbstractSnippetInfoService.cs) to filter out _only_ the snippets that out team owns so we do not break third-party snippets. + +### Custom Completion Sorting Logic + +We may need to adjust the item sorting logic [here](https://github.com/dotnet/roslyn/blob/1667bc61ac41e5e63ea672c2a39c1a0bebe5f8e9/src/Features/Core/Portable/Completion/CompletionService.cs#L202) considering the synonym matching that we want to do. + +### Complex Edits + +Serveral of these complation behaviors will be complex edits to the docuement. Based on the existing API shape this should not be a problem but we may want to ensure that snippets (that the user generally thinks of a lightweight operation) do not slow things down by doing _overly_ complex things. + +### LSP Considerations + +The expectation is that LSP clients should be able to use these completion providers without issue but we should keep in contact with those teams to ensure this remains the case. + +## Test Plan + +### Ensuring we don't break muscle memory + +- Type in the following locations and ensure the same text is committed given the same keystroked + - inside namespace + - `cla⇥⇥Hi` -> `class Hi { }` + - `us⇥Sys⇥;` -> `using System;` + - inside class + - `svm⇥⇥` -> `static void Main(string[] args) { }` + - `prop⇥⇥` -> `public int MyProperty { get; set; }` + - `over⇥↓⇥` -> `public override bool Equals(object? obj) { return base.Equals(obj); }` + - `ev⇥Act⇥?MyEvent;` -> `event Action MyEvent;` + - inside method body, lambda, property, or local function + - `if⇥⇥` -> `if (true) { }` + - `forr⇥⇥` -> `for (int i = length - 1; i >= 0; i--) { }` + - `str⇥name = "Some Name;` -> `string name = "Some Name";` + - inside parameter list + - `str⇥name = "Some Name` -> `string name = "Some Name"` + +## Q & A + +- [C# snippet Docs](https://docs.microsoft.com/visualstudio/ide/visual-csharp-code-snippets) +- [Visual Studio Snippet XML Schema](https://docs.microsoft.com//visualstudio/ide/code-snippets-schema-reference) diff --git a/docs/wiki/NuGet-packages.md b/docs/wiki/NuGet-packages.md index 396d05b798509..5a70764af7896 100644 --- a/docs/wiki/NuGet-packages.md +++ b/docs/wiki/NuGet-packages.md @@ -42,6 +42,8 @@ Below are the versions of the language available in the NuGet packages. Remember See the [history of C# language features](https://github.com/dotnet/csharplang/blob/main/Language-Version-History.md) for more details. +See the [.NET SDK, MSBuild, and Visual Studio versioning](https://docs.microsoft.com/dotnet/core/porting/versioning-sdk-msbuild-vs#lifecycle) docs page for details of SDK versioning. + ## Other packages A few other packages are relevant or related to Roslyn, but are not produced from the Roslyn repo. diff --git a/dotnet-tools.json b/dotnet-tools.json index 447b894f9dc94..b81fdc2997f8c 100644 --- a/dotnet-tools.json +++ b/dotnet-tools.json @@ -2,7 +2,7 @@ "isRoot": true, "tools": { "dotnet-format": { - "version": "6.3.317301", + "version": "6.4.326609", "commands": [ "dotnet-format" ] diff --git a/eng/InternalTools.props b/eng/InternalTools.props index 86463f2831055..1bb4d145598c3 100644 --- a/eng/InternalTools.props +++ b/eng/InternalTools.props @@ -9,6 +9,8 @@ + + diff --git a/eng/Signing.props b/eng/Signing.props index 828f775c2b2a7..a3b096a15d715 100644 --- a/eng/Signing.props +++ b/eng/Signing.props @@ -35,11 +35,20 @@ + + + + + + + + + diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 6cae2029f0f28..019b9fe20522c 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -6,9 +6,9 @@ 7e80445ee82adbf9a8e6ae601ac5e239d982afaa - + https://github.com/dotnet/source-build-externals - 56bbc060090d56d5d61962b829826799dabf9673 + ee790b0477953dd30ea83e0e47af909a04fd0ca3 diff --git a/eng/Versions.props b/eng/Versions.props index 31d634e1d03bd..5cf152e53a40b 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -6,16 +6,16 @@ --> 4 - 3 + 4 0 - 3 + 2 $(MajorVersion).$(MinorVersion).$(PatchVersion) $(MajorVersion).$(MinorVersion).0.0 - 4.2.0-1.final + 4.3.0-1.final @@ -24,7 +24,7 @@ 1.1.2-beta1.22122.4 0.1.132-beta - 4.2.0-2.final + 4.3.0-1.final 17.3.174 @@ -32,17 +32,18 @@ 5.0.0-alpha1.19409.1 5.0.0-preview.1.20112.8 17.3.3101 - 17.3.2017 + 17.4.1004-preview 17.3.32809.331 16.5.0 - 3.8.0 + 4.1.0 7.0.0-alpha.1.22060.1 4.0.2048 17.3.44 + 17.4.0-preview-20220707-01 + 6.0.6 + diff --git a/eng/build.sh b/eng/build.sh index 9ec073ab72113..a08cbea099dbf 100755 --- a/eng/build.sh +++ b/eng/build.sh @@ -36,6 +36,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.sln)" echo "" echo "Command line arguments starting with '/p:' are passed through to MSBuild." } @@ -74,6 +75,7 @@ prepare_machine=false warn_as_error=false properties="" source_build=false +solution_to_build="Compilers.sln" args="" @@ -160,6 +162,11 @@ while [[ $# > 0 ]]; do # have an alias. source_build=true ;; + --solution) + solution_to_build=$2 + args="$args $1" + shift + ;; /p:*) properties="$properties $1" ;; @@ -203,7 +210,7 @@ function MakeBootstrapBuild { } function BuildSolution { - local solution="Compilers.sln" + local solution=$solution_to_build echo "$solution:" InitializeToolset @@ -320,6 +327,6 @@ if [[ "$test_core_clr" == true ]]; then if [[ "$ci" != true ]]; then runtests_args="$runtests_args --html" fi - dotnet exec "$scriptroot/../artifacts/bin/RunTests/${configuration}/net6.0/RunTests.dll" --tfm net6.0 --configuration ${configuration} --dotnet ${_InitializeDotNetCli}/dotnet $runtests_args + dotnet exec "$scriptroot/../artifacts/bin/RunTests/${configuration}/net6.0/RunTests.dll" --tfm net6.0 --configuration ${configuration} --logs ${log_dir} --dotnet ${_InitializeDotNetCli}/dotnet $runtests_args fi ExitWithExitCode 0 diff --git a/eng/config/BannedSymbols.txt b/eng/config/BannedSymbols.txt index a3112c9c224c5..054e6fb4c538a 100644 --- a/eng/config/BannedSymbols.txt +++ b/eng/config/BannedSymbols.txt @@ -34,3 +34,4 @@ M:Microsoft.CodeAnalysis.Simplification.Simplifier.ReduceAsync(Microsoft.CodeAna M:Microsoft.CodeAnalysis.Simplification.Simplifier.ReduceAsync(Microsoft.CodeAnalysis.Document,Microsoft.CodeAnalysis.SyntaxAnnotation,Microsoft.CodeAnalysis.Options.OptionSet,System.Threading.CancellationToken); Use overload that takes SimplifierOptions M:Microsoft.CodeAnalysis.Simplification.Simplifier.ReduceAsync(Microsoft.CodeAnalysis.Document,Microsoft.CodeAnalysis.Text.TextSpan,Microsoft.CodeAnalysis.Options.OptionSet,System.Threading.CancellationToken); Use overload that takes SimplifierOptions M:Microsoft.CodeAnalysis.Simplification.Simplifier.ReduceAsync(Microsoft.CodeAnalysis.Document,System.Collections.Generic.IEnumerable{Microsoft.CodeAnalysis.Text.TextSpan},Microsoft.CodeAnalysis.Options.OptionSet,System.Threading.CancellationToken); Use overload that takes SimplifierOptions +M:Microsoft.CodeAnalysis.Editing.SyntaxEditor.#ctor(Microsoft.CodeAnalysis.SyntaxNode,Microsoft.CodeAnalysis.Host.HostWorkspaceServices); Use overload that takes HostSolutionServices instead \ No newline at end of file diff --git a/eng/config/PublishData.json b/eng/config/PublishData.json index e2ecb671d676d..5cc9c2e35ca66 100644 --- a/eng/config/PublishData.json +++ b/eng/config/PublishData.json @@ -113,37 +113,26 @@ ], "vsBranch": "rel/d17.3", "vsMajorVersion": 17, - "insertionTitlePrefix": "[d17.3p2]" + "insertionTitlePrefix": "[d17.3]" }, - "main": { - "nugetKind": [ - "Shipping", - "NonShipping" - ], - "vsBranch": "main", - "vsMajorVersion": 17, - "insertionTitlePrefix": "[Validation]", - "insertionCreateDraftPR": true - }, - "main-vs-deps": { + "release/dev17.4": { "nugetKind": [ "Shipping", "NonShipping" ], - "vsBranch": "main", + "vsBranch": "rel/d17.4", "vsMajorVersion": 17, - "insertionCreateDraftPR": true, - "insertionTitlePrefix": "[d17.3p3]" + "insertionTitlePrefix": "[d17.4p1]" }, - "release/dev17.4-vs-deps": { + "main": { "nugetKind": [ "Shipping", "NonShipping" ], "vsBranch": "main", "vsMajorVersion": 17, - "insertionCreateDraftPR": true, - "insertionTitlePrefix": "[d17.4p1]" + "insertionCreateDraftPR": false, + "insertionTitlePrefix": "[d17.4p2]" } } } diff --git a/eng/evaluate-changed-paths.sh b/eng/evaluate-changed-paths.sh new file mode 100755 index 0000000000000..5ad7583301035 --- /dev/null +++ b/eng/evaluate-changed-paths.sh @@ -0,0 +1,168 @@ +#!/usr/bin/env bash + +# Disable globbing in this bash script since we iterate over path patterns +set -f + +# Stop script if unbound variable found (use ${var:-} if intentional) +set -u + +# Stop script if command returns non-zero exit code. +# Prevents hidden errors caused by missing error code propagation. +set -e + +usage() +{ + echo "Script that evaluates changed paths and emits an azure devops variable if the changes contained in the current HEAD against the difftarget meet the includepahts/excludepaths filters:" + echo " --difftarget SHA or branch to diff against. (i.e: HEAD^1, origin/main, 0f4hd36, etc.)" + echo " --excludepaths Escaped list of paths to exclude from diff separated by '+'. (i.e: 'src/libraries/*+'src/installer/*')" + echo " --includepaths Escaped list of paths to include on diff separated by '+'. (i.e: 'src/libraries/System.Private.CoreLib/*')" + echo " --subset Subset name for which we're evaluating in order to include it in logs" + echo " --azurevariable Name of azure devops variable to create if change meets filter criteria" + echo "" + + echo "Arguments can also be passed in with a single hyphen." +} + +source="${BASH_SOURCE[0]}" + +# resolve $source until the file is no longer a symlink +while [[ -h "$source" ]]; do + scriptroot="$( cd -P "$( dirname "$source" )" && pwd )" + source="$(readlink "$source")" + # if $source was a relative symlink, we need to resolve it relative to the path where the + # symlink file was located + [[ $source != /* ]] && source="$scriptroot/$source" +done + +scriptroot="$( cd -P "$( dirname "$source" )" && pwd )" +eng_root=`cd -P "$scriptroot" && pwd` + +exclude_paths=() +include_paths=() +subset_name='' +azure_variable='' +diff_target='' + +while [[ $# > 0 ]]; do + opt="$(echo "${1/#--/-}" | tr "[:upper:]" "[:lower:]")" + case "$opt" in + -help|-h) + usage + exit 0 + ;; + -difftarget) + diff_target=$2 + shift + ;; + -excludepaths) + IFS='+' read -r -a tmp <<< $2 + exclude_paths+=(${tmp[@]}) + shift + ;; + -includepaths) + IFS='+' read -r -a tmp <<< $2 + include_paths+=(${tmp[@]}) + shift + ;; + -subset) + subset_name=$2 + shift + ;; + -azurevariable) + azure_variable=$2 + shift + ;; + esac + + shift +done + +ci=true # Needed in order to use pipeline-logging-functions.sh +. "$eng_root/common/pipeline-logging-functions.sh" + +# -- expected args -- +# $@: git diff arguments +customGitDiff() { + ( + set -x + git diff -M -C -b --ignore-cr-at-eol --ignore-space-at-eol "$@" + ) +} + +# runs git diff with supplied filter. +# -- exit codes -- +# 0: No match was found +# 1: At least 1 match was found +# +# -- expected args -- +# $@: filter string +probePathsWithExitCode() { + local _filter=$@ + echo "" + customGitDiff --exit-code --quiet $diff_target -- $_filter +} + +# -- expected args -- +# $@: filter string +printMatchedPaths() { + local _subset=$subset_name + local _filter=$@ + echo "" + echo "----- Matching files for $_subset -----" + customGitDiff --name-only $diff_target -- $_filter +} + +probePaths() { + local _subset=$subset_name + local _azure_devops_var_name=$azure_variable + local exclude_path_string="" + local include_path_string="" + local found_applying_changes=false + + if [[ ${#exclude_paths[@]} -gt 0 ]]; then + echo "" + echo "******* Probing $_subset exclude paths *******"; + for _path in "${exclude_paths[@]}"; do + echo "$_path" + if [[ -z "$exclude_path_string" ]]; then + exclude_path_string=":!$_path" + else + exclude_path_string="$exclude_path_string :!$_path" + fi + done + + if ! probePathsWithExitCode $exclude_path_string; then + found_applying_changes=true + printMatchedPaths $exclude_path_string + fi + fi + + if [[ $found_applying_changes != true && ${#include_paths[@]} -gt 0 ]]; then + echo "" + echo "******* Probing $_subset include paths *******"; + for _path in "${include_paths[@]}"; do + echo "$_path" + if [[ -z "$include_path_string" ]]; then + include_path_string=":$_path" + else + include_path_string="$include_path_string :$_path" + fi + done + + if ! probePathsWithExitCode $include_path_string; then + found_applying_changes=true + printMatchedPaths $include_path_string + fi + fi + + if [[ $found_applying_changes == true ]]; then + echo "" + echo "Setting pipeline variable $_azure_devops_var_name=true" + Write-PipelineSetVariable -name $_azure_devops_var_name -value true -is_multi_job_variable true + else + echo "" + echo "No changed files for $_subset" + fi +} + +probePaths \ No newline at end of file diff --git a/eng/pipelines/build-unix-job.yml b/eng/pipelines/build-unix-job.yml index 4d295295984d6..f1304b25680da 100644 --- a/eng/pipelines/build-unix-job.yml +++ b/eng/pipelines/build-unix-job.yml @@ -20,7 +20,7 @@ jobs: - job: ${{ parameters.jobName }} pool: ${{ if ne(parameters.queueName, '') }}: - name: NetCore-Svc-Public + name: NetCore-Public demands: ImageOverride -equals ${{ parameters.queueName }} ${{ if ne(parameters.vmImageName, '') }}: diff --git a/eng/pipelines/build-windows-job.yml b/eng/pipelines/build-windows-job.yml index 247cceaae8c45..8d490a209fc38 100644 --- a/eng/pipelines/build-windows-job.yml +++ b/eng/pipelines/build-windows-job.yml @@ -15,6 +15,9 @@ parameters: - name: vmImageName type: string default: '' +- name: restoreArguments + type: string + default: '' - name: buildArguments type: string default: '' @@ -23,12 +26,14 @@ jobs: - job: ${{ parameters.jobName }} pool: ${{ if ne(parameters.queueName, '') }}: - name: NetCore-Svc-Public + name: NetCore-Public demands: ImageOverride -equals ${{ parameters.queueName }} ${{ if ne(parameters.vmImageName, '') }}: vmImage: ${{ parameters.vmImageName }} timeoutInMinutes: 40 + variables: + artifactName: ${{ parameters.testArtifactName }} steps: - template: checkout-windows-task.yml @@ -37,25 +42,27 @@ jobs: displayName: Restore inputs: filePath: eng/build.ps1 - arguments: -configuration ${{ parameters.configuration }} -prepareMachine -ci -restore -binaryLog + arguments: -configuration ${{ parameters.configuration }} -prepareMachine -ci -restore -binaryLog ${{ parameters.restoreArguments }} - task: PowerShell@2 displayName: Build inputs: filePath: eng/build.ps1 - arguments: -configuration ${{ parameters.configuration }} -prepareMachine -ci -build -publish -binaryLog -skipDocumentation ${{ parameters.buildArguments }} + arguments: -configuration ${{ parameters.configuration }} -prepareMachine -ci -build -binaryLog -skipDocumentation ${{ parameters.buildArguments }} - task: PowerShell@2 displayName: Prepare Unit Tests inputs: filePath: eng/prepare-tests.ps1 arguments: -configuration ${{ parameters.configuration }} + condition: and(ne(variables['artifactName'], ''), succeeded()) - task: PublishPipelineArtifact@1 displayName: Publish Test Payload inputs: targetPath: '$(Build.SourcesDirectory)\artifacts\testPayload' artifactName: ${{ parameters.testArtifactName }} + condition: and(ne(variables['artifactName'], ''), succeeded()) - template: publish-logs.yml parameters: diff --git a/eng/pipelines/checkout-unix-task.yml b/eng/pipelines/checkout-unix-task.yml index 5a6a75335c610..e65175caf5a7d 100644 --- a/eng/pipelines/checkout-unix-task.yml +++ b/eng/pipelines/checkout-unix-task.yml @@ -1,11 +1,14 @@ # Shallow checkout sources on Unix + steps: - checkout: none - script: | set -x git init + git config --local checkout.workers 0 + git config --local fetch.parallel 0 git remote add origin "$(Build.Repository.Uri)" - git fetch --progress --no-tags --depth=1 origin "$(Build.SourceVersion)" + git fetch --no-tags --no-auto-maintenance --depth=1 origin "$(Build.SourceVersion)" git checkout "$(Build.SourceVersion)" - displayName: Shallow Checkout \ No newline at end of file + displayName: Shallow Checkout diff --git a/eng/pipelines/checkout-windows-task.yml b/eng/pipelines/checkout-windows-task.yml index b506b0d888e53..304aa7868a5f9 100644 --- a/eng/pipelines/checkout-windows-task.yml +++ b/eng/pipelines/checkout-windows-task.yml @@ -5,10 +5,12 @@ steps: - checkout: none - script: | - @echo on set PATH=$(Agent.HomeDirectory)\externals\git\cmd;%PATH% + @echo on git init + git config --local checkout.workers 0 + git config --local fetch.parallel 0 git remote add origin "$(Build.Repository.Uri)" - git fetch --progress --no-tags --depth=1 origin "$(Build.SourceVersion)" + git fetch --no-tags --no-auto-maintenance --depth=1 origin "$(Build.SourceVersion)" git checkout "$(Build.SourceVersion)" displayName: Shallow Checkout diff --git a/eng/pipelines/evaluate-changed-files-group.yml b/eng/pipelines/evaluate-changed-files-group.yml new file mode 100644 index 0000000000000..820b0f7f4e0b8 --- /dev/null +++ b/eng/pipelines/evaluate-changed-files-group.yml @@ -0,0 +1,19 @@ +# This step template evaluates git changes using git based on a include/exclude path filter. +# For more information on how the path evaluation works look at evaluate-changed-paths.sh docs +# at the beginning of that file. + +parameters: + # Name for the subset that we're evaluating changes for. + # It is required to name the step correctly and so the variable created can be consumable. + subsetName: '' + # Array containing the arguments that are to be passed down to evaluate-changed-paths.sh + # Note that --azurevariable is always set to containschange, no need to pass it down. + arguments: [] + +steps: + - ${{ if ne(parameters.arguments[0], '') }}: + - script: eng/evaluate-changed-paths.sh + --azurevariable containsChange + ${{ join(' ', parameters.arguments) }} + displayName: Evaluate paths for ${{ parameters.subsetName }} + name: ${{ format('SetPathVars_{0}', parameters.subsetName) }} # need a name to access output variable \ No newline at end of file diff --git a/eng/pipelines/evaluate-changed-files.yml b/eng/pipelines/evaluate-changed-files.yml new file mode 100644 index 0000000000000..ff61d577afe38 --- /dev/null +++ b/eng/pipelines/evaluate-changed-files.yml @@ -0,0 +1,53 @@ +# Template to evaluate common paths in different pipelines. +parameters: +- name: jobName + type: string + default: '' +- name: queueName + type: string + default: '' +- name: vmImageName + type: string + default: '' +- name: paths + type: object + default: [] + +jobs: +- job: ${{ parameters.jobName }} + pool: + ${{ if ne(parameters.queueName, '') }}: + name: NetCore-Public + demands: ImageOverride -equals ${{ parameters.queueName }} + + ${{ if ne(parameters.vmImageName, '') }}: + vmImage: ${{ parameters.vmImageName }} + timeoutInMinutes: 10 + + steps: + - checkout: none + + - script: | + set -x + git init + git config --local checkout.workers 0 + git config --local fetch.parallel 0 + git remote add origin "$(Build.Repository.Uri)" + git fetch --no-tags --no-auto-maintenance --depth=2 origin "$(Build.SourceVersion)" + git checkout "$(Build.SourceVersion)" + displayName: Shallow Checkout + + - ${{ if ne(parameters.paths[0], '') }}: + - ${{ each path in parameters.paths }}: + - template: evaluate-changed-files-group.yml + parameters: + subsetName: ${{ path.subset }} + arguments: + # The commit that we're building is always a merge commit that is merging into the target branch. + # So the first parent of the commit is on the target branch and the second parent is on the source branch. + - --difftarget HEAD^1 + - --subset ${{ path.subset }} + - ${{ if ne(path.include[0], '') }}: + - --includepaths '${{ join('+', path.include) }}' + - ${{ if ne(path.exclude[0], '') }}: + - --excludepaths '${{ join('+', path.exclude) }}' \ No newline at end of file diff --git a/eng/pipelines/test-integration-job.yml b/eng/pipelines/test-integration-job.yml index 2f1156bbc8007..47804a6d9fae4 100644 --- a/eng/pipelines/test-integration-job.yml +++ b/eng/pipelines/test-integration-job.yml @@ -14,12 +14,13 @@ parameters: - name: lspEditor type: string default: false - - name: shallowCheckout + - name: skipCheckout type: boolean - default: true + default: false steps: - - ${{ if eq(parameters.shallowCheckout, true) }}: + # Pipelines like the DartLab integration pipeline skip checkout because it is performed elsewhere. + - ${{ if eq(parameters.skipCheckout, false) }}: - template: checkout-windows-task.yml - task: PowerShell@2 diff --git a/eng/pipelines/test-unix-job-single-machine.yml b/eng/pipelines/test-unix-job-single-machine.yml index 5bbdae6a587a9..3656369a48294 100644 --- a/eng/pipelines/test-unix-job-single-machine.yml +++ b/eng/pipelines/test-unix-job-single-machine.yml @@ -6,9 +6,6 @@ parameters: - name: jobName type: string default: '' -- name: buildJobName - type: string - default: '' - name: testArtifactName type: string default: '' @@ -27,15 +24,14 @@ parameters: jobs: - job: ${{ parameters.jobName }} - dependsOn: ${{ parameters.buildJobName }} pool: ${{ if ne(parameters.queueName, '') }}: - name: NetCore-Svc-Public + name: NetCore-Public demands: ImageOverride -equals ${{ parameters.queueName }} ${{ if ne(parameters.vmImageName, '') }}: vmImage: ${{ parameters.vmImageName }} - timeoutInMinutes: 40 + timeoutInMinutes: 50 variables: DOTNET_ROLL_FORWARD: LatestMajor DOTNET_ROLL_FORWARD_TO_PRERELEASE: 1 diff --git a/eng/pipelines/test-unix-job.yml b/eng/pipelines/test-unix-job.yml index 7da8c1726bf26..a0120fbd9cbf4 100644 --- a/eng/pipelines/test-unix-job.yml +++ b/eng/pipelines/test-unix-job.yml @@ -6,9 +6,6 @@ parameters: - name: jobName type: string default: '' -- name: buildJobName - type: string - default: '' - name: testArtifactName type: string default: '' @@ -21,7 +18,6 @@ parameters: jobs: - job: ${{ parameters.jobName }} - dependsOn: ${{ parameters.buildJobName }} pool: # Note that when helix is enabled, the agent running this job is essentially # a thin client that kicks off a helix job and waits for it to complete. diff --git a/eng/pipelines/test-windows-job-single-machine.yml b/eng/pipelines/test-windows-job-single-machine.yml index 53cfc1e7b9a2e..fb640cc819878 100644 --- a/eng/pipelines/test-windows-job-single-machine.yml +++ b/eng/pipelines/test-windows-job-single-machine.yml @@ -6,9 +6,6 @@ parameters: - name: jobName type: string default: '' -- name: buildJobName - type: string - default: '' - name: testArtifactName type: string default: '' @@ -24,9 +21,8 @@ parameters: jobs: - job: ${{ parameters.jobName }} - dependsOn: ${{ parameters.buildJobName }} pool: - name: NetCore-Svc-Public + name: NetCore-Public demands: ImageOverride -equals ${{ parameters.queueName }} timeoutInMinutes: 120 variables: diff --git a/eng/pipelines/test-windows-job.yml b/eng/pipelines/test-windows-job.yml index 3f5eab6f6bddc..8a63210991e24 100644 --- a/eng/pipelines/test-windows-job.yml +++ b/eng/pipelines/test-windows-job.yml @@ -6,9 +6,6 @@ parameters: - name: jobName type: string default: '' -- name: buildJobName - type: string - default: '' - name: testArtifactName type: string default: '' @@ -21,7 +18,6 @@ parameters: jobs: - job: ${{ parameters.jobName }} - dependsOn: ${{ parameters.buildJobName }} pool: # Note that when helix is enabled, the agent running this job is essentially # a thin client that kicks off a helix job and waits for it to complete. diff --git a/eng/prepare-tests.ps1 b/eng/prepare-tests.ps1 index cfdcee17742ef..2d2bd79c8296f 100644 --- a/eng/prepare-tests.ps1 +++ b/eng/prepare-tests.ps1 @@ -11,7 +11,7 @@ try { $dotnet = Ensure-DotnetSdk # permissions issues make this a pain to do in PrepareTests itself. Remove-Item -Recurse -Force "$RepoRoot\artifacts\testPayload" -ErrorAction SilentlyContinue - Exec-Console $dotnet "$RepoRoot\artifacts\bin\PrepareTests\$configuration\net6.0\PrepareTests.dll --source $RepoRoot --destination $RepoRoot\artifacts\testPayload" + Exec-Console $dotnet "$RepoRoot\artifacts\bin\PrepareTests\$configuration\net6.0\PrepareTests.dll --source $RepoRoot --destination $RepoRoot\artifacts\testPayload --dotnetPath `"$dotnet`"" exit 0 } catch { diff --git a/eng/prepare-tests.sh b/eng/prepare-tests.sh index 5b0310573bd1f..4d6cff2d5da83 100755 --- a/eng/prepare-tests.sh +++ b/eng/prepare-tests.sh @@ -28,4 +28,4 @@ InitializeDotNetCli true # permissions issues make this a pain to do in PrepareTests itself. rm -rf "$repo_root/artifacts/testPayload" -dotnet "$repo_root/artifacts/bin/PrepareTests/Debug/net6.0/PrepareTests.dll" --source "$repo_root" --destination "$repo_root/artifacts/testPayload" --unix +dotnet "$repo_root/artifacts/bin/PrepareTests/Debug/net6.0/PrepareTests.dll" --source "$repo_root" --destination "$repo_root/artifacts/testPayload" --unix --dotnetPath ${_InitializeDotNetCli}/dotnet \ No newline at end of file diff --git a/eng/targets/DoNotDeployToSymStore_Workaround.targets b/eng/targets/DoNotDeployToSymStore_Workaround.targets new file mode 100644 index 0000000000000..42d9c7317db84 --- /dev/null +++ b/eng/targets/DoNotDeployToSymStore_Workaround.targets @@ -0,0 +1,7 @@ + + + + + + \ No newline at end of file diff --git a/eng/targets/DoNotGenerateSatelliteAssemblies_Workaround.targets b/eng/targets/DoNotGenerateSatelliteAssemblies_Workaround.targets new file mode 100644 index 0000000000000..97b1f4b3dfb7b --- /dev/null +++ b/eng/targets/DoNotGenerateSatelliteAssemblies_Workaround.targets @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/eng/targets/GenerateServiceHubConfigurationFiles.targets b/eng/targets/GenerateServiceHubConfigurationFiles.targets index bd2a648d1226f..e692e65643593 100644 --- a/eng/targets/GenerateServiceHubConfigurationFiles.targets +++ b/eng/targets/GenerateServiceHubConfigurationFiles.targets @@ -19,7 +19,7 @@ - + NON_EXISTENT_FILE @@ -39,6 +40,9 @@ Microsoft.Common.CurrentVersion.targets to see how it is consumed --> false + + true + false enable @@ -53,6 +57,13 @@ false false + + + + false + @@ -4250,7 +4247,7 @@ - n + diff --git a/src/Compilers/CSharp/Portable/Syntax/SyntaxFactory.cs b/src/Compilers/CSharp/Portable/Syntax/SyntaxFactory.cs index 0ec3762eed18e..a2e2e72a2d5b5 100644 --- a/src/Compilers/CSharp/Portable/Syntax/SyntaxFactory.cs +++ b/src/Compilers/CSharp/Portable/Syntax/SyntaxFactory.cs @@ -290,9 +290,8 @@ public static SyntaxToken MissingToken(SyntaxTriviaList leading, SyntaxKind kind /// /// Creates a token with kind IdentifierToken containing the specified text. - /// The raw text of the identifier name, including any escapes or leading '@' - /// character. /// + /// The raw text of the identifier name, including any escapes or leading '@' character. public static SyntaxToken Identifier(string text) { return new SyntaxToken(Syntax.InternalSyntax.SyntaxFactory.Identifier(ElasticMarker.UnderlyingNode, text, ElasticMarker.UnderlyingNode)); diff --git a/src/Compilers/CSharp/Portable/Syntax/SyntaxKind.cs b/src/Compilers/CSharp/Portable/Syntax/SyntaxKind.cs index 99d3d48bf3055..8c49e1a020211 100644 --- a/src/Compilers/CSharp/Portable/Syntax/SyntaxKind.cs +++ b/src/Compilers/CSharp/Portable/Syntax/SyntaxKind.cs @@ -16,8 +16,11 @@ public enum SyntaxKind : ushort TildeToken = 8193, /// Represents ! token. ExclamationToken = 8194, - /// Represents $ token. - /// This is a debugger special punctuation and not related to string interpolation. + /// Represents $ token. + /// + /// This is a debugger special punctuation and not related to string interpolation. + /// + /// DollarToken = 8195, /// Represents % token. PercentToken = 8196, @@ -408,6 +411,8 @@ public enum SyntaxKind : ushort RequiredKeyword = 8447, /// Represents . ScopedKeyword = 8448, + /// Represents . + FileKeyword = 8449, // when adding a contextual keyword following functions must be adapted: // @@ -474,11 +479,17 @@ public enum SyntaxKind : ushort VarKeyword = 8490, /// Represents _ token. UnderscoreToken = 8491, - /// Represents that nothing was specified as a type argument. - /// For example Dictionary<,> which has as a child of before and after the . + /// Represents that nothing was specified as a type argument. + /// For example Dictionary<,> which has as a child of + /// before and after the . + /// + /// OmittedTypeArgumentToken = 8492, - /// Represents that nothing was specified as an array size. - /// For example int[,] which has as a child of before and after the . + /// Represents that nothing was specified as an array size. + /// For example int[,] which has as a child of + /// before and after the . + /// + /// OmittedArraySizeExpressionToken = 8493, /// Represents a token that comes after the end of a directive such as #endif. EndOfDirectiveToken = 8494, diff --git a/src/Compilers/CSharp/Portable/Syntax/SyntaxKindFacts.cs b/src/Compilers/CSharp/Portable/Syntax/SyntaxKindFacts.cs index db242c0548924..d6624d597b04b 100644 --- a/src/Compilers/CSharp/Portable/Syntax/SyntaxKindFacts.cs +++ b/src/Compilers/CSharp/Portable/Syntax/SyntaxKindFacts.cs @@ -1138,7 +1138,7 @@ public static SyntaxKind GetPreprocessorKeywordKind(string text) public static IEnumerable GetContextualKeywordKinds() { - for (int i = (int)SyntaxKind.YieldKeyword; i <= (int)SyntaxKind.ScopedKeyword; i++) + for (int i = (int)SyntaxKind.YieldKeyword; i <= (int)SyntaxKind.FileKeyword; i++) { yield return (SyntaxKind)i; } @@ -1193,6 +1193,7 @@ public static bool IsContextualKeyword(SyntaxKind kind) case SyntaxKind.UnmanagedKeyword: case SyntaxKind.RequiredKeyword: case SyntaxKind.ScopedKeyword: + case SyntaxKind.FileKeyword: return true; default: return false; @@ -1316,6 +1317,8 @@ public static SyntaxKind GetContextualKeywordKind(string text) return SyntaxKind.RequiredKeyword; case "scoped": return SyntaxKind.ScopedKeyword; + case "file": + return SyntaxKind.FileKeyword; default: return SyntaxKind.None; } @@ -1759,6 +1762,8 @@ public static string GetText(SyntaxKind kind) return "required"; case SyntaxKind.ScopedKeyword: return "scoped"; + case SyntaxKind.FileKeyword: + return "file"; default: return string.Empty; } diff --git a/src/Compilers/CSharp/Portable/Syntax/SyntaxNodeExtensions.cs b/src/Compilers/CSharp/Portable/Syntax/SyntaxNodeExtensions.cs index fb81d2bb470b4..58999510e96a4 100644 --- a/src/Compilers/CSharp/Portable/Syntax/SyntaxNodeExtensions.cs +++ b/src/Compilers/CSharp/Portable/Syntax/SyntaxNodeExtensions.cs @@ -230,25 +230,12 @@ internal static RefKind GetRefKind(this TypeSyntax syntax) internal static TypeSyntax SkipRef(this TypeSyntax syntax, out RefKind refKind) { - return SkipRef(syntax, out refKind, allowScoped: true, diagnostics: null); - } - - internal static TypeSyntax SkipRef(this TypeSyntax syntax, out RefKind refKind, bool allowScoped, BindingDiagnosticBag? diagnostics) - { - Debug.Assert(allowScoped || diagnostics is { }); - if (syntax.Kind() == SyntaxKind.RefType) { var refType = (RefTypeSyntax)syntax; refKind = refType.ReadOnlyKeyword.Kind() == SyntaxKind.ReadOnlyKeyword ? RefKind.RefReadOnly : RefKind.Ref; - if (refType.ScopedKeyword.Kind() == SyntaxKind.ScopedKeyword && - !allowScoped && - diagnostics is { }) - { - diagnostics.Add(ErrorCode.ERR_BadMemberFlag, refType.ScopedKeyword.GetLocation(), SyntaxFacts.GetText(SyntaxKind.ScopedKeyword)); - } return refType.Type; } diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf index 64ef6c5d2b535..c1531e0b5d576 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf @@ -207,6 +207,11 @@ Operátor {0} nejde použít pro operand {1}. + + The parameter modifier '{0}' cannot follow '{1}' + The parameter modifier '{0}' cannot follow '{1}' + + Invalid operand for pattern match; value required, but found '{0}'. Neplatný operand pro porovnávací vzorek. Vyžaduje se hodnota, ale nalezeno: {0}. @@ -257,6 +262,11 @@ Nedal se odvodit typ delegáta. + + 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 specifc numeric type. + + 'managed' calling convention cannot be combined with unmanaged calling convention specifiers. Konvence volání managed se nedá kombinovat se specifikátory konvence nespravovaného volání. @@ -472,6 +482,11 @@ Nepoužívejte System.Runtime.CompilerServices.RequiredMemberAttribute. Místo toho použijte klíčové slovo required pro povinná pole a vlastnosti. + + Do not use 'System.Runtime.CompilerServices.ScopedRefAttribute'. Use the 'scoped' keyword instead. + Do not use 'System.Runtime.CompilerServices.ScopedRefAttribute'. Use the 'scoped' keyword instead. + + The given expression cannot be used in a fixed statement Daný výraz nelze použít v příkazu fixed. @@ -552,6 +567,11 @@ Funkce {0} není v C# 10.0 dostupná. Použijte prosím jazykovou verzi {1} nebo novější. + + Feature '{0}' is not available in C# 11.0. Please use language version {1} or greater. + Feature '{0}' is not available in C# 11.0. Please use language version {1} or greater. + + Feature '{0}' is not available in C# 8.0. Please use language version {1} or greater. Funkce {0} není v C# 8.0 dostupná. Použijte prosím jazykovou verzi {1} nebo větší. @@ -582,6 +602,31 @@ Obor názvů pro celý soubor musí předcházet všem ostatním členům v souboru. + + File-local type '{0}' cannot be used as a base type of non-file-local type '{1}'. + File-local type '{0}' cannot be used as a base type of non-file-local type '{1}'. + + + + File-local type '{0}' cannot be used in a member signature in non-file-local type '{1}'. + File-local type '{0}' cannot be used in a member signature in non-file-local type '{1}'. + + + + Types and aliases cannot be named 'file'. + Types and aliases cannot be named 'file'. + + + + File-local type '{0}' must be defined in a top level type; '{0}' is a nested type. + File-local type '{0}' must be defined in a top level type; '{0}' is a nested type. + + + + File-local type '{0}' cannot use accessibility modifiers. + File-local type '{0}' cannot use accessibility modifiers. + + A fixed field must not be a ref field. Pevné pole nesmí být pole ref. @@ -627,6 +672,11 @@ Globální direktiva using musí předcházet všem direktivám using, které nejsou globální. + + File-local type '{0}' cannot be used in a 'global using static' directive. + File-local type '{0}' cannot be used in a 'global using static' directive. + + A goto cannot jump to a location before a using declaration within the same block. Příkaz goto nemůže přejít na místo před deklarací using ve stejném bloku. @@ -882,6 +932,11 @@ Neočekávané klíčové slovo record. Měli jste na mysli record struct nebo record class? + + Unexpected contextual keyword 'scoped'. Did you mean 'scoped ref' or '@scoped'? + Unexpected contextual keyword 'scoped'. Did you mean 'scoped ref' or '@scoped'? + + Slice patterns may only be used once and directly inside a list pattern. Vzory řezů se dají použít jenom jednou a přímo uvnitř vzoru seznamu. @@ -923,8 +978,8 @@ - Module initializer method '{0}' must be static, must have no parameters, and must return 'void' - Inicializační metoda modulu {0} musí být statická, nesmí mít žádné parametry a musí vracet void. + Module initializer method '{0}' must be static, and non-virtual, must have no parameters, and must return 'void' + Inicializační metoda modulu {0} musí být statická, nesmí mít žádné parametry a musí vracet void. @@ -1227,6 +1282,11 @@ Pole ref nemůže odkazovat na hodnotu ref struct. + + A ref field can only be declared in a ref struct. + A ref field can only be declared in a ref struct. + + The left-hand side of a ref assignment must be a ref variable. Levá strana přiřazení odkazu musí být parametr Ref. @@ -1297,6 +1357,11 @@ Cílový modul runtime nepodporuje pro člena rozhraní přístupnost na úrovni Protected, Protected internal nebo Private protected. + + Target runtime doesn't support ref fields. + Target runtime doesn't support ref fields. + + Target runtime doesn't support static abstract members in interfaces. Cílový modul runtime nepodporuje statické abstraktní členy v rozhraních. @@ -1332,6 +1397,11 @@ Modifikátor scoped se dá použít jen pro hodnoty refs a ref struct. + + Types and aliases cannot be named 'scoped'. + Types and aliases cannot be named 'scoped'. + + Required members are not allowed on the top level of a script or submission. Povinní členové nejsou povoleni na nejvyšší úrovni skriptu nebo odeslání. @@ -1512,6 +1582,16 @@ {0} má atribut UnmanagedCallersOnly a nedá se převést na typ delegáta. Pro tuto metodu získejte ukazatel na funkci. UnmanagedCallersOnly is not localizable. + + UnscopedRefAttribute can only be applied to 'out' parameters, 'ref' and 'in' parameters that refer to 'ref struct' types, and instance methods and properties on 'struct' types other than constructors and 'init' accessors. + UnscopedRefAttribute can only be applied to 'out' parameters, 'ref' and 'in' parameters that refer to 'ref struct' types, and instance methods and properties on 'struct' types other than constructors and 'init' accessors. + + + + UnscopedRefAttribute cannot be applied to parameters that have a 'scoped' modifier. + UnscopedRefAttribute cannot be applied to parameters that have a 'scoped' modifier. + + '{0}' requires compiler feature '{1}', which is not supported by this version of the C# compiler. {0} vyžaduje funkci kompilátoru {1}, což tato verze kompilátoru C# nepodporuje. @@ -1562,6 +1642,11 @@ Direktiva using se dříve zobrazovala jako globální direktiva using + + array access + array access + + async method builder override přepsání tvůrce asynchronní metody @@ -1602,6 +1687,11 @@ obor názvů pro celý soubor + + file types + file types + + generic attributes obecné atributy @@ -1719,7 +1809,12 @@ pattern matching ReadOnly/Span<char> on constant string - vzor odpovídající ReadOnly/Span<char> na konstantním řetězci + pattern matching ReadOnly/Span<char> on constant string + + + + pointer element access + pointer element access @@ -2260,7 +2355,7 @@ -instrument:TestCoverage Vytvoří sestavení instrumentované ke shromažďování informací o pokrytí. -sourcelink:<file> Informace o zdrojovém odkazu vkládané do souboru PDB.. - + - CHYBY A UPOZORNĚNÍ - -warnaserror[+|-] Hlásí všechna upozornění jako chyby. -warnaserror[+|-]:<warn list> Hlásí zadaná upozornění jako chyby. @@ -10477,11 +10572,6 @@ Pokud chcete odstranit toto varování, můžete místo toho použít /reference Proběhlo volání funkce GetDeclarationName kvůli uzlu deklarací, který by mohl obsahovat několik variabilních deklarátorů. - - tree not part of compilation - strom není součástí kompilace - - Position is not within syntax tree with full span {0} Pozice není v rámci stromu syntaxe s plným rozpětím {0}. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf index 024b561d76453..c5aa15aaf181a 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf @@ -207,6 +207,11 @@ Der Operator "{0}" kann nicht auf den Operanden "{1}" angewendet werden. + + The parameter modifier '{0}' cannot follow '{1}' + The parameter modifier '{0}' cannot follow '{1}' + + Invalid operand for pattern match; value required, but found '{0}'. Ungültiger Operand für die Musterübereinstimmung. Ein Wert ist erforderlich, gefunden wurde aber "{0}". @@ -257,6 +262,11 @@ Der Delegattyp konnte nicht abgeleitet werden. + + 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 specifc numeric type. + + 'managed' calling convention cannot be combined with unmanaged calling convention specifiers. Die Aufrufkonvention "managed" kann nicht mit Spezifizierern für nicht verwaltete Aufrufkonventionen kombiniert werden. @@ -472,6 +482,11 @@ Verwenden Sie "System.Runtime.CompilerServices.RequiredMemberAttribute" nicht. Verwenden Sie stattdessen das Schlüsselwort "erforderlich" für erforderliche Felder und Eigenschaften. + + Do not use 'System.Runtime.CompilerServices.ScopedRefAttribute'. Use the 'scoped' keyword instead. + Do not use 'System.Runtime.CompilerServices.ScopedRefAttribute'. Use the 'scoped' keyword instead. + + The given expression cannot be used in a fixed statement Der angegebene Ausdruck kann nicht in einer fixed-Anweisung verwendet werden. @@ -552,6 +567,11 @@ Die Funktion „{0}“ ist in C# 10.0 nicht verfügbar. Bitte verwenden Sie Sprachversion {1} oder höher. + + Feature '{0}' is not available in C# 11.0. Please use language version {1} or greater. + Feature '{0}' is not available in C# 11.0. Please use language version {1} or greater. + + Feature '{0}' is not available in C# 8.0. Please use language version {1} or greater. Das Feature "{0}" ist in C# 8.0 nicht verfügbar. Verwenden Sie Sprachversion {1} oder höher. @@ -582,6 +602,31 @@ Der Dateibereichsnamespace muss allen anderen Elementen in einer Datei vorangestellt sein. + + File-local type '{0}' cannot be used as a base type of non-file-local type '{1}'. + File-local type '{0}' cannot be used as a base type of non-file-local type '{1}'. + + + + File-local type '{0}' cannot be used in a member signature in non-file-local type '{1}'. + File-local type '{0}' cannot be used in a member signature in non-file-local type '{1}'. + + + + Types and aliases cannot be named 'file'. + Types and aliases cannot be named 'file'. + + + + File-local type '{0}' must be defined in a top level type; '{0}' is a nested type. + File-local type '{0}' must be defined in a top level type; '{0}' is a nested type. + + + + File-local type '{0}' cannot use accessibility modifiers. + File-local type '{0}' cannot use accessibility modifiers. + + A fixed field must not be a ref field. Ein festes Feld darf kein Referenzfeld sein. @@ -627,6 +672,11 @@ Eine globale using-Anweisung muss allen nicht globalen using-Anweisungen vorangehen. + + File-local type '{0}' cannot be used in a 'global using static' directive. + File-local type '{0}' cannot be used in a 'global using static' directive. + + A goto cannot jump to a location before a using declaration within the same block. Mit "goto" kann nicht an eine Position vor einer using-Deklaration im selben Block gesprungen werden. @@ -882,6 +932,11 @@ Unerwartetes Schlüsselwort „Datensatz“. Meinten Sie „Datensatzstruktur“ oder „Datensatzklasse“? + + Unexpected contextual keyword 'scoped'. Did you mean 'scoped ref' or '@scoped'? + Unexpected contextual keyword 'scoped'. Did you mean 'scoped ref' or '@scoped'? + + Slice patterns may only be used once and directly inside a list pattern. Segmentmuster dürfen nur einmal und direkt innerhalb eines Listenmusters verwendet werden. @@ -923,8 +978,8 @@ - Module initializer method '{0}' must be static, must have no parameters, and must return 'void' - Die Modulinitialisierermethode "{0}" muss statisch sein, darf keine Parameter enthalten und muss "void" zurückgeben. + Module initializer method '{0}' must be static, and non-virtual, must have no parameters, and must return 'void' + Die Modulinitialisierermethode "{0}" muss statisch sein, darf keine Parameter enthalten und muss "void" zurückgeben. @@ -1227,6 +1282,11 @@ Ein Ref-Feld kann nicht auf eine Ref-Struktur verweisen. + + A ref field can only be declared in a ref struct. + A ref field can only be declared in a ref struct. + + The left-hand side of a ref assignment must be a ref variable. Die linke Seite einer Ref-Zuweisung muss eine Ref-Variable sein. @@ -1297,6 +1357,11 @@ Die Zugriffsoptionen "protected", "protected internal" oder "private protected" werden von der Zielruntime für einen Member einer Schnittstelle nicht unterstützt. + + Target runtime doesn't support ref fields. + Target runtime doesn't support ref fields. + + Target runtime doesn't support static abstract members in interfaces. Die Zielruntime unterstützt keine statischen abstrakten Elemente in Schnittstellen. @@ -1332,6 +1397,11 @@ Der Modifikator ‚Scoped‘ kann nur für Refs und Ref-Strukturwerte verwendet werden. + + Types and aliases cannot be named 'scoped'. + Types and aliases cannot be named 'scoped'. + + Required members are not allowed on the top level of a script or submission. Erforderliche Mitglieder sind auf der obersten Ebene eines Skripts oder einer Übermittlung nicht zulässig. @@ -1512,6 +1582,16 @@ "{0}" ist mit dem Attribut "UnmanagedCallersOnly" versehen und kann nicht in einen Delegattyp konvertiert werden. Rufen Sie einen Funktionszeiger auf diese Methode ab. UnmanagedCallersOnly is not localizable. + + UnscopedRefAttribute can only be applied to 'out' parameters, 'ref' and 'in' parameters that refer to 'ref struct' types, and instance methods and properties on 'struct' types other than constructors and 'init' accessors. + UnscopedRefAttribute can only be applied to 'out' parameters, 'ref' and 'in' parameters that refer to 'ref struct' types, and instance methods and properties on 'struct' types other than constructors and 'init' accessors. + + + + UnscopedRefAttribute cannot be applied to parameters that have a 'scoped' modifier. + UnscopedRefAttribute cannot be applied to parameters that have a 'scoped' modifier. + + '{0}' requires compiler feature '{1}', which is not supported by this version of the C# compiler. '{0}' erfordert die Compilerfunktion '{1}', die von dieser Version des C#-Compilers nicht unterstützt wird. @@ -1562,6 +1642,11 @@ Die Verwenden-Anweisung wurde zuvor als „Global verwenden“ angezeigt + + array access + array access + + async method builder override Außerkraftsetzung des asynchronen Methoden-Generators @@ -1602,6 +1687,11 @@ Dateibereichsnamespace + + file types + file types + + generic attributes Generische Attribute @@ -1722,6 +1812,11 @@ Musterabgleich ReadOnly/Span<char> bei konstanter Zeichenfolge + + pointer element access + pointer element access + + The assembly '{0}' containing type '{1}' references .NET Framework, which is not supported. Die Assembly "{0}" mit dem Typ "{1}" verweist auf das .NET Framework. Dies wird nicht unterstützt. @@ -2263,7 +2358,7 @@ – FEHLER UND WARNUNGEN – -warnaserror[+|-] Meldet alle Warnungen als Fehler. --warnaserror[+|-]:<Warnungsliste> Meldet bestimmte Warnungen als Fehler +-warnaserror[+|-]:<Warnungsliste> Meldet bestimmte Warnungen als Fehler (Verwendung von "nullable" für alle Warnungen zur NULL-Zulässigkeit). -warn:<n> Legt die Warnstufe fest (0 oder höher) (Kurzform: -w). -nowarn:<Warnungsliste> Deaktiviert bestimmte Warnmeldungen @@ -10477,11 +10572,6 @@ Um die Warnung zu beheben, können Sie stattdessen /reference verwenden (Einbett GetDeclarationName wurde für einen Deklarationsknoten aufgerufen, der möglicherweise mehrere Variablendeklaratoren enthalten kann. - - tree not part of compilation - Der Baum ist nicht Teil der Kompilierung. - - Position is not within syntax tree with full span {0} Die Position ist nicht innerhalb des Syntaxbaums mit dem Vollbereich {0}. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf index 824cd7117fbcb..b4c26b2d593d3 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf @@ -207,6 +207,11 @@ El operador "{0}" no se puede aplicar al operando del tipo "{1}" + + The parameter modifier '{0}' cannot follow '{1}' + The parameter modifier '{0}' cannot follow '{1}' + + Invalid operand for pattern match; value required, but found '{0}'. Operando no válido para la coincidencia de patrones. Se requería un valor, pero se encontró '{0}'. @@ -257,6 +262,11 @@ El tipo de delegado no se puede deducir. + + 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 specifc numeric type. + + 'managed' calling convention cannot be combined with unmanaged calling convention specifiers. La convención de llamada "managed" no se puede combinar con especificadores de convención de llamada no administrados. @@ -472,6 +482,11 @@ No use 'System.Runtime.CompilerServices.RequiredMemberAttribute'. Use la palabra clave 'required' en campos y propiedades obligatorios en su lugar. + + Do not use 'System.Runtime.CompilerServices.ScopedRefAttribute'. Use the 'scoped' keyword instead. + Do not use 'System.Runtime.CompilerServices.ScopedRefAttribute'. Use the 'scoped' keyword instead. + + The given expression cannot be used in a fixed statement La expresión proporcionada no se puede utilizar en una instrucción "fixed" @@ -552,6 +567,11 @@ La característica "{0}" no está disponible en C# 10.0. Use la versión {1} del lenguaje o una posterior. + + Feature '{0}' is not available in C# 11.0. Please use language version {1} or greater. + Feature '{0}' is not available in C# 11.0. Please use language version {1} or greater. + + Feature '{0}' is not available in C# 8.0. Please use language version {1} or greater. La característica "{0}" no está disponible en C# 8.0. Use la versión {1} del lenguaje o una posterior. @@ -582,6 +602,31 @@ El espacio de nombres con ámbito de archivo debe preceder a todos los demás miembros de un archivo. + + File-local type '{0}' cannot be used as a base type of non-file-local type '{1}'. + File-local type '{0}' cannot be used as a base type of non-file-local type '{1}'. + + + + File-local type '{0}' cannot be used in a member signature in non-file-local type '{1}'. + File-local type '{0}' cannot be used in a member signature in non-file-local type '{1}'. + + + + Types and aliases cannot be named 'file'. + Types and aliases cannot be named 'file'. + + + + File-local type '{0}' must be defined in a top level type; '{0}' is a nested type. + File-local type '{0}' must be defined in a top level type; '{0}' is a nested type. + + + + File-local type '{0}' cannot use accessibility modifiers. + File-local type '{0}' cannot use accessibility modifiers. + + A fixed field must not be a ref field. Un campo fijo no debe ser un campo de referencia. @@ -627,6 +672,11 @@ Una directiva de uso global debe ser anterior a todas las directivas no globales que no son de uso. + + File-local type '{0}' cannot be used in a 'global using static' directive. + File-local type '{0}' cannot be used in a 'global using static' directive. + + A goto cannot jump to a location before a using declaration within the same block. Una instrucción goto no puede saltar a una ubicación antes que una declaración using dentro del mismo bloque. @@ -882,6 +932,11 @@ Palabra clave \"record\" inesperada. ¿Quería decir \"record struct\" o \"record class\"? + + Unexpected contextual keyword 'scoped'. Did you mean 'scoped ref' or '@scoped'? + Unexpected contextual keyword 'scoped'. Did you mean 'scoped ref' or '@scoped'? + + Slice patterns may only be used once and directly inside a list pattern. Los patrones de segmento solo se pueden utilizar una vez directamente dentro de un patrón de lista. @@ -923,8 +978,8 @@ - Module initializer method '{0}' must be static, must have no parameters, and must return 'void' - El método inicializador de módulos "{0}" debe ser estático, no debe tener parámetros y debe devolver "void". + Module initializer method '{0}' must be static, and non-virtual, must have no parameters, and must return 'void' + El método inicializador de módulos "{0}" debe ser estático, no debe tener parámetros y debe devolver "void". @@ -1227,6 +1282,11 @@ Un campo de referencia no puede hacer referencia a una estructura de referencia. + + A ref field can only be declared in a ref struct. + A ref field can only be declared in a ref struct. + + The left-hand side of a ref assignment must be a ref variable. La parte izquierda de una asignación de referencias debe ser una variable local. @@ -1297,6 +1357,11 @@ El entorno de ejecución de destino no admite la accesibilidad protegida, protegida interna o protegida privada para un miembro de una interfaz. + + Target runtime doesn't support ref fields. + Target runtime doesn't support ref fields. + + Target runtime doesn't support static abstract members in interfaces. El tiempo de ejecución de destino no admite miembros abstractos estáticos en interfaces. @@ -1332,6 +1397,11 @@ El modificador 'scoped' solo se puede usar para referencias y valores de estructura de referencia. + + Types and aliases cannot be named 'scoped'. + Types and aliases cannot be named 'scoped'. + + Required members are not allowed on the top level of a script or submission. No se permiten miembros necesarios en el nivel superior de un script o envío. @@ -1512,6 +1582,16 @@ ' {0} ' tiene un atributo ' UnmanagedCallersOnly ' y no se puede convertir en un tipo de delegado. Obtenga un puntero de función a este método. UnmanagedCallersOnly is not localizable. + + UnscopedRefAttribute can only be applied to 'out' parameters, 'ref' and 'in' parameters that refer to 'ref struct' types, and instance methods and properties on 'struct' types other than constructors and 'init' accessors. + UnscopedRefAttribute can only be applied to 'out' parameters, 'ref' and 'in' parameters that refer to 'ref struct' types, and instance methods and properties on 'struct' types other than constructors and 'init' accessors. + + + + UnscopedRefAttribute cannot be applied to parameters that have a 'scoped' modifier. + UnscopedRefAttribute cannot be applied to parameters that have a 'scoped' modifier. + + '{0}' requires compiler feature '{1}', which is not supported by this version of the C# compiler. '{0}' requiere la característica del compilador '{1}', que no es compatible con esta versión del compilador de C#. @@ -1562,6 +1642,11 @@ La directiva using aparecía anteriormente como using global + + array access + array access + + async method builder override invalidación del generador de métodos asincrónicos @@ -1602,6 +1687,11 @@ espacio de nombres con ámbito de archivo + + file types + file types + + generic attributes atributos genéricos @@ -1722,6 +1812,11 @@ patrón que coincide con ReadOnly/Span<char> en una cadena constante + + pointer element access + pointer element access + + The assembly '{0}' containing type '{1}' references .NET Framework, which is not supported. El ensamblado "{0}" que contiene el tipo "{1}" hace referencia a .NET Framework, lo cual no se admite. @@ -2198,7 +2293,7 @@ Opciones del compilador de Visual C# - ARCHIVOS DE SALIDA - --out:<archivo> Especifica el nombre del archivo de salida (el valor predeterminado: nombre base del +-out:<archivo> Especifica el nombre del archivo de salida (el valor predeterminado: nombre base del archivo con la clase principal o el primer archivo) -target:exe Compila un archivo ejecutable de consola (predeterminado) (forma corta: -t:exe) @@ -2260,7 +2355,7 @@ -instrument:TestCoverage Produce un ensamblado instrumentado para recopilar información de cobertura. -sourcelink:<archivo> Información del vínculo de origen para insertar en el PDB. - + - ERRORES Y ADVERTENCIAS - -warnaserror[+|-] Notifica todas las advertencias como errores. -warnaserror[+|-]:<lista de advertencias > Notifica advertencias específicas como errores @@ -2332,7 +2427,7 @@ -pdb:<archivo> Especifica el nombre de archivo de información de depuración (valor predeterminado: nombre de archivo de salida con la extensión .pdb). -errorendlocation Línea y columna de salida de la ubicación final de - cada error. + cada error. -preferreduilang Especifica el nombre del lenguaje de salida preferido. -nosdkpath Deshabilita la búsqueda de la ruta del SDK predeterminada para los ensamblados de biblioteca estándar. -nostdlib[+|-] No hace referencia a la biblioteca estándar (mscorlib.dll). @@ -10477,11 +10572,6 @@ Para eliminar la advertencia puede usar /reference (establezca la propiedad Embe Se ha llamado a GetDeclarationName para un nodo de declaración que puede contener varios declaradores de variables. - - tree not part of compilation - el árbol no forma parte de la compilación - - Position is not within syntax tree with full span {0} La posición no está dentro del árbol de sintaxis con el intervalo completo {0} diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf index 87942ab0dd7c7..391f9476a5ca6 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf @@ -207,6 +207,11 @@ Impossible d'appliquer l'opérateur '{0}' à un opérande '{1}' + + The parameter modifier '{0}' cannot follow '{1}' + The parameter modifier '{0}' cannot follow '{1}' + + Invalid operand for pattern match; value required, but found '{0}'. Opérande non valide pour les critères spéciaux ; la valeur nécessaire n'est pas celle trouvée, '{0}'. @@ -257,6 +262,11 @@ Impossible de déduire le type délégué. + + 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 specifc numeric type. + + 'managed' calling convention cannot be combined with unmanaged calling convention specifiers. Impossible d'associer la convention d'appel 'managed' à des spécificateurs de convention d'appel non managés. @@ -472,6 +482,11 @@ N’utilisez pas « System.Runtime.CompilerServices.RequiredMemberAttribute ». Utilisez plutôt le mot clé « required » sur les champs et propriétés requis. + + Do not use 'System.Runtime.CompilerServices.ScopedRefAttribute'. Use the 'scoped' keyword instead. + Do not use 'System.Runtime.CompilerServices.ScopedRefAttribute'. Use the 'scoped' keyword instead. + + The given expression cannot be used in a fixed statement Impossible d'utiliser l'expression donnée dans une instruction fixed @@ -552,6 +567,11 @@ La fonctionnalité '{0}' n'est pas disponible en C# 9.0. Utilisez la version de langage {1} ou une version ultérieure. + + Feature '{0}' is not available in C# 11.0. Please use language version {1} or greater. + Feature '{0}' is not available in C# 11.0. Please use language version {1} or greater. + + Feature '{0}' is not available in C# 8.0. Please use language version {1} or greater. La fonctionnalité '{0}' n'est pas disponible en C# 8.0. Utilisez la version de langage {1} ou une version ultérieure. @@ -582,6 +602,31 @@ Un espace de noms de portée de fichier doit précéder tous les autres membres d’un fichier. + + File-local type '{0}' cannot be used as a base type of non-file-local type '{1}'. + File-local type '{0}' cannot be used as a base type of non-file-local type '{1}'. + + + + File-local type '{0}' cannot be used in a member signature in non-file-local type '{1}'. + File-local type '{0}' cannot be used in a member signature in non-file-local type '{1}'. + + + + Types and aliases cannot be named 'file'. + Types and aliases cannot be named 'file'. + + + + File-local type '{0}' must be defined in a top level type; '{0}' is a nested type. + File-local type '{0}' must be defined in a top level type; '{0}' is a nested type. + + + + File-local type '{0}' cannot use accessibility modifiers. + File-local type '{0}' cannot use accessibility modifiers. + + A fixed field must not be a ref field. Un champ fixe ne doit pas être un champ ref. @@ -627,6 +672,11 @@ Une directive using globale doit précéder toutes les directives using non globales. + + File-local type '{0}' cannot be used in a 'global using static' directive. + File-local type '{0}' cannot be used in a 'global using static' directive. + + A goto cannot jump to a location before a using declaration within the same block. Un goto ne peut pas accéder à un emplacement avant une déclaration using dans le même bloc. @@ -882,6 +932,11 @@ Mot clé 'record' inattendu. Vouliez-vous dire « struct d’enregistrement » ou « classe d’enregistrement » ? + + Unexpected contextual keyword 'scoped'. Did you mean 'scoped ref' or '@scoped'? + Unexpected contextual keyword 'scoped'. Did you mean 'scoped ref' or '@scoped'? + + Slice patterns may only be used once and directly inside a list pattern. Les modèles de tranche ne peuvent être utilisés qu'une seule fois et directement à l'intérieur d'un modèle de liste. @@ -923,8 +978,8 @@ - Module initializer method '{0}' must be static, must have no parameters, and must return 'void' - La méthode d'initialiseur de module '{0}' doit être statique, ne doit avoir aucun paramètre et doit retourner 'void' + Module initializer method '{0}' must be static, and non-virtual, must have no parameters, and must return 'void' + La méthode d'initialiseur de module '{0}' doit être statique, ne doit avoir aucun paramètre et doit retourner 'void' @@ -1227,6 +1282,11 @@ Un champ ref ne peut pas faire référence à un struct ref. + + A ref field can only be declared in a ref struct. + A ref field can only be declared in a ref struct. + + The left-hand side of a ref assignment must be a ref variable. Le côté gauche d’une affectation ref doit être une variable ref. @@ -1297,6 +1357,11 @@ Le runtime cible ne prend pas en charge l'accessibilité 'protected', 'protected internal' ou 'private protected' d'un membre d'interface. + + Target runtime doesn't support ref fields. + Target runtime doesn't support ref fields. + + Target runtime doesn't support static abstract members in interfaces. Le runtime cible ne prend pas en charge les membres abstraits statiques dans les interfaces. @@ -1332,6 +1397,11 @@ Le modificateur 'scoped' ne peut être utilisé que pour les valeurs refs et ref struct. + + Types and aliases cannot be named 'scoped'. + Types and aliases cannot be named 'scoped'. + + Required members are not allowed on the top level of a script or submission. Les membres requis ne sont pas autorisés au niveau supérieur d’un script ou d’une soumission. @@ -1512,6 +1582,16 @@ '{0}' est attribué avec 'UnmanagedCallersOnly' et ne peut pas être converti en type délégué. Obtenez un pointeur de fonction vers cette méthode. UnmanagedCallersOnly is not localizable. + + UnscopedRefAttribute can only be applied to 'out' parameters, 'ref' and 'in' parameters that refer to 'ref struct' types, and instance methods and properties on 'struct' types other than constructors and 'init' accessors. + UnscopedRefAttribute can only be applied to 'out' parameters, 'ref' and 'in' parameters that refer to 'ref struct' types, and instance methods and properties on 'struct' types other than constructors and 'init' accessors. + + + + UnscopedRefAttribute cannot be applied to parameters that have a 'scoped' modifier. + UnscopedRefAttribute cannot be applied to parameters that have a 'scoped' modifier. + + '{0}' requires compiler feature '{1}', which is not supported by this version of the C# compiler. '{0}' nécessite la fonctionnalité de compilateur '{1}', qui n’est pas prise en charge par cette version du compilateur C#. @@ -1562,6 +1642,11 @@ La directive using est apparue précédemment comme using global + + array access + array access + + async method builder override Remplacement du générateur de méthode asynchrone @@ -1602,6 +1687,11 @@ espace de noms inclus dans l'étendue de fichier + + file types + file types + + generic attributes attributs génériques @@ -1722,6 +1812,11 @@ modèle correspondant à ReadOnly/Span<char> sur une chaîne constante + + pointer element access + pointer element access + + The assembly '{0}' containing type '{1}' references .NET Framework, which is not supported. L'assembly '{0}' contenant le type '{1}' référence le .NET Framework, ce qui n'est pas pris en charge. @@ -2260,7 +2355,7 @@ -instrument:TestCoverage Produire un assembly instrumenté pour collecter les informations de couverture -sourcelink:<fichier> Informations du lien source à incorporer dans le fichier PDB. - + - ERREURS ET AVERTISSEMENTS - -warnaserror[+|-] Signaler tous les avertissements comme des erreurs -warnaserror[+|-]:<avertiss.> Signaler des avertissements spécifiques comme des erreurs @@ -10477,11 +10572,6 @@ Pour supprimer l'avertissement, vous pouvez utiliser la commande /reference (dé GetDeclarationName appelé pour un nœud de déclaration susceptible de contenir plusieurs déclarateurs de variable. - - tree not part of compilation - arborescence non intégrée à la compilation - - Position is not within syntax tree with full span {0} La position ne se trouve pas dans l'étendue complète {0} de l'arborescence de syntaxe diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf index 1cb147e0adc03..6694b2568a4d5 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf @@ -207,6 +207,11 @@ Non è possibile applicare l'operatore '{0}' all'operando '{1}' + + The parameter modifier '{0}' cannot follow '{1}' + The parameter modifier '{0}' cannot follow '{1}' + + Invalid operand for pattern match; value required, but found '{0}'. L'operando non è valido per i criteri di ricerca. È richiesto un valore ma è stato trovato '{0}'. @@ -257,6 +262,11 @@ Non è possibile dedurre il tipo di delegato. + + 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 specifc numeric type. + + 'managed' calling convention cannot be combined with unmanaged calling convention specifiers. Non è possibile combinare la convenzione di chiamata 'managed' con identificatori di convenzione di chiamata non gestita. @@ -472,6 +482,11 @@ Non usare 'System.Runtime.CompilerServices.RequiredMemberAttribute'. Usare la parola chiave 'obbligatorio' nei campi e nelle proprietà obbligatori. + + Do not use 'System.Runtime.CompilerServices.ScopedRefAttribute'. Use the 'scoped' keyword instead. + Do not use 'System.Runtime.CompilerServices.ScopedRefAttribute'. Use the 'scoped' keyword instead. + + The given expression cannot be used in a fixed statement Non è possibile usare l'espressione specificata in un'istruzione fixed @@ -552,6 +567,11 @@ La funzionalità '{0}' non è disponibile in C# 10.0. Usare la versione {1} o versioni successive del linguaggio. + + Feature '{0}' is not available in C# 11.0. Please use language version {1} or greater. + Feature '{0}' is not available in C# 11.0. Please use language version {1} or greater. + + Feature '{0}' is not available in C# 8.0. Please use language version {1} or greater. La funzionalità '{0}' non è disponibile in C# 8.0. Usare la versione {1} o versioni successive del linguaggio. @@ -582,6 +602,31 @@ Lo spazio dei nomi con ambito file deve precedere tutti gli altri membri di un file. + + File-local type '{0}' cannot be used as a base type of non-file-local type '{1}'. + File-local type '{0}' cannot be used as a base type of non-file-local type '{1}'. + + + + File-local type '{0}' cannot be used in a member signature in non-file-local type '{1}'. + File-local type '{0}' cannot be used in a member signature in non-file-local type '{1}'. + + + + Types and aliases cannot be named 'file'. + Types and aliases cannot be named 'file'. + + + + File-local type '{0}' must be defined in a top level type; '{0}' is a nested type. + File-local type '{0}' must be defined in a top level type; '{0}' is a nested type. + + + + File-local type '{0}' cannot use accessibility modifiers. + File-local type '{0}' cannot use accessibility modifiers. + + A fixed field must not be a ref field. Un campo fisso non deve essere un campo ref. @@ -627,6 +672,11 @@ Una direttiva sull'utilizzo globale deve precedere tutte le direttiva non sull'uso non globale. + + File-local type '{0}' cannot be used in a 'global using static' directive. + File-local type '{0}' cannot be used in a 'global using static' directive. + + A goto cannot jump to a location before a using declaration within the same block. Un'istruzione goto non può passare a una posizione che precede una dichiarazione using all'interno dello stesso blocco. @@ -882,6 +932,11 @@ Parola chiave 'record' imprevista. Si intendeva 'struct record' o 'classe record'? + + Unexpected contextual keyword 'scoped'. Did you mean 'scoped ref' or '@scoped'? + Unexpected contextual keyword 'scoped'. Did you mean 'scoped ref' or '@scoped'? + + Slice patterns may only be used once and directly inside a list pattern. I modelli di sezione possono essere usati solo una volta e direttamente all'interno di un modello di elenco. @@ -923,8 +978,8 @@ - Module initializer method '{0}' must be static, must have no parameters, and must return 'void' - Il metodo '{0}' dell'inizializzatore di modulo deve essere statico, non deve contenere parametri e deve restituire 'void' + Module initializer method '{0}' must be static, and non-virtual, must have no parameters, and must return 'void' + Il metodo '{0}' dell'inizializzatore di modulo deve essere statico, non deve contenere parametri e deve restituire 'void' @@ -1227,6 +1282,11 @@ Un campo ref non può fare riferimento a un ref struct. + + A ref field can only be declared in a ref struct. + A ref field can only be declared in a ref struct. + + The left-hand side of a ref assignment must be a ref variable. La parte sinistra di un'assegnazione ref deve essere una variabile ref. @@ -1297,6 +1357,11 @@ Il runtime di destinazione non supporta l'accessibilità 'protected', 'protected internal' o 'private protected' per un membro di un'interfaccia. + + Target runtime doesn't support ref fields. + Target runtime doesn't support ref fields. + + Target runtime doesn't support static abstract members in interfaces. Il runtime di destinazione non supporta membri astratti statici nelle interfacce. @@ -1332,6 +1397,11 @@ Il modificatore 'scoped' può essere usato solo per i riferimenti e i valori ref struct. + + Types and aliases cannot be named 'scoped'. + Types and aliases cannot be named 'scoped'. + + Required members are not allowed on the top level of a script or submission. I membri obbligatori non sono consentiti al primo livello di uno script o di un invio. @@ -1512,6 +1582,16 @@ '{0}', a cui è assegnato l'attributo 'UnmanagedCallersOnly', non può essere convertito in un tipo delegato. Ottenere un puntatore a funzione per questo metodo. UnmanagedCallersOnly is not localizable. + + UnscopedRefAttribute can only be applied to 'out' parameters, 'ref' and 'in' parameters that refer to 'ref struct' types, and instance methods and properties on 'struct' types other than constructors and 'init' accessors. + UnscopedRefAttribute can only be applied to 'out' parameters, 'ref' and 'in' parameters that refer to 'ref struct' types, and instance methods and properties on 'struct' types other than constructors and 'init' accessors. + + + + UnscopedRefAttribute cannot be applied to parameters that have a 'scoped' modifier. + UnscopedRefAttribute cannot be applied to parameters that have a 'scoped' modifier. + + '{0}' requires compiler feature '{1}', which is not supported by this version of the C# compiler. '{0}' richiede la funzionalità del compilatore '{1}', che non è supportata da questa versione del compilatore C#. @@ -1562,6 +1642,11 @@ La direttiva using è già presente come using globale + + array access + array access + + async method builder override override del generatore di metodi asincroni @@ -1602,6 +1687,11 @@ spazio dei nomi con ambito file + + file types + file types + + generic attributes attributi generici @@ -1722,6 +1812,11 @@ criterio corrispondente a ReadOnly/Span<char> su stringa costante + + pointer element access + pointer element access + + The assembly '{0}' containing type '{1}' references .NET Framework, which is not supported. L'assembly '{0}' che contiene il tipo '{1}' fa riferimento a .NET Framework, che non è supportato. @@ -2223,7 +2318,7 @@ ai caratteri jolly specificati -reference:<alias>=<file> Crea un riferimento ai metadati dal file di assembly specificato usando l'alias indicato. Forma breve: -r --reference:<elenco file> Crea un riferimento ai metadati dai file di assembly +-reference:<elenco file> Crea un riferimento ai metadati dai file di assembly specificati. Forma breve: -r -addmodule:<elenco file> Collega i moduli specificati in questo assembly -link:<elenco file> Incorpora metadati dai file di assembly di @@ -2260,7 +2355,7 @@ -instrument:TestCoverage Produce un assembly instrumentato per raccogliere informazioni sul code coverage -sourcelink:<file> Informazioni sul collegamento all'origine da incorporare nel file PDB. - + - ERRORI E AVVISI - -warnaserror[+|-] Segnala tutti gli avvisi come errori -warnaserror[+|-]:<elenco avvisi> Segnala determinati avvisi come errori @@ -2314,7 +2409,7 @@ - AVANZATE - -baseaddress:<indirizzo> Indirizzo di base della libreria da compilare --checksumalgorithm:<alg> Consente di specificare l'algoritmo per calcolare il checksum +-checksumalgorithm:<alg> Consente di specificare l'algoritmo per calcolare il checksum del file di origine archiviato nel file PDB. I valori supportati sono: SHA1 o SHA256 (impostazione predefinita). -codepage:<n> Consente di specificare la tabella codici da usare all'apertura dei file @@ -10477,11 +10572,6 @@ Per rimuovere l'avviso, è invece possibile usare /reference (impostare la propr È stato chiamato GetDeclarationName per un nodo di dichiarazione che può contenere più dichiarazioni di variabile. - - tree not part of compilation - l'albero non fa parte della compilazione - - Position is not within syntax tree with full span {0} Position non è compreso nell'albero della sintassi con full span {0} diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf index 59303f20826fc..8b15c4b79081c 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf @@ -207,6 +207,11 @@ 演算子 '{0}' はオペランド '{1}' に適用できません + + The parameter modifier '{0}' cannot follow '{1}' + The parameter modifier '{0}' cannot follow '{1}' + + Invalid operand for pattern match; value required, but found '{0}'. パターン マッチには使用できないオペランドです。値が必要ですが、'{0}' が見つかりました。 @@ -257,6 +262,11 @@ デリゲート型を推論できませんでした。 + + 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 specifc numeric type. + + 'managed' calling convention cannot be combined with unmanaged calling convention specifiers. 'マネージド' 呼び出し規則をアンマネージド呼び出し規則指定子と組み合わせることはできません。 @@ -472,6 +482,11 @@ 'System.Runtime.CompilerServices.RequiredMemberAttribute' を使用しないでください。代わりに、必須フィールドとプロパティに 'required' キーワードを使用してください。 + + Do not use 'System.Runtime.CompilerServices.ScopedRefAttribute'. Use the 'scoped' keyword instead. + Do not use 'System.Runtime.CompilerServices.ScopedRefAttribute'. Use the 'scoped' keyword instead. + + The given expression cannot be used in a fixed statement 指定された式を fixed ステートメントで使用することはできません @@ -552,6 +567,11 @@ 機能 '{0}' は C# 10.0 では使用できません。言語バージョン {1} 以上を使用してください。 + + Feature '{0}' is not available in C# 11.0. Please use language version {1} or greater. + Feature '{0}' is not available in C# 11.0. Please use language version {1} or greater. + + Feature '{0}' is not available in C# 8.0. Please use language version {1} or greater. 機能 '{0}' は C# 8.0 では使用できません。言語バージョン {1} 以上を使用してください。 @@ -582,6 +602,31 @@ ファイルスコープの名前空間は、ファイル内の他のすべてのメンバーの前に指定する必要があります。 + + File-local type '{0}' cannot be used as a base type of non-file-local type '{1}'. + File-local type '{0}' cannot be used as a base type of non-file-local type '{1}'. + + + + File-local type '{0}' cannot be used in a member signature in non-file-local type '{1}'. + File-local type '{0}' cannot be used in a member signature in non-file-local type '{1}'. + + + + Types and aliases cannot be named 'file'. + Types and aliases cannot be named 'file'. + + + + File-local type '{0}' must be defined in a top level type; '{0}' is a nested type. + File-local type '{0}' must be defined in a top level type; '{0}' is a nested type. + + + + File-local type '{0}' cannot use accessibility modifiers. + File-local type '{0}' cannot use accessibility modifiers. + + A fixed field must not be a ref field. 固定フィールドを ref フィールドにすることはできません。 @@ -627,6 +672,11 @@ グローバル using ディレクティブは、すべての非グローバル using ディレクティブの前に指定する必要があります。 + + File-local type '{0}' cannot be used in a 'global using static' directive. + File-local type '{0}' cannot be used in a 'global using static' directive. + + A goto cannot jump to a location before a using declaration within the same block. goto は同じブロック内の using 宣言より前の位置にはジャンプできません。 @@ -882,6 +932,11 @@ 予期しないキーワード 'record' です。'record struct' または 'record class' のつもりでしたか? + + Unexpected contextual keyword 'scoped'. Did you mean 'scoped ref' or '@scoped'? + Unexpected contextual keyword 'scoped'. Did you mean 'scoped ref' or '@scoped'? + + Slice patterns may only be used once and directly inside a list pattern. スライス パターンは、1 回限り、リスト パターン内で直接使用される可能性があります。 @@ -923,8 +978,8 @@ - Module initializer method '{0}' must be static, must have no parameters, and must return 'void' - モジュール初期化子メソッド '{0}' は、static でなければならず、パラメーターを持ってはならず、'void' を返す必要があります + Module initializer method '{0}' must be static, and non-virtual, must have no parameters, and must return 'void' + モジュール初期化子メソッド '{0}' は、static でなければならず、パラメーターを持ってはならず、'void' を返す必要があります @@ -1227,6 +1282,11 @@ ref フィールドは ref 構造体を参照できません。 + + A ref field can only be declared in a ref struct. + A ref field can only be declared in a ref struct. + + The left-hand side of a ref assignment must be a ref variable. ref 代入の左辺は ref 変数である必要があります。 @@ -1297,6 +1357,11 @@ ターゲット ランタイムは、インターフェイスのメンバーに対して 'protected'、'protected internal'、'private protected' アクセシビリティをサポートしていません。 + + Target runtime doesn't support ref fields. + Target runtime doesn't support ref fields. + + Target runtime doesn't support static abstract members in interfaces. ターゲット ランタイムでは、インターフェイスの静的な抽象メンバーをサポートしていません。 @@ -1332,6 +1397,11 @@ 'scoped' 修飾子は refs および ref 構造体の値にのみ使用できます。 + + Types and aliases cannot be named 'scoped'. + Types and aliases cannot be named 'scoped'. + + Required members are not allowed on the top level of a script or submission. 必要なメンバーは、スクリプトまたは送信の最上位レベルでは許可されていません。 @@ -1512,6 +1582,16 @@ '{0}' は 'UnmanagedCallersOnly' 属性が設定されているため、デリゲート型に変換できません。このメソッドへの関数ポインターを取得してください。 UnmanagedCallersOnly is not localizable. + + UnscopedRefAttribute can only be applied to 'out' parameters, 'ref' and 'in' parameters that refer to 'ref struct' types, and instance methods and properties on 'struct' types other than constructors and 'init' accessors. + UnscopedRefAttribute can only be applied to 'out' parameters, 'ref' and 'in' parameters that refer to 'ref struct' types, and instance methods and properties on 'struct' types other than constructors and 'init' accessors. + + + + UnscopedRefAttribute cannot be applied to parameters that have a 'scoped' modifier. + UnscopedRefAttribute cannot be applied to parameters that have a 'scoped' modifier. + + '{0}' requires compiler feature '{1}', which is not supported by this version of the C# compiler. '{0}' にはコンパイラ機能 '{1}' が必要ですが、このバージョンのC## コンパイラではサポートされていません。 @@ -1562,6 +1642,11 @@ using ディレクティブは、以前に global using として使用されています + + array access + array access + + async method builder override 非同期メソッド ビルダーのオーバーライド @@ -1602,6 +1687,11 @@ ファイルスコープの名前空間 + + file types + file types + + generic attributes 汎用属性 @@ -1722,6 +1812,11 @@ 定数文字列の ReadOnly/Span<char> に一致するパターン + + pointer element access + pointer element access + + The assembly '{0}' containing type '{1}' references .NET Framework, which is not supported. 型 '{1}' を含むアセンブリ '{0}' が .NET Framework を参照しています。これはサポートされていません。 @@ -2260,7 +2355,7 @@ -instrument:TestCoverage カバレッジ情報を収集するようにインストルメント化された アセンブリを生成します -sourcelink:<file> PDB に埋め込むソース リンク情報。 - + - エラーと警告 - -warnaserror[+|-] すべての警告をエラーとして報告します -warnaserror[+|-]:<warn list> 特定の警告をエラーとして報告します @@ -10477,11 +10572,6 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ 複数の変数宣言子を含んでいる可能性がある宣言ノードに対して GetDeclarationName を呼び出しました。 - - tree not part of compilation - ツリーはコンパイルの一部ではありません - - Position is not within syntax tree with full span {0} 場所が全スパン {0} の構文ツリー内にありません diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf index c120d854343ff..05d62be0e4a48 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf @@ -207,6 +207,11 @@ '{0}' 연산자는 '{1}' 피연산자에 적용할 수 없습니다. + + The parameter modifier '{0}' cannot follow '{1}' + The parameter modifier '{0}' cannot follow '{1}' + + Invalid operand for pattern match; value required, but found '{0}'. 패턴 일치에 대한 피연산자가 잘못되었습니다. 값이 필요하지만 '{0}'을(를) 찾았습니다. @@ -257,6 +262,11 @@ 대리자 형식을 유추할 수 없습니다. + + 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 specifc numeric type. + + 'managed' calling convention cannot be combined with unmanaged calling convention specifiers. '관리되는' 호출 규칙은 관리되지 않는 호출 규칙 지정자와 함께 사용할 수 없습니다. @@ -472,6 +482,11 @@ 'System.Runtime.CompilerServices.RequiredMemberAttribute'를 사용하지 마세요. 대신 필수 필드 및 특성에 'required' 키워드를 사용하세요. + + Do not use 'System.Runtime.CompilerServices.ScopedRefAttribute'. Use the 'scoped' keyword instead. + Do not use 'System.Runtime.CompilerServices.ScopedRefAttribute'. Use the 'scoped' keyword instead. + + The given expression cannot be used in a fixed statement fixed 문에서는 지정된 식을 사용할 수 없습니다. @@ -552,6 +567,11 @@ '{0}' 기능은 C# 10.0에서 사용할 수 없습니다. 언어 버전 {1} 이상을 사용하세요. + + Feature '{0}' is not available in C# 11.0. Please use language version {1} or greater. + Feature '{0}' is not available in C# 11.0. Please use language version {1} or greater. + + Feature '{0}' is not available in C# 8.0. Please use language version {1} or greater. '{0}' 기능은 C# 8.0에서 사용할 수 없습니다. 언어 버전 {1} 이상을 사용하세요. @@ -582,6 +602,31 @@ 파일 범위 네임스페이스는 파일의 다른 모든 멤버보다 앞에 와야 합니다. + + File-local type '{0}' cannot be used as a base type of non-file-local type '{1}'. + File-local type '{0}' cannot be used as a base type of non-file-local type '{1}'. + + + + File-local type '{0}' cannot be used in a member signature in non-file-local type '{1}'. + File-local type '{0}' cannot be used in a member signature in non-file-local type '{1}'. + + + + Types and aliases cannot be named 'file'. + Types and aliases cannot be named 'file'. + + + + File-local type '{0}' must be defined in a top level type; '{0}' is a nested type. + File-local type '{0}' must be defined in a top level type; '{0}' is a nested type. + + + + File-local type '{0}' cannot use accessibility modifiers. + File-local type '{0}' cannot use accessibility modifiers. + + A fixed field must not be a ref field. 고정 필드는 참조 필드가 아니어야 합니다. @@ -627,6 +672,11 @@ 전역 using 지시문은 전역이 아닌 모든 using 지시문 앞에 있어야 합니다. + + File-local type '{0}' cannot be used in a 'global using static' directive. + File-local type '{0}' cannot be used in a 'global using static' directive. + + A goto cannot jump to a location before a using declaration within the same block. goto는 동일한 블록 내의 using 선언 앞 위치로 이동할 수 없습니다. @@ -882,6 +932,11 @@ 예기치 않은 'record' 키워드가 있습니다. 'record struct' 또는 'record class'를 사용할까요? + + Unexpected contextual keyword 'scoped'. Did you mean 'scoped ref' or '@scoped'? + Unexpected contextual keyword 'scoped'. Did you mean 'scoped ref' or '@scoped'? + + Slice patterns may only be used once and directly inside a list pattern. 조각 패턴은 목록 패턴 내에서 바로 한 번만 사용할 수 있습니다. @@ -923,8 +978,8 @@ - Module initializer method '{0}' must be static, must have no parameters, and must return 'void' - 모듈 이니셜라이저 메서드 '{0}'은(는) 정적이어야 하고, 매개 변수가 없어야 하며, 'void'를 반환해야 합니다. + Module initializer method '{0}' must be static, and non-virtual, must have no parameters, and must return 'void' + 모듈 이니셜라이저 메서드 '{0}'은(는) 정적이어야 하고, 매개 변수가 없어야 하며, 'void'를 반환해야 합니다. @@ -1227,6 +1282,11 @@ ref 필드는 ref 구조체를 참조할 수 없습니다. + + A ref field can only be declared in a ref struct. + A ref field can only be declared in a ref struct. + + The left-hand side of a ref assignment must be a ref variable. ref 할당의 왼쪽은 ref 변수여야 합니다. @@ -1297,6 +1357,11 @@ 대상 런타임이 인터페이스 멤버의 'protected', 'protected internal' 또는 'private protected' 접근성을 지원하지 않습니다. + + Target runtime doesn't support ref fields. + Target runtime doesn't support ref fields. + + Target runtime doesn't support static abstract members in interfaces. 대상 런타임은 인터페이스에서 정적 추상 멤버를 지원하지 않습니다. @@ -1332,6 +1397,11 @@ 'scoped' 한정자는 ref 및 ref 구조체 값에만 사용할 수 있습니다. + + Types and aliases cannot be named 'scoped'. + Types and aliases cannot be named 'scoped'. + + Required members are not allowed on the top level of a script or submission. 필수 멤버는 스크립트 또는 제출의 최상위 수준에서 허용되지 않습니다. @@ -1512,6 +1582,16 @@ '{0}'에는 'UnmanagedCallersOnly' 특성이 지정되어 있으며 이 항목은 대리자 형식으로 변환할 수 없습니다. 이 메서드에 대한 함수 포인터를 가져오세요. UnmanagedCallersOnly is not localizable. + + UnscopedRefAttribute can only be applied to 'out' parameters, 'ref' and 'in' parameters that refer to 'ref struct' types, and instance methods and properties on 'struct' types other than constructors and 'init' accessors. + UnscopedRefAttribute can only be applied to 'out' parameters, 'ref' and 'in' parameters that refer to 'ref struct' types, and instance methods and properties on 'struct' types other than constructors and 'init' accessors. + + + + UnscopedRefAttribute cannot be applied to parameters that have a 'scoped' modifier. + UnscopedRefAttribute cannot be applied to parameters that have a 'scoped' modifier. + + '{0}' requires compiler feature '{1}', which is not supported by this version of the C# compiler. '{0}'에는 이 버전의 C # 컴파일러에서 지원되지 않는 컴파일러 기능 '{1}'이(가) 필요합니다. @@ -1562,6 +1642,11 @@ using 지시문은 이전에 전역 using으로 나타났습니다. + + array access + array access + + async method builder override 비동기 메서드 빌더 재정의 @@ -1602,6 +1687,11 @@ 파일 범위 네임스페이스 + + file types + file types + + generic attributes 제네릭 특성 @@ -1722,6 +1812,11 @@ 상수 문자열에서 ReadOnly/Span<char>과 일치하는 패턴 + + pointer element access + pointer element access + + The assembly '{0}' containing type '{1}' references .NET Framework, which is not supported. '{1}' 형식을 포함하는 '{0}' 어셈블리가 지원되지 않는 .NET Framework를 참조합니다. @@ -2206,7 +2301,7 @@ -target:library 라이브러리를 빌드합니다. (약식: -t:library) -target:module 다른 어셈블리에 추가할 수 있는 모듈을 빌드합니다. (약식: -t:module) --target:appcontainerexe Appcontainer 실행 파일을 빌드합니다. (약식: +-target:appcontainerexe Appcontainer 실행 파일을 빌드합니다. (약식: -t:appcontainerexe) -target:winmdobj WinMDExp에서 사용되는 Windows 런타임 중간 파일을 빌드합니다. (약식: -t:winmdobj) @@ -2320,7 +2415,7 @@ 지정합니다. -utf8output 컴파일러 메시지를 UTF-8 인코딩으로 출력합니다. -main:<type> 진입점이 포함된 형식을 지정합니다(다른 - 모든 가능한 진입점 무시). + 모든 가능한 진입점 무시). (약식: -m) -fullpaths 컴파일러가 정규화된 경로를 생성합니다. -filealign:<n> 출력 파일 섹션에 사용되는 맞춤을 @@ -10476,11 +10571,6 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ 여러 변수 선언자를 포함할 수 있는 선언 노드에 대해 호출된 GetDeclarationName입니다. - - tree not part of compilation - 트리는 컴파일의 일부가 아닙니다. - - Position is not within syntax tree with full span {0} {0} 전체 범위를 사용한 구문 트리 내에 위치가 없습니다. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf index eee33667bbc8d..4e2906d3b17c5 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf @@ -207,6 +207,11 @@ Nie można zastosować operatora „{0}” do operandu „{1}” + + The parameter modifier '{0}' cannot follow '{1}' + The parameter modifier '{0}' cannot follow '{1}' + + Invalid operand for pattern match; value required, but found '{0}'. Nieprawidłowy operand dla dopasowania wzorca; wymagana jest wartość, a znaleziono „{0}”. @@ -257,6 +262,11 @@ Nie można wywnioskować typu delegowania. + + 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 specifc numeric type. + + 'managed' calling convention cannot be combined with unmanaged calling convention specifiers. Konwencji wywoływania „managed” nie można łączyć z niezarządzanymi specyfikatorami konwencji wywoływania. @@ -472,6 +482,11 @@ Nie używaj elementu „System.Runtime.CompilerServices.RequiredMemberAttribute”. Zamiast tego użyj słowa kluczowego „required” w wymaganych polach i właściwościach. + + Do not use 'System.Runtime.CompilerServices.ScopedRefAttribute'. Use the 'scoped' keyword instead. + Do not use 'System.Runtime.CompilerServices.ScopedRefAttribute'. Use the 'scoped' keyword instead. + + The given expression cannot be used in a fixed statement Podanego wyrażenia nie można użyć w instrukcji fixed @@ -552,6 +567,11 @@ Funkcja "{0}" nie jest dostępna w języku C# 10.0. Użyj języka w wersji {1} lub nowszej. + + Feature '{0}' is not available in C# 11.0. Please use language version {1} or greater. + Feature '{0}' is not available in C# 11.0. Please use language version {1} or greater. + + Feature '{0}' is not available in C# 8.0. Please use language version {1} or greater. Funkcja „{0}” nie jest dostępna w języku C# 8.0. Użyj języka w wersji {1} lub nowszej. @@ -582,6 +602,31 @@ Przestrzeń nazw z określonym zakresem plików musi poprzedzać wszystkie inne składowe w pliku. + + File-local type '{0}' cannot be used as a base type of non-file-local type '{1}'. + File-local type '{0}' cannot be used as a base type of non-file-local type '{1}'. + + + + File-local type '{0}' cannot be used in a member signature in non-file-local type '{1}'. + File-local type '{0}' cannot be used in a member signature in non-file-local type '{1}'. + + + + Types and aliases cannot be named 'file'. + Types and aliases cannot be named 'file'. + + + + File-local type '{0}' must be defined in a top level type; '{0}' is a nested type. + File-local type '{0}' must be defined in a top level type; '{0}' is a nested type. + + + + File-local type '{0}' cannot use accessibility modifiers. + File-local type '{0}' cannot use accessibility modifiers. + + A fixed field must not be a ref field. Pole stałe nie może być polem referencyjnym. @@ -627,6 +672,11 @@ Globalne używające dyrektywy muszą poprzedzać wszystkie nieglobalne używające dyrektywy. + + File-local type '{0}' cannot be used in a 'global using static' directive. + File-local type '{0}' cannot be used in a 'global using static' directive. + + A goto cannot jump to a location before a using declaration within the same block. Instrukcja goto nie może przechodzić do lokalizacji występującej przed deklaracją using w tym samym bloku. @@ -882,6 +932,11 @@ Nieoczekiwane słowo kluczowe „record”. Czy chodziło o „record struct” lub „record class”? + + Unexpected contextual keyword 'scoped'. Did you mean 'scoped ref' or '@scoped'? + Unexpected contextual keyword 'scoped'. Did you mean 'scoped ref' or '@scoped'? + + Slice patterns may only be used once and directly inside a list pattern. Wzorce wycinków mogą być używane tylko raz i bezpośrednio wewnątrz wzorca listy. @@ -923,8 +978,8 @@ - Module initializer method '{0}' must be static, must have no parameters, and must return 'void' - Metoda inicjatora modułu „{0}” musi być statyczna, nie może mieć parametrów i musi zwracać typ „void” + Module initializer method '{0}' must be static, and non-virtual, must have no parameters, and must return 'void' + Metoda inicjatora modułu „{0}” musi być statyczna, nie może mieć parametrów i musi zwracać typ „void” @@ -1227,6 +1282,11 @@ Pole referencyjne nie może odwoływać się do struktury referencyjnej. + + A ref field can only be declared in a ref struct. + A ref field can only be declared in a ref struct. + + The left-hand side of a ref assignment must be a ref variable. Lewa strona przypisania referencyjnego musi być zmienną referencyjną. @@ -1297,6 +1357,11 @@ Docelowe środowisko uruchomieniowe nie obsługuje specyfikatorów dostępu „protected”, „protected internal” i „private protected” dla składowej interfejsu. + + Target runtime doesn't support ref fields. + Target runtime doesn't support ref fields. + + Target runtime doesn't support static abstract members in interfaces. Docelowe środowisko uruchomieniowe nie obsługuje statycznych składowych abstrakcyjnych w interfejsach. @@ -1332,6 +1397,11 @@ Modyfikator „scoped" może być używany tylko w przypadku odwołań i wartości struktury referencyjnej. + + Types and aliases cannot be named 'scoped'. + Types and aliases cannot be named 'scoped'. + + Required members are not allowed on the top level of a script or submission. Wymagane składowe są niedozwolone na najwyższym poziomie skryptu lub żądania przesłania. @@ -1512,6 +1582,16 @@ Element „{0}” ma atrybut „UnmanagedCallersOnly” i nie można go przekonwertować na typ delegowany. Uzyskaj wskaźnik funkcji do tej metody. UnmanagedCallersOnly is not localizable. + + UnscopedRefAttribute can only be applied to 'out' parameters, 'ref' and 'in' parameters that refer to 'ref struct' types, and instance methods and properties on 'struct' types other than constructors and 'init' accessors. + UnscopedRefAttribute can only be applied to 'out' parameters, 'ref' and 'in' parameters that refer to 'ref struct' types, and instance methods and properties on 'struct' types other than constructors and 'init' accessors. + + + + UnscopedRefAttribute cannot be applied to parameters that have a 'scoped' modifier. + UnscopedRefAttribute cannot be applied to parameters that have a 'scoped' modifier. + + '{0}' requires compiler feature '{1}', which is not supported by this version of the C# compiler. „{0}” wymaga funkcji kompilatora „{1}”, która nie jest obsługiwana przez tę wersję kompilatora języka C#. @@ -1562,6 +1642,11 @@ Dyrektywa użycia pojawiła się wcześniej jako użycie globalne + + array access + array access + + async method builder override zastąpienie konstruktora metodą asynchroniczną @@ -1602,6 +1687,11 @@ przestrzeń nazw z określonym zakresem plików + + file types + file types + + generic attributes atrybuty ogólne @@ -1719,7 +1809,12 @@ pattern matching ReadOnly/Span<char> on constant string - dopasowanie wzorca ReadOnly/Span<char> w ciągu stałym + pattern matching ReadOnly/Span<char> on constant string + + + + pointer element access + pointer element access @@ -2198,35 +2293,35 @@ Opcje kompilatora Visual C# - PLIKI WYJŚCIOWE - --out:<plik> Określ nazwę pliku wyjściowego (domyślnie: nazwa podstawowa +-out:<plik> Określ nazwę pliku wyjściowego (domyślnie: nazwa podstawowa pliku z klasą główną lub pierwszego pliku) --target:exe Kompiluj plik wykonywalny konsoli (domyślnie) (krótka +-target:exe Kompiluj plik wykonywalny konsoli (domyślnie) (krótka wersja: -t:exe) --target:winexe Kompiluj plik wykonywalny systemu Windows (krótka wersja: +-target:winexe Kompiluj plik wykonywalny systemu Windows (krótka wersja: -t:winexe) -target:library Kompiluj bibliotekę (krótka wersja: -t:library) --target:module Kompiluj moduł, który można dodać do innego +-target:module Kompiluj moduł, który można dodać do innego zestawu (krótka wersja: -t:module) --target:appcontainerexe Kompiluj plik wykonywalny kontenera aplikacji (krótka wersja: +-target:appcontainerexe Kompiluj plik wykonywalny kontenera aplikacji (krótka wersja: -t:appcontainerexe) --target:winmdobj Kompiluj plik pośredni środowiska uruchomieniowego systemu Windows +-target:winmdobj Kompiluj plik pośredni środowiska uruchomieniowego systemu Windows przeznaczony dla narzędzia WinMDExp (krótka wersja: -t:winmdobj) -doc:<plik> Plik dokumentacji XML do wygenerowania -refout:<plik> Dane wyjściowe zestawu odwołania do wygenerowania -platform:<ciąg> Ogranicz platformy, na których można uruchamiać ten kod: x86, - Itanium, x64, arm, arm64, anycpu32bitpreferred lub + Itanium, x64, arm, arm64, anycpu32bitpreferred lub anycpu. Wartość domyślna to anycpu. - PLIKI WEJŚCIOWE - --recurse:<symbol wieloznaczny> Uwzględnij wszystkie pliki zawarte w bieżącym katalogu i - podkatalogach zgodnie ze specyfikacją określoną przy użyciu +-recurse:<symbol wieloznaczny> Uwzględnij wszystkie pliki zawarte w bieżącym katalogu i + podkatalogach zgodnie ze specyfikacją określoną przy użyciu symboli wieloznacznych --reference:<alias>=<plik> Odwołuj się do metadanych z określonego pliku +-reference:<alias>=<plik> Odwołuj się do metadanych z określonego pliku zestawu przy użyciu podanego aliasu (krótka wersja: -r) --reference:<lista_plików> Odwołuj się do metadanych z określonych +-reference:<lista_plików> Odwołuj się do metadanych z określonych plików zestawów (krótka wersja: -r) -addmodule:<lista plików> Połącz określone moduły z tym zestawem --link:<lista_plików> Osadź metadane z określonych plików +-link:<lista_plików> Osadź metadane z określonych plików zestawów międzyoperacyjnych (krótka wersja: -l) -analyzer:<lista_plików> Uruchom analizatory z tego zestawu (krótka wersja: -a) @@ -2242,16 +2337,16 @@ -win32manifest:<plik> Określ plik manifestu środowiska Win32 (xml) -nowin32manifest Nie dołączaj domyślnego manifestu środowiska Win32 -resource:<informacje_o_zasobie> Osadź określony zasób (krótka wersja: -res) --linkresource:<informacje_o_zasobie> Połącz określony zasób z tym zestawem - (krótka wersja: -linkres), gdzie format informacji o zasobie +-linkresource:<informacje_o_zasobie> Połącz określony zasób z tym zestawem + (krótka wersja: -linkres), gdzie format informacji o zasobie to <plik>[,<nazwa ciągu>[,public|private]] - GENEROWANIE KODU - -debug[+|-] Emituj informacje o debugowaniu -debug:{full|pdbonly|portable|embedded} - Określ typ debugowania (wartość domyślna to „full”, + Określ typ debugowania (wartość domyślna to „full”, wartość „portable” to format międzyplatformowy, - a wartość „embedded” to format międzyplatformowy wbudowany w + a wartość „embedded” to format międzyplatformowy wbudowany w docelowym pliku dll lub exe) -optimize[+|-] Włącz optymalizacje (krótka wersja: -o) -deterministic Utwórz zestaw deterministyczny @@ -2278,11 +2373,11 @@ -reportanalyzer Zgłaszaj dodatkowe informacje analizatora, takie jak czas wykonywania. -skipanalyzers[+|-] Pomiń wykonywanie analizatorów diagnostycznych. - + -JĘZYK - -checked[+|-] Generuj operacje sprawdzenia przepełnienia -unsafe[+|-] Zezwalaj na niebezpieczny kod --define:<lista symboli> Zdefiniuj symbole kompilacji warunkowej (krótka +-define:<lista symboli> Zdefiniuj symbole kompilacji warunkowej (krótka wersja: -d) -langversion:? Wyświetl dozwolone wartości dla wersji języka -langversion:<ciąg> Określ wersję języka, na przykład @@ -2296,7 +2391,7 @@ Określ opcję kontekstu dopuszczającego wartość null: enable|disable|warnings|annotations. - ZABEZPIECZENIA - --delaysign[+|-] Podpisz z opóźnieniem zestaw, używając tylko +-delaysign[+|-] Podpisz z opóźnieniem zestaw, używając tylko części publicznej klucza o silnej nazwie -publicsign[+|-] Podpisz publicznie zestaw, używając tylko części publicznej klucza o silnej nazwie @@ -2317,34 +2412,34 @@ -checksumalgorithm:<algorytm> Określ algorytm do obliczania sumy kontrolnej pliku źródłowego przechowywanej w pliku PDB. Obsługiwane wartości: SHA1 lub SHA256 (domyślnie). --codepage:<n> Określ stronę kodową do użycia podczas otwierania +-codepage:<n> Określ stronę kodową do użycia podczas otwierania plików źródłowych -utf8output Wyprowadź komunikaty kompilatora przy użyciu kodowania UTF-8 --main:<typ> Określ typ zawierający punkt wejścia - (zignoruj wszystkie pozostałe możliwe punkty wejścia) (krótka +-main:<typ> Określ typ zawierający punkt wejścia + (zignoruj wszystkie pozostałe możliwe punkty wejścia) (krótka wersja: -m) -fullpaths Kompilator generuje w pełni kwalifikowane ścieżki --filealign:<n> Określ wyrównanie stosowane dla sekcji +-filealign:<n> Określ wyrównanie stosowane dla sekcji plików wyjściowych --pathmap:<K1>=<W1>,<K2>=<W2>,... - Określ mapowanie dla nazw ścieżek źródłowych wyprowadzanych przez +-pathmap:<K1>=<W1>,<K2>=<W2>,... + Określ mapowanie dla nazw ścieżek źródłowych wyprowadzanych przez kompilator. --pdb:<plik> Określ nazwę pliku z informacjami o debugowaniu (domyślnie: +-pdb:<plik> Określ nazwę pliku z informacjami o debugowaniu (domyślnie: nazwa pliku wyjściowego z rozszerzeniem pdb) --errorendlocation Wyprowadź wiersz i kolumnę lokalizacji końcowej dla +-errorendlocation Wyprowadź wiersz i kolumnę lokalizacji końcowej dla każdego błędu -preferreduilang Określ nazwę preferowanego języka wyjściowego. -nosdkpath Wyłącz przeszukiwanie domyślnej ścieżki zestawu SDK dla zestawów biblioteki standardowej. -nostdlib[+|-] Nie odwołuj się do biblioteki standardowej (mscorlib.dll) -subsystemversion:<ciąg> Określ wersję podsystemu tego zestawu --lib:<lista plików> Określ dodatkowe katalogi do przeszukania pod kątem +-lib:<lista plików> Określ dodatkowe katalogi do przeszukania pod kątem odwołań --errorreport:<ciąg> Określ, w jaki sposób obsługiwać wewnętrzne błędy kompilatora: - prompt, send, queue lub none. Wartość domyślna to +-errorreport:<ciąg> Określ, w jaki sposób obsługiwać wewnętrzne błędy kompilatora: + prompt, send, queue lub none. Wartość domyślna to queue. --appconfig:<plik> Określ plik konfiguracji aplikacji +-appconfig:<plik> Określ plik konfiguracji aplikacji zawierający ustawienia powiązania zestawu --moduleassemblyname:<ciąg> Nazwa zestawu, którego częścią +-moduleassemblyname:<ciąg> Nazwa zestawu, którego częścią ma być ten moduł -modulename:<ciąg> Określ nazwę modułu źródłowego -generatedfilesout:<katalog> Umieść pliki wygenerowane podczas kompilacji @@ -10477,11 +10572,6 @@ Aby usunąć ostrzeżenie, możesz zamiast tego użyć opcji /reference (ustaw w Wywołano metodę GetDeclarationName dla węzła deklaracji, który może zawierać wiele deklaratorów zmiennych. - - tree not part of compilation - drzewo nie jest częścią kompilacji - - Position is not within syntax tree with full span {0} Pozycja nie znajduje się w drzewie składni o pełnym zasięgu {0} diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf index d2cff5d5aeed6..330ce90993687 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf @@ -207,6 +207,11 @@ O operador '{0}' não pode ser aplicado ao operando '{1}' + + The parameter modifier '{0}' cannot follow '{1}' + The parameter modifier '{0}' cannot follow '{1}' + + Invalid operand for pattern match; value required, but found '{0}'. Operando inválido para correspondência de padrão. Um valor era obrigatório, mas '{0}' foi encontrado. @@ -257,6 +262,11 @@ O tipo de representante não pôde ser inferido. + + 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 specifc numeric type. + + 'managed' calling convention cannot be combined with unmanaged calling convention specifiers. A convenção de chamada 'managed' não pode ser combinada com especificadores de convenção de chamada não gerenciados. @@ -472,6 +482,11 @@ Não use 'System.Runtime.CompilerServices.RequiredMemberAttribute'. Use a palavra-chave 'required' nos campos e propriedades requeridos. + + Do not use 'System.Runtime.CompilerServices.ScopedRefAttribute'. Use the 'scoped' keyword instead. + Do not use 'System.Runtime.CompilerServices.ScopedRefAttribute'. Use the 'scoped' keyword instead. + + The given expression cannot be used in a fixed statement A expressão determinada não pode ser usada em uma instrução fixed @@ -552,6 +567,11 @@ O recurso '{0}' não está disponível no C# 10.0. Use a versão da linguagem {1} ou superior. + + Feature '{0}' is not available in C# 11.0. Please use language version {1} or greater. + Feature '{0}' is not available in C# 11.0. Please use language version {1} or greater. + + Feature '{0}' is not available in C# 8.0. Please use language version {1} or greater. O recurso '{0}' não está disponível em C# 8.0. Use a versão de linguagem {1} ou superior. @@ -582,6 +602,31 @@ O namespace de escopo de arquivo deve preceder todos os outros membros em um arquivo. + + File-local type '{0}' cannot be used as a base type of non-file-local type '{1}'. + File-local type '{0}' cannot be used as a base type of non-file-local type '{1}'. + + + + File-local type '{0}' cannot be used in a member signature in non-file-local type '{1}'. + File-local type '{0}' cannot be used in a member signature in non-file-local type '{1}'. + + + + Types and aliases cannot be named 'file'. + Types and aliases cannot be named 'file'. + + + + File-local type '{0}' must be defined in a top level type; '{0}' is a nested type. + File-local type '{0}' must be defined in a top level type; '{0}' is a nested type. + + + + File-local type '{0}' cannot use accessibility modifiers. + File-local type '{0}' cannot use accessibility modifiers. + + A fixed field must not be a ref field. Um campo fixo não deve ser um campo ref. @@ -627,6 +672,11 @@ Uma diretiva de uso global deve preceder todas as diretivas de uso não global. + + File-local type '{0}' cannot be used in a 'global using static' directive. + File-local type '{0}' cannot be used in a 'global using static' directive. + + A goto cannot jump to a location before a using declaration within the same block. Um goto não pode saltar para um local antes de uma declaração using no mesmo bloco. @@ -882,6 +932,11 @@ Palavra-chave inesperada “record”. Você quis dizer “record struct” or “record class”? + + Unexpected contextual keyword 'scoped'. Did you mean 'scoped ref' or '@scoped'? + Unexpected contextual keyword 'scoped'. Did you mean 'scoped ref' or '@scoped'? + + Slice patterns may only be used once and directly inside a list pattern. Os padrões de fatia somente podem ser usados uma vez e diretamente dentro de um padrão de lista. @@ -923,8 +978,8 @@ - Module initializer method '{0}' must be static, must have no parameters, and must return 'void' - O método inicializador do módulo '{0}' precisa ser estático, não pode ter parâmetros e precisa retornar 'void' + Module initializer method '{0}' must be static, and non-virtual, must have no parameters, and must return 'void' + O método inicializador do módulo '{0}' precisa ser estático, não pode ter parâmetros e precisa retornar 'void' @@ -1227,6 +1282,11 @@ Um campo ref não pode se referir a um struct ref. + + A ref field can only be declared in a ref struct. + A ref field can only be declared in a ref struct. + + The left-hand side of a ref assignment must be a ref variable. O lado esquerdo de uma atribuição ref deve ser uma variável ref. @@ -1297,6 +1357,11 @@ O runtime de destino não é compatível com a acessibilidade 'protected', 'protected internal' ou 'private protected' para um membro de uma interface. + + Target runtime doesn't support ref fields. + Target runtime doesn't support ref fields. + + Target runtime doesn't support static abstract members in interfaces. O runtime de destino não dá suporte aos membros abstratos estáticos em interfaces. @@ -1332,6 +1397,11 @@ O modificador 'scoped' só pode ser usado para valores de struct refs e ref. + + Types and aliases cannot be named 'scoped'. + Types and aliases cannot be named 'scoped'. + + Required members are not allowed on the top level of a script or submission. Os membros necessários não são permitidos no nível superior de um script ou envio. @@ -1512,6 +1582,16 @@ '{0}' foi atribuído com 'UnmanagedCallersOnly' e não pode ser convertido em um tipo delegado. Obtenha um ponteiro de função para esse método. UnmanagedCallersOnly is not localizable. + + UnscopedRefAttribute can only be applied to 'out' parameters, 'ref' and 'in' parameters that refer to 'ref struct' types, and instance methods and properties on 'struct' types other than constructors and 'init' accessors. + UnscopedRefAttribute can only be applied to 'out' parameters, 'ref' and 'in' parameters that refer to 'ref struct' types, and instance methods and properties on 'struct' types other than constructors and 'init' accessors. + + + + UnscopedRefAttribute cannot be applied to parameters that have a 'scoped' modifier. + UnscopedRefAttribute cannot be applied to parameters that have a 'scoped' modifier. + + '{0}' requires compiler feature '{1}', which is not supported by this version of the C# compiler. '{0}' requer o recurso de compilador '{1}', o que não é suportado por esta versão do compilador de C#. @@ -1562,6 +1642,11 @@ A diretiva using apareceu anteriormente como using global + + array access + array access + + async method builder override substituição do construtor de método assíncrono @@ -1602,6 +1687,11 @@ namespace de escopo de arquivo + + file types + file types + + generic attributes atributos genéricos @@ -1722,6 +1812,11 @@ padrões correspondentes a ReadOnly/Span<char> na cadeia de caracteres constante + + pointer element access + pointer element access + + The assembly '{0}' containing type '{1}' references .NET Framework, which is not supported. O assembly '{0}' contendo o tipo '{1}' referencia o .NET Framework, mas não há suporte para isso. @@ -2223,7 +2318,7 @@ curinga -reference:<alias>=<file> Metadados de referência do arquivo de assembly especificado usando o alias fornecido (Forma abreviada: -r) --reference:<file list> Metadados de referência dos arquivos de assembly +-reference:<file list> Metadados de referência dos arquivos de assembly especificados (Forma abreviada: -r) -addmodule:<file list> Vincular o módulo especificado a este assembly -link:<file list> Inserir os metadados dos arquivos de assembly de @@ -2251,7 +2346,7 @@ -debug:{full|pdbonly|portable|embedded} Especificar o tipo de depuração ('full' é o padrão, 'portable' é um formato multiplataforma, - 'embedded' é um formato multiplataforma inserido no + 'embedded' é um formato multiplataforma inserido no .dll ou no .exe de destino) -optimize[+|-] Habilitar as otimizações (Forma abreviada: -o) -deterministic Produzir um assembly determinístico @@ -2285,7 +2380,7 @@ -define:<symbol list> Definir os símbolos de compilação condicional (Forma abreviada: -d) -langversion:? Exibir os valores permitidos para a versão da linguagem --langversion:<string> Especificar a versão da linguagem, como +-langversion:<string> Especificar a versão da linguagem, como `latest` (última versão, incluindo as versões secundárias), `default` (igual a `latest`), `latestmajor` (última versão, excluindo as versões secundárias), @@ -2302,7 +2397,7 @@ da chave de nome forte -keyfile:<file> Especificar a arquivo de chave de nome forte -keycontainer:<string> Especificar o contêiner de chave de nome forte --highentropyva[+|-] Habilitar a ASLR de alta entropia +-highentropyva[+|-] Habilitar a ASLR de alta entropia – DIVERSOS – @<file> Ler o arquivo de resposta de mais opções @@ -10477,11 +10572,6 @@ Para incorporar informações de tipo de interoperabilidade para os dois assembl GetDeclarationName chamado para um nó de declaração que possivelmente pode conter múltiplos declaradores variáveis. - - tree not part of compilation - árvore não faz parte da compilação - - Position is not within syntax tree with full span {0} Posição não está dentro da árvore de sintaxe com intervalo total {0} diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf index b66aa56f986a0..a7e622cbfd36e 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf @@ -207,6 +207,11 @@ Оператор "{0}" невозможно применить к операнду "{1}". + + The parameter modifier '{0}' cannot follow '{1}' + The parameter modifier '{0}' cannot follow '{1}' + + Invalid operand for pattern match; value required, but found '{0}'. Недопустимый операнд для сопоставления с шаблоном. Требуется значение, но найдено "{0}". @@ -257,6 +262,11 @@ Не удалось вывести тип делегата. + + 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 specifc numeric type. + + 'managed' calling convention cannot be combined with unmanaged calling convention specifiers. Соглашение о вызовах "managed" невозможно использовать вместе с спецификаторами неуправляемых соглашений о вызовах. @@ -472,6 +482,11 @@ Не используйте "System.Runtime.CompilerServices.RequiredMemberAttribute". Вместо этого используйте ключевое слово "required" для обязательных полей и свойств. + + Do not use 'System.Runtime.CompilerServices.ScopedRefAttribute'. Use the 'scoped' keyword instead. + Do not use 'System.Runtime.CompilerServices.ScopedRefAttribute'. Use the 'scoped' keyword instead. + + The given expression cannot be used in a fixed statement Заданное выражение невозможно использовать в операторе fixed @@ -552,6 +567,11 @@ Функция "{0}" недоступна в C# 10.0. Используйте версию языка {1} или более позднюю. + + Feature '{0}' is not available in C# 11.0. Please use language version {1} or greater. + Feature '{0}' is not available in C# 11.0. Please use language version {1} or greater. + + Feature '{0}' is not available in C# 8.0. Please use language version {1} or greater. Функция "{0}" недоступна в C# 8.0. Используйте версию языка {1} или более позднюю. @@ -582,6 +602,31 @@ Пространство имен с файловой областью должно быть раньше всех остальных элементов в файле. + + File-local type '{0}' cannot be used as a base type of non-file-local type '{1}'. + File-local type '{0}' cannot be used as a base type of non-file-local type '{1}'. + + + + File-local type '{0}' cannot be used in a member signature in non-file-local type '{1}'. + File-local type '{0}' cannot be used in a member signature in non-file-local type '{1}'. + + + + Types and aliases cannot be named 'file'. + Types and aliases cannot be named 'file'. + + + + File-local type '{0}' must be defined in a top level type; '{0}' is a nested type. + File-local type '{0}' must be defined in a top level type; '{0}' is a nested type. + + + + File-local type '{0}' cannot use accessibility modifiers. + File-local type '{0}' cannot use accessibility modifiers. + + A fixed field must not be a ref field. Фиксированное поле не должно быть полем ref. @@ -627,6 +672,11 @@ Глобальная директива using должна предшествовать всем неглобальным директивам using. + + File-local type '{0}' cannot be used in a 'global using static' directive. + File-local type '{0}' cannot be used in a 'global using static' directive. + + A goto cannot jump to a location before a using declaration within the same block. Оператор goto не может переходить к расположению раньше объявления using в том же блоке. @@ -882,6 +932,11 @@ Непредвиденное ключевое слово \"record\". Возможно, вы имели в виду \"record struct\" или \"record class\"? + + Unexpected contextual keyword 'scoped'. Did you mean 'scoped ref' or '@scoped'? + Unexpected contextual keyword 'scoped'. Did you mean 'scoped ref' or '@scoped'? + + Slice patterns may only be used once and directly inside a list pattern. Шаблоны среза можно использовать только один раз и непосредственно внутри шаблона списка. @@ -923,8 +978,8 @@ - Module initializer method '{0}' must be static, must have no parameters, and must return 'void' - Метод инициализатора модуля "{0}" должен быть статическим, не должен иметь параметров и должен возвращать "void". + Module initializer method '{0}' must be static, and non-virtual, must have no parameters, and must return 'void' + Метод инициализатора модуля "{0}" должен быть статическим, не должен иметь параметров и должен возвращать "void". @@ -1227,6 +1282,11 @@ Поле ref не должно ссылаться на ref struct. + + A ref field can only be declared in a ref struct. + A ref field can only be declared in a ref struct. + + The left-hand side of a ref assignment must be a ref variable. Левая сторона назначения ref должна быть переменной ref. @@ -1297,6 +1357,11 @@ Целевая среда выполнения не поддерживает специальные возможности "защищенный", "внутренний защищенный" или "частный защищенный" для члена интерфейса. + + Target runtime doesn't support ref fields. + Target runtime doesn't support ref fields. + + Target runtime doesn't support static abstract members in interfaces. Целевая среда выполнения не поддерживает статические абстрактные элементы в интерфейсах. @@ -1332,6 +1397,11 @@ Модификатор "scoped" можно использовать только для ref и для значений ref struct. + + Types and aliases cannot be named 'scoped'. + Types and aliases cannot be named 'scoped'. + + Required members are not allowed on the top level of a script or submission. Обязательные члены не разрешены на верхнем уровне сценария или отправки. @@ -1512,6 +1582,16 @@ "{0}" имеет атрибут "UnmanagedCallersOnly" и не может быть преобразован в тип делегата. Получите указатель на функцию для этого метода. UnmanagedCallersOnly is not localizable. + + UnscopedRefAttribute can only be applied to 'out' parameters, 'ref' and 'in' parameters that refer to 'ref struct' types, and instance methods and properties on 'struct' types other than constructors and 'init' accessors. + UnscopedRefAttribute can only be applied to 'out' parameters, 'ref' and 'in' parameters that refer to 'ref struct' types, and instance methods and properties on 'struct' types other than constructors and 'init' accessors. + + + + UnscopedRefAttribute cannot be applied to parameters that have a 'scoped' modifier. + UnscopedRefAttribute cannot be applied to parameters that have a 'scoped' modifier. + + '{0}' requires compiler feature '{1}', which is not supported by this version of the C# compiler. Для "{0}" требуется функция компилятора "{1}", которая не поддерживается в этой версии компилятора C#. @@ -1562,6 +1642,11 @@ Директива using ранее использовалась в качестве глобальной + + array access + array access + + async method builder override переопределение построителя методов async @@ -1602,6 +1687,11 @@ пространство имен с файловой областью + + file types + file types + + generic attributes универсальные атрибуты @@ -1722,6 +1812,11 @@ сопоставление шаблонов ReadOnly/Span<char> в строке константы + + pointer element access + pointer element access + + The assembly '{0}' containing type '{1}' references .NET Framework, which is not supported. Сборка "{0}", содержащая тип "{1}", ссылается на платформу .NET Framework, которая не поддерживается. @@ -2260,7 +2355,7 @@ -instrument:TestCoverage Создать сборку, инструментированную для сбора сведений об объеме протестированного кода -sourcelink:<file> Данные о ссылке на исходные файлы для внедрения в PDB. - + — Ошибки и предупреждения - -warnaserror[+|-] Регистрировать все предупреждения как ошибки -warnaserror[+|-]:<warn list> Регистрировать указанные предупреждения как ошибки @@ -10477,11 +10572,6 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ GetDeclarationName вызывается для узла объявления, который может содержать множество операторов объявления переменных. - - tree not part of compilation - дерево не является частью компиляции - - Position is not within syntax tree with full span {0} Позиция не находится в пределах синтаксического дерева с полным диапазоном {0}. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf index 9c2646dd3c9fc..2ecf8b19fa9a3 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf @@ -207,6 +207,11 @@ '{0}' işleci '{1}' türündeki işlenene uygulanamaz + + The parameter modifier '{0}' cannot follow '{1}' + The parameter modifier '{0}' cannot follow '{1}' + + Invalid operand for pattern match; value required, but found '{0}'. Desen eşleşmesi için işlenen geçersiz. Değer gerekiyordu ancak '{0}' bulundu. @@ -257,6 +262,11 @@ Temsilci türü çıkarsanamadı. + + 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 specifc numeric type. + + 'managed' calling convention cannot be combined with unmanaged calling convention specifiers. 'managed' çağırma kuralı, yönetilmeyen çağırma kuralı tanımlayıcılarla birleştirilemez. @@ -472,6 +482,11 @@ 'System.Runtime.CompilerServices.RequiredMemberAttribute' kullanmayın. Bunun yerine gerekli alanlarda ve özelliklerde 'required' anahtar sözcüğünü kullanın. + + Do not use 'System.Runtime.CompilerServices.ScopedRefAttribute'. Use the 'scoped' keyword instead. + Do not use 'System.Runtime.CompilerServices.ScopedRefAttribute'. Use the 'scoped' keyword instead. + + The given expression cannot be used in a fixed statement Belirtilen ifade, fixed deyiminde kullanılamıyor @@ -552,6 +567,11 @@ '{0}' özelliği C# 10.0'da kullanılamıyor. Lütfen {1} veya daha yüksek dil sürümünü kullanın. + + Feature '{0}' is not available in C# 11.0. Please use language version {1} or greater. + Feature '{0}' is not available in C# 11.0. Please use language version {1} or greater. + + Feature '{0}' is not available in C# 8.0. Please use language version {1} or greater. '{0}' özelliği C# 8.0'da kullanılamaz. Lütfen {1} veya daha yüksek bir dil sürümü kullanın. @@ -582,6 +602,31 @@ Dosya kapsamlı ad alanı bir dosyadaki diğer tüm üyelerin önünde olmalıdır. + + File-local type '{0}' cannot be used as a base type of non-file-local type '{1}'. + File-local type '{0}' cannot be used as a base type of non-file-local type '{1}'. + + + + File-local type '{0}' cannot be used in a member signature in non-file-local type '{1}'. + File-local type '{0}' cannot be used in a member signature in non-file-local type '{1}'. + + + + Types and aliases cannot be named 'file'. + Types and aliases cannot be named 'file'. + + + + File-local type '{0}' must be defined in a top level type; '{0}' is a nested type. + File-local type '{0}' must be defined in a top level type; '{0}' is a nested type. + + + + File-local type '{0}' cannot use accessibility modifiers. + File-local type '{0}' cannot use accessibility modifiers. + + A fixed field must not be a ref field. Sabit bir alan bir başvuru alanı olamaz. @@ -627,6 +672,11 @@ Genel bir using yönergesi genel olmayan tüm using yönergelerinden önce gelmelidir. + + File-local type '{0}' cannot be used in a 'global using static' directive. + File-local type '{0}' cannot be used in a 'global using static' directive. + + A goto cannot jump to a location before a using declaration within the same block. Bir goto, aynı blok içinde yer alan using bildiriminden önceki bir konuma atlayamaz. @@ -882,6 +932,11 @@ Beklenmeyen 'record' anahtar sözcüğü. 'record struct' veya 'record class' mi demek istediniz? + + Unexpected contextual keyword 'scoped'. Did you mean 'scoped ref' or '@scoped'? + Unexpected contextual keyword 'scoped'. Did you mean 'scoped ref' or '@scoped'? + + Slice patterns may only be used once and directly inside a list pattern. Dilim desenleri yalnızca bir kez ve doğrudan bir liste deseninin içinde kullanılabilir. @@ -923,8 +978,8 @@ - Module initializer method '{0}' must be static, must have no parameters, and must return 'void' - '{0}' modül başlatıcısı metodu statik olmalıdır, hiç parametresi olmamalıdır ve 'void' döndürmelidir + Module initializer method '{0}' must be static, and non-virtual, must have no parameters, and must return 'void' + '{0}' modül başlatıcısı metodu statik olmalıdır, hiç parametresi olmamalıdır ve 'void' döndürmelidir @@ -1227,6 +1282,11 @@ Başvuru alanı bir başvuru yapısına başvuramaz. + + A ref field can only be declared in a ref struct. + A ref field can only be declared in a ref struct. + + The left-hand side of a ref assignment must be a ref variable. ref atamasının sol tarafı, ref değişkeni olmalıdır. @@ -1297,6 +1357,11 @@ Hedef çalışma zamanı, bir arabirim üyesi için 'protected', 'protected internal' veya 'private protected' erişilebilirliğini desteklemez. + + Target runtime doesn't support ref fields. + Target runtime doesn't support ref fields. + + Target runtime doesn't support static abstract members in interfaces. Hedef çalışma zamanı, arabirimlerdeki statik soyut üyeleri desteklemiyor. @@ -1332,6 +1397,11 @@ 'scoped' değiştiricisi yalnızca başvurular ve başvuru yapı değerleri için kullanılabilir. + + Types and aliases cannot be named 'scoped'. + Types and aliases cannot be named 'scoped'. + + Required members are not allowed on the top level of a script or submission. Bir betiğin veya gönderimin en üst düzeyinde gerekli üyelere izin verilmez. @@ -1512,6 +1582,16 @@ '{0}', 'UnmanagedCallersOnly' özniteliğine sahip ve temsilci türüne dönüştürülemez. Bu yöntem için bir işlev işaretçisi edinin. UnmanagedCallersOnly is not localizable. + + UnscopedRefAttribute can only be applied to 'out' parameters, 'ref' and 'in' parameters that refer to 'ref struct' types, and instance methods and properties on 'struct' types other than constructors and 'init' accessors. + UnscopedRefAttribute can only be applied to 'out' parameters, 'ref' and 'in' parameters that refer to 'ref struct' types, and instance methods and properties on 'struct' types other than constructors and 'init' accessors. + + + + UnscopedRefAttribute cannot be applied to parameters that have a 'scoped' modifier. + UnscopedRefAttribute cannot be applied to parameters that have a 'scoped' modifier. + + '{0}' requires compiler feature '{1}', which is not supported by this version of the C# compiler. '{0}', C# derleyicisinin bu sürümü tarafından desteklenmeyen '{1}' derleyici özelliğini gerektirir. @@ -1562,6 +1642,11 @@ Daha önce genel kullanım olarak görünen kullanım yönergesi + + array access + array access + + async method builder override zaman uyumsuz yöntem oluşturucusunu geçersiz kılma @@ -1602,6 +1687,11 @@ dosya kapsamlı ad alanı + + file types + file types + + generic attributes genel öznitelikler @@ -1722,6 +1812,11 @@ sabit dizede ReadOnly/Span<char> ile eşleşen desen + + pointer element access + pointer element access + + The assembly '{0}' containing type '{1}' references .NET Framework, which is not supported. '{1}' türünü içeren '{0}' bütünleştirilmiş kodu, desteklenmeyen .NET Framework'e başvuruyor. @@ -10477,11 +10572,6 @@ Uyarıyı kaldırmak için, /reference kullanabilirsiniz (Birlikte Çalışma T Birden çok değişken bildirimcisi içerebilecek bir bildirim düğümü için GetDeclarationName çağrıldı. - - tree not part of compilation - ağaç derlemenin parçası değildir - - Position is not within syntax tree with full span {0} Konum, tam kapsam {0} ile sözdizimi ağacı içinde değil diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf index 4c766312bb2fe..678148ca1551e 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf @@ -207,6 +207,11 @@ 运算符“{0}”无法应用于操作数“{1}” + + The parameter modifier '{0}' cannot follow '{1}' + The parameter modifier '{0}' cannot follow '{1}' + + Invalid operand for pattern match; value required, but found '{0}'. 用于模式匹配的操作数无效;需要值,但找到的是“{0}”。 @@ -257,6 +262,11 @@ 无法推断委托类型。 + + 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 specifc numeric type. + + 'managed' calling convention cannot be combined with unmanaged calling convention specifiers. "managed" 调用约定不能与非托管调用约定说明符一起使用。 @@ -472,6 +482,11 @@ 不要使用 'System.Runtime.CompilerServices.RequiredMemberAttribute'。请改为在必填字段和属性上使用 'required' 关键字。 + + Do not use 'System.Runtime.CompilerServices.ScopedRefAttribute'. Use the 'scoped' keyword instead. + Do not use 'System.Runtime.CompilerServices.ScopedRefAttribute'. Use the 'scoped' keyword instead. + + The given expression cannot be used in a fixed statement 给定表达式不能用于 fixed 语句中 @@ -552,6 +567,11 @@ 功能“{0}”在 C# 10.0 中不可用。请使用语言版本 {1} 或更高版本。 + + Feature '{0}' is not available in C# 11.0. Please use language version {1} or greater. + Feature '{0}' is not available in C# 11.0. Please use language version {1} or greater. + + Feature '{0}' is not available in C# 8.0. Please use language version {1} or greater. 功能“{0}”在 C# 8.0 中不可用。请使用语言版本 {1} 或更高版本。 @@ -582,6 +602,31 @@ 文件范围内的命名空间必须位于文件中所有其他成员之前。 + + File-local type '{0}' cannot be used as a base type of non-file-local type '{1}'. + File-local type '{0}' cannot be used as a base type of non-file-local type '{1}'. + + + + File-local type '{0}' cannot be used in a member signature in non-file-local type '{1}'. + File-local type '{0}' cannot be used in a member signature in non-file-local type '{1}'. + + + + Types and aliases cannot be named 'file'. + Types and aliases cannot be named 'file'. + + + + File-local type '{0}' must be defined in a top level type; '{0}' is a nested type. + File-local type '{0}' must be defined in a top level type; '{0}' is a nested type. + + + + File-local type '{0}' cannot use accessibility modifiers. + File-local type '{0}' cannot use accessibility modifiers. + + A fixed field must not be a ref field. 固定字段不能是 ref 字段。 @@ -627,6 +672,11 @@ 全局 using 指令必须位于所有非全局 using 指令之前。 + + File-local type '{0}' cannot be used in a 'global using static' directive. + File-local type '{0}' cannot be used in a 'global using static' directive. + + A goto cannot jump to a location before a using declaration within the same block. goto 无法跳转到同一块中 using 声明之前的某个位置。 @@ -882,6 +932,11 @@ 意外的关键字 \"record\"。你的意思是 \"record struct\" 还是 \"record class\"? + + Unexpected contextual keyword 'scoped'. Did you mean 'scoped ref' or '@scoped'? + Unexpected contextual keyword 'scoped'. Did you mean 'scoped ref' or '@scoped'? + + Slice patterns may only be used once and directly inside a list pattern. 切片模式只能使用一次,并且直接在列表模式内使用。 @@ -923,8 +978,8 @@ - Module initializer method '{0}' must be static, must have no parameters, and must return 'void' - 模块初始值设定项方法“{0}”必须是静态的,不能有任何参数,并且必须返回 "void" + Module initializer method '{0}' must be static, and non-virtual, must have no parameters, and must return 'void' + 模块初始值设定项方法“{0}”必须是静态的,不能有任何参数,并且必须返回 "void" @@ -1227,6 +1282,11 @@ ref 字段不能引用 ref 结构。 + + A ref field can only be declared in a ref struct. + A ref field can only be declared in a ref struct. + + The left-hand side of a ref assignment must be a ref variable. ref 赋值的左侧必须为 ref 变量。 @@ -1297,6 +1357,11 @@ 目标运行时不支持对接口的成员使用 "protected"、"protected internal" 或 "private protected" 辅助功能。 + + Target runtime doesn't support ref fields. + Target runtime doesn't support ref fields. + + Target runtime doesn't support static abstract members in interfaces. 目标运行时不支持接口中的静态抽象成员。 @@ -1332,6 +1397,11 @@ "scoped" 修饰符只能用于 refs 和 ref 结构值。 + + Types and aliases cannot be named 'scoped'. + Types and aliases cannot be named 'scoped'. + + Required members are not allowed on the top level of a script or submission. 所需成员不在脚本或提交的顶层受允许。 @@ -1512,6 +1582,16 @@ “{0}”使用 "UnmanagedCallersOnly" 进行特性化,无法转换为委托类型。请获取指向此方法的函数指针。 UnmanagedCallersOnly is not localizable. + + UnscopedRefAttribute can only be applied to 'out' parameters, 'ref' and 'in' parameters that refer to 'ref struct' types, and instance methods and properties on 'struct' types other than constructors and 'init' accessors. + UnscopedRefAttribute can only be applied to 'out' parameters, 'ref' and 'in' parameters that refer to 'ref struct' types, and instance methods and properties on 'struct' types other than constructors and 'init' accessors. + + + + UnscopedRefAttribute cannot be applied to parameters that have a 'scoped' modifier. + UnscopedRefAttribute cannot be applied to parameters that have a 'scoped' modifier. + + '{0}' requires compiler feature '{1}', which is not supported by this version of the C# compiler. '{0}' 需要编译器功能 '{1}',此版本的 C# 编译器不支持此功能。 @@ -1562,6 +1642,11 @@ Using 指令在以前显示为全局使用 + + array access + array access + + async method builder override 异步方法生成器替代 @@ -1602,6 +1687,11 @@ 文件范围内的命名空间 + + file types + file types + + generic attributes 通用属性 @@ -1722,6 +1812,11 @@ 与常量字符串上的 ReadOnly/Span<char> 匹配的模式 + + pointer element access + pointer element access + + The assembly '{0}' containing type '{1}' references .NET Framework, which is not supported. 包含类型“{1}”的程序集“{0}”引用了 .NET Framework,而此操作不受支持。 @@ -2213,12 +2308,12 @@ (短格式: - t:winmdobj) -doc:<file> 要生成的 XML 文档文件 -refout:<file> 要生成的引用程序集输出 - + -platform:<string> 限制可以运行此代码的平台: x86、 Itanium、x64、arm、arm64、 anycpu32bitpreferred 或 anycpu。默认值是 anycpu。 - - 输入文件 - + - 输入文件 - -recurse:<wildcard> 根据通配符规范包括当前目录和 子目录中的 所有文件 @@ -2232,7 +2327,7 @@ -analyzer:<file list> 从此程序集运行分析器 (短格式: -a) -additionalfile:<file list> 不直接影响代码生成 - 但由分析器用于生成错误或警报 + 但由分析器用于生成错误或警报 的其他文件。 -embed 在 PDB 中嵌入所有源文件。 -embed:<file list> 在 PDB 中嵌入特定文件。 @@ -2245,7 +2340,7 @@ -resource:<resinfo> 嵌入指定的资源(短格式: -res) - linkresource:<resinfo> 将指定资源关联到此程序集 (短格式: -linkres),其中 resinfo 格式 - + 是 <file>[,<string name>[,public|private]] - 代码生成 - @@ -2262,16 +2357,16 @@ -instrument:TestCoverage 生成 已检测的程序集以收集 覆盖范围信息 -sourcelink:<file> 要嵌入 PDB 的源链接信息。 - + - 错误和警报 - -warnaserror[+|-] 将所有警报报告为错误 -warnaserror[+|-]:<warn list> 将特定警报报告为错误 (将 "nullable" 用于所有可为 null 的警报) -warn:<n> 设置警报级别(0 或更高) (短格式: -w) - + -nowarn:<warn list> 禁用特定警报消息 (将 "nullable" 用于所有可为 null 的警报) - + -ruleset:<file> 指定禁用特定诊断的规则集 文件。 -errorlog:<file> [,version=<sarif_version>] @@ -2280,7 +2375,7 @@ sarif_version:{1|2|2.1} 默认值是 1. 2 和 2.1 这两者 都是指 SARIF 版本 2.1.0。 -reportanalyzer 报告其他分析器信息,例如 - 执行时间。 + 执行时间。 -skipanalyzers[+|-] 跳过诊断分析器的执行。 - 语言 - @@ -2321,7 +2416,7 @@ -checksumalgorithm:<alg> 指定算法以计算存储在 PDB 中的源文件 校验和。支持的值是: SHA1 或 SHA256 (默认)。 - + -codepage:<n> 指定打开源文件时使用的 代码页 -utf8output 采用 UTF-8 编码的输出编译器消息 @@ -10482,11 +10577,6 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ 为可能包含多个变量声明符的声明节点调用了 GetDeclarationName。 - - tree not part of compilation - 树不属于编译 - - Position is not within syntax tree with full span {0} 位置不在具有完整范围 {0} 的语法树中 diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf index 7556b82b63d89..d0ffc1bd1b689 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf @@ -139,12 +139,12 @@ The first operand of an overloaded shift operator must have the same type as the containing type or its type parameter constrained to it - 多載移位 (Shift) 運算子的第一個運算元的類型必須和包含的類型相同,或是其型別參數受限於該運算子 + The first operand of an overloaded shift operator must have the same type as the containing type or its type parameter constrained to it A static virtual or abstract interface member can be accessed only on a type parameter. - 只能在型別參數上存取靜態虛擬或抽象介面成員。 + A static virtual or abstract interface member can be accessed only on a type parameter. @@ -207,6 +207,11 @@ 運算子 '{0}' 不可套用至運算元 '{1}' + + The parameter modifier '{0}' cannot follow '{1}' + The parameter modifier '{0}' cannot follow '{1}' + + Invalid operand for pattern match; value required, but found '{0}'. 模式比對運算元無效; 需要值,但找到 '{0}'。 @@ -249,7 +254,7 @@ Cannot convert &method group '{0}' to delegate type '{1}'. - 無法將方法群組 '{0}' 轉換成委派類型 '{1}'(&M)。 + Cannot convert &method group '{0}' to delegate type '{1}'. @@ -257,6 +262,11 @@ 無法推斷委派類型。 + + 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 specifc numeric type. + + 'managed' calling convention cannot be combined with unmanaged calling convention specifiers. 'managed' 呼叫慣例不得與未受控的呼叫慣例指定名稱並用。 @@ -304,12 +314,12 @@ This constructor must add 'SetsRequiredMembers' because it chains to a constructor that has that attribute. - 此建構函式必須新增 'SetsRequiredMembers',因為它鏈結至具有該屬性的建構函式。 + This constructor must add 'SetsRequiredMembers' because it chains to a constructor that has that attribute. The operator '{0}' requires a matching non-checked version of the operator to also be defined - 運算子 '{0}' 需要也同時定義運算子的相符未檢查版本 + The operator '{0}' requires a matching non-checked version of the operator to also be defined @@ -469,7 +479,12 @@ Do not use 'System.Runtime.CompilerServices.RequiredMemberAttribute'. Use the 'required' keyword on required fields and properties instead. - 請勿使用 'System.Runtime.CompilerServices.RequiredMemberAttribute'。請改為在必要的欄位和屬性上使用 'required' 關鍵字。 + Do not use 'System.Runtime.CompilerServices.RequiredMemberAttribute'. Use the 'required' keyword on required fields and properties instead. + + + + Do not use 'System.Runtime.CompilerServices.ScopedRefAttribute'. Use the 'scoped' keyword instead. + Do not use 'System.Runtime.CompilerServices.ScopedRefAttribute'. Use the 'scoped' keyword instead. @@ -489,7 +504,7 @@ An expression tree may not contain an access of static virtual or abstract interface member - 運算式樹狀架構不可包含靜態虛擬或抽象介面成員的存取權 + An expression tree may not contain an access of static virtual or abstract interface member @@ -552,6 +567,11 @@ C# 10.0 中無法使用 '{0}' 功能。請使用語言版本 {1} 或更高的版本。 + + Feature '{0}' is not available in C# 11.0. Please use language version {1} or greater. + Feature '{0}' is not available in C# 11.0. Please use language version {1} or greater. + + Feature '{0}' is not available in C# 8.0. Please use language version {1} or greater. C# 8.0 中無法使用功能 '{0}'。請使用 {1} 或更新的語言版本。 @@ -582,6 +602,31 @@ 以檔為範圍的命名空間必須在檔案中的所有其他成員之前。 + + File-local type '{0}' cannot be used as a base type of non-file-local type '{1}'. + File-local type '{0}' cannot be used as a base type of non-file-local type '{1}'. + + + + File-local type '{0}' cannot be used in a member signature in non-file-local type '{1}'. + File-local type '{0}' cannot be used in a member signature in non-file-local type '{1}'. + + + + Types and aliases cannot be named 'file'. + Types and aliases cannot be named 'file'. + + + + File-local type '{0}' must be defined in a top level type; '{0}' is a nested type. + File-local type '{0}' must be defined in a top level type; '{0}' is a nested type. + + + + File-local type '{0}' cannot use accessibility modifiers. + File-local type '{0}' cannot use accessibility modifiers. + + A fixed field must not be a ref field. 修正的欄位不能是 ref 欄位。 @@ -627,6 +672,11 @@ 全域 using 指示詞必須在所有非全域 using 指示詞之前。 + + File-local type '{0}' cannot be used in a 'global using static' directive. + File-local type '{0}' cannot be used in a 'global using static' directive. + + A goto cannot jump to a location before a using declaration within the same block. 在相同區塊內,goto 不可跳到 using 宣告前的位置。 @@ -654,7 +704,7 @@ An 'implicit' user-defined conversion operator cannot be declared checked - 無法將「隱式」使用者定義轉換運算子宣告為已檢查 + An 'implicit' user-defined conversion operator cannot be declared checked @@ -882,6 +932,11 @@ 未預期的關鍵字 'record'。您是指 'record struct' 或 'record class'? + + Unexpected contextual keyword 'scoped'. Did you mean 'scoped ref' or '@scoped'? + Unexpected contextual keyword 'scoped'. Did you mean 'scoped ref' or '@scoped'? + + Slice patterns may only be used once and directly inside a list pattern. 切片模式只能在清單模式中使用一次且直接使用。 @@ -889,7 +944,7 @@ Unexpected keyword 'unchecked' - 未預期的關鍵字 'unchecked' + Unexpected keyword 'unchecked' @@ -923,8 +978,8 @@ - Module initializer method '{0}' must be static, must have no parameters, and must return 'void' - 模組初始設定式方法 '{0}' 必須是靜態,不得具有任何參數,而且必須傳回 'void' + Module initializer method '{0}' must be static, and non-virtual, must have no parameters, and must return 'void' + 模組初始設定式方法 '{0}' 必須是靜態,不得具有任何參數,而且必須傳回 'void' @@ -954,7 +1009,7 @@ '{2}' cannot satisfy the 'new()' constraint on parameter '{1}' in the generic type or or method '{0}' because '{2}' has required members. - '{2}' 無法滿足泛型型別或方法 '{0}' 中參數 '{1}' 的 'new()' 限制式,因為 '{2}' 具有必要的成員。 + '{2}' cannot satisfy the 'new()' constraint on parameter '{1}' in the generic type or or method '{0}' because '{2}' has required members. @@ -1074,7 +1129,7 @@ User-defined operator '{0}' cannot be declared checked - 使用者定義的運算子 '{0}' 無法宣告為已檢查 + User-defined operator '{0}' cannot be declared checked @@ -1089,7 +1144,7 @@ '{0}' must be required because it overrides required member '{1}' - '{0}' 必須為必要項目,因為它會覆蓋必要的成員 '{1}' + '{0}' must be required because it overrides required member '{1}' @@ -1104,7 +1159,7 @@ The 'parameter null-checking' feature is not supported. - 不支援 'parameter null-checking' 功能。 + The 'parameter null-checking' feature is not supported. @@ -1154,7 +1209,7 @@ A string 'null' constant is not supported as a pattern for '{0}'. Use an empty string instead. - 不支援字串 'null' 常數做為 '{0}' 的模式。請改為使用空字串。 + A string 'null' constant is not supported as a pattern for '{0}'. Use an empty string instead. @@ -1227,6 +1282,11 @@ ref 欄位不能參考 ref 結構。 + + A ref field can only be declared in a ref struct. + A ref field can only be declared in a ref struct. + + The left-hand side of a ref assignment must be a ref variable. 參考指派的左側必須為 ref 變數。 @@ -1234,7 +1294,7 @@ Ref returning properties cannot be required. - 無法要求 Ref 傳回屬性。 + Ref returning properties cannot be required. @@ -1244,42 +1304,42 @@ Required member '{0}' cannot be hidden by '{1}'. - '{1}' 無法隱藏必要成員 '{0}'。 + Required member '{0}' cannot be hidden by '{1}'. Required member '{0}' cannot be less visible or have a setter less visible than the containing type '{1}'. - 必要成員 '{0}' 可見度不能較低,或 setter 的可見程度低於包含的類型 '{1}'。 + Required member '{0}' cannot be less visible or have a setter less visible than the containing type '{1}'. Required member '{0}' must be set in the object initializer or attribute constructor. - 必須在物件初始設定式或屬性建構函式中設定必要的成員 '{0}'。 + Required member '{0}' must be set in the object initializer or attribute constructor. Required member '{0}' must be settable. - 必要的成員 '{0}' 必須可設定。 + Required member '{0}' must be settable. The required members list for the base type '{0}' is malformed and cannot be interpreted. To use this constructor, apply the 'SetsRequiredMembers' attribute. - 基底類型 '{0}' 所需的成員清單格式錯誤,無法解譯。若要使用此建構函式,請套用 'SetsRequiredMembers' 屬性。 + The required members list for the base type '{0}' is malformed and cannot be interpreted. To use this constructor, apply the 'SetsRequiredMembers' attribute. The required members list for '{0}' is malformed and cannot be interpreted. - '{0}' 的必要成員清單格式錯誤,無法解譯。 + The required members list for '{0}' is malformed and cannot be interpreted. Required member '{0}' must be assigned a value, it cannot use a nested member or collection initializer. - 必要的成員 '{0}' 必須指派值,它無法使用巢狀成員或集合初始設定式。 + Required member '{0}' must be assigned a value, it cannot use a nested member or collection initializer. Types and aliases cannot be named 'required'. - 類型和別名不能命名為 'required'。 + Types and aliases cannot be named 'required'. @@ -1297,6 +1357,11 @@ 目標執行階段不支援介面成員的 'protected'、'protected internal' 或 'private protected' 存取權。 + + Target runtime doesn't support ref fields. + Target runtime doesn't support ref fields. + + Target runtime doesn't support static abstract members in interfaces. 目標執行階段不支援介面中的靜態抽象成員。 @@ -1332,6 +1397,11 @@ 'scoped' 修飾元只能用於 refs 和 ref 結構值。 + + Types and aliases cannot be named 'scoped'. + Types and aliases cannot be named 'scoped'. + + Required members are not allowed on the top level of a script or submission. 指令碼或提交的頂層不允許必要的成員。 @@ -1494,12 +1564,12 @@ 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}' 以自動預設屬性。 + 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. Field '{0}' must be fully assigned before control is returned to the caller. Consider updating to language version '{1}' to auto-default the field. - 在控制項傳回呼叫者之前,必須先完全指派欄位 '{0}'。請考慮更新至語言版本 '{1}' 以自動預設欄位。 + Field '{0}' must be fully assigned before control is returned to the caller. Consider updating to language version '{1}' to auto-default the field. @@ -1512,9 +1582,19 @@ '{0}' 使用 'UnmanagedCallersOnly' 屬性化,因此無法轉換為委派類型。取得此方法的函式指標。 UnmanagedCallersOnly is not localizable. + + UnscopedRefAttribute can only be applied to 'out' parameters, 'ref' and 'in' parameters that refer to 'ref struct' types, and instance methods and properties on 'struct' types other than constructors and 'init' accessors. + UnscopedRefAttribute can only be applied to 'out' parameters, 'ref' and 'in' parameters that refer to 'ref struct' types, and instance methods and properties on 'struct' types other than constructors and 'init' accessors. + + + + UnscopedRefAttribute cannot be applied to parameters that have a 'scoped' modifier. + UnscopedRefAttribute cannot be applied to parameters that have a 'scoped' modifier. + + '{0}' requires compiler feature '{1}', which is not supported by this version of the C# compiler. - '{0}' 需要編譯器功能 '{1}',此版本的 C# 編譯器不支援此功能。 + '{0}' requires compiler feature '{1}', which is not supported by this version of the C# compiler. @@ -1534,17 +1614,17 @@ Use of possibly unassigned field '{0}'. Consider updating to language version '{1}' to auto-default the field. - 使用可能未指派的欄位 '{0}'。請考慮更新語言版本 '{1}' 以自動預設欄位。 + Use of possibly unassigned field '{0}'. Consider updating to language version '{1}' to auto-default the field. Use of possibly unassigned auto-implemented property '{0}'. Consider updating to language version '{1}' to auto-default the property. - 使用可能未指派的自動實作屬性 '{0}'。請考慮更新語言版本 '{1}' 以自動預設屬性。 + Use of possibly unassigned auto-implemented property '{0}'. Consider updating to language version '{1}' to auto-default the property. The 'this' object cannot be used before all of its fields have been assigned. Consider updating to language version '{0}' to auto-default the unassigned fields. - 在指派 'this' 物件的所有欄位之前,無法使用該物件。請考慮更新語言版本 '{0}',以自動預設未指派的欄位。 + The 'this' object cannot be used before all of its fields have been assigned. Consider updating to language version '{0}' to auto-default the unassigned fields. @@ -1562,6 +1642,11 @@ Using 指示詞先前顯示為全域 using + + array access + array access + + async method builder override 非同步方法建立器覆寫 @@ -1569,12 +1654,12 @@ auto default struct fields - 自動預設結構欄位 + auto default struct fields checked user-defined operators - 已檢查使用者定義的運算子 + checked user-defined operators @@ -1602,6 +1687,11 @@ 以檔案為範圍的命名空間 + + file types + file types + + generic attributes 一般屬性 @@ -1674,12 +1764,12 @@ relaxed shift operator - 寬鬆移位 (Shift) 運算子 + relaxed shift operator required members - 必要成員 + required members @@ -1694,7 +1784,7 @@ unsigned right shift - 未簽署右移位 + unsigned right shift @@ -1719,7 +1809,12 @@ pattern matching ReadOnly/Span<char> on constant string - 常數字串上的模式比對 ReadOnly/Span<char> + pattern matching ReadOnly/Span<char> on constant string + + + + pointer element access + pointer element access @@ -1864,12 +1959,12 @@ Required member '{0}' should not be attributed with 'ObsoleteAttribute' unless the containing type is obsolete or all constructors are obsolete. - 除非包含的類型已過時或所有建構函式已過時,否則必要成員 '{0}' 的屬性不應為 'ObsoleteAttribute'。 + Required member '{0}' should not be attributed with 'ObsoleteAttribute' unless the containing type is obsolete or all constructors are obsolete. Members attributed with 'ObsoleteAttribute' should not be required unless the containing type is obsolete or all constructors are obsolete. - 除非包含的類型已過時或所有建構函式已過時,否則不應要求具有 'ObsoleteAttribute' 屬性的成員。 + Members attributed with 'ObsoleteAttribute' should not be required unless the containing type is obsolete or all constructors are obsolete. @@ -1984,7 +2079,7 @@ 'UnmanagedCallersOnly' can only be applied to ordinary static non-abstract, non-virtual methods or static local functions. - 'UnmanagedCallersOnly' 僅適用於一般靜態非抽象方法、非虛擬方法或靜態區域函式。 + 'UnmanagedCallersOnly' can only be applied to ordinary static non-abstract, non-virtual methods or static local functions. UnmanagedCallersOnly is not localizable. @@ -2260,7 +2355,7 @@ -instrument:TestCoverage 產生經檢測的組件,以收集 涵蓋範圍資訊 -sourcelink:<file> 要內嵌至 PDB 的來源連結資訊。 - + - 錯誤與警告 - -warnaserror[+|-] 將所有警告回報為錯誤 -warnaserror[+|-]:<warn list> 將特定警告回報為錯誤 @@ -3768,42 +3863,42 @@ Control is returned to caller before auto-implemented property '{0}' is explicitly assigned, causing a preceding implicit assignment of 'default'. - 在明確指派自動實作屬性 '{0}' 之前會先將控制項傳回呼叫者,導致先前隱含的指派為 'default'。 + Control is returned to caller before auto-implemented property '{0}' is explicitly assigned, causing a preceding implicit assignment of 'default'. Control is returned to caller before auto-implemented property is explicitly assigned, causing a preceding implicit assignment of 'default'. - 在明確指派自動實作屬性之前會先將控制項傳回呼叫者,導致先前隱含的指派為 'default'。 + Control is returned to caller before auto-implemented property is explicitly assigned, causing a preceding implicit assignment of 'default'. 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}' 以自動預設屬性。 + 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. An auto-implemented property must be fully assigned before control is returned to the caller. Consider updating the language version to auto-default the property. - 在控制項傳回呼叫者之前,必須先完全指派自動實作屬性。請考慮更新至語言版本以自動預設屬性。 + An auto-implemented property must be fully assigned before control is returned to the caller. Consider updating the language version to auto-default the property. Control is returned to caller before field '{0}' is explicitly assigned, causing a preceding implicit assignment of 'default'. - 在明確指派欄位 '{0}' 之前會先將控制項傳回呼叫者,導致先前隱含的指派為 'default'。 + Control is returned to caller before field '{0}' is explicitly assigned, causing a preceding implicit assignment of 'default'. Control is returned to caller before field is explicitly assigned, causing a preceding implicit assignment of 'default'. - 在明確指派欄位之前會先將控制項傳回呼叫者,導致先前隱含的指派為 'default'。 + Control is returned to caller before field is explicitly assigned, causing a preceding implicit assignment of 'default'. Field '{0}' must be fully assigned before control is returned to the caller. Consider updating to language version '{1}' to auto-default the field. - 在控制項傳回呼叫者之前,必須先完全指派欄位 '{0}'。請考慮更新至語言版本 '{1}' 以自動預設欄位。 + Field '{0}' must be fully assigned before control is returned to the caller. Consider updating to language version '{1}' to auto-default the field. Fields of a struct must be fully assigned in a constructor before control is returned to the caller. Consider updating the language version to auto-default the field. - 在控制項傳回呼叫者之前,必須先在建構函式中完全指派結構的欄位。請考慮更新至語言版本以自動預設欄位。 + Fields of a struct must be fully assigned in a constructor before control is returned to the caller. Consider updating the language version to auto-default the field. @@ -3868,22 +3963,22 @@ Field '{0}' is read before being explicitly assigned, causing a preceding implicit assignment of 'default'. - 在明確指派之前會先讀取欄位 '{0}',導致先前隱含的指派為 'default'。 + Field '{0}' is read before being explicitly assigned, causing a preceding implicit assignment of 'default'. Field is read before being explicitly assigned, causing a preceding implicit assignment of 'default'. - 在明確指派之前會先讀取欄位,導致先前隱含的指派為 'default'。 + Field is read before being explicitly assigned, causing a preceding implicit assignment of 'default'. Use of possibly unassigned field '{0}'. Consider updating to language version '{1}' to auto-default the field. - 使用可能未指派的欄位 '{0}'。請考慮更新語言版本 '{1}' 以自動預設欄位。 + Use of possibly unassigned field '{0}'. Consider updating to language version '{1}' to auto-default the field. Use of possibly unassigned field. Consider updating the language version to auto-default the field. - 使用可能未指派的欄位。請考慮更新語言版本以自動預設欄位。 + Use of possibly unassigned field. Consider updating the language version to auto-default the field. @@ -3908,22 +4003,22 @@ Auto-implemented property '{0}' is read before being explicitly assigned, causing a preceding implicit assignment of 'default'. - 在明確指派之前會先讀取自動實作屬性 '{0}',導致先前隱含的指派為 'default'。 + Auto-implemented property '{0}' is read before being explicitly assigned, causing a preceding implicit assignment of 'default'. Auto-implemented property is read before being explicitly assigned, causing a preceding implicit assignment of 'default'. - 在明確指派之前會先讀取自動實作屬性,導致先前隱含的指派為 'default'。 + Auto-implemented property is read before being explicitly assigned, causing a preceding implicit assignment of 'default'. Use of possibly unassigned auto-implemented property '{0}'. Consider updating to language version '{1}' to auto-default the property. - 使用可能未指派的自動實作屬性 '{0}'。請考慮更新語言版本 '{1}' 以自動預設屬性。 + Use of possibly unassigned auto-implemented property '{0}'. Consider updating to language version '{1}' to auto-default the property. Use of possibly unassigned auto-implemented property. Consider updating the language version to auto-default the property. - 使用可能未指派的自動實作屬性。請考慮更新語言版本以自動預設屬性。 + Use of possibly unassigned auto-implemented property. Consider updating the language version to auto-default the property. @@ -3933,22 +4028,22 @@ The 'this' object is read before all of its fields have been assigned, causing preceding implicit assignments of 'default' to non-explicitly assigned fields. - 在指派 'this' 物件的所有欄位之前,會先讀取該物件,導致先前對未明確指派的欄位進行隱含的 'default' 指派。 + The 'this' object is read before all of its fields have been assigned, causing preceding implicit assignments of 'default' to non-explicitly assigned fields. The 'this' object is read before all of its fields have been assigned, causing preceding implicit assignments of 'default' to non-explicitly assigned fields. - 在指派 'this' 物件的所有欄位之前,會先讀取該物件,導致先前對未明確指派的欄位進行隱含的 'default' 指派。 + The 'this' object is read before all of its fields have been assigned, causing preceding implicit assignments of 'default' to non-explicitly assigned fields. The 'this' object cannot be used before all of its fields have been assigned. Consider updating to language version '{0}' to auto-default the unassigned fields. - 在指派 'this' 物件的所有欄位之前,無法使用該物件。請考慮更新語言版本 '{0}',以自動預設未指派的欄位。 + The 'this' object cannot be used before all of its fields have been assigned. Consider updating to language version '{0}' to auto-default the unassigned fields. The 'this' object cannot be used in a constructor before all of its fields have been assigned. Consider updating the language version to auto-default the unassigned fields. - 在指派 'this' 物件的所有欄位之前,無法在建構函式中使用。請考慮更新語言版本,以自動預設未指派的欄位。 + The 'this' object cannot be used in a constructor before all of its fields have been assigned. Consider updating the language version to auto-default the unassigned fields. @@ -5987,7 +6082,7 @@ If such a class is used as a base class and if the deriving class defines a dest The first operand of an overloaded shift operator must have the same type as the containing type - 多載移位 (Shift) 運算子的第一個運算元的類型必須和包含類型相同 + The first operand of an overloaded shift operator must have the same type as the containing type @@ -10477,11 +10572,6 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ 為可能包含多重變數宣告子的宣告節點,呼叫了 GetDeclarationName。 - - tree not part of compilation - 樹狀結構不是編譯的一部分 - - Position is not within syntax tree with full span {0} 位置不在有完整範圍 {0} 的語法樹狀結構內 diff --git a/src/Compilers/CSharp/Test/CommandLine/CommandLineTestBase.cs b/src/Compilers/CSharp/Test/CommandLine/CommandLineTestBase.cs index d9788dd37f7aa..ca6ea2255bbd5 100644 --- a/src/Compilers/CSharp/Test/CommandLine/CommandLineTestBase.cs +++ b/src/Compilers/CSharp/Test/CommandLine/CommandLineTestBase.cs @@ -2,8 +2,6 @@ // The .NET Foundation 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,21 +46,21 @@ string getSdkDirectory(TempRoot temp) } } - internal CSharpCommandLineArguments DefaultParse(IEnumerable args, string baseDirectory, string sdkDirectory = null, string additionalReferenceDirectories = null) + internal CSharpCommandLineArguments DefaultParse(IEnumerable args, string baseDirectory, string? sdkDirectory = null, string? additionalReferenceDirectories = null) { sdkDirectory = sdkDirectory ?? SdkDirectory; return CSharpCommandLineParser.Default.Parse(args, baseDirectory, sdkDirectory, additionalReferenceDirectories); } - internal MockCSharpCompiler CreateCSharpCompiler(string[] args, ImmutableArray analyzers = default, ImmutableArray generators = default, AnalyzerAssemblyLoader loader = null, GeneratorDriverCache driverCache = null) + internal MockCSharpCompiler CreateCSharpCompiler(string[] args, DiagnosticAnalyzer[]? analyzers = null, ISourceGenerator[]? generators = null, AnalyzerAssemblyLoader? loader = null, GeneratorDriverCache? driverCache = null) { return CreateCSharpCompiler(null, WorkingDirectory, args, analyzers, generators, loader, driverCache); } - internal MockCSharpCompiler CreateCSharpCompiler(string responseFile, string workingDirectory, string[] args, ImmutableArray analyzers = default, ImmutableArray generators = default, AnalyzerAssemblyLoader loader = null, GeneratorDriverCache driverCache = null) + internal MockCSharpCompiler CreateCSharpCompiler(string? responseFile, string workingDirectory, string[] args, DiagnosticAnalyzer[]? analyzers = null, ISourceGenerator[]? generators = null, AnalyzerAssemblyLoader? loader = null, GeneratorDriverCache? driverCache = null) { var buildPaths = RuntimeUtilities.CreateBuildPaths(workingDirectory, sdkDirectory: SdkDirectory); - return new MockCSharpCompiler(responseFile, buildPaths, args, analyzers, generators, loader, driverCache); + return new MockCSharpCompiler(responseFile, buildPaths, args, analyzers.AsImmutableOrEmpty(), generators.AsImmutableOrEmpty(), loader, driverCache); } } } diff --git a/src/Compilers/CSharp/Test/CommandLine/CommandLineTests.cs b/src/Compilers/CSharp/Test/CommandLine/CommandLineTests.cs index caa82ebcfbd60..ca6fda946960f 100644 --- a/src/Compilers/CSharp/Test/CommandLine/CommandLineTests.cs +++ b/src/Compilers/CSharp/Test/CommandLine/CommandLineTests.cs @@ -34,6 +34,7 @@ using Roslyn.Test.Utilities; using Roslyn.Test.Utilities.TestGenerators; using Roslyn.Utilities; +using TestResources.Analyzers; using Xunit; using Basic.Reference.Assemblies; using static Microsoft.CodeAnalysis.CommonDiagnosticAnalyzers; @@ -1614,7 +1615,7 @@ public void LangVersion_NoValueSpecified() [InlineData("iso1")] [InlineData("8.1")] [InlineData("10.1")] - [InlineData("11")] + [InlineData("12")] [InlineData("1000")] public void LangVersion_BadVersion(string value) { @@ -1670,7 +1671,7 @@ public void LanguageVersionAdded_Canary() // - update all the tests that call this canary // - update MaxSupportedLangVersion (a relevant test should break when new version is introduced) // - email release management to add to the release notes (see old example: https://github.com/dotnet/core/pull/1454) - AssertEx.SetEqual(new[] { "default", "1", "2", "3", "4", "5", "6", "7.0", "7.1", "7.2", "7.3", "8.0", "9.0", "10.0", "latest", "latestmajor", "preview" }, + AssertEx.SetEqual(new[] { "default", "1", "2", "3", "4", "5", "6", "7.0", "7.1", "7.2", "7.3", "8.0", "9.0", "10.0", "11.0", "latest", "latestmajor", "preview" }, Enum.GetValues(typeof(LanguageVersion)).Cast().Select(v => v.ToDisplayString())); // For minor versions and new major versions, the format should be "x.y", such as "7.1" } @@ -1703,6 +1704,7 @@ public void LanguageVersion_GetErrorCode() ErrorCode.ERR_FeatureNotAvailableInVersion8, ErrorCode.ERR_FeatureNotAvailableInVersion9, ErrorCode.ERR_FeatureNotAvailableInVersion10, + ErrorCode.ERR_FeatureNotAvailableInVersion11, }; AssertEx.SetEqual(versions, errorCodes); @@ -1725,9 +1727,10 @@ public void LanguageVersion_GetErrorCode() InlineData(LanguageVersion.CSharp8, LanguageVersion.CSharp8), InlineData(LanguageVersion.CSharp9, LanguageVersion.CSharp9), InlineData(LanguageVersion.CSharp10, LanguageVersion.CSharp10), - InlineData(LanguageVersion.CSharp10, LanguageVersion.LatestMajor), - InlineData(LanguageVersion.CSharp10, LanguageVersion.Latest), - InlineData(LanguageVersion.CSharp10, LanguageVersion.Default), + InlineData(LanguageVersion.CSharp11, LanguageVersion.CSharp11), + InlineData(LanguageVersion.CSharp11, LanguageVersion.LatestMajor), + InlineData(LanguageVersion.CSharp11, LanguageVersion.Latest), + InlineData(LanguageVersion.CSharp11, LanguageVersion.Default), InlineData(LanguageVersion.Preview, LanguageVersion.Preview), ] public void LanguageVersion_MapSpecifiedToEffectiveVersion(LanguageVersion expectedMappedVersion, LanguageVersion input) @@ -1768,6 +1771,8 @@ public void LanguageVersion_MapSpecifiedToEffectiveVersion(LanguageVersion expec InlineData("9.0", true, LanguageVersion.CSharp9), InlineData("10", true, LanguageVersion.CSharp10), InlineData("10.0", true, LanguageVersion.CSharp10), + InlineData("11", true, LanguageVersion.CSharp11), + InlineData("11.0", true, LanguageVersion.CSharp11), InlineData("08", false, LanguageVersion.Default), InlineData("07.1", false, LanguageVersion.Default), InlineData("default", true, LanguageVersion.Default), @@ -9192,12 +9197,19 @@ public void ReportAnalyzerOutput() var srcDirectory = Path.GetDirectoryName(srcFile.Path); var outWriter = new StringWriter(CultureInfo.InvariantCulture); - var csc = CreateCSharpCompiler(null, srcDirectory, new[] { "/reportanalyzer", "/t:library", "/a:" + Assembly.GetExecutingAssembly().Location, srcFile.Path }); + var csc = CreateCSharpCompiler( + responseFile: null, + srcDirectory, + new[] { "/reportanalyzer", "/t:library", srcFile.Path }, + analyzers: new[] { new WarningDiagnosticAnalyzer() }, + generators: new[] { new DoNothingGenerator().AsSourceGenerator() }); var exitCode = csc.Run(outWriter); Assert.Equal(0, exitCode); var output = outWriter.ToString(); Assert.Contains(CodeAnalysisResources.AnalyzerExecutionTimeColumnHeader, output, StringComparison.Ordinal); - Assert.Contains("WarningDiagnosticAnalyzer (Warning01)", output, StringComparison.Ordinal); + Assert.Contains($"{nameof(WarningDiagnosticAnalyzer)} (Warning01)", output, StringComparison.Ordinal); + Assert.Contains(CodeAnalysisResources.GeneratorNameColumnHeader, output, StringComparison.Ordinal); + Assert.Contains(typeof(DoNothingGenerator).FullName, output, StringComparison.Ordinal); CleanupAllGeneratedFiles(srcFile.Path); } @@ -9234,16 +9246,55 @@ public void SkipAnalyzersParse() Assert.False(parsedArgs.SkipAnalyzers); } - [Theory, CombinatorialData] + [Fact] + [WorkItem(40926, "https://github.com/dotnet/roslyn/issues/40926")] + public void SkipAnalyzersFlagFiltersAnalyzers() + { + var srcFile = Temp.CreateFile().WriteAllText(@"class C {}"); + var srcDirectory = Path.GetDirectoryName(srcFile.Path); + + var args = new List() { "/reportanalyzer", "/t:library", "/a:" + typeof(DoNothingGenerator).Assembly.Location, srcFile.Path }; + var csc = CreateCSharpCompiler( + responseFile: null, + srcDirectory, + args.ToArray()); + + csc.ResolveAnalyzersFromArguments( + skipAnalyzers: false, + out _, + out var analyzers, + out var generators); + Assert.NotEmpty(analyzers); + Assert.NotEmpty(generators); + + csc.ResolveAnalyzersFromArguments( + skipAnalyzers: true, + out _, + out analyzers, + out generators); + Assert.All(analyzers, static x => Assert.IsAssignableFrom(x)); + Assert.NotEmpty(generators); + + CleanupAllGeneratedFiles(srcFile.Path); + } + + [Theory] + [CombinatorialData] [WorkItem(40926, "https://github.com/dotnet/roslyn/issues/40926")] - public void SkipAnalyzersSemantics(bool skipAnalyzers) + public void NoAnalyzersReportSemantics(bool skipAnalyzers) { var srcFile = Temp.CreateFile().WriteAllText(@"class C {}"); var srcDirectory = Path.GetDirectoryName(srcFile.Path); var outWriter = new StringWriter(CultureInfo.InvariantCulture); - var skipAnalyzersFlag = "/skipanalyzers" + (skipAnalyzers ? "+" : "-"); - var csc = CreateCSharpCompiler(null, srcDirectory, new[] { skipAnalyzersFlag, "/reportanalyzer", "/t:library", "/a:" + Assembly.GetExecutingAssembly().Location, srcFile.Path }); + var analyzers = skipAnalyzers + ? Array.Empty() + : new DiagnosticAnalyzer[] { new HiddenDiagnosticAnalyzer(), new WarningDiagnosticAnalyzer() }; + var csc = CreateCSharpCompiler( + responseFile: null, + srcDirectory, + new[] { "/reportanalyzer", "/t:library", srcFile.Path }, + analyzers: analyzers); var exitCode = csc.Run(outWriter); Assert.Equal(0, exitCode); var output = outWriter.ToString(); @@ -9275,7 +9326,7 @@ class C { } null, workingDirectory: Path.GetDirectoryName(srcFile.Path), args: new[] { "/errorlog:" + errorLog.Path, "/warnaserror+", "/nologo", "/t:library", srcFile.Path }, - analyzers: ImmutableArray.Create(new WarningDiagnosticAnalyzer())); + analyzers: new[] { new WarningDiagnosticAnalyzer() }); var outWriter = new StringWriter(CultureInfo.InvariantCulture); var exitCode = csc.Run(outWriter); @@ -9297,7 +9348,7 @@ public void AnalyzerDiagnosticThrowsInGetMessage() var outWriter = new StringWriter(CultureInfo.InvariantCulture); var csc = CreateCSharpCompiler(null, WorkingDirectory, new[] { "/t:library", srcFile.Path }, - analyzers: ImmutableArray.Create(new AnalyzerThatThrowsInGetMessage())); + analyzers: new[] { new AnalyzerThatThrowsInGetMessage() }); var exitCode = csc.Run(outWriter); Assert.Equal(0, exitCode); @@ -9322,7 +9373,7 @@ public void AnalyzerExceptionDiagnosticCanBeConfigured() var outWriter = new StringWriter(CultureInfo.InvariantCulture); var csc = CreateCSharpCompiler(null, WorkingDirectory, new[] { "/t:library", $"/warnaserror:{AnalyzerExecutor.AnalyzerExceptionDiagnosticId}", srcFile.Path }, - analyzers: ImmutableArray.Create(new AnalyzerThatThrowsInGetMessage())); + analyzers: new[] { new AnalyzerThatThrowsInGetMessage() }); var exitCode = csc.Run(outWriter); Assert.NotEqual(0, exitCode); @@ -9344,7 +9395,7 @@ public void AnalyzerReportsMisformattedDiagnostic() var outWriter = new StringWriter(CultureInfo.InvariantCulture); var csc = CreateCSharpCompiler(null, WorkingDirectory, new[] { "/t:library", srcFile.Path }, - analyzers: ImmutableArray.Create(new AnalyzerReportingMisformattedDiagnostic())); + analyzers: new[] { new AnalyzerReportingMisformattedDiagnostic() }); var exitCode = csc.Run(outWriter); Assert.Equal(0, exitCode); @@ -10221,9 +10272,9 @@ private string VerifyOutput(TempDirectory sourceDir, TempFile sourceFile, int? expectedExitCode = null, bool errorlog = false, bool skipAnalyzers = false, - IEnumerable generators = null, - GeneratorDriverCache driverCache = null, - params DiagnosticAnalyzer[] analyzers) + DiagnosticAnalyzer[] analyzers = null, + ISourceGenerator[] generators = null, + GeneratorDriverCache driverCache = null) { var args = new[] { "/nologo", "/preferreduilang:en", "/t:library", @@ -10249,7 +10300,7 @@ private string VerifyOutput(TempDirectory sourceDir, TempFile sourceFile, args = args.Append(additionalFlags); } - var csc = CreateCSharpCompiler(null, sourceDir.Path, args, analyzers: analyzers.ToImmutableArrayOrEmpty(), generators: generators.ToImmutableArrayOrEmpty(), driverCache: driverCache); + var csc = CreateCSharpCompiler(null, sourceDir.Path, args, analyzers: analyzers, generators: generators, driverCache: driverCache); var outWriter = new StringWriter(CultureInfo.InvariantCulture); var exitCode = csc.Run(outWriter); var output = outWriter.ToString(); @@ -12170,7 +12221,7 @@ long M(int i) additionalFlags: new[] { "/warnAsError" }, includeCurrentAssemblyAsAnalyzerReference: false, errorlog: true, - analyzers: suppressor); + analyzers: new[] { suppressor }); Assert.DoesNotContain($"error CS0078", output, StringComparison.Ordinal); Assert.DoesNotContain($"warning CS0078", output, StringComparison.Ordinal); @@ -12222,7 +12273,7 @@ void M(int i) suppressor.SuppressionDescriptor.Justification); output = VerifyOutput(srcDirectory, srcFile, expectedInfoCount: 1, expectedWarningCount: 0, includeCurrentAssemblyAsAnalyzerReference: false, - analyzers: suppressor, errorlog: true, skipAnalyzers: skipAnalyzers); + analyzers: new[] { suppressor }, errorlog: true, skipAnalyzers: skipAnalyzers); Assert.DoesNotContain($"warning CS1522", output, StringComparison.Ordinal); Assert.Contains($"info SP0001", output, StringComparison.Ordinal); Assert.Contains(suppressionMessage, output, StringComparison.Ordinal); @@ -12239,7 +12290,7 @@ void M(int i) includeCurrentAssemblyAsAnalyzerReference: false, errorlog: true, skipAnalyzers: skipAnalyzers, - analyzers: suppressor); + analyzers: new[] { suppressor }); Assert.DoesNotContain($"error CS1522", output, StringComparison.Ordinal); Assert.DoesNotContain($"warning CS1522", output, StringComparison.Ordinal); Assert.Contains("info SP0001", output, StringComparison.Ordinal); @@ -12278,7 +12329,7 @@ class C suppressor.SuppressionDescriptor.Justification); output = VerifyOutput(srcDirectory, srcFile, expectedInfoCount: 1, expectedWarningCount: 0, includeCurrentAssemblyAsAnalyzerReference: false, - analyzers: suppressor, errorlog: true, skipAnalyzers: skipAnalyzers); + analyzers: new[] { suppressor }, errorlog: true, skipAnalyzers: skipAnalyzers); Assert.DoesNotContain($"warning CS0169", output, StringComparison.Ordinal); Assert.Contains("info SP0001", output, StringComparison.Ordinal); Assert.Contains(suppressionMessage, output, StringComparison.Ordinal); @@ -12295,7 +12346,7 @@ class C includeCurrentAssemblyAsAnalyzerReference: false, errorlog: true, skipAnalyzers: skipAnalyzers, - analyzers: suppressor); + analyzers: new[] { suppressor }); Assert.DoesNotContain($"error CS0169", output, StringComparison.Ordinal); Assert.DoesNotContain($"warning CS0169", output, StringComparison.Ordinal); Assert.Contains("info SP0001", output, StringComparison.Ordinal); @@ -12321,7 +12372,7 @@ class { }"; // Verify that compiler syntax error CS1001 cannot be suppressed with diagnostic suppressor. output = VerifyOutput(srcDirectory, srcFile, expectedErrorCount: 1, includeCurrentAssemblyAsAnalyzerReference: false, - analyzers: new DiagnosticSuppressorForId("CS1001")); + analyzers: new[] { new DiagnosticSuppressorForId("CS1001") }); Assert.Contains("error CS1001", output, StringComparison.Ordinal); CleanupAllGeneratedFiles(srcFile.Path); @@ -12347,7 +12398,7 @@ void M(UndefinedType x) { } // Verify that compiler error CS0246 cannot be suppressed with diagnostic suppressor. output = VerifyOutput(srcDirectory, srcFile, expectedErrorCount: 1, includeCurrentAssemblyAsAnalyzerReference: false, - analyzers: new DiagnosticSuppressorForId("CS0246")); + analyzers: new[] { new DiagnosticSuppressorForId("CS0246") }); Assert.Contains("error CS0246", output, StringComparison.Ordinal); CleanupAllGeneratedFiles(srcFile.Path); @@ -12367,7 +12418,7 @@ class C { }"; var analyzer = new CompilationAnalyzerWithSeverity(DiagnosticSeverity.Warning, configurable: true); var output = VerifyOutput(srcDirectory, srcFile, expectedWarningCount: 1, includeCurrentAssemblyAsAnalyzerReference: false, - analyzers: analyzer); + analyzers: new[] { analyzer }); Assert.Contains($"warning {analyzer.Descriptor.Id}", output, StringComparison.Ordinal); // Verify that analyzer warning is suppressed with diagnostic suppressor @@ -12394,7 +12445,7 @@ class C { }"; output = VerifyOutput(srcDirectory, srcFile, expectedErrorCount: 1, additionalFlags: new[] { "/warnAsError" }, includeCurrentAssemblyAsAnalyzerReference: false, - analyzers: analyzer); + analyzers: new[] { analyzer }); Assert.Contains($"error {analyzer.Descriptor.Id}", output, StringComparison.Ordinal); // Verify that analyzer warning is suppressed with diagnostic suppressor even with /warnaserror @@ -12434,7 +12485,7 @@ class C { }"; var analyzer = new CompilationAnalyzerWithSeverity(DiagnosticSeverity.Error, configurable: true); var output = VerifyOutput(srcDirectory, srcFile, expectedErrorCount: 1, includeCurrentAssemblyAsAnalyzerReference: false, - analyzers: analyzer); + analyzers: new[] { analyzer }); Assert.Contains($"error {analyzer.Descriptor.Id}", output, StringComparison.Ordinal); // Verify that analyzer error cannot be suppressed with diagnostic suppressor. @@ -12711,7 +12762,7 @@ private void TestBulkAnalyzerConfigurationCore( } var cmd = CreateCSharpCompiler(null, dir.Path, arguments, - analyzers: ImmutableArray.Create(analyzer)); + analyzers: new[] { analyzer }); Assert.Equal(analyzerConfig.Path, Assert.Single(cmd.Arguments.AnalyzerConfigPaths)); @@ -12952,7 +13003,7 @@ private void TestAnalyzerConfigRespectedCore(DiagnosticAnalyzer analyzer, Diagno } var cmd = CreateCSharpCompiler(null, dir.Path, arguments, - analyzers: ImmutableArray.Create(analyzer)); + analyzers: new[] { analyzer }); Assert.Equal(analyzerConfig.Path, Assert.Single(cmd.Arguments.AnalyzerConfigPaths)); @@ -13041,7 +13092,7 @@ public void TestAnalyzerFilteringBasedOnSeverity(DiagnosticSeverity defaultSever if (errorlog) args = args.Append("/errorlog:errorlog"); - var cmd = CreateCSharpCompiler(null, dir.Path, args, analyzers: ImmutableArray.Create(analyzer)); + var cmd = CreateCSharpCompiler(null, dir.Path, args, analyzers: new[] { analyzer }); var outWriter = new StringWriter(CultureInfo.InvariantCulture); var exitCode = cmd.Run(outWriter); Assert.Equal(0, exitCode); @@ -13077,7 +13128,7 @@ public void TestWarnAsErrorMinusDoesNotEnableDisabledByDefaultAnalyzers(Diagnost // Verify '/warnaserror-:DiagnosticId' behavior. var args = new[] { "/warnaserror+", $"/warnaserror-:{diagnosticId}", "/nologo", "/t:library", "/preferreduilang:en", src.Path }; - var cmd = CreateCSharpCompiler(null, dir.Path, args, analyzers: ImmutableArray.Create(analyzer)); + var cmd = CreateCSharpCompiler(null, dir.Path, args, analyzers: new[] { analyzer }); var outWriter = new StringWriter(CultureInfo.InvariantCulture); var exitCode = cmd.Run(outWriter); var expectedExitCode = !analyzerShouldBeSkipped && defaultSeverity == DiagnosticSeverity.Error ? 1 : 0; @@ -13267,6 +13318,49 @@ class C Directory.Delete(dir.Path, true); } + [Fact] + public void SourceGenerators_ChecksumAlgorithm() + { + var dir = Temp.CreateDirectory(); + var src = dir.CreateFile("temp.cs"); + src.WriteAllText("class C { }"); + + var genPath1 = Path.Combine(dir.Path, "Microsoft.CodeAnalysis.Test.Utilities", "Roslyn.Test.Utilities.TestGenerators.TestSourceGenerator", "hint1.cs"); + var genPath2 = Path.Combine(dir.Path, "Microsoft.CodeAnalysis.Test.Utilities", "Roslyn.Test.Utilities.TestGenerators.TestSourceGenerator", "hint2.cs"); + + var generator = new TestSourceGenerator() + { + ExecuteImpl = context => + { + context.AddSource("hint1", "class G1 { void F() {} }"); + context.AddSource("hint2", SourceText.From("class G2 { void F() {} }", Encoding.UTF8, checksumAlgorithm: SourceHashAlgorithm.Sha1)); + } + }; + + VerifyOutput( + dir, + src, + includeCurrentAssemblyAsAnalyzerReference: false, + additionalFlags: new[] { "/langversion:preview", "/out:checksum.exe", "/pdb:checksum.pdb", "/debug:portable", "/checksumAlgorithm:SHA256" }, + generators: new[] { generator }, + analyzers: null); + + using (Stream peStream = File.OpenRead(Path.Combine(dir.Path, "checksum.exe")), pdbStream = File.OpenRead(Path.Combine(dir.Path, "checksum.pdb"))) + { + // TOOD: /checksumAlgorithm setting should override any checksum algorithms set by the generators: + PdbValidation.VerifyPdb(peStream, pdbStream, $@" + + + + + + +", PdbValidationOptions.ExcludeMethods); + } + + Directory.Delete(dir.Path, true); + } + [Fact] public void SourceGenerators_WriteGeneratedSources() { @@ -13650,7 +13744,7 @@ class C src.Path }; - var cmd = CreateCSharpCompiler(null, dir.Path, args, generators: ImmutableArray.Create(generator)); + var cmd = CreateCSharpCompiler(null, dir.Path, args, generators: new[] { generator }); var outWriter = new StringWriter(CultureInfo.InvariantCulture); var exitCode = cmd.Run(outWriter); Assert.Equal(0, exitCode); @@ -13767,7 +13861,7 @@ public ValueTuple(T1 item1) null, WorkingDirectory, new[] { "/nologo", "/t:library", srcFile.Path }, - analyzers: ImmutableArray.Create(new FieldAnalyzer())); // at least one analyzer required + analyzers: new[] { new FieldAnalyzer() }); // at least one analyzer required var exitCode = csc.Run(outWriter); Assert.Equal(0, exitCode); var output = outWriter.ToString(); @@ -14062,9 +14156,9 @@ class C dotnet_diagnostic.Warning01.severity = error; "); - VerifyOutput(dir, src, additionalFlags: new[] { "/analyzerconfig:" + globalConfig.Path }, expectedErrorCount: 1, includeCurrentAssemblyAsAnalyzerReference: false, analyzers: new WarningDiagnosticAnalyzer()); + VerifyOutput(dir, src, additionalFlags: new[] { "/analyzerconfig:" + globalConfig.Path }, expectedErrorCount: 1, includeCurrentAssemblyAsAnalyzerReference: false, analyzers: new[] { new WarningDiagnosticAnalyzer() }); - VerifyOutput(dir, src, additionalFlags: new[] { "/nowarn:Warning01", "/analyzerconfig:" + globalConfig.Path }, includeCurrentAssemblyAsAnalyzerReference: false, analyzers: new WarningDiagnosticAnalyzer()); + VerifyOutput(dir, src, additionalFlags: new[] { "/nowarn:Warning01", "/analyzerconfig:" + globalConfig.Path }, includeCurrentAssemblyAsAnalyzerReference: false, analyzers: new[] { new WarningDiagnosticAnalyzer() }); } [Theory, CombinatorialData] @@ -14085,7 +14179,7 @@ public void TestAdditionalFileAnalyzer(bool registerFromInitialize) var output = VerifyOutput(srcDirectory, srcFile, expectedWarningCount: 1, includeCurrentAssemblyAsAnalyzerReference: false, additionalFlags: new[] { "/additionalfile:" + additionalFile.Path }, - analyzers: analyzer); + analyzers: new[] { analyzer }); Assert.Contains("b.txt(1,3): warning ID0001", output, StringComparison.Ordinal); CleanupAllGeneratedFiles(srcDirectory.Path); diff --git a/src/Compilers/CSharp/Test/CommandLine/SarifErrorLoggerTests.cs b/src/Compilers/CSharp/Test/CommandLine/SarifErrorLoggerTests.cs index 44f07f5579c65..6429cc64d8660 100644 --- a/src/Compilers/CSharp/Test/CommandLine/SarifErrorLoggerTests.cs +++ b/src/Compilers/CSharp/Test/CommandLine/SarifErrorLoggerTests.cs @@ -140,7 +140,7 @@ public class C string[] arguments = new[] { "/nologo", "/t:library", $"/out:{outputFilePath}", sourceFile, "/preferreduilang:en", $"/errorlog:{errorLogFile}{ErrorLogQualifier}" }; var cmd = CreateCSharpCompiler(null, WorkingDirectory, arguments, - analyzers: ImmutableArray.Create(new AnalyzerForErrorLogTest())); + analyzers: new[] { new AnalyzerForErrorLogTest() }); var outWriter = new StringWriter(CultureInfo.InvariantCulture); @@ -176,7 +176,7 @@ class C string[] arguments = new[] { "/nologo", "/t:library", sourceFile, "/preferreduilang:en", $"/errorlog:{errorLogFile}{ErrorLogQualifier}" }; var cmd = CreateCSharpCompiler(null, WorkingDirectory, arguments, - analyzers: ImmutableArray.Create(new AnalyzerForErrorLogTest())); + analyzers: new[] { new AnalyzerForErrorLogTest() }); var outWriter = new StringWriter(CultureInfo.InvariantCulture); var exitCode = cmd.Run(outWriter); @@ -211,7 +211,7 @@ class C string[] arguments = new[] { "/nologo", "/t:library", sourceFile, "/preferreduilang:en", $"/errorlog:{errorLogFile}{ErrorLogQualifier}" }; var cmd = CreateCSharpCompiler(null, WorkingDirectory, arguments, - analyzers: ImmutableArray.Create(new AnalyzerForErrorLogTest())); + analyzers: new[] { new AnalyzerForErrorLogTest() }); var outWriter = new StringWriter(CultureInfo.InvariantCulture); var exitCode = cmd.Run(outWriter); @@ -246,7 +246,7 @@ class C string[] arguments = new[] { "/nologo", "/t:library", sourceFile, "/preferreduilang:en", $"/errorlog:{errorLogFile}{ErrorLogQualifier}" }; var cmd = CreateCSharpCompiler(null, WorkingDirectory, arguments, - analyzers: ImmutableArray.Create(new AnalyzerForErrorLogTest())); + analyzers: new[] { new AnalyzerForErrorLogTest() }); var outWriter = new StringWriter(CultureInfo.InvariantCulture); var exitCode = cmd.Run(outWriter); @@ -281,7 +281,7 @@ class C string[] arguments = new[] { "/nologo", "/t:library", sourceFile, "/preferreduilang:en", $"/errorlog:{errorLogFile}{ErrorLogQualifier}" }; var cmd = CreateCSharpCompiler(null, WorkingDirectory, arguments, - analyzers: ImmutableArray.Create(new AnalyzerForErrorLogTest())); + analyzers: new[] { new AnalyzerForErrorLogTest() }); var outWriter = new StringWriter(CultureInfo.InvariantCulture); var exitCode = cmd.Run(outWriter); diff --git a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncMethodBuilderOverrideTests.cs b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncMethodBuilderOverrideTests.cs index e76fddcd11a38..d4376cd3e4eb2 100644 --- a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncMethodBuilderOverrideTests.cs +++ b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncMethodBuilderOverrideTests.cs @@ -2085,7 +2085,7 @@ public void BuilderOnMethod_InternalReturnType() [AsyncMethodBuilder(null)] internal class MyTaskType {{ }} // Make the builder factory and the builder internal as well -{AsyncBuilderCode("MyTaskTypeBuilder", "MyTaskType").Replace("public class MyTaskType", "internal class MyTaskType") } +{AsyncBuilderCode("MyTaskTypeBuilder", "MyTaskType").Replace("public class MyTaskType", "internal class MyTaskType")} class C {{ diff --git a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenDeconstructTests.cs b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenDeconstructTests.cs index 3c4d9d745ae24..eaa9ca2934399 100644 --- a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenDeconstructTests.cs +++ b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenDeconstructTests.cs @@ -3001,7 +3001,7 @@ public void Deconstruct(out int a, out string b) comp.VerifyDiagnostics(); } - [Fact(Skip = "https://github.com/dotnet/roslyn/issues/12400")] + [Fact] [WorkItem(12400, "https://github.com/dotnet/roslyn/issues/12400")] public void AssignWithPostfixOperator() { @@ -3031,12 +3031,44 @@ public void Deconstruct(out int a, out string b) } } "; - // https://github.com/dotnet/roslyn/issues/12400 - // we expect "2 hello" instead, which means the evaluation order is wrong var comp = CompileAndVerify(source, expectedOutput: "1 hello"); comp.VerifyDiagnostics(); } + [Fact] + [WorkItem(12400, "https://github.com/dotnet/roslyn/issues/12400")] + public void AssignWithPrefixOperator() + { + string source = @" +class C +{ + int state = 1; + + static void Main() + { + long x; + string y; + C c = new C(); + (x, y) = ++c; + System.Console.WriteLine(x + "" "" + y); + } + + public void Deconstruct(out int a, out string b) + { + a = state; + b = ""hello""; + } + + public static C operator ++(C c1) + { + return new C() { state = 2 }; + } +} +"; + var comp = CompileAndVerify(source, expectedOutput: "2 hello"); + comp.VerifyDiagnostics(); + } + [Fact] [WorkItem(13631, "https://github.com/dotnet/roslyn/issues/13631")] public void DeconstructionDeclaration() @@ -3724,7 +3756,7 @@ static void Main() var x34Var = (DeclarationExpressionSyntax)x3.Parent.Parent; Assert.Equal("var", x34Var.Type.ToString()); - Assert.Null(model.GetSymbolInfo(x34Var.Type).Symbol); // The var in `var (x3, x4)` has no symbol + Assert.Equal("(System.Int32 x3, System.Int32 x4)", model.GetSymbolInfo(x34Var.Type).Symbol.ToTestDisplayString()); }; var comp = CompileAndVerify(source, expectedOutput: "1 2 3 4", sourceSymbolValidator: validator); @@ -3818,7 +3850,7 @@ static void Main() // extra check on var var x12Var = (DeclarationExpressionSyntax)x1.Parent.Parent; Assert.Equal("var", x12Var.Type.ToString()); - Assert.Null(model.GetSymbolInfo(x12Var.Type).Symbol); // The var in `var (x1, x2)` has no symbol + Assert.Equal("(System.Int32 x1, System.Int32 x2)", model.GetSymbolInfo(x12Var.Type).Symbol.ToTestDisplayString()); }; var comp = CompileAndVerify(source, expectedOutput: "1 2", sourceSymbolValidator: validator); @@ -4004,7 +4036,7 @@ static void Main() var x12Var = (DeclarationExpressionSyntax)x1.Parent.Parent; Assert.Equal("var", x12Var.Type.ToString()); Assert.Equal("(System.Int32 x1, System.Int32 x2)", model.GetTypeInfo(x12Var).Type.ToTestDisplayString()); - Assert.Null(model.GetSymbolInfo(x12Var.Type).Symbol); // The var in `var (x1, x2)` has no symbol + Assert.Equal("(System.Int32 x1, System.Int32 x2)", model.GetSymbolInfo(x12Var.Type).Symbol.ToTestDisplayString()); // verify deconstruction info var deconstructionForeach = tree.GetRoot().DescendantNodes().OfType().Single(); @@ -4111,7 +4143,7 @@ static void Main() // extra check on var var x12Var = (DeclarationExpressionSyntax)x1.Parent.Parent; Assert.Equal("var", x12Var.Type.ToString()); - Assert.Null(model.GetSymbolInfo(x12Var.Type).Symbol); // The var in `var (x1, x2)` has no symbol + Assert.Equal("(System.Int32 x1, System.Int32 x2)", model.GetSymbolInfo(x12Var.Type).Symbol.ToTestDisplayString()); }; var comp = CompileAndVerify(source, expectedOutput: "1 2 - 3 4 -", sourceSymbolValidator: validator); @@ -4194,7 +4226,7 @@ static void Main() // extra check on var var x12Var = (DeclarationExpressionSyntax)x1.Parent.Parent; Assert.Equal("var", x12Var.Type.ToString()); - Assert.Null(model.GetSymbolInfo(x12Var.Type).Symbol); // The var in `var (x1, x2)` has no symbol + Assert.Equal("(System.Int32 x1, System.Int32 x2)", model.GetSymbolInfo(x12Var.Type).Symbol.ToTestDisplayString()); }; var comp = CompileAndVerify(source, expectedOutput: "1 2 - 3 4 - 5 6 - 7 8 -", sourceSymbolValidator: validator); @@ -4305,7 +4337,7 @@ public static void Deconstruct(this char value, out int item1, out int item2) // extra check on var var x12Var = (DeclarationExpressionSyntax)x1.Parent.Parent; Assert.Equal("var", x12Var.Type.ToString()); - Assert.Null(model.GetSymbolInfo(x12Var.Type).Symbol); // The var in `var (x1, x2)` has no symbol + Assert.Equal("(System.Int32 x1, System.Int32 x2)", model.GetSymbolInfo(x12Var.Type).Symbol.ToTestDisplayString()); }; var comp = CompileAndVerify(source, expectedOutput: "1 1 - 2 2 - 3 3 - ", sourceSymbolValidator: validator); @@ -4426,7 +4458,7 @@ static void Main() // extra check on var var x23Var = (DeclarationExpressionSyntax)x2.Parent.Parent; Assert.Equal("var", x23Var.Type.ToString()); - Assert.Null(model.GetSymbolInfo(x23Var.Type).Symbol); // The var in `var (x2, x3)` has no symbol + Assert.Equal("(System.Int32 x2, System.Int32 x3)", model.GetSymbolInfo(x23Var.Type).Symbol.ToTestDisplayString()); }; var comp = CompileAndVerify(source, expectedOutput: "1 2 3 4 5 - 6 7 8 9 10 -", sourceSymbolValidator: validator); @@ -4572,7 +4604,7 @@ static void Main() // extra check on var var x23Var = (DeclarationExpressionSyntax)x2.Parent.Parent; Assert.Equal("var", x23Var.Type.ToString()); - Assert.Null(model.GetSymbolInfo(x23Var.Type).Symbol); // The var in `var (x2, x3)` has no symbol + Assert.Equal("(System.Int32 x2, System.Int32 x3)", model.GetSymbolInfo(x23Var.Type).Symbol.ToTestDisplayString()); }; string expected = @@ -5159,7 +5191,7 @@ public void NestedVarDeconstructionInScript() // extra check on x2 and x3's var var x23Var = (DeclarationExpressionSyntax)x2.Parent.Parent; Assert.Equal("var", x23Var.Type.ToString()); - Assert.Null(model.GetSymbolInfo(x23Var.Type).Symbol); // The var in `var (x2, x3)` has no symbol + Assert.Equal("(System.Int32 x2, System.Int32 x3)", model.GetSymbolInfo(x23Var.Type).Symbol.ToTestDisplayString()); }; var comp = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.Script, options: TestOptions.DebugExe, references: s_valueTupleRefs); @@ -5708,8 +5740,8 @@ public void VarAliasInVarDeconstructionInScript() // extra check on var var x123Var = (DeclarationExpressionSyntax)x1.Parent.Parent; Assert.Equal("var", x123Var.Type.ToString()); - Assert.Null(model.GetTypeInfo(x123Var.Type).Type); - Assert.Null(model.GetSymbolInfo(x123Var.Type).Symbol); // The var in `var (x1, x2)` has no symbol + Assert.Equal("System.Byte", model.GetTypeInfo(x123Var.Type).Type.ToTestDisplayString()); + Assert.Equal("System.Byte", model.GetSymbolInfo(x123Var.Type).Symbol.ToTestDisplayString()); } [Fact] @@ -5750,8 +5782,8 @@ class @var // extra check on var var x123Var = (DeclarationExpressionSyntax)x1.Parent.Parent; Assert.Equal("var", x123Var.Type.ToString()); - Assert.Null(model.GetTypeInfo(x123Var.Type).Type); - Assert.Null(model.GetSymbolInfo(x123Var.Type).Symbol); // The var in `var (x1, x2)` has no symbol + Assert.Equal("Script.var", model.GetTypeInfo(x123Var.Type).Type.ToTestDisplayString()); + Assert.Equal("Script.var", model.GetSymbolInfo(x123Var.Type).Symbol.ToTestDisplayString()); } [Fact] @@ -8900,12 +8932,12 @@ public ValueTuple(T1 item1, T2 item2) // (13,20): warning CS0169: The field '(T1, T2).Item2' is never used // private T2 Item2; Diagnostic(ErrorCode.WRN_UnreferencedField, "Item2").WithArguments("(T1, T2).Item2").WithLocation(13, 20), - // (14,16): error CS0171: Field '(T1, T2).Item2' must be fully assigned before control is returned to the caller. Consider updating to language version 'preview' to auto-default the field. + // (14,16): error CS0171: Field '(T1, T2).Item2' must be fully assigned before control is returned to the caller. Consider updating to language version '11.0' to auto-default the field. // public ValueTuple(T1 item1, T2 item2) - Diagnostic(ErrorCode.ERR_UnassignedThisUnsupportedVersion, "ValueTuple").WithArguments("(T1, T2).Item2", "preview").WithLocation(14, 16), - // (14,16): error CS0171: Field '(T1, T2).Item2' must be fully assigned before control is returned to the caller. Consider updating to language version 'preview' to auto-default the field. + Diagnostic(ErrorCode.ERR_UnassignedThisUnsupportedVersion, "ValueTuple").WithArguments("(T1, T2).Item2", "11.0").WithLocation(14, 16), + // (14,16): error CS0171: Field '(T1, T2).Item2' must be fully assigned before control is returned to the caller. Consider updating to language version '11.0' to auto-default the field. // public ValueTuple(T1 item1, T2 item2) - Diagnostic(ErrorCode.ERR_UnassignedThisUnsupportedVersion, "ValueTuple").WithArguments("(T1, T2).Item2", "preview").WithLocation(14, 16), + Diagnostic(ErrorCode.ERR_UnassignedThisUnsupportedVersion, "ValueTuple").WithArguments("(T1, T2).Item2", "11.0").WithLocation(14, 16), // (17,13): error CS0229: Ambiguity between '(T1, T2).Item2' and '(T1, T2).Item2' // Item2 = item2; Diagnostic(ErrorCode.ERR_AmbigMember, "Item2").WithArguments("(T1, T2).Item2", "(T1, T2).Item2").WithLocation(17, 13) diff --git a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenFunctionPointersTests.cs b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenFunctionPointersTests.cs index 47e24a34c1b00..32d996ffce7db 100644 --- a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenFunctionPointersTests.cs +++ b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenFunctionPointersTests.cs @@ -10911,10 +10911,11 @@ static ref int ReturnPtrByRef(delegate* ptr, ref int i) ); } - [Fact, WorkItem(49315, "https://github.com/dotnet/roslyn/issues/49315")] + [WorkItem(49315, "https://github.com/dotnet/roslyn/issues/49315")] + [Fact] public void ReturnByRefFromRefReturningMethod_NotSafeToEscape() { - var comp = CreateCompilationWithSpan(@" + string source = @" using System; unsafe { @@ -10926,9 +10927,10 @@ static ref Span ReturnPtrByRef(delegate*, ref Span> ptr) return ref ptr(ref span); } - static ref Span ReturnByRef(ref Span i) => ref i; -}", options: TestOptions.UnsafeReleaseExe); + static ref Span ReturnByRef(ref Span i) => throw null; +}"; + var comp = CreateCompilationWithSpan(source, parseOptions: TestOptions.Regular10, options: TestOptions.UnsafeReleaseExe); comp.VerifyDiagnostics( // (10,20): error CS8347: Cannot use a result of 'delegate*, ref Span>' in this context because it may expose variables referenced by parameter '0' outside of their declaration scope // return ref ptr(ref span); @@ -10937,12 +10939,23 @@ static ref Span ReturnPtrByRef(delegate*, ref Span> ptr) // return ref ptr(ref span); Diagnostic(ErrorCode.ERR_RefReturnLocal, "span").WithArguments("span").WithLocation(10, 28) ); + + // delegate*<,> parameter is implicitly scoped ref in C#11. + comp = CreateCompilationWithSpan(source, options: TestOptions.UnsafeReleaseExe); + comp.VerifyDiagnostics( + // (10,20): error CS8347: Cannot use a result of 'delegate*, ref Span>' in this context because it may expose variables referenced by parameter '0' outside of their declaration scope + // return ref ptr(ref span); + Diagnostic(ErrorCode.ERR_EscapeCall, "ptr(ref span)").WithArguments("delegate*, ref System.Span>", "0").WithLocation(10, 20), + // (10,28): error CS8352: Cannot use variable 'span' in this context because it may expose referenced variables outside of their declaration scope + // return ref ptr(ref span); + Diagnostic(ErrorCode.ERR_EscapeVariable, "span").WithArguments("span").WithLocation(10, 28) + ); } [Fact, WorkItem(49315, "https://github.com/dotnet/roslyn/issues/49315")] public void ReturnByRefFromRefReturningMethod_SafeToEscape() { - var comp = CreateCompilationWithSpan(@" + string source = @" using System; unsafe { @@ -10956,10 +10969,10 @@ static ref Span ReturnPtrByRef(delegate*, ref Span> ptr, => ref ptr(ref s); static ref Span ReturnByRef(ref Span i) => ref i; -}", options: TestOptions.UnsafeReleaseExe); +}"; + var comp = CreateCompilationWithSpan(source, parseOptions: TestOptions.Regular10, options: TestOptions.UnsafeReleaseExe); var verifier = CompileAndVerify(comp, expectedOutput: "2", verify: Verification.Skipped); - verifier.VerifyIL("Program.<
$>g__ReturnPtrByRef|0_0(delegate*, ref System.Span>, ref System.Span)", @" { // Code size 10 (0xa) @@ -10973,6 +10986,12 @@ .locals init (delegate*, ref System.Span> V_0) IL_0009: ret } "); + + comp = CreateCompilationWithSpan(source, options: TestOptions.UnsafeReleaseExe); + comp.VerifyDiagnostics( + // (14,62): error CS8166: Cannot return a parameter by reference 'i' because it is not a ref parameter + // static ref Span ReturnByRef(ref Span i) => ref i; + Diagnostic(ErrorCode.ERR_RefReturnParameter, "i").WithArguments("i").WithLocation(14, 62)); } [Fact, WorkItem(49315, "https://github.com/dotnet/roslyn/issues/49315")] diff --git a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenOperators.cs b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenOperators.cs index d3cfb27c9413a..482f4f502c04b 100644 --- a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenOperators.cs +++ b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenOperators.cs @@ -5173,7 +5173,7 @@ static void Main() public static long Calculate1(long[] f) { -" + $" return { BuildSequenceOfBinaryExpressions_01() };" + @" +" + $" return {BuildSequenceOfBinaryExpressions_01()};" + @" } public static long Calculate2(long[] f) @@ -5233,7 +5233,7 @@ static void Main() public static double Calculate(long[] f) { -" + $" return checked({ BuildSequenceOfBinaryExpressions_01() });" + @" +" + $" return checked({BuildSequenceOfBinaryExpressions_01()});" + @" } } "; @@ -5264,7 +5264,7 @@ static void Main() public static bool Calculate(bool[] a, bool[] f) { -" + $" return { BuildSequenceOfBinaryExpressions_03(count) };" + @" +" + $" return {BuildSequenceOfBinaryExpressions_03(count)};" + @" } } "; @@ -5323,7 +5323,7 @@ static void Main() public static double? Calculate(float?[] f) { -" + $" return { BuildSequenceOfBinaryExpressions_01() };" + @" +" + $" return {BuildSequenceOfBinaryExpressions_01()};" + @" } } "; @@ -5364,7 +5364,7 @@ static void Test1() public static double? Calculate(double?[] f) { -" + $" return { BuildSequenceOfBinaryExpressions_01(count) };" + @" +" + $" return {BuildSequenceOfBinaryExpressions_01(count)};" + @" } static void Test2() @@ -5380,7 +5380,7 @@ static void Test2() public static double Calculate(double[] f) { -" + $" return { BuildSequenceOfBinaryExpressions_01(count) };" + @" +" + $" return {BuildSequenceOfBinaryExpressions_01(count)};" + @" } } "; @@ -5403,7 +5403,7 @@ static void Main() public static bool Calculate(S1[] a, S1[] f) { -" + $" return { BuildSequenceOfBinaryExpressions_03() };" + @" +" + $" return {BuildSequenceOfBinaryExpressions_03()};" + @" } } diff --git a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenRefLocalTests.cs b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenRefLocalTests.cs index 595354aec6ef1..3f748ca9a9337 100644 --- a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenRefLocalTests.cs +++ b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenRefLocalTests.cs @@ -3730,30 +3730,35 @@ static void F(S[] a) } }"; var verifier = CompileAndVerify(source, options: TestOptions.DebugExe, expectedOutput: ""); - verifier.VerifyIL("Program.F", -@"{ - // Code size 11 (0xb) + verifier.VerifyIL("Program.F", """ +{ + // Code size 17 (0x11) .maxstack 2 .locals init (S& V_0) //b IL_0000: nop IL_0001: ldarg.0 IL_0002: ldc.i4.0 - IL_0003: ldelema ""S"" + IL_0003: ldelema "S" IL_0008: stloc.0 - IL_0009: nop - IL_000a: ret -}"); + IL_0009: ldloc.0 + IL_000a: ldobj "S" + IL_000f: pop + IL_0010: ret +} +"""); verifier = CompileAndVerify(source, options: TestOptions.ReleaseExe, expectedOutput: ""); - verifier.VerifyIL("Program.F", -@"{ - // Code size 9 (0x9) + verifier.VerifyIL("Program.F", """ +{ + // Code size 14 (0xe) .maxstack 2 IL_0000: ldarg.0 IL_0001: ldc.i4.0 - IL_0002: ldelema ""S"" - IL_0007: pop - IL_0008: ret -}"); + IL_0002: ldelema "S" + IL_0007: ldobj "S" + IL_000c: pop + IL_000d: ret +} +"""); } [Fact] @@ -3778,28 +3783,33 @@ static void F(S s) } }"; var verifier = CompileAndVerify(source, options: TestOptions.DebugExe, expectedOutput: ""); - verifier.VerifyIL("Program.F", -@"{ - // Code size 11 (0xb) + verifier.VerifyIL("Program.F", """ +{ + // Code size 17 (0x11) .maxstack 1 .locals init (T& V_0) //t IL_0000: nop IL_0001: ldarga.s V_0 - IL_0003: ldflda ""T S.F"" + IL_0003: ldflda "T S.F" IL_0008: stloc.0 - IL_0009: nop - IL_000a: ret -}"); + IL_0009: ldloc.0 + IL_000a: ldobj "T" + IL_000f: pop + IL_0010: ret +} +"""); verifier = CompileAndVerify(source, options: TestOptions.ReleaseExe, expectedOutput: ""); - verifier.VerifyIL("Program.F", -@"{ - // Code size 9 (0x9) + verifier.VerifyIL("Program.F", """ +{ + // Code size 14 (0xe) .maxstack 1 IL_0000: ldarga.s V_0 - IL_0002: ldflda ""T S.F"" - IL_0007: pop - IL_0008: ret -}"); + IL_0002: ldflda "T S.F" + IL_0007: ldobj "T" + IL_000c: pop + IL_000d: ret +} +"""); } [Fact] @@ -3825,28 +3835,33 @@ static void F(ref S s) } }"; var verifier = CompileAndVerify(source, options: TestOptions.DebugExe, expectedOutput: ""); - verifier.VerifyIL("Program.F", -@"{ - // Code size 10 (0xa) + verifier.VerifyIL("Program.F", """ +{ + // Code size 16 (0x10) .maxstack 1 .locals init (T& V_0) //t IL_0000: nop IL_0001: ldarg.0 - IL_0002: ldflda ""T S.F"" + IL_0002: ldflda "T S.F" IL_0007: stloc.0 - IL_0008: nop - IL_0009: ret -}"); + IL_0008: ldloc.0 + IL_0009: ldobj "T" + IL_000e: pop + IL_000f: ret +} +"""); verifier = CompileAndVerify(source, options: TestOptions.ReleaseExe, expectedOutput: ""); - verifier.VerifyIL("Program.F", -@"{ - // Code size 8 (0x8) + verifier.VerifyIL("Program.F", """ +{ + // Code size 13 (0xd) .maxstack 1 IL_0000: ldarg.0 - IL_0001: ldflda ""T S.F"" - IL_0006: pop - IL_0007: ret -}"); + IL_0001: ldflda "T S.F" + IL_0006: ldobj "T" + IL_000b: pop + IL_000c: ret +} +"""); } [Fact] @@ -3871,28 +3886,33 @@ static void F(in S s) } }"; var verifier = CompileAndVerify(source, options: TestOptions.DebugExe, expectedOutput: ""); - verifier.VerifyIL("Program.F", -@"{ - // Code size 10 (0xa) + verifier.VerifyIL("Program.F", """ +{ + // Code size 16 (0x10) .maxstack 1 .locals init (T& V_0) //t IL_0000: nop IL_0001: ldarg.0 - IL_0002: ldflda ""T S.F"" + IL_0002: ldflda "T S.F" IL_0007: stloc.0 - IL_0008: nop - IL_0009: ret -}"); + IL_0008: ldloc.0 + IL_0009: ldobj "T" + IL_000e: pop + IL_000f: ret +} +"""); verifier = CompileAndVerify(source, options: TestOptions.ReleaseExe, expectedOutput: ""); - verifier.VerifyIL("Program.F", -@"{ - // Code size 8 (0x8) + verifier.VerifyIL("Program.F", """ +{ + // Code size 13 (0xd) .maxstack 1 IL_0000: ldarg.0 - IL_0001: ldflda ""T S.F"" - IL_0006: pop - IL_0007: ret -}"); + IL_0001: ldflda "T S.F" + IL_0006: ldobj "T" + IL_000b: pop + IL_000c: ret +} +"""); } [Fact] diff --git a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenRefReadonlyReturnTests.cs b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenRefReadonlyReturnTests.cs index 1bf2b92258347..045073469bafa 100644 --- a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenRefReadonlyReturnTests.cs +++ b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenRefReadonlyReturnTests.cs @@ -367,14 +367,16 @@ static void M() static ref readonly int Helper() => ref (new int[1])[0]; }"); - verifier.VerifyIL("C.M()", @" + verifier.VerifyIL("C.M()", """ { - // Code size 7 (0x7) + // Code size 8 (0x8) .maxstack 1 - IL_0000: call ""ref readonly int C.Helper()"" - IL_0005: pop - IL_0006: ret -}"); + IL_0000: call "ref readonly int C.Helper()" + IL_0005: ldind.i4 + IL_0006: pop + IL_0007: ret +} +"""); } [Fact] @@ -392,14 +394,60 @@ static void M() static ref int Helper() => ref (new int[1])[0]; }"); - verifier.VerifyIL("C.M()", @" + verifier.VerifyIL("C.M()", """ { - // Code size 7 (0x7) + // Code size 8 (0x8) .maxstack 1 - IL_0000: call ""ref int C.Helper()"" - IL_0005: pop - IL_0006: ret -}"); + IL_0000: call "ref int C.Helper()" + IL_0005: ldind.i4 + IL_0006: pop + IL_0007: ret +} +"""); + } + + [Fact] + public void RefReturnAssign3() + { + var verifier = CompileAndVerify(@" +try +{ + C.M(); +} +catch (System.NullReferenceException) +{ + System.Console.WriteLine(""NullReferenceException""); +} + +class C +{ + public static void M() + { + ref readonly int x = ref Helper(); + ref readonly int y = ref Helper(); + _ = x + y; + } + + static unsafe ref int Helper() + => ref *(int*)0; +}", options: TestOptions.UnsafeReleaseExe, verify: Verification.Skipped, expectedOutput: "NullReferenceException"); + + verifier.VerifyIL("C.M()", """ +{ + // Code size 17 (0x11) + .maxstack 2 + .locals init (int& V_0) //y + IL_0000: call "ref int C.Helper()" + IL_0005: call "ref int C.Helper()" + IL_000a: stloc.0 + IL_000b: ldind.i4 + IL_000c: pop + IL_000d: ldloc.0 + IL_000e: ldind.i4 + IL_000f: pop + IL_0010: ret +} +"""); } diff --git a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenTupleTest.cs b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenTupleTest.cs index 33342c0110253..3228d914ff818 100644 --- a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenTupleTest.cs +++ b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenTupleTest.cs @@ -232,12 +232,12 @@ public ValueTuple(T1 item1, T2 item2) // (7,20): warning CS0169: The field '(T1, T2).Item2' is never used // private T2 Item2; Diagnostic(ErrorCode.WRN_UnreferencedField, "Item2").WithArguments("(T1, T2).Item2").WithLocation(7, 20), - // (8,16): error CS0171: Field '(T1, T2).Item2' must be fully assigned before control is returned to the caller. Consider updating to language version 'preview' to auto-default the field. + // (8,16): error CS0171: Field '(T1, T2).Item2' must be fully assigned before control is returned to the caller. Consider updating to language version '11.0' to auto-default the field. // public ValueTuple(T1 item1, T2 item2) - Diagnostic(ErrorCode.ERR_UnassignedThisUnsupportedVersion, "ValueTuple").WithArguments("(T1, T2).Item2", "preview").WithLocation(8, 16), - // (8,16): error CS0171: Field '(T1, T2).Item2' must be fully assigned before control is returned to the caller. Consider updating to language version 'preview' to auto-default the field. + Diagnostic(ErrorCode.ERR_UnassignedThisUnsupportedVersion, "ValueTuple").WithArguments("(T1, T2).Item2", "11.0").WithLocation(8, 16), + // (8,16): error CS0171: Field '(T1, T2).Item2' must be fully assigned before control is returned to the caller. Consider updating to language version '11.0' to auto-default the field. // public ValueTuple(T1 item1, T2 item2) - Diagnostic(ErrorCode.ERR_UnassignedThisUnsupportedVersion, "ValueTuple").WithArguments("(T1, T2).Item2", "preview").WithLocation(8, 16), + Diagnostic(ErrorCode.ERR_UnassignedThisUnsupportedVersion, "ValueTuple").WithArguments("(T1, T2).Item2", "11.0").WithLocation(8, 16), // (11,18): error CS0229: Ambiguity between '(T1, T2).Item2' and '(T1, T2).Item2' // this.Item2 = item2; Diagnostic(ErrorCode.ERR_AmbigMember, "Item2").WithArguments("(T1, T2).Item2", "(T1, T2).Item2").WithLocation(11, 18) diff --git a/src/Compilers/CSharp/Test/Emit/CodeGen/ObjectAndCollectionInitializerTests.cs b/src/Compilers/CSharp/Test/Emit/CodeGen/ObjectAndCollectionInitializerTests.cs index ec99d6dd3ae82..8d9d8a27aea00 100644 --- a/src/Compilers/CSharp/Test/Emit/CodeGen/ObjectAndCollectionInitializerTests.cs +++ b/src/Compilers/CSharp/Test/Emit/CodeGen/ObjectAndCollectionInitializerTests.cs @@ -1311,7 +1311,6 @@ static void Main() CompileAndVerify(comp, expectedOutput: expectedOutput); } - [Fact] public void DictionaryInitializerTestSideeffects001a() { diff --git a/src/Compilers/CSharp/Test/Emit/CodeGen/PatternTests.cs b/src/Compilers/CSharp/Test/Emit/CodeGen/PatternTests.cs index 5a29c09b7c7f0..50d2c3cd98e22 100644 --- a/src/Compilers/CSharp/Test/Emit/CodeGen/PatternTests.cs +++ b/src/Compilers/CSharp/Test/Emit/CodeGen/PatternTests.cs @@ -558,11 +558,11 @@ .locals init (object V_0, IL_000e: unbox.any ""double"" IL_0013: stloc.1 IL_0014: ldloc.1 - IL_0015: ldc.r8 3.14 - IL_001e: beq.s IL_0055 - IL_0020: ldloc.1 - IL_0021: call ""bool double.IsNaN(double)"" - IL_0026: brtrue.s IL_004b + IL_0015: call ""bool double.IsNaN(double)"" + IL_001a: brtrue.s IL_004b + IL_001c: ldloc.1 + IL_001d: ldc.r8 3.14 + IL_0026: beq.s IL_0055 IL_0028: br.s IL_005f IL_002a: ldloc.0 IL_002b: isinst ""float"" @@ -571,11 +571,11 @@ .locals init (object V_0, IL_0033: unbox.any ""float"" IL_0038: stloc.2 IL_0039: ldloc.2 - IL_003a: ldc.r4 3.14 - IL_003f: beq.s IL_005a + IL_003a: call ""bool float.IsNaN(float)"" + IL_003f: brtrue.s IL_0050 IL_0041: ldloc.2 - IL_0042: call ""bool float.IsNaN(float)"" - IL_0047: brtrue.s IL_0050 + IL_0042: ldc.r4 3.14 + IL_0047: beq.s IL_005a IL_0049: br.s IL_005f IL_004b: ldc.i4.1 IL_004c: stloc.s V_4 @@ -6530,5 +6530,304 @@ .locals init (string V_0) } #endregion Pattern Combinators + + [Fact, WorkItem(62563, "https://github.com/dotnet/roslyn/issues/62563")] + public void AssignToStructFieldOnClassTypeThroughCall_01() + { + var source = @" +using System; + +struct Inner +{ + public int Value { get; set; } +} + +class Outer +{ + public Inner Inner; +} + +class Program +{ + static T Id(T t) => t; + + static void Main() + { + var outer = new Outer(); + Console.Write(outer.Inner.Value); + + M1(outer); + M2(outer); + } + + static void M1(Outer outer) + { + Id(outer).Inner.Value = 1; + Console.Write(outer.Inner.Value); + } + + static void M2(Outer outer) + { + Id(outer).Inner.Value = outer switch + { + _ => 2 + }; + Console.Write(outer.Inner.Value); + } +} +"; + var verifier = CompileAndVerify(source, options: TestOptions.DebugExe, expectedOutput: "012"); + verifier.VerifyDiagnostics(); + + verifier.VerifyIL("Program.M1", """ + { + // Code size 37 (0x25) + .maxstack 2 + IL_0000: nop + IL_0001: ldarg.0 + IL_0002: call "Outer Program.Id(Outer)" + IL_0007: ldflda "Inner Outer.Inner" + IL_000c: ldc.i4.1 + IL_000d: call "void Inner.Value.set" + IL_0012: nop + IL_0013: ldarg.0 + IL_0014: ldflda "Inner Outer.Inner" + IL_0019: call "readonly int Inner.Value.get" + IL_001e: call "void System.Console.Write(int)" + IL_0023: nop + IL_0024: ret + } + """); + + verifier.VerifyIL("Program.M2", """ + { + // Code size 53 (0x35) + .maxstack 2 + .locals init (Outer V_0, + int V_1) + IL_0000: nop + IL_0001: ldarg.0 + IL_0002: call "Outer Program.Id(Outer)" + IL_0007: stloc.0 + IL_0008: ldc.i4.1 + IL_0009: brtrue.s IL_000c + IL_000b: nop + IL_000c: br.s IL_000e + IL_000e: ldc.i4.2 + IL_000f: stloc.1 + IL_0010: br.s IL_0012 + IL_0012: ldc.i4.1 + IL_0013: brtrue.s IL_0016 + IL_0015: nop + IL_0016: ldloc.0 + IL_0017: ldflda "Inner Outer.Inner" + IL_001c: ldloc.1 + IL_001d: call "void Inner.Value.set" + IL_0022: nop + IL_0023: ldarg.0 + IL_0024: ldflda "Inner Outer.Inner" + IL_0029: call "readonly int Inner.Value.get" + IL_002e: call "void System.Console.Write(int)" + IL_0033: nop + IL_0034: ret + } + """); + } + + [Fact, WorkItem(62563, "https://github.com/dotnet/roslyn/issues/62563")] + public void AssignToStructFieldOnClassTypeThroughCall_02() + { + var source = """ +using System; + + +var val = 0.1; +var obj = new Obj(); +ThrowWhenNull(obj).Color.Value = val switch +{ + 0 => "green", + _ => "red" +}; +Console.WriteLine($"{obj.Color.Value ?? "null"} should not be null"); +ThrowWhenNull(obj).Color.Value = "yikes"; +Console.WriteLine(obj.Color.Value); // yikes +ThrowWhenNull(obj).Color.Value = val == 0 ? "green" : "red"; +Console.WriteLine(obj.Color.Value); // red + +static T ThrowWhenNull(T obj) => obj ?? throw new System.InvalidOperationException(); + +struct Wrapper +{ + private T _value; + public T Value + { + get => _value; + set => _value = value; + } +} + +class Obj +{ + public Wrapper Color; +} +"""; + var verifier = CompileAndVerify(source, options: TestOptions.ReleaseExe, expectedOutput: """ + red should not be null + yikes + red + """); + verifier.VerifyDiagnostics(); + + verifier.VerifyIL("", """ + { + // Code size 186 (0xba) + .maxstack 4 + .locals init (double V_0, //val + string V_1) + IL_0000: ldc.r8 0.1 + IL_0009: stloc.0 + IL_000a: newobj "Obj..ctor()" + IL_000f: dup + IL_0010: call "Obj Program.<
$>g__ThrowWhenNull|0_0(Obj)" + IL_0015: ldloc.0 + IL_0016: ldc.r8 0 + IL_001f: bne.un.s IL_0029 + IL_0021: ldstr "green" + IL_0026: stloc.1 + IL_0027: br.s IL_002f + IL_0029: ldstr "red" + IL_002e: stloc.1 + IL_002f: ldflda "Wrapper Obj.Color" + IL_0034: ldloc.1 + IL_0035: call "void Wrapper.Value.set" + IL_003a: dup + IL_003b: ldflda "Wrapper Obj.Color" + IL_0040: call "string Wrapper.Value.get" + IL_0045: dup + IL_0046: brtrue.s IL_004e + IL_0048: pop + IL_0049: ldstr "null" + IL_004e: ldstr " should not be null" + IL_0053: call "string string.Concat(string, string)" + IL_0058: call "void System.Console.WriteLine(string)" + IL_005d: dup + IL_005e: call "Obj Program.<
$>g__ThrowWhenNull|0_0(Obj)" + IL_0063: ldflda "Wrapper Obj.Color" + IL_0068: ldstr "yikes" + IL_006d: call "void Wrapper.Value.set" + IL_0072: dup + IL_0073: ldflda "Wrapper Obj.Color" + IL_0078: call "string Wrapper.Value.get" + IL_007d: call "void System.Console.WriteLine(string)" + IL_0082: dup + IL_0083: call "Obj Program.<
$>g__ThrowWhenNull|0_0(Obj)" + IL_0088: ldflda "Wrapper Obj.Color" + IL_008d: ldloc.0 + IL_008e: ldc.r8 0 + IL_0097: beq.s IL_00a0 + IL_0099: ldstr "red" + IL_009e: br.s IL_00a5 + IL_00a0: ldstr "green" + IL_00a5: call "void Wrapper.Value.set" + IL_00aa: ldflda "Wrapper Obj.Color" + IL_00af: call "string Wrapper.Value.get" + IL_00b4: call "void System.Console.WriteLine(string)" + IL_00b9: ret + } + """); + } + + [Fact, WorkItem(62563, "https://github.com/dotnet/roslyn/issues/62563")] + public void AssignToEventFieldOnClassTypeThroughCall() + { + var source = @" +using System; + +class Outer +{ + static readonly Action A = () => { }; + static T Id(T t) => t; + + public event Action Inner; + + + static void Main() + { + var outer = new Outer(); + Console.Write(outer.Inner); + + M1(outer); + + outer.Inner = null; + M2(outer); + } + + static void M1(Outer outer) + { + Id(outer).Inner = A; + Console.Write(outer.Inner); + } + + static void M2(Outer outer) + { + Id(outer).Inner = outer switch + { + _ => A + }; + Console.Write(outer.Inner); + } +} +"; + var verifier = CompileAndVerify(source, options: TestOptions.DebugExe, expectedOutput: "System.ActionSystem.Action"); + verifier.VerifyDiagnostics(); + + verifier.VerifyIL("Outer.M1", """ + { + // Code size 30 (0x1e) + .maxstack 2 + IL_0000: nop + IL_0001: ldarg.0 + IL_0002: call "Outer Outer.Id(Outer)" + IL_0007: ldsfld "System.Action Outer.A" + IL_000c: stfld "System.Action Outer.Inner" + IL_0011: ldarg.0 + IL_0012: ldfld "System.Action Outer.Inner" + IL_0017: call "void System.Console.Write(object)" + IL_001c: nop + IL_001d: ret + } + """); + + verifier.VerifyIL("Outer.M2", """ + { + // Code size 46 (0x2e) + .maxstack 2 + .locals init (Outer V_0, + System.Action V_1) + IL_0000: nop + IL_0001: ldarg.0 + IL_0002: call "Outer Outer.Id(Outer)" + IL_0007: stloc.0 + IL_0008: ldc.i4.1 + IL_0009: brtrue.s IL_000c + IL_000b: nop + IL_000c: br.s IL_000e + IL_000e: ldsfld "System.Action Outer.A" + IL_0013: stloc.1 + IL_0014: br.s IL_0016 + IL_0016: ldc.i4.1 + IL_0017: brtrue.s IL_001a + IL_0019: nop + IL_001a: ldloc.0 + IL_001b: ldloc.1 + IL_001c: stfld "System.Action Outer.Inner" + IL_0021: ldarg.0 + IL_0022: ldfld "System.Action Outer.Inner" + IL_0027: call "void System.Console.Write(object)" + IL_002c: nop + IL_002d: ret + } + """); + } } } diff --git a/src/Compilers/CSharp/Test/Emit/CodeGen/SwitchTests.cs b/src/Compilers/CSharp/Test/Emit/CodeGen/SwitchTests.cs index 23a68895a0263..24ed6c83f40d5 100644 --- a/src/Compilers/CSharp/Test/Emit/CodeGen/SwitchTests.cs +++ b/src/Compilers/CSharp/Test/Emit/CodeGen/SwitchTests.cs @@ -9913,162 +9913,156 @@ static int M(double d) expectedOutput: expectedOutput); compVerifier.VerifyIL("C.M", @" { - // Code size 499 (0x1f3) + // Code size 478 (0x1de) .maxstack 2 .locals init (int V_0) IL_0000: ldarg.0 - IL_0001: ldc.r8 13.1 - IL_000a: blt.un IL_00fb - IL_000f: ldarg.0 - IL_0010: ldc.r8 21.1 - IL_0019: blt.un.s IL_008b + IL_0001: ldc.r8 27.1 + IL_000a: blt.un.s IL_002f + IL_000c: ldarg.0 + IL_000d: ldc.r8 29.1 + IL_0016: blt IL_017e IL_001b: ldarg.0 - IL_001c: ldc.r8 27.1 - IL_0025: blt.un.s IL_004a - IL_0027: ldarg.0 - IL_0028: ldc.r8 29.1 - IL_0031: blt IL_0193 - IL_0036: ldarg.0 - IL_0037: ldc.r8 29.1 - IL_0040: beq IL_01b3 - IL_0045: br IL_01ef - IL_004a: ldarg.0 - IL_004b: ldc.r8 23.1 - IL_0054: blt IL_01a9 - IL_0059: ldarg.0 - IL_005a: ldc.r8 25.1 - IL_0063: blt IL_01d3 - IL_0068: ldarg.0 - IL_0069: ldc.r8 25.1 - IL_0072: beq IL_01e1 - IL_0077: ldarg.0 - IL_0078: ldc.r8 26.1 - IL_0081: beq IL_0198 - IL_0086: br IL_01ef - IL_008b: ldarg.0 - IL_008c: ldc.r8 16.1 - IL_0095: blt.un.s IL_00d8 - IL_0097: ldarg.0 - IL_0098: ldc.r8 18.1 - IL_00a1: blt IL_01ce - IL_00a6: ldarg.0 - IL_00a7: ldc.r8 18.1 - IL_00b0: beq IL_01d8 - IL_00b5: ldarg.0 - IL_00b6: ldc.r8 19.1 - IL_00bf: beq IL_01ae - IL_00c4: ldarg.0 - IL_00c5: ldc.r8 20.1 - IL_00ce: beq IL_01e6 - IL_00d3: br IL_01ef - IL_00d8: ldarg.0 - IL_00d9: ldc.r8 15.1 - IL_00e2: blt IL_01b8 - IL_00e7: ldarg.0 - IL_00e8: ldc.r8 15.1 - IL_00f1: beq IL_01c1 - IL_00f6: br IL_01ef - IL_00fb: ldarg.0 - IL_00fc: ldc.r8 7.1 - IL_0105: blt.un.s IL_015f - IL_0107: ldarg.0 - IL_0108: ldc.r8 9.1 - IL_0111: blt IL_01dd - IL_0116: ldarg.0 - IL_0117: ldc.r8 10.1 - IL_0120: bgt.un.s IL_0142 - IL_0122: ldarg.0 - IL_0123: ldc.r8 9.1 - IL_012c: beq.s IL_019d - IL_012e: ldarg.0 - IL_012f: ldc.r8 10.1 - IL_0138: beq IL_01bd - IL_013d: br IL_01ef - IL_0142: ldarg.0 - IL_0143: ldc.r8 11.1 - IL_014c: beq.s IL_01c6 - IL_014e: ldarg.0 - IL_014f: ldc.r8 12.1 - IL_0158: beq.s IL_01a5 - IL_015a: br IL_01ef - IL_015f: ldarg.0 - IL_0160: ldc.r8 4.1 - IL_0169: bge.un.s IL_0179 - IL_016b: ldarg.0 - IL_016c: ldc.r8 2.1 - IL_0175: bge.s IL_01a1 - IL_0177: br.s IL_01ef - IL_0179: ldarg.0 - IL_017a: ldc.r8 5.1 - IL_0183: bge.s IL_01eb - IL_0185: ldarg.0 - IL_0186: ldc.r8 4.1 - IL_018f: beq.s IL_01ca - IL_0191: br.s IL_01ef - IL_0193: ldc.i4.s 19 - IL_0195: stloc.0 - IL_0196: br.s IL_01f1 - IL_0198: ldc.i4.s 18 - IL_019a: stloc.0 - IL_019b: br.s IL_01f1 - IL_019d: ldc.i4.5 - IL_019e: stloc.0 - IL_019f: br.s IL_01f1 - IL_01a1: ldc.i4.1 - IL_01a2: stloc.0 - IL_01a3: br.s IL_01f1 - IL_01a5: ldc.i4.8 - IL_01a6: stloc.0 - IL_01a7: br.s IL_01f1 - IL_01a9: ldc.i4.s 15 - IL_01ab: stloc.0 - IL_01ac: br.s IL_01f1 - IL_01ae: ldc.i4.s 13 - IL_01b0: stloc.0 - IL_01b1: br.s IL_01f1 - IL_01b3: ldc.i4.s 20 - IL_01b5: stloc.0 - IL_01b6: br.s IL_01f1 - IL_01b8: ldc.i4.s 9 - IL_01ba: stloc.0 - IL_01bb: br.s IL_01f1 - IL_01bd: ldc.i4.6 - IL_01be: stloc.0 - IL_01bf: br.s IL_01f1 - IL_01c1: ldc.i4.s 10 - IL_01c3: stloc.0 - IL_01c4: br.s IL_01f1 - IL_01c6: ldc.i4.7 - IL_01c7: stloc.0 - IL_01c8: br.s IL_01f1 - IL_01ca: ldc.i4.2 - IL_01cb: stloc.0 - IL_01cc: br.s IL_01f1 - IL_01ce: ldc.i4.s 11 - IL_01d0: stloc.0 - IL_01d1: br.s IL_01f1 - IL_01d3: ldc.i4.s 16 - IL_01d5: stloc.0 - IL_01d6: br.s IL_01f1 - IL_01d8: ldc.i4.s 12 - IL_01da: stloc.0 - IL_01db: br.s IL_01f1 - IL_01dd: ldc.i4.4 - IL_01de: stloc.0 - IL_01df: br.s IL_01f1 - IL_01e1: ldc.i4.s 17 - IL_01e3: stloc.0 - IL_01e4: br.s IL_01f1 - IL_01e6: ldc.i4.s 14 - IL_01e8: stloc.0 - IL_01e9: br.s IL_01f1 - IL_01eb: ldc.i4.3 - IL_01ec: stloc.0 - IL_01ed: br.s IL_01f1 - IL_01ef: ldc.i4.0 - IL_01f0: stloc.0 - IL_01f1: ldloc.0 - IL_01f2: ret + IL_001c: ldc.r8 29.1 + IL_0025: beq IL_019e + IL_002a: br IL_01da + IL_002f: ldarg.0 + IL_0030: ldc.r8 26.1 + IL_0039: beq IL_0183 + IL_003e: ldarg.0 + IL_003f: ldc.r8 9.1 + IL_0048: beq IL_0188 + IL_004d: ldarg.0 + IL_004e: ldc.r8 2.1 + IL_0057: blt.un IL_01da + IL_005c: ldarg.0 + IL_005d: ldc.r8 4.1 + IL_0066: blt IL_018c + IL_006b: ldarg.0 + IL_006c: ldc.r8 12.1 + IL_0075: beq IL_0190 + IL_007a: ldarg.0 + IL_007b: ldc.r8 21.1 + IL_0084: blt.un.s IL_00b8 + IL_0086: ldarg.0 + IL_0087: ldc.r8 23.1 + IL_0090: blt IL_0194 + IL_0095: ldarg.0 + IL_0096: ldc.r8 25.1 + IL_009f: blt IL_01be + IL_00a4: ldarg.0 + IL_00a5: ldc.r8 25.1 + IL_00ae: beq IL_01cc + IL_00b3: br IL_01da + IL_00b8: ldarg.0 + IL_00b9: ldc.r8 19.1 + IL_00c2: beq IL_0199 + IL_00c7: ldarg.0 + IL_00c8: ldc.r8 13.1 + IL_00d1: blt.un.s IL_0132 + IL_00d3: ldarg.0 + IL_00d4: ldc.r8 15.1 + IL_00dd: blt IL_01a3 + IL_00e2: ldarg.0 + IL_00e3: ldc.r8 15.1 + IL_00ec: beq IL_01ac + IL_00f1: ldarg.0 + IL_00f2: ldc.r8 16.1 + IL_00fb: blt.un IL_01da + IL_0100: ldarg.0 + IL_0101: ldc.r8 18.1 + IL_010a: blt IL_01b9 + IL_010f: ldarg.0 + IL_0110: ldc.r8 18.1 + IL_0119: beq IL_01c3 + IL_011e: ldarg.0 + IL_011f: ldc.r8 20.1 + IL_0128: beq IL_01d1 + IL_012d: br IL_01da + IL_0132: ldarg.0 + IL_0133: ldc.r8 10.1 + IL_013c: beq.s IL_01a8 + IL_013e: ldarg.0 + IL_013f: ldc.r8 11.1 + IL_0148: beq.s IL_01b1 + IL_014a: ldarg.0 + IL_014b: ldc.r8 4.1 + IL_0154: beq.s IL_01b5 + IL_0156: ldarg.0 + IL_0157: ldc.r8 7.1 + IL_0160: blt.un.s IL_0170 + IL_0162: ldarg.0 + IL_0163: ldc.r8 9.1 + IL_016c: blt.s IL_01c8 + IL_016e: br.s IL_01da + IL_0170: ldarg.0 + IL_0171: ldc.r8 5.1 + IL_017a: bge.s IL_01d6 + IL_017c: br.s IL_01da + IL_017e: ldc.i4.s 19 + IL_0180: stloc.0 + IL_0181: br.s IL_01dc + IL_0183: ldc.i4.s 18 + IL_0185: stloc.0 + IL_0186: br.s IL_01dc + IL_0188: ldc.i4.5 + IL_0189: stloc.0 + IL_018a: br.s IL_01dc + IL_018c: ldc.i4.1 + IL_018d: stloc.0 + IL_018e: br.s IL_01dc + IL_0190: ldc.i4.8 + IL_0191: stloc.0 + IL_0192: br.s IL_01dc + IL_0194: ldc.i4.s 15 + IL_0196: stloc.0 + IL_0197: br.s IL_01dc + IL_0199: ldc.i4.s 13 + IL_019b: stloc.0 + IL_019c: br.s IL_01dc + IL_019e: ldc.i4.s 20 + IL_01a0: stloc.0 + IL_01a1: br.s IL_01dc + IL_01a3: ldc.i4.s 9 + IL_01a5: stloc.0 + IL_01a6: br.s IL_01dc + IL_01a8: ldc.i4.6 + IL_01a9: stloc.0 + IL_01aa: br.s IL_01dc + IL_01ac: ldc.i4.s 10 + IL_01ae: stloc.0 + IL_01af: br.s IL_01dc + IL_01b1: ldc.i4.7 + IL_01b2: stloc.0 + IL_01b3: br.s IL_01dc + IL_01b5: ldc.i4.2 + IL_01b6: stloc.0 + IL_01b7: br.s IL_01dc + IL_01b9: ldc.i4.s 11 + IL_01bb: stloc.0 + IL_01bc: br.s IL_01dc + IL_01be: ldc.i4.s 16 + IL_01c0: stloc.0 + IL_01c1: br.s IL_01dc + IL_01c3: ldc.i4.s 12 + IL_01c5: stloc.0 + IL_01c6: br.s IL_01dc + IL_01c8: ldc.i4.4 + IL_01c9: stloc.0 + IL_01ca: br.s IL_01dc + IL_01cc: ldc.i4.s 17 + IL_01ce: stloc.0 + IL_01cf: br.s IL_01dc + IL_01d1: ldc.i4.s 14 + IL_01d3: stloc.0 + IL_01d4: br.s IL_01dc + IL_01d6: ldc.i4.3 + IL_01d7: stloc.0 + IL_01d8: br.s IL_01dc + IL_01da: ldc.i4.0 + IL_01db: stloc.0 + IL_01dc: ldloc.0 + IL_01dd: ret } " ); @@ -10177,162 +10171,156 @@ static int M(float d) expectedOutput: expectedOutput); compVerifier.VerifyIL("C.M", @" { - // Code size 388 (0x184) + // Code size 374 (0x176) .maxstack 2 .locals init (int V_0) IL_0000: ldarg.0 - IL_0001: ldc.r4 13.1 - IL_0006: blt.un IL_00bb - IL_000b: ldarg.0 - IL_000c: ldc.r4 21.1 - IL_0011: blt.un.s IL_0067 + IL_0001: ldc.r4 27.1 + IL_0006: blt.un.s IL_0023 + IL_0008: ldarg.0 + IL_0009: ldc.r4 29.1 + IL_000e: blt IL_0116 IL_0013: ldarg.0 - IL_0014: ldc.r4 27.1 - IL_0019: blt.un.s IL_0036 - IL_001b: ldarg.0 - IL_001c: ldc.r4 29.1 - IL_0021: blt IL_0124 - IL_0026: ldarg.0 - IL_0027: ldc.r4 29.1 - IL_002c: beq IL_0144 - IL_0031: br IL_0180 - IL_0036: ldarg.0 - IL_0037: ldc.r4 23.1 - IL_003c: blt IL_013a - IL_0041: ldarg.0 - IL_0042: ldc.r4 25.1 - IL_0047: blt IL_0164 - IL_004c: ldarg.0 - IL_004d: ldc.r4 25.1 - IL_0052: beq IL_0172 - IL_0057: ldarg.0 - IL_0058: ldc.r4 26.1 - IL_005d: beq IL_0129 - IL_0062: br IL_0180 - IL_0067: ldarg.0 - IL_0068: ldc.r4 16.1 - IL_006d: blt.un.s IL_00a0 - IL_006f: ldarg.0 - IL_0070: ldc.r4 18.1 - IL_0075: blt IL_015f - IL_007a: ldarg.0 - IL_007b: ldc.r4 18.1 - IL_0080: beq IL_0169 - IL_0085: ldarg.0 - IL_0086: ldc.r4 19.1 - IL_008b: beq IL_013f - IL_0090: ldarg.0 - IL_0091: ldc.r4 20.1 - IL_0096: beq IL_0177 - IL_009b: br IL_0180 - IL_00a0: ldarg.0 - IL_00a1: ldc.r4 15.1 - IL_00a6: blt IL_0149 - IL_00ab: ldarg.0 - IL_00ac: ldc.r4 15.1 - IL_00b1: beq IL_0152 - IL_00b6: br IL_0180 - IL_00bb: ldarg.0 - IL_00bc: ldc.r4 7.1 - IL_00c1: blt.un.s IL_0100 - IL_00c3: ldarg.0 - IL_00c4: ldc.r4 9.1 - IL_00c9: blt IL_016e - IL_00ce: ldarg.0 - IL_00cf: ldc.r4 10.1 - IL_00d4: bgt.un.s IL_00eb - IL_00d6: ldarg.0 - IL_00d7: ldc.r4 9.1 - IL_00dc: beq.s IL_012e - IL_00de: ldarg.0 - IL_00df: ldc.r4 10.1 - IL_00e4: beq.s IL_014e - IL_00e6: br IL_0180 - IL_00eb: ldarg.0 - IL_00ec: ldc.r4 11.1 - IL_00f1: beq.s IL_0157 - IL_00f3: ldarg.0 - IL_00f4: ldc.r4 12.1 - IL_00f9: beq.s IL_0136 - IL_00fb: br IL_0180 - IL_0100: ldarg.0 - IL_0101: ldc.r4 4.1 - IL_0106: bge.un.s IL_0112 - IL_0108: ldarg.0 - IL_0109: ldc.r4 2.1 - IL_010e: bge.s IL_0132 - IL_0110: br.s IL_0180 - IL_0112: ldarg.0 - IL_0113: ldc.r4 5.1 - IL_0118: bge.s IL_017c - IL_011a: ldarg.0 - IL_011b: ldc.r4 4.1 - IL_0120: beq.s IL_015b - IL_0122: br.s IL_0180 - IL_0124: ldc.i4.s 19 - IL_0126: stloc.0 - IL_0127: br.s IL_0182 - IL_0129: ldc.i4.s 18 - IL_012b: stloc.0 - IL_012c: br.s IL_0182 - IL_012e: ldc.i4.5 - IL_012f: stloc.0 - IL_0130: br.s IL_0182 - IL_0132: ldc.i4.1 + IL_0014: ldc.r4 29.1 + IL_0019: beq IL_0136 + IL_001e: br IL_0172 + IL_0023: ldarg.0 + IL_0024: ldc.r4 26.1 + IL_0029: beq IL_011b + IL_002e: ldarg.0 + IL_002f: ldc.r4 9.1 + IL_0034: beq IL_0120 + IL_0039: ldarg.0 + IL_003a: ldc.r4 2.1 + IL_003f: blt.un IL_0172 + IL_0044: ldarg.0 + IL_0045: ldc.r4 4.1 + IL_004a: blt IL_0124 + IL_004f: ldarg.0 + IL_0050: ldc.r4 12.1 + IL_0055: beq IL_0128 + IL_005a: ldarg.0 + IL_005b: ldc.r4 21.1 + IL_0060: blt.un.s IL_0088 + IL_0062: ldarg.0 + IL_0063: ldc.r4 23.1 + IL_0068: blt IL_012c + IL_006d: ldarg.0 + IL_006e: ldc.r4 25.1 + IL_0073: blt IL_0156 + IL_0078: ldarg.0 + IL_0079: ldc.r4 25.1 + IL_007e: beq IL_0164 + IL_0083: br IL_0172 + IL_0088: ldarg.0 + IL_0089: ldc.r4 19.1 + IL_008e: beq IL_0131 + IL_0093: ldarg.0 + IL_0094: ldc.r4 13.1 + IL_0099: blt.un.s IL_00e2 + IL_009b: ldarg.0 + IL_009c: ldc.r4 15.1 + IL_00a1: blt IL_013b + IL_00a6: ldarg.0 + IL_00a7: ldc.r4 15.1 + IL_00ac: beq IL_0144 + IL_00b1: ldarg.0 + IL_00b2: ldc.r4 16.1 + IL_00b7: blt.un IL_0172 + IL_00bc: ldarg.0 + IL_00bd: ldc.r4 18.1 + IL_00c2: blt IL_0151 + IL_00c7: ldarg.0 + IL_00c8: ldc.r4 18.1 + IL_00cd: beq IL_015b + IL_00d2: ldarg.0 + IL_00d3: ldc.r4 20.1 + IL_00d8: beq IL_0169 + IL_00dd: br IL_0172 + IL_00e2: ldarg.0 + IL_00e3: ldc.r4 10.1 + IL_00e8: beq.s IL_0140 + IL_00ea: ldarg.0 + IL_00eb: ldc.r4 11.1 + IL_00f0: beq.s IL_0149 + IL_00f2: ldarg.0 + IL_00f3: ldc.r4 4.1 + IL_00f8: beq.s IL_014d + IL_00fa: ldarg.0 + IL_00fb: ldc.r4 7.1 + IL_0100: blt.un.s IL_010c + IL_0102: ldarg.0 + IL_0103: ldc.r4 9.1 + IL_0108: blt.s IL_0160 + IL_010a: br.s IL_0172 + IL_010c: ldarg.0 + IL_010d: ldc.r4 5.1 + IL_0112: bge.s IL_016e + IL_0114: br.s IL_0172 + IL_0116: ldc.i4.s 19 + IL_0118: stloc.0 + IL_0119: br.s IL_0174 + IL_011b: ldc.i4.s 18 + IL_011d: stloc.0 + IL_011e: br.s IL_0174 + IL_0120: ldc.i4.5 + IL_0121: stloc.0 + IL_0122: br.s IL_0174 + IL_0124: ldc.i4.1 + IL_0125: stloc.0 + IL_0126: br.s IL_0174 + IL_0128: ldc.i4.8 + IL_0129: stloc.0 + IL_012a: br.s IL_0174 + IL_012c: ldc.i4.s 15 + IL_012e: stloc.0 + IL_012f: br.s IL_0174 + IL_0131: ldc.i4.s 13 IL_0133: stloc.0 - IL_0134: br.s IL_0182 - IL_0136: ldc.i4.8 - IL_0137: stloc.0 - IL_0138: br.s IL_0182 - IL_013a: ldc.i4.s 15 - IL_013c: stloc.0 - IL_013d: br.s IL_0182 - IL_013f: ldc.i4.s 13 + IL_0134: br.s IL_0174 + IL_0136: ldc.i4.s 20 + IL_0138: stloc.0 + IL_0139: br.s IL_0174 + IL_013b: ldc.i4.s 9 + IL_013d: stloc.0 + IL_013e: br.s IL_0174 + IL_0140: ldc.i4.6 IL_0141: stloc.0 - IL_0142: br.s IL_0182 - IL_0144: ldc.i4.s 20 + IL_0142: br.s IL_0174 + IL_0144: ldc.i4.s 10 IL_0146: stloc.0 - IL_0147: br.s IL_0182 - IL_0149: ldc.i4.s 9 - IL_014b: stloc.0 - IL_014c: br.s IL_0182 - IL_014e: ldc.i4.6 - IL_014f: stloc.0 - IL_0150: br.s IL_0182 - IL_0152: ldc.i4.s 10 - IL_0154: stloc.0 - IL_0155: br.s IL_0182 - IL_0157: ldc.i4.7 + IL_0147: br.s IL_0174 + IL_0149: ldc.i4.7 + IL_014a: stloc.0 + IL_014b: br.s IL_0174 + IL_014d: ldc.i4.2 + IL_014e: stloc.0 + IL_014f: br.s IL_0174 + IL_0151: ldc.i4.s 11 + IL_0153: stloc.0 + IL_0154: br.s IL_0174 + IL_0156: ldc.i4.s 16 IL_0158: stloc.0 - IL_0159: br.s IL_0182 - IL_015b: ldc.i4.2 - IL_015c: stloc.0 - IL_015d: br.s IL_0182 - IL_015f: ldc.i4.s 11 + IL_0159: br.s IL_0174 + IL_015b: ldc.i4.s 12 + IL_015d: stloc.0 + IL_015e: br.s IL_0174 + IL_0160: ldc.i4.4 IL_0161: stloc.0 - IL_0162: br.s IL_0182 - IL_0164: ldc.i4.s 16 + IL_0162: br.s IL_0174 + IL_0164: ldc.i4.s 17 IL_0166: stloc.0 - IL_0167: br.s IL_0182 - IL_0169: ldc.i4.s 12 + IL_0167: br.s IL_0174 + IL_0169: ldc.i4.s 14 IL_016b: stloc.0 - IL_016c: br.s IL_0182 - IL_016e: ldc.i4.4 + IL_016c: br.s IL_0174 + IL_016e: ldc.i4.3 IL_016f: stloc.0 - IL_0170: br.s IL_0182 - IL_0172: ldc.i4.s 17 - IL_0174: stloc.0 - IL_0175: br.s IL_0182 - IL_0177: ldc.i4.s 14 - IL_0179: stloc.0 - IL_017a: br.s IL_0182 - IL_017c: ldc.i4.3 - IL_017d: stloc.0 - IL_017e: br.s IL_0182 - IL_0180: ldc.i4.0 - IL_0181: stloc.0 - IL_0182: ldloc.0 - IL_0183: ret + IL_0170: br.s IL_0174 + IL_0172: ldc.i4.0 + IL_0173: stloc.0 + IL_0174: ldloc.0 + IL_0175: ret } " ); diff --git a/src/Compilers/CSharp/Test/Emit/Emit/EditAndContinue/EditAndContinueStateMachineTests.cs b/src/Compilers/CSharp/Test/Emit/Emit/EditAndContinue/EditAndContinueStateMachineTests.cs index 758d76ec9fd83..01bc887139dc8 100644 --- a/src/Compilers/CSharp/Test/Emit/Emit/EditAndContinue/EditAndContinueStateMachineTests.cs +++ b/src/Compilers/CSharp/Test/Emit/Emit/EditAndContinue/EditAndContinueStateMachineTests.cs @@ -8064,6 +8064,116 @@ static void F() "<>u__2: System.Runtime.CompilerServices.TaskAwaiter"); } + [Fact, WorkItem(63294, "https://github.com/dotnet/roslyn/issues/63294")] + public void LiftedClosure() + { + var source0 = MarkedSource(@" +using System.Threading.Tasks; +static class C +{ + static async Task M() + { + int num = 1; + F(); + + await Task.Delay(1); + + int F() => num; + } +}"); + + var source1 = MarkedSource(@" +using System.Threading.Tasks; +static class C +{ + static async Task M() + { + int num = 1; + F(); + + await Task.Delay(2); + + int F() => num; + } +}"); + var compilation0 = CreateCompilationWithMscorlib45(new[] { source0.Tree }, options: ComSafeDebugDll); + var compilation1 = compilation0.WithSource(source1.Tree); + + var m0 = compilation0.GetMember("C.M"); + var m1 = compilation1.GetMember("C.M"); + + var v0 = CompileAndVerify(compilation0); + using var md0 = ModuleMetadata.CreateFromImage(v0.EmittedAssemblyData); + var reader0 = md0.MetadataReader; + var generation0 = EmitBaseline.CreateInitialBaseline(md0, v0.CreateSymReader().GetEncMethodDebugInfo); + + // Notice encLocalSlotMap CDI on both M and MoveNext methods. + // The former is used to calculate mapping for variables lifted to fields of the state machine, + // the latter is used to map local variable slots in the MoveNext method. + // Here, the variable lifted to the state machine field is the closure pointer storage. + v0.VerifyPdb(@" + + + + + + + + + + 0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +", options: PdbValidationOptions.ExcludeDocuments | PdbValidationOptions.ExcludeSequencePoints | PdbValidationOptions.ExcludeNamespaces | PdbValidationOptions.ExcludeScopes); + + CheckNames(reader0, reader0.GetTypeDefNames(), "", "C", "<>c__DisplayClass0_0", "d__0"); + CheckNames(reader0, reader0.GetFieldDefNames(), "num", "<>1__state", "<>t__builder", "<>8__1", "<>u__1"); + + var diff1 = compilation1.EmitDifference( + generation0, + ImmutableArray.Create( + SemanticEdit.Create(SemanticEditKind.Update, m0, m1, GetSyntaxMapFromMarkers(source0, source1), preserveLocalVariables: true))); + + // Notice that we reused field "<>8__1" (there is no "<>8__2"), which stores the local function closure pointer. + diff1.VerifySynthesizedMembers( + "C: {g__F|0_0, <>c__DisplayClass0_0, d__0}", + "C.d__0: {<>1__state, <>t__builder, <>8__1, <>u__1, MoveNext, SetStateMachine}", + "C.<>c__DisplayClass0_0: {num}"); + } + [Fact, WorkItem(1170899, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/1170899")] public void HoistedAnonymousTypes1() { @@ -10274,7 +10384,7 @@ class C public async void F(string? x) { - var y = await G(() => new { A = id(x) }); + var y = await G(() => new { A = id(x) }); var z = H(() => y.A); } } @@ -10293,7 +10403,7 @@ class C public async void F(string? x) { if (x is null) throw new Exception(); - var y = await G(() => new { A = id(x) }); + var y = await G(() => new { A = id(x) }); var z = H(() => y.A); } } @@ -10329,7 +10439,7 @@ public async void F(string? x) "C: {<>c__DisplayClass3_0, d__3}", ": {Microsoft, System, System}", "System: {Runtime, Runtime}", - "C.d__3: {<>1__state, <>t__builder, x, <>4__this, <>8__4, 5__2, <>s__5, <>u__1, MoveNext, SetStateMachine}"); + "C.d__3: {<>1__state, <>t__builder, x, <>4__this, <>8__1, 5__2, <>s__3, <>u__1, MoveNext, SetStateMachine}"); diff1.VerifyIL("C.<>c__DisplayClass3_0.b__1()", @" { diff --git a/src/Compilers/CSharp/Test/Emit/Emit/EditAndContinue/EditAndContinueTest.GenerationVerifier.cs b/src/Compilers/CSharp/Test/Emit/Emit/EditAndContinue/EditAndContinueTest.GenerationVerifier.cs index 8572f285c8403..edb5586b3e34d 100644 --- a/src/Compilers/CSharp/Test/Emit/Emit/EditAndContinue/EditAndContinueTest.GenerationVerifier.cs +++ b/src/Compilers/CSharp/Test/Emit/Emit/EditAndContinue/EditAndContinueTest.GenerationVerifier.cs @@ -65,6 +65,12 @@ internal void VerifyPropertyDefNames(params string[] expected) AssertEx.Equal(expected, actual, message: GetAssertMessage("PropertyDefs don't match")); } + internal void VerifyDeletedMembers(params string[] expected) + { + var actual = _generationInfo.Baseline.DeletedMembers.Select(e => e.Key.ToString() + ": {" + string.Join(", ", e.Value.Select(v => v.Name)) + "}"); + AssertEx.SetEqual(expected, actual, itemSeparator: ",\r\n", itemInspector: s => $"\"{s}\""); + } + internal void VerifyTableSize(TableIndex table, int expected) { AssertEx.AreEqual(expected, _metadataReader.GetTableRowCount(table), message: GetAssertMessage($"{table} table size doesnt't match")); diff --git a/src/Compilers/CSharp/Test/Emit/Emit/EditAndContinue/EditAndContinueTest.cs b/src/Compilers/CSharp/Test/Emit/Emit/EditAndContinue/EditAndContinueTest.cs index 04447d026e1da..45f43f7eace84 100644 --- a/src/Compilers/CSharp/Test/Emit/Emit/EditAndContinue/EditAndContinueTest.cs +++ b/src/Compilers/CSharp/Test/Emit/Emit/EditAndContinue/EditAndContinueTest.cs @@ -7,6 +7,7 @@ using System.Collections.Immutable; using System.Linq; using System.Reflection.Metadata; +using System.Runtime.InteropServices; using Microsoft.CodeAnalysis.CSharp.Test.Utilities; using Microsoft.CodeAnalysis.Emit; using Microsoft.CodeAnalysis.Test.Utilities; @@ -112,7 +113,11 @@ private ImmutableArray GetSemanticEdits(SemanticEditDescription[] public void Dispose() { - Assert.True(_hasVerified, "No Verify call since the last AddGeneration call."); + // If the test has thrown an exception, or the test host has crashed, we don't want to assert here + // or we'll hide it, so we need to do this dodgy looking thing. + var isInException = Marshal.GetExceptionPointers() != IntPtr.Zero; + + Assert.True(isInException || _hasVerified, "No Verify call since the last AddGeneration call."); foreach (var disposable in _disposables) { disposable.Dispose(); diff --git a/src/Compilers/CSharp/Test/Emit/Emit/EditAndContinue/EditAndContinueTestBase.cs b/src/Compilers/CSharp/Test/Emit/Emit/EditAndContinue/EditAndContinueTestBase.cs index 0990411a4ccea..ba8a0e8c0f7e6 100644 --- a/src/Compilers/CSharp/Test/Emit/Emit/EditAndContinue/EditAndContinueTestBase.cs +++ b/src/Compilers/CSharp/Test/Emit/Emit/EditAndContinue/EditAndContinueTestBase.cs @@ -145,27 +145,48 @@ internal static EntityHandle Handle(int rowNumber, TableIndex table) internal static bool IsDefinition(HandleKind kind) => kind is not (HandleKind.AssemblyReference or HandleKind.ModuleReference or HandleKind.TypeReference or HandleKind.MemberReference or HandleKind.TypeSpecification or HandleKind.MethodSpecification); + /// + /// Checks that the EncLog contains specified rows. + /// Any default values in the expected are ignored to facilitate conditional code. + /// internal static void CheckEncLog(MetadataReader reader, params EditAndContinueLogEntry[] rows) { - AssertEx.Equal(rows, reader.GetEditAndContinueLogEntries(), itemInspector: EncLogRowToString); + AssertEx.Equal( + rows.Where(r => r.Handle != default), + reader.GetEditAndContinueLogEntries(), itemInspector: EncLogRowToString); } /// /// Checks that the EncLog contains specified definition rows. References are ignored as they are usually not interesting to validate. They are emitted as needed. + /// Any default values in the expected are ignored to facilitate conditional code. /// internal static void CheckEncLogDefinitions(MetadataReader reader, params EditAndContinueLogEntry[] rows) { - AssertEx.Equal(rows, reader.GetEditAndContinueLogEntries().Where(e => IsDefinition(e.Handle.Kind)), itemInspector: EncLogRowToString); + AssertEx.Equal( + rows.Where(r => r.Handle != default), + reader.GetEditAndContinueLogEntries().Where(e => IsDefinition(e.Handle.Kind)), itemInspector: EncLogRowToString); } + /// + /// Checks that the EncMap contains specified handles. + /// Any default values in the expected are ignored to facilitate conditional code. + /// internal static void CheckEncMap(MetadataReader reader, params EntityHandle[] handles) { - AssertEx.Equal(handles, reader.GetEditAndContinueMapEntries(), itemInspector: EncMapRowToString); + AssertEx.Equal( + handles.Where(h => h != default), + reader.GetEditAndContinueMapEntries(), itemInspector: EncMapRowToString); } + /// + /// Checks that the EncMap contains specified definition handles. References are ignored as they are usually not interesting to validate. They are emitted as needed. + /// Any default values in the expected are ignored to facilitate conditional code. + /// internal static void CheckEncMapDefinitions(MetadataReader reader, params EntityHandle[] handles) { - AssertEx.Equal(handles, reader.GetEditAndContinueMapEntries().Where(e => IsDefinition(e.Kind)), itemInspector: EncMapRowToString); + AssertEx.Equal( + handles.Where(h => h != default), + reader.GetEditAndContinueMapEntries().Where(e => IsDefinition(e.Kind)), itemInspector: EncMapRowToString); } internal static void CheckAttributes(MetadataReader reader, params CustomAttributeRow[] rows) @@ -203,7 +224,7 @@ private static void CheckNames( Func toHandle, string[] expectedNames) { - var aggregator = new MetadataAggregator(readers[0], readers.Skip(1).ToArray()); + var aggregator = GetAggregator(readers); AssertEx.Equal(expectedNames, entityHandles.Select(handle => { @@ -215,6 +236,27 @@ private static void CheckNames( })); } + public static void CheckBlobValue(IList readers, BlobHandle valueHandle, byte[] expectedValue) + { + var aggregator = GetAggregator(readers); + + var genHandle = (BlobHandle)aggregator.GetGenerationHandle(valueHandle, out int blobGeneration); + var attributeData = readers[blobGeneration].GetBlobBytes(genHandle); + AssertEx.Equal(expectedValue, attributeData); + } + + public static void CheckStringValue(IList readers, StringHandle valueHandle, string expectedValue) + { + var aggregator = GetAggregator(readers); + + var genHandle = (StringHandle)aggregator.GetGenerationHandle(valueHandle, out int blobGeneration); + var attributeData = readers[blobGeneration].GetString(genHandle); + AssertEx.Equal(expectedValue, attributeData); + } + + public static MetadataAggregator GetAggregator(IList readers) + => new MetadataAggregator(readers[0], readers.Skip(1).ToArray()); + internal static string EncLogRowToString(EditAndContinueLogEntry row) { TableIndex tableIndex; diff --git a/src/Compilers/CSharp/Test/Emit/Emit/EditAndContinue/EditAndContinueTests.cs b/src/Compilers/CSharp/Test/Emit/Emit/EditAndContinue/EditAndContinueTests.cs index 4a9568a43ef6e..29af80774efc0 100644 --- a/src/Compilers/CSharp/Test/Emit/Emit/EditAndContinue/EditAndContinueTests.cs +++ b/src/Compilers/CSharp/Test/Emit/Emit/EditAndContinue/EditAndContinueTests.cs @@ -12,6 +12,7 @@ using System.Linq; using System.Reflection.Metadata; using System.Reflection.Metadata.Ecma335; +using System.Runtime.InteropServices; using Microsoft.CodeAnalysis.CodeGen; using Microsoft.CodeAnalysis.CSharp.Symbols; using Microsoft.CodeAnalysis.CSharp.Test.Utilities; @@ -38,6 +39,73 @@ private static IEnumerable DumpTypeRefs(MetadataReader[] readers) } } + [Fact] + public void Constructor_Delete() + { + using var _ = new EditAndContinueTest(options: TestOptions.DebugDll, targetFramework: TargetFramework.NetStandard20) + .AddGeneration( + source: $$""" + class C + { + public C() + { + } + + public C(int x) + { + } + } + """, + validator: g => + { + g.VerifyTypeDefNames("", "C"); + g.VerifyMethodDefNames(".ctor", ".ctor"); + g.VerifyMemberRefNames(/*CompilationRelaxationsAttribute.*/".ctor", /*RuntimeCompatibilityAttribute.*/".ctor", /*Object.*/".ctor", /*DebuggableAttribute*/".ctor"); + }) + + .AddGeneration( + source: """ + class C + { + public C() + { + } + } + """, + edits: new[] { + Edit(SemanticEditKind.Delete, symbolProvider: c => c.GetMember("C").InstanceConstructors.FirstOrDefault(c => c.Parameters.Length == 1), newSymbolProvider: c => c.GetMember("C")), + }, + validator: g => + { + g.VerifyTypeDefNames(); + g.VerifyMethodDefNames(".ctor"); + g.VerifyMemberRefNames(/* MissingMethodException */ ".ctor"); + g.VerifyEncLogDefinitions(new[] + { + Row(2, TableIndex.MethodDef, EditAndContinueOperation.Default), + Row(1, TableIndex.Param, EditAndContinueOperation.Default) + }); + g.VerifyEncMapDefinitions(new[] + { + Handle(2, TableIndex.MethodDef), + Handle(1, TableIndex.Param) + }); + + var expectedIL = """ + { + // Code size 6 (0x6) + .maxstack 8 + IL_0000: newobj 0x0A000005 + IL_0005: throw + } + """; + + // Can't verify the IL of individual methods because that requires IMethodSymbolInternal implementations + g.VerifyIL(expectedIL); + }) + .Verify(); + } + [Fact] public void Diagnostics_Nullable() { @@ -2913,6 +2981,136 @@ class C Handle(3, TableIndex.MethodSemantics)); } + [Fact] + public void Property_Delete() + { + using var _ = new EditAndContinueTest(options: TestOptions.DebugDll, targetFramework: TargetFramework.NetStandard20) + .AddGeneration( + source: $$""" + class C + { + public string P { get; set; } + } + """, + validator: g => + { + g.VerifyTypeDefNames("", "C"); + g.VerifyMethodDefNames("get_P", "set_P", ".ctor"); + g.VerifyMemberRefNames(/*CompilationRelaxationsAttribute.*/".ctor", /*RuntimeCompatibilityAttribute.*/".ctor", /*Object.*/".ctor", /*DebuggableAttribute*/".ctor", ".ctor", ".ctor"); + }) + + .AddGeneration( + source: """ + class C + { + } + """, + edits: new[] { + Edit(SemanticEditKind.Delete, symbolProvider: c => c.GetMember("C.get_P"), newSymbolProvider: c => c.GetMember("C")), + Edit(SemanticEditKind.Delete, symbolProvider: c => c.GetMember("C.set_P"), newSymbolProvider: c => c.GetMember("C")), + }, + validator: g => + { + g.VerifyTypeDefNames(); + g.VerifyMethodDefNames("get_P", "set_P"); + g.VerifyMemberRefNames(/* MissingMethodException */ ".ctor", ".ctor"); + g.VerifyEncLogDefinitions(new[] + { + Row(1, TableIndex.MethodDef, EditAndContinueOperation.Default), + Row(2, TableIndex.MethodDef, EditAndContinueOperation.Default), + Row(1, TableIndex.Param, EditAndContinueOperation.Default), + Row(1, TableIndex.CustomAttribute, EditAndContinueOperation.Default), + Row(7, TableIndex.CustomAttribute, EditAndContinueOperation.Default) + }); + g.VerifyEncMapDefinitions(new[] + { + Handle(1, TableIndex.MethodDef), + Handle(2, TableIndex.MethodDef), + Handle(1, TableIndex.Param), + Handle(1, TableIndex.CustomAttribute), + Handle(7, TableIndex.CustomAttribute) + }); + + var expectedIL = """ + { + // Code size 6 (0x6) + .maxstack 8 + IL_0000: newobj 0x0A000008 + IL_0005: throw + } + """; + + // Can't verify the IL of individual methods because that requires IMethodSymbolInternal implementations + g.VerifyIL(expectedIL); + }) + .Verify(); + } + + [Fact] + public void Indexer_Delete() + { + using var _ = new EditAndContinueTest(options: TestOptions.DebugDll, targetFramework: TargetFramework.NetStandard20) + .AddGeneration( + source: $$""" + class C + { + public int this[int x] { get { return 1; } set { } } + } + """, + validator: g => + { + g.VerifyTypeDefNames("", "C"); + g.VerifyMethodDefNames("get_Item", "set_Item", ".ctor"); + g.VerifyMemberRefNames(/*CompilationRelaxationsAttribute.*/".ctor", /*RuntimeCompatibilityAttribute.*/".ctor", /*Object.*/".ctor", /*DebuggableAttribute*/".ctor", ".ctor"); + }) + + .AddGeneration( + source: """ + class C + { + } + """, + edits: new[] { + Edit(SemanticEditKind.Delete, symbolProvider: c => c.GetMember("C.get_Item"), newSymbolProvider: c => c.GetMember("C")), + Edit(SemanticEditKind.Delete, symbolProvider: c => c.GetMember("C.set_Item"), newSymbolProvider: c => c.GetMember("C")), + }, + validator: g => + { + g.VerifyTypeDefNames(); + g.VerifyMethodDefNames("get_Item", "set_Item"); + g.VerifyMemberRefNames(/* MissingMethodException */ ".ctor"); + g.VerifyEncLogDefinitions(new[] + { + Row(1, TableIndex.MethodDef, EditAndContinueOperation.Default), + Row(2, TableIndex.MethodDef, EditAndContinueOperation.Default), + Row(1, TableIndex.Param, EditAndContinueOperation.Default), + Row(2, TableIndex.Param, EditAndContinueOperation.Default), + Row(3, TableIndex.Param, EditAndContinueOperation.Default), + }); + g.VerifyEncMapDefinitions(new[] + { + Handle(1, TableIndex.MethodDef), + Handle(2, TableIndex.MethodDef), + Handle(1, TableIndex.Param), + Handle(2, TableIndex.Param), + Handle(3, TableIndex.Param), + }); + + var expectedIL = """ + { + // Code size 6 (0x6) + .maxstack 8 + IL_0000: newobj 0x0A000006 + IL_0005: throw + } + """; + + // Can't verify the IL of individual methods because that requires IMethodSymbolInternal implementations + g.VerifyIL(expectedIL); + }) + .Verify(); + } + [Fact] public void Event_Add() { @@ -3052,6 +3250,73 @@ class C Handle(4, TableIndex.MethodSemantics)); } + [Fact] + public void Event_Delete() + { + using var _ = new EditAndContinueTest(options: TestOptions.DebugDll, targetFramework: TargetFramework.NetStandard20) + .AddGeneration( + source: $$""" + class C + { + public event System.EventHandler E; + } + """, + validator: g => + { + g.VerifyTypeDefNames("", "C"); + g.VerifyMethodDefNames("add_E", "remove_E", ".ctor"); + g.VerifyMemberRefNames(/*CompilationRelaxationsAttribute.*/".ctor", /*RuntimeCompatibilityAttribute.*/".ctor", /*Object.*/".ctor", /*DebuggableAttribute*/".ctor", ".ctor", "Combine", "CompareExchange", "Remove", ".ctor"); + }) + + .AddGeneration( + source: """ + class C + { + } + """, + edits: new[] { + Edit(SemanticEditKind.Delete, symbolProvider: c => c.GetMember("C.add_E"), newSymbolProvider: c => c.GetMember("C")), + Edit(SemanticEditKind.Delete, symbolProvider: c => c.GetMember("C.remove_E"), newSymbolProvider: c => c.GetMember("C")), + }, + validator: g => + { + g.VerifyTypeDefNames(); + g.VerifyMethodDefNames("add_E", "remove_E"); + g.VerifyMemberRefNames(/* MissingMethodException */ ".ctor", ".ctor"); + g.VerifyEncLogDefinitions(new[] + { + Row(1, TableIndex.MethodDef, EditAndContinueOperation.Default), + Row(2, TableIndex.MethodDef, EditAndContinueOperation.Default), + Row(1, TableIndex.Param, EditAndContinueOperation.Default), + Row(2, TableIndex.Param, EditAndContinueOperation.Default), + Row(1, TableIndex.CustomAttribute, EditAndContinueOperation.Default), + Row(7, TableIndex.CustomAttribute, EditAndContinueOperation.Default) + }); + g.VerifyEncMapDefinitions(new[] + { + Handle(1, TableIndex.MethodDef), + Handle(2, TableIndex.MethodDef), + Handle(1, TableIndex.Param), + Handle(2, TableIndex.Param), + Handle(1, TableIndex.CustomAttribute), + Handle(7, TableIndex.CustomAttribute) + }); + + var expectedIL = """ + { + // Code size 6 (0x6) + .maxstack 8 + IL_0000: newobj 0x0A00000B + IL_0005: throw + } + """; + + // Can't verify the IL of individual methods because that requires IMethodSymbolInternal implementations + g.VerifyIL(expectedIL); + }) + .Verify(); + } + [WorkItem(1175704, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/1175704")] [Fact] public void EventFields() @@ -3204,31 +3469,58 @@ class C Handle(5, TableIndex.CustomAttribute)); } - [Fact] - public void ReplaceType() + public static string MetadataUpdateOriginalTypeAttributeSource = @" +namespace System.Runtime.CompilerServices +{ + [AttributeUsage(System.AttributeTargets.Class | System.AttributeTargets.Struct, AllowMultiple=false, Inherited=false)] + public class MetadataUpdateOriginalTypeAttribute : Attribute + { + public MetadataUpdateOriginalTypeAttribute(Type originalType) => OriginalType = originalType; + public Type OriginalType { get; } + } +} +"; + + public static string BadMetadataUpdateOriginalTypeAttributeSource = @" +namespace System.Runtime.CompilerServices +{ + [AttributeUsage(System.AttributeTargets.Class | System.AttributeTargets.Struct, AllowMultiple=false, Inherited=false)] + public class MetadataUpdateOriginalTypeAttribute : Attribute + { + public MetadataUpdateOriginalTypeAttribute(object originalType) => OriginalType = (Type)originalType; + public Type OriginalType { get; } + } +} +"; + + [Theory] + [CombinatorialData] + public void ReplaceType(bool hasAttribute) { + // using incorrect definition of the attribute so that it's easier to compare the two emit results (having and attribute and not having one): + var attributeSource = hasAttribute ? MetadataUpdateOriginalTypeAttributeSource : BadMetadataUpdateOriginalTypeAttributeSource; + var source0 = @" class C { void F(int x) {} -} -"; +}" + attributeSource; var source1 = @" class C { void F(int x, int y) { } -}"; +}" + attributeSource; var source2 = @" class C { void F(int x, int y) { System.Console.WriteLine(1); } -}"; +}" + attributeSource; var source3 = @" [System.Obsolete] class C { void F(int x, int y) { System.Console.WriteLine(2); } -}"; +}" + attributeSource; var compilation0 = CreateCompilation(source0, options: TestOptions.DebugDll, targetFramework: TargetFramework.NetStandard20); var compilation1 = compilation0.WithSource(source1); @@ -3247,77 +3539,99 @@ class C using var md0 = ModuleMetadata.CreateFromImage(bytes0); var reader0 = md0.MetadataReader; - CheckNames(reader0, reader0.GetTypeDefNames(), "", "C"); + CheckNames(reader0, reader0.GetTypeDefNames(), "", "C", "MetadataUpdateOriginalTypeAttribute"); var generation0 = EmitBaseline.CreateInitialBaseline( md0, EmptyLocalsProvider); + var baseTypeCount = reader0.TypeDefinitions.Count; + var baseMethodCount = reader0.MethodDefinitions.Count; + var baseAttributeCount = reader0.CustomAttributes.Count; + var baseParameterCount = reader0.GetParameters().Count(); + + Assert.Equal(3, baseTypeCount); + Assert.Equal(4, baseMethodCount); + Assert.Equal(7, baseAttributeCount); + Assert.Equal(2, baseParameterCount); + + var attributeTypeDefHandle = reader0.TypeDefinitions.Single(d => reader0.StringComparer.Equals(reader0.GetTypeDefinition(d).Name, "MetadataUpdateOriginalTypeAttribute")); + var attributeCtorDefHandle = reader0.MethodDefinitions.Single(d => + { + var methodDef = reader0.GetMethodDefinition(d); + return methodDef.GetDeclaringType() == attributeTypeDefHandle && reader0.StringComparer.Equals(methodDef.Name, ".ctor"); + }); + + void ValidateReplacedType(CompilationDifference diff, MetadataReader[] readers) + { + var generation = diff.NextGeneration.Ordinal; + var reader = readers[generation]; + + CheckNames(readers, diff.EmitResult.ChangedTypes, "C#" + generation); + CheckNames(readers, reader.GetTypeDefNames(), "C#" + generation); + + CheckEncLogDefinitions(reader, + Row(baseTypeCount + generation, TableIndex.TypeDef, EditAndContinueOperation.Default), // adding a type def + Row(baseTypeCount + generation, TableIndex.TypeDef, EditAndContinueOperation.AddMethod), + Row(baseMethodCount + generation * 2 - 1, TableIndex.MethodDef, EditAndContinueOperation.Default), + Row(baseTypeCount + generation, TableIndex.TypeDef, EditAndContinueOperation.AddMethod), + Row(baseMethodCount + generation * 2, TableIndex.MethodDef, EditAndContinueOperation.Default), + Row(baseMethodCount + generation * 2 - 1, TableIndex.MethodDef, EditAndContinueOperation.AddParameter), + Row(baseParameterCount + generation * 2 - 1, TableIndex.Param, EditAndContinueOperation.Default), + Row(baseMethodCount + generation * 2 - 1, TableIndex.MethodDef, EditAndContinueOperation.AddParameter), + Row(baseParameterCount + generation * 2, TableIndex.Param, EditAndContinueOperation.Default), + hasAttribute ? Row(baseAttributeCount + generation, TableIndex.CustomAttribute, EditAndContinueOperation.Default) : default); // adding a new attribute row for attribute on C#* definition + + CheckEncMapDefinitions(reader, + Handle(baseTypeCount + generation, TableIndex.TypeDef), + Handle(baseMethodCount + generation * 2 - 1, TableIndex.MethodDef), + Handle(baseMethodCount + generation * 2, TableIndex.MethodDef), + Handle(baseParameterCount + generation * 2 - 1, TableIndex.Param), + Handle(baseParameterCount + generation * 2, TableIndex.Param), + hasAttribute ? Handle(baseAttributeCount + generation, TableIndex.CustomAttribute) : default); + + var newTypeDefHandle = reader.TypeDefinitions.Single(); + var newTypeDef = reader.GetTypeDefinition(newTypeDefHandle); + CheckStringValue(readers, newTypeDef.Name, "C#" + generation); + + if (hasAttribute) + { + var attribute = reader.GetCustomAttribute(reader.CustomAttributes.Single()); + + // parent should be C#1 + var aggregator = GetAggregator(readers); + var parentHandle = aggregator.GetGenerationHandle(attribute.Parent, out var parentGeneration); + Assert.Equal(generation, parentGeneration); + Assert.Equal(newTypeDefHandle, parentHandle); + + // attribute contructor should match + var ctorHandle = aggregator.GetGenerationHandle(attribute.Constructor, out var ctorGeneration); + Assert.Equal(0, ctorGeneration); + Assert.Equal(attributeCtorDefHandle, ctorHandle); + + // The attribute value encodes serialized type name. It should be the base name "C", not "C#1". + CheckBlobValue(readers, attribute.Value, new byte[] { 0x01, 0x00, 0x01, (byte)'C', 0x00, 0x00 }); + } + } + // This update emulates "Reloadable" type behavior - a new type is generated instead of updating the existing one. var diff1 = compilation1.EmitDifference( generation0, ImmutableArray.Create( SemanticEdit.Create(SemanticEditKind.Replace, null, c1))); - // Verify delta metadata contains expected rows. using var md1 = diff1.GetMetadata(); - var reader1 = md1.Reader; - var readers = new[] { reader0, reader1 }; + ValidateReplacedType(diff1, new[] { reader0, md1.Reader }); - CheckNames(readers, reader1.GetTypeDefNames(), "C#1"); - CheckNames(readers, diff1.EmitResult.ChangedTypes, "C#1"); - - CheckEncLogDefinitions(reader1, - Row(3, TableIndex.TypeDef, EditAndContinueOperation.Default), - Row(3, TableIndex.TypeDef, EditAndContinueOperation.AddMethod), - Row(3, TableIndex.MethodDef, EditAndContinueOperation.Default), - Row(3, TableIndex.TypeDef, EditAndContinueOperation.AddMethod), - Row(4, TableIndex.MethodDef, EditAndContinueOperation.Default), - Row(3, TableIndex.MethodDef, EditAndContinueOperation.AddParameter), - Row(2, TableIndex.Param, EditAndContinueOperation.Default), - Row(3, TableIndex.MethodDef, EditAndContinueOperation.AddParameter), - Row(3, TableIndex.Param, EditAndContinueOperation.Default)); - - CheckEncMapDefinitions(reader1, - Handle(3, TableIndex.TypeDef), - Handle(3, TableIndex.MethodDef), - Handle(4, TableIndex.MethodDef), - Handle(2, TableIndex.Param), - Handle(3, TableIndex.Param)); - - // This update emulates "Reloadable" type behavior - a new type is generated instead of updating the existing one. var diff2 = compilation2.EmitDifference( diff1.NextGeneration, ImmutableArray.Create( SemanticEdit.Create(SemanticEditKind.Replace, null, c2))); - // Verify delta metadata contains expected rows. using var md2 = diff2.GetMetadata(); - var reader2 = md2.Reader; - readers = new[] { reader0, reader1, reader2 }; - - CheckNames(readers, reader2.GetTypeDefNames(), "C#2"); - CheckNames(readers, diff2.EmitResult.ChangedTypes, "C#2"); + ValidateReplacedType(diff2, new[] { reader0, md1.Reader, md2.Reader }); - CheckEncLogDefinitions(reader2, - Row(4, TableIndex.TypeDef, EditAndContinueOperation.Default), - Row(4, TableIndex.TypeDef, EditAndContinueOperation.AddMethod), - Row(5, TableIndex.MethodDef, EditAndContinueOperation.Default), - Row(4, TableIndex.TypeDef, EditAndContinueOperation.AddMethod), - Row(6, TableIndex.MethodDef, EditAndContinueOperation.Default), - Row(5, TableIndex.MethodDef, EditAndContinueOperation.AddParameter), - Row(4, TableIndex.Param, EditAndContinueOperation.Default), - Row(5, TableIndex.MethodDef, EditAndContinueOperation.AddParameter), - Row(5, TableIndex.Param, EditAndContinueOperation.Default)); - - CheckEncMapDefinitions(reader2, - Handle(4, TableIndex.TypeDef), - Handle(5, TableIndex.MethodDef), - Handle(6, TableIndex.MethodDef), - Handle(4, TableIndex.Param), - Handle(5, TableIndex.Param)); - - // This update is an EnC update - even reloadable types are update in-place + // This update is an EnC update - even reloadable types are updated in-place var diff3 = compilation3.EmitDifference( diff2.NextGeneration, ImmutableArray.Create( @@ -3327,24 +3641,28 @@ class C // Verify delta metadata contains expected rows. using var md3 = diff3.GetMetadata(); var reader3 = md3.Reader; - readers = new[] { reader0, reader1, reader2, reader3 }; + var readers = new[] { reader0, md1.Reader, md2.Reader, reader3 }; CheckNames(readers, reader3.GetTypeDefNames(), "C#2"); CheckNames(readers, diff3.EmitResult.ChangedTypes, "C#2"); + // Obsolete attribute is added. MetadataUpdateOriginalTypeAttribute is still present on the type. CheckEncLogDefinitions(reader3, - Row(4, TableIndex.TypeDef, EditAndContinueOperation.Default), - Row(5, TableIndex.MethodDef, EditAndContinueOperation.Default), - Row(4, TableIndex.Param, EditAndContinueOperation.Default), + Row(5, TableIndex.TypeDef, EditAndContinueOperation.Default), + Row(7, TableIndex.MethodDef, EditAndContinueOperation.Default), Row(5, TableIndex.Param, EditAndContinueOperation.Default), - Row(4, TableIndex.CustomAttribute, EditAndContinueOperation.Default)); + Row(6, TableIndex.Param, EditAndContinueOperation.Default), + Row(hasAttribute ? 9 : 8, TableIndex.CustomAttribute, EditAndContinueOperation.Default)); CheckEncMapDefinitions(reader3, - Handle(4, TableIndex.TypeDef), - Handle(5, TableIndex.MethodDef), - Handle(4, TableIndex.Param), + Handle(5, TableIndex.TypeDef), + Handle(7, TableIndex.MethodDef), Handle(5, TableIndex.Param), - Handle(4, TableIndex.CustomAttribute)); + Handle(6, TableIndex.Param), + Handle(hasAttribute ? 9 : 8, TableIndex.CustomAttribute)); + + // Obsolete attribute: + CheckBlobValue(readers, reader3.GetCustomAttribute(reader3.CustomAttributes.First()).Value, new byte[] { 0x01, 0x00, 0x00, 0x00 }); } [Fact] @@ -9433,6 +9751,64 @@ .maxstack 1 }"); } + [Fact] + public void Operator_Delete() + { + using var _ = new EditAndContinueTest(options: TestOptions.DebugDll, targetFramework: TargetFramework.NetStandard20) + .AddGeneration( + source: $$""" + class C + { + public static bool operator !(C c) => true; + } + """, + validator: g => + { + g.VerifyTypeDefNames("", "C"); + g.VerifyMethodDefNames("op_LogicalNot", ".ctor"); + g.VerifyMemberRefNames(/*CompilationRelaxationsAttribute.*/".ctor", /*RuntimeCompatibilityAttribute.*/".ctor", /*Object.*/".ctor", /*DebuggableAttribute*/".ctor"); + }) + + .AddGeneration( + source: """ + class C + { + } + """, + edits: new[] { + Edit(SemanticEditKind.Delete, symbolProvider: c => c.GetMember("C.op_LogicalNot"), newSymbolProvider: c => c.GetMember("C")), + }, + validator: g => + { + g.VerifyTypeDefNames(); + g.VerifyMethodDefNames("op_LogicalNot"); + g.VerifyMemberRefNames(/* MissingMethodException */ ".ctor"); + g.VerifyEncLogDefinitions(new[] + { + Row(1, TableIndex.MethodDef, EditAndContinueOperation.Default), + Row(1, TableIndex.Param, EditAndContinueOperation.Default), + }); + g.VerifyEncMapDefinitions(new[] + { + Handle(1, TableIndex.MethodDef), + Handle(1, TableIndex.Param), + }); + + var expectedIL = """ + { + // Code size 6 (0x6) + .maxstack 8 + IL_0000: newobj 0x0A000005 + IL_0005: throw + } + """; + + // Can't verify the IL of individual methods because that requires IMethodSymbolInternal implementations + g.VerifyIL(expectedIL); + }) + .Verify(); + } + /// /// Should use TypeDef rather than TypeRef for unrecognized /// local of a type defined in the original assembly. @@ -13302,7 +13678,7 @@ void M1() { } } """, edits: new[] { - Edit(SemanticEditKind.Delete, symbolProvider: c => c.GetMember("C.M2"), newSymbolProvider: c=>c.GetMember("C")), + Edit(SemanticEditKind.Delete, symbolProvider: c => c.GetMember("C.M2"), newSymbolProvider: c => c.GetMember("C")), }, validator: g => { @@ -13357,7 +13733,7 @@ class C } """, edits: new[] { - Edit(SemanticEditKind.Delete, symbolProvider: c => c.GetMember("C.M1"), newSymbolProvider: c=>c.GetMember("C")), + Edit(SemanticEditKind.Delete, symbolProvider: c => c.GetMember("C.M1"), newSymbolProvider: c => c.GetMember("C")), }, validator: g => { @@ -13459,7 +13835,7 @@ class C } """, edits: new[] { - Edit(SemanticEditKind.Delete, symbolProvider: c => c.GetMember("C.M1"), newSymbolProvider: c=>c.GetMember("C")), + Edit(SemanticEditKind.Delete, symbolProvider: c => c.GetMember("C.M1"), newSymbolProvider: c => c.GetMember("C")), }, validator: g => { @@ -13636,7 +14012,7 @@ void Goo() { } } """, edits: new[] { - Edit(SemanticEditKind.Delete, symbolProvider: c => c.GetMember("C.M1"), newSymbolProvider: c=>c.GetMember("C")), + Edit(SemanticEditKind.Delete, symbolProvider: c => c.GetMember("C.M1"), newSymbolProvider: c => c.GetMember("C")), }, validator: g => { @@ -13716,5 +14092,517 @@ .maxstack 1 }) .Verify(); } + + [Fact] + public void Method_Rename_Multiple() + { + using var test = new EditAndContinueTest(options: TestOptions.DebugDll, targetFramework: TargetFramework.NetStandard20) + .AddGeneration( + source: $$""" + class C + { + int M1() { return 0; } + } + """, + validator: g => + { + g.VerifyTypeDefNames("", "C"); + g.VerifyMethodDefNames("M1", ".ctor"); + g.VerifyMemberRefNames(/*CompilationRelaxationsAttribute.*/".ctor", /*RuntimeCompatibilityAttribute.*/".ctor", /*Object.*/".ctor", /*DebuggableAttribute*/".ctor"); + }); + + for (int i = 0; i < 10; i++) + { + test.AddGeneration( + source: @$" +class C +{{ + int M2() {{ return {i}; }} +}}", + edits: new[] { + Edit(SemanticEditKind.Delete, symbolProvider: c => c.GetMember("C.M1"), newSymbolProvider: c => c.GetMember("C")), + Edit(SemanticEditKind.Insert, symbolProvider: c => c.GetMember("C.M2")), + }, + validator: g => + { + g.VerifyTypeDefNames(); + g.VerifyMethodDefNames("M1", "M2"); + g.VerifyDeletedMembers("C: {M1}"); + }) + .AddGeneration( + source: @$" +class C +{{ + int M1() {{ return {i}; }} +}}", + edits: new[] { + Edit(SemanticEditKind.Delete, symbolProvider: c => c.GetMember("C.M2"), newSymbolProvider: c => c.GetMember("C")), + Edit(SemanticEditKind.Insert, symbolProvider: c => c.GetMember("C.M1")), + }, + validator: g => + { + g.VerifyTypeDefNames(); + g.VerifyMethodDefNames("M1", "M2"); + g.VerifyDeletedMembers("C: {M2}"); + }); + } + + test.Verify(); + } + + [Fact] + public void Method_ChangeParameterType() + { + using var _ = new EditAndContinueTest(options: TestOptions.DebugDll, targetFramework: TargetFramework.NetStandard20) + .AddGeneration( + source: $$""" + class C + { + void M(int someInt) { someInt.ToString(); } + } + """, + validator: g => + { + g.VerifyTypeDefNames("", "C"); + g.VerifyMethodDefNames("M", ".ctor"); + }) + .AddGeneration( + source: $$""" + class C + { + void M(bool someBool) { someBool.ToString(); } + } + """, + edits: new[] { + Edit(SemanticEditKind.Delete, symbolProvider: c => c.GetMembers("C.M").FirstOrDefault(m => m.GetParameterTypes()[0].SpecialType == SpecialType.System_Int32)?.ISymbol, newSymbolProvider: c=>c.GetMember("C")), + Edit(SemanticEditKind.Insert, symbolProvider: c => c.GetMembers("C.M").FirstOrDefault(m => m.GetParameterTypes()[0].SpecialType == SpecialType.System_Boolean)?.ISymbol), + }, + validator: g => + { + g.VerifyTypeDefNames(); + g.VerifyMethodDefNames("M", "M"); + g.VerifyDeletedMembers("C: {M}"); + + g.VerifyEncLogDefinitions(new[] + { + Row(1, TableIndex.MethodDef, EditAndContinueOperation.Default), + Row(2, TableIndex.TypeDef, EditAndContinueOperation.AddMethod), + Row(3, TableIndex.MethodDef, EditAndContinueOperation.Default), + Row(1, TableIndex.Param, EditAndContinueOperation.Default), + Row(3, TableIndex.MethodDef, EditAndContinueOperation.AddParameter), + Row(2, TableIndex.Param, EditAndContinueOperation.Default) + }); + g.VerifyEncMapDefinitions(new[] + { + Handle(1, TableIndex.MethodDef), + Handle(3, TableIndex.MethodDef), + Handle(1, TableIndex.Param), + Handle(2, TableIndex.Param) + }); + + var expectedIL = """ + { + // Code size 6 (0x6) + .maxstack 8 + IL_0000: newobj 0x0A000006 + IL_0005: throw + } + { + // Code size 10 (0xa) + .maxstack 8 + IL_0000: nop + IL_0001: ldarga.s V_1 + IL_0003: call 0x0A000007 + IL_0008: pop + IL_0009: ret + } + """; + + // Can't verify the IL of individual methods because that requires IMethodSymbolInternal implementations + g.VerifyIL(expectedIL); + }) + .AddGeneration( + source: $$""" + class C + { + void M(int someInt) { someInt.ToString(); } + } + """, + edits: new[] { + Edit(SemanticEditKind.Delete, symbolProvider: c => c.GetMembers("C.M").FirstOrDefault(m => m.GetParameterTypes()[0].SpecialType == SpecialType.System_Boolean)?.ISymbol, newSymbolProvider: c=>c.GetMember("C")), + Edit(SemanticEditKind.Insert, symbolProvider: c => c.GetMembers("C.M").FirstOrDefault(m => m.GetParameterTypes()[0].SpecialType == SpecialType.System_Int32)?.ISymbol), + }, + validator: g => + { + g.VerifyTypeDefNames(); + g.VerifyMethodDefNames("M", "M"); + g.VerifyDeletedMembers("C: {M}"); + + g.VerifyEncLogDefinitions(new[] + { + Row(1, TableIndex.MethodDef, EditAndContinueOperation.Default), + Row(3, TableIndex.MethodDef, EditAndContinueOperation.Default), + Row(1, TableIndex.Param, EditAndContinueOperation.Default), + Row(2, TableIndex.Param, EditAndContinueOperation.Default) + }); + g.VerifyEncMapDefinitions(new[] + { + Handle(1, TableIndex.MethodDef), + Handle(3, TableIndex.MethodDef), + Handle(1, TableIndex.Param), + Handle(2, TableIndex.Param) + }); + + var expectedIL = """ + { + // Code size 10 (0xa) + .maxstack 8 + IL_0000: nop + IL_0001: ldarga.s V_1 + IL_0003: call 0x0A000008 + IL_0008: pop + IL_0009: ret + } + { + // Code size 6 (0x6) + .maxstack 8 + IL_0000: newobj 0x0A000009 + IL_0005: throw + } + """; + + // Can't verify the IL of individual methods because that requires IMethodSymbolInternal implementations + g.VerifyIL(expectedIL); + }) + .Verify(); + } + + [Fact] + public void FileTypes_01() + { + var source0 = MarkedSource(@" +using System; +file class C +{ + void M() + { + Console.Write(1); + } +}", "file1.cs"); + var source1 = MarkedSource(@" +using System; +file class C +{ + void M() + { + Console.Write(2); + } +}", "file1.cs"); + + var compilation0 = CreateCompilation(source0.Tree, options: ComSafeDebugDll); + var compilation1 = compilation0.WithSource(source1.Tree); + + var method0 = compilation0.GetMember("C.M"); + var method1 = compilation1.GetMember("C.M"); + + var v0 = CompileAndVerify(compilation0, verify: Verification.Skipped); + + v0.VerifyIL("C@file1.M", @" +{ + // Code size 9 (0x9) + .maxstack 1 + IL_0000: nop + IL_0001: ldc.i4.1 + IL_0002: call ""void System.Console.Write(int)"" + IL_0007: nop + IL_0008: ret +} +"); + + using var md0 = ModuleMetadata.CreateFromImage(v0.EmittedAssemblyData); + + var generation0 = EmitBaseline.CreateInitialBaseline(md0, v0.CreateSymReader().GetEncMethodDebugInfo); + + var diff = compilation1.EmitDifference( + generation0, + ImmutableArray.Create( + SemanticEdit.Create(SemanticEditKind.Update, method0, method1, GetSyntaxMapFromMarkers(source0, source1), preserveLocalVariables: true))); + + // There should be no diagnostics from rude edits + diff.EmitResult.Diagnostics.Verify(); + + diff.VerifyIL("C@file1.M", @" +{ + // Code size 9 (0x9) + .maxstack 1 + IL_0000: nop + IL_0001: ldc.i4.2 + IL_0002: call ""void System.Console.Write(int)"" + IL_0007: nop + IL_0008: ret +}"); + } + + [Fact] + public void FileTypes_02() + { + var source0 = MarkedSource(@" +using System; +file class C +{ + void M() + { + Console.Write(1); + } +}", "file1.cs"); + var source1 = MarkedSource(@" +using System; +file class C +{ + void M() + { + Console.Write(2); + } +}", "file1.cs"); + var source2 = MarkedSource(@" +using System; +file class C +{ + void M() + { + Console.Write(3); + } +}", "file2.cs"); + + var compilation0 = CreateCompilation(source0.Tree, options: ComSafeDebugDll); + var compilation1 = compilation0.WithSource(new[] { source1.Tree, source2.Tree }); + + var cm1_gen0 = compilation0.GetMember("C.M"); + var cm1_gen1 = ((NamedTypeSymbol)compilation1.GetMembers("C")[0]).GetMember("M"); + var c2_gen1 = ((NamedTypeSymbol)compilation1.GetMembers("C")[1]); + + var v0 = CompileAndVerify(compilation0, verify: Verification.Skipped); + + v0.VerifyIL("C@file1.M", @" +{ + // Code size 9 (0x9) + .maxstack 1 + IL_0000: nop + IL_0001: ldc.i4.1 + IL_0002: call ""void System.Console.Write(int)"" + IL_0007: nop + IL_0008: ret +} +"); + + using var md0 = ModuleMetadata.CreateFromImage(v0.EmittedAssemblyData); + + var generation0 = EmitBaseline.CreateInitialBaseline(md0, v0.CreateSymReader().GetEncMethodDebugInfo); + + var diff = compilation1.EmitDifference( + generation0, + ImmutableArray.Create( + SemanticEdit.Create(SemanticEditKind.Update, cm1_gen0, cm1_gen1, GetSyntaxMapFromMarkers(source0, source1), preserveLocalVariables: true), + SemanticEdit.Create(SemanticEditKind.Insert, null, c2_gen1, syntaxMap: null, preserveLocalVariables: true))); + + // There should be no diagnostics from rude edits + diff.EmitResult.Diagnostics.Verify(); + + diff.VerifyIL("C@file1.M", @" +{ + // Code size 9 (0x9) + .maxstack 1 + IL_0000: nop + IL_0001: ldc.i4.2 + IL_0002: call ""void System.Console.Write(int)"" + IL_0007: nop + IL_0008: ret +}"); + + diff.VerifyIL("C@file2.M", @" +{ + // Code size 9 (0x9) + .maxstack 1 + IL_0000: nop + IL_0001: ldc.i4.3 + IL_0002: call ""void System.Console.Write(int)"" + IL_0007: nop + IL_0008: ret +}"); + } + + [Fact] + public void FileTypes_03() + { + var source0_gen0 = MarkedSource(@" +using System; +file class C +{ + void M() + { + Console.Write(1); + } +}", "file1.cs"); + var source1_gen1 = MarkedSource(@" +using System; +file class C +{ + void M() + { + Console.Write(2); + } +}", "file2.cs"); + var source0_gen1 = MarkedSource(@" +using System; +file class C +{ + void M() + { + Console.Write(3); + } +}", "file1.cs"); + + var compilation0 = CreateCompilation(source0_gen0.Tree, options: ComSafeDebugDll); + // Because the order of syntax trees has changed here, the original type is considered deleted and the two new types are completely new, unrelated types. + + // https://github.com/dotnet/roslyn/issues/61999 + // we should handle this as a modification of an existing type rather than deletion and insertion of distinct types. + // most likely, we either need to identify file types based on something stable like the SyntaxTree.FilePath, or store a mapping of the ordinals from one generation to the next. + // although "real-world" compilations disallow duplicated file paths, duplicated or empty file paths are very common via direct use of the APIs, so there's not necessarily a single slam-dunk answer here. + var compilation1 = compilation0.WithSource(new[] { source1_gen1.Tree, source0_gen1.Tree }); + + var c1_gen0 = compilation0.GetMember("C"); + var c1_gen1 = ((NamedTypeSymbol)compilation1.GetMembers("C")[0]); + var c2_gen1 = ((NamedTypeSymbol)compilation1.GetMembers("C")[1]); + + var v0 = CompileAndVerify(compilation0, verify: Verification.Skipped); + + v0.VerifyIL("C@file1.M", @" +{ + // Code size 9 (0x9) + .maxstack 1 + IL_0000: nop + IL_0001: ldc.i4.1 + IL_0002: call ""void System.Console.Write(int)"" + IL_0007: nop + IL_0008: ret +} +"); + + using var md0 = ModuleMetadata.CreateFromImage(v0.EmittedAssemblyData); + + var generation0 = EmitBaseline.CreateInitialBaseline(md0, v0.CreateSymReader().GetEncMethodDebugInfo); + + var diff = compilation1.EmitDifference( + generation0, + ImmutableArray.Create( + SemanticEdit.Create(SemanticEditKind.Delete, c1_gen0, null, syntaxMap: null, preserveLocalVariables: true), + SemanticEdit.Create(SemanticEditKind.Insert, null, c1_gen1, syntaxMap: null, preserveLocalVariables: true), + SemanticEdit.Create(SemanticEditKind.Insert, null, c2_gen1, syntaxMap: null, preserveLocalVariables: true))); + + // There should be no diagnostics from rude edits + diff.EmitResult.Diagnostics.Verify(); + + diff.VerifyIL("C@file1.M", @" +{ + // Code size 9 (0x9) + .maxstack 1 + IL_0000: nop + IL_0001: ldc.i4.3 + IL_0002: call ""void System.Console.Write(int)"" + IL_0007: nop + IL_0008: ret +}"); + + diff.VerifyIL("C@file2.M", @" +{ + // Code size 9 (0x9) + .maxstack 1 + IL_0000: nop + IL_0001: ldc.i4.2 + IL_0002: call ""void System.Console.Write(int)"" + IL_0007: nop + IL_0008: ret +}"); + } + + [Fact] + public void FileTypes_04() + { + var source1_gen0 = MarkedSource(@" +using System; +file class C +{ + void M() + { + Console.Write(1); + } +}", "file1.cs"); + var source2_gen0 = MarkedSource(@" +using System; +file class C +{ + void M() + { + Console.Write(2); + } +}", "file2.cs"); + var source2_gen1 = MarkedSource(@" +using System; +file class C +{ + void M() + { + Console.Write(3); + } +}", "file2.cs"); + + var compilation0 = CreateCompilation(new[] { source1_gen0.Tree, source2_gen0.Tree }, options: ComSafeDebugDll); + + var compilation1 = compilation0.WithSource(new[] { source2_gen1.Tree }); + + var c1_gen0 = ((NamedTypeSymbol)compilation0.GetMembers("C")[0]); + var c2_gen0 = ((NamedTypeSymbol)compilation0.GetMembers("C")[1]); + var c2_gen1 = compilation1.GetMember("C"); + + var v0 = CompileAndVerify(compilation0, verify: Verification.Skipped); + + v0.VerifyIL("C@file2.M", @" +{ + // Code size 9 (0x9) + .maxstack 1 + IL_0000: nop + IL_0001: ldc.i4.2 + IL_0002: call ""void System.Console.Write(int)"" + IL_0007: nop + IL_0008: ret +} +"); + + using var md0 = ModuleMetadata.CreateFromImage(v0.EmittedAssemblyData); + + var generation0 = EmitBaseline.CreateInitialBaseline(md0, v0.CreateSymReader().GetEncMethodDebugInfo); + + var diff = compilation1.EmitDifference( + generation0, + ImmutableArray.Create( + SemanticEdit.Create(SemanticEditKind.Delete, c1_gen0, null, syntaxMap: null, preserveLocalVariables: true), + SemanticEdit.Create(SemanticEditKind.Delete, c2_gen0, null, syntaxMap: null, preserveLocalVariables: true), + SemanticEdit.Create(SemanticEditKind.Insert, null, c2_gen1, syntaxMap: null, preserveLocalVariables: true))); + + // There should be no diagnostics from rude edits + diff.EmitResult.Diagnostics.Verify(); + + diff.VerifyIL("C@file2.M", @" +{ + // Code size 9 (0x9) + .maxstack 1 + IL_0000: nop + IL_0001: ldc.i4.3 + IL_0002: call ""void System.Console.Write(int)"" + IL_0007: nop + IL_0008: ret +}"); + } } } diff --git a/src/Compilers/CSharp/Test/Emit/PDB/PDBTests.cs b/src/Compilers/CSharp/Test/Emit/PDB/PDBTests.cs index a20ca98ab257f..067247d66b484 100644 --- a/src/Compilers/CSharp/Test/Emit/PDB/PDBTests.cs +++ b/src/Compilers/CSharp/Test/Emit/PDB/PDBTests.cs @@ -5,6 +5,7 @@ #nullable disable using System; +using System.Collections.Generic; using System.IO; using System.Linq; using System.Reflection; @@ -20,6 +21,7 @@ using Microsoft.CodeAnalysis.Text; using Roslyn.Test.PdbUtilities; using Roslyn.Test.Utilities; +using Roslyn.Test.Utilities.TestGenerators; using Xunit; namespace Microsoft.CodeAnalysis.CSharp.UnitTests.PDB @@ -79,6 +81,44 @@ public void EmitDebugInfoForSourceTextWithoutEncoding2() ", options: PdbValidationOptions.ExcludeMethods); } + [Fact] + public void SourceGeneratedFiles() + { + Compilation compilation = CreateCompilation("class C { }", options: TestOptions.DebugDll, parseOptions: TestOptions.Regular); + compilation.VerifyDiagnostics(); + + Assert.Single(compilation.SyntaxTrees); + + var testGenerator = new TestSourceGenerator() + { + ExecuteImpl = context => + { + context.AddSource("hint1", "class G1 { void F() {} }"); + context.AddSource("hint2", SourceText.From("class G2 { void F() {} }", Encoding.UTF8, checksumAlgorithm: SourceHashAlgorithm.Sha256)); + + Assert.Throws(() => context.AddSource("hint3", SourceText.From("class G3 { void F() {} }", encoding: null, checksumAlgorithm: SourceHashAlgorithm.Sha256))); + } + }; + + var driver = CSharpGeneratorDriver.Create(new[] { testGenerator }, parseOptions: TestOptions.Regular); + driver.RunGeneratorsAndUpdateCompilation(compilation, out var outputCompilation, out _); + + var result = outputCompilation.Emit(new MemoryStream(), pdbStream: new MemoryStream()); + result.Diagnostics.Verify(); + Assert.True(result.Success); + + var path1 = Path.Combine("Microsoft.CodeAnalysis.Test.Utilities", "Roslyn.Test.Utilities.TestGenerators.TestSourceGenerator", "hint1.cs"); + var path2 = Path.Combine("Microsoft.CodeAnalysis.Test.Utilities", "Roslyn.Test.Utilities.TestGenerators.TestSourceGenerator", "hint2.cs"); + + outputCompilation.VerifyPdb($@" + + + + + +", options: PdbValidationOptions.ExcludeMethods); + } + [WorkItem(846584, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/846584")] [ConditionalFact(typeof(WindowsOnly))] public void RelativePathForExternalSource_Sha1_Windows() diff --git a/src/Compilers/CSharp/Test/Emit2/Attributes/AttributeTests.cs b/src/Compilers/CSharp/Test/Emit2/Attributes/AttributeTests.cs index 60da94c4657fb..6fc4dd25fc3f9 100644 --- a/src/Compilers/CSharp/Test/Emit2/Attributes/AttributeTests.cs +++ b/src/Compilers/CSharp/Test/Emit2/Attributes/AttributeTests.cs @@ -5801,14 +5801,14 @@ class Goo } "; - var compilation = CreateCompilation(source, parseOptions: TestOptions.Regular9); + var compilation = CreateCompilation(source, parseOptions: TestOptions.Regular10); compilation.VerifyDiagnostics( // (2,2): error CS0616: 'Goo' is not an attribute class // [Goo] Diagnostic(ErrorCode.ERR_NotAnAttributeClass, "Goo").WithArguments("Goo").WithLocation(2, 2), - // (2,2): error CS8652: The feature 'generic attributes' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // (2,2): error CS8936: Feature 'generic attributes' is not available in C# 10.0. Please use language version 11.0 or greater. // [Goo] - Diagnostic(ErrorCode.ERR_FeatureInPreview, "Goo").WithArguments("generic attributes").WithLocation(2, 2)); + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "Goo").WithArguments("generic attributes", "11.0").WithLocation(2, 2)); compilation = CreateCompilation(source, parseOptions: TestOptions.RegularPreview); compilation.VerifyDiagnostics( @@ -5861,14 +5861,14 @@ class Goo } "; - var compilation = CreateCompilation(source, parseOptions: TestOptions.Regular9); + var compilation = CreateCompilation(source, parseOptions: TestOptions.Regular10); compilation.VerifyDiagnostics( // (2,2): error CS0616: 'Goo' is not an attribute class // [Goo] Diagnostic(ErrorCode.ERR_NotAnAttributeClass, "Goo").WithArguments("Goo").WithLocation(2, 2), - // (2,2): error CS8652: The feature 'generic attributes' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // (2,2): error CS8936: Feature 'generic attributes' is not available in C# 10.0. Please use language version 11.0 or greater. // [Goo] - Diagnostic(ErrorCode.ERR_FeatureInPreview, "Goo").WithArguments("generic attributes").WithLocation(2, 2)); + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "Goo").WithArguments("generic attributes", "11.0").WithLocation(2, 2)); compilation = CreateCompilation(source, parseOptions: TestOptions.RegularPreview); compilation.VerifyDiagnostics( @@ -7432,12 +7432,12 @@ public static int Main() }"; CSharpCompilationOptions opt = TestOptions.ReleaseDll; - var compilation = CreateCompilation(source, null, options: opt, parseOptions: TestOptions.Regular9); + var compilation = CreateCompilation(source, null, options: opt, parseOptions: TestOptions.Regular10); compilation.VerifyDiagnostics( - // (3,16): error CS8652: The feature 'generic attributes' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // (3,16): error CS8936: Feature 'generic attributes' is not available in C# 10.0. Please use language version 11.0 or greater. // class Gen2: System.Attribute {} - Diagnostic(ErrorCode.ERR_FeatureInPreview, "System.Attribute").WithArguments("generic attributes").WithLocation(3, 16), + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "System.Attribute").WithArguments("generic attributes", "11.0").WithLocation(3, 16), // (5,2): error CS0616: 'Gen' is not an attribute class // [Gen] Diagnostic(ErrorCode.ERR_NotAnAttributeClass, "Gen").WithArguments("Gen").WithLocation(5, 2), @@ -8406,32 +8406,32 @@ public class C : Attribute // 20 } "; - var comp = CreateCompilation(source, parseOptions: TestOptions.Regular9); + var comp = CreateCompilation(source, parseOptions: TestOptions.Regular10); comp.VerifyDiagnostics( // (4,2): error CS0308: The non-generic type 'A' cannot be used with type arguments // [A<>] // 1, 2 Diagnostic(ErrorCode.ERR_HasNoTypeVars, "A<>").WithArguments("A", "type").WithLocation(4, 2), - // (4,2): error CS8652: The feature 'generic attributes' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // (4,2): error CS8936: Feature 'generic attributes' is not available in C# 10.0. Please use language version 11.0 or greater. // [A<>] // 1, 2 - Diagnostic(ErrorCode.ERR_FeatureInPreview, "A<>").WithArguments("generic attributes").WithLocation(4, 2), + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "A<>").WithArguments("generic attributes", "11.0").WithLocation(4, 2), // (5,2): error CS0308: The non-generic type 'A' cannot be used with type arguments // [A] // 3, 4 Diagnostic(ErrorCode.ERR_HasNoTypeVars, "A").WithArguments("A", "type").WithLocation(5, 2), - // (5,2): error CS8652: The feature 'generic attributes' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // (5,2): error CS8936: Feature 'generic attributes' is not available in C# 10.0. Please use language version 11.0 or greater. // [A] // 3, 4 - Diagnostic(ErrorCode.ERR_FeatureInPreview, "A").WithArguments("generic attributes").WithLocation(5, 2), + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "A").WithArguments("generic attributes", "11.0").WithLocation(5, 2), // (6,2): error CS0305: Using the generic type 'B' requires 1 type arguments // [B] // 5 Diagnostic(ErrorCode.ERR_BadArity, "B").WithArguments("B", "type", "1").WithLocation(6, 2), // (7,2): error CS7003: Unexpected use of an unbound generic name // [B<>] // 6, 7 Diagnostic(ErrorCode.ERR_UnexpectedUnboundGenericName, "B<>").WithLocation(7, 2), - // (7,2): error CS8652: The feature 'generic attributes' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // (7,2): error CS8936: Feature 'generic attributes' is not available in C# 10.0. Please use language version 11.0 or greater. // [B<>] // 6, 7 - Diagnostic(ErrorCode.ERR_FeatureInPreview, "B<>").WithArguments("generic attributes").WithLocation(7, 2), - // (8,2): error CS8652: The feature 'generic attributes' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "B<>").WithArguments("generic attributes", "11.0").WithLocation(7, 2), + // (8,2): error CS8936: Feature 'generic attributes' is not available in C# 10.0. Please use language version 11.0 or greater. // [B] // 8, 9 - Diagnostic(ErrorCode.ERR_FeatureInPreview, "B").WithArguments("generic attributes").WithLocation(8, 2), + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "B").WithArguments("generic attributes", "11.0").WithLocation(8, 2), // (8,2): error CS0579: Duplicate 'B<>' attribute // [B] // 8, 9 Diagnostic(ErrorCode.ERR_DuplicateAttribute, "B").WithArguments("B<>").WithLocation(8, 2), @@ -8441,33 +8441,33 @@ public class C : Attribute // 20 // (10,2): error CS0305: Using the generic type 'C' requires 2 type arguments // [C<>] // 11, 12 Diagnostic(ErrorCode.ERR_BadArity, "C<>").WithArguments("C", "type", "2").WithLocation(10, 2), - // (10,2): error CS8652: The feature 'generic attributes' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // (10,2): error CS8936: Feature 'generic attributes' is not available in C# 10.0. Please use language version 11.0 or greater. // [C<>] // 11, 12 - Diagnostic(ErrorCode.ERR_FeatureInPreview, "C<>").WithArguments("generic attributes").WithLocation(10, 2), + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "C<>").WithArguments("generic attributes", "11.0").WithLocation(10, 2), // (11,2): error CS0305: Using the generic type 'C' requires 2 type arguments // [C] // 13, 14 Diagnostic(ErrorCode.ERR_BadArity, "C").WithArguments("C", "type", "2").WithLocation(11, 2), - // (11,2): error CS8652: The feature 'generic attributes' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // (11,2): error CS8936: Feature 'generic attributes' is not available in C# 10.0. Please use language version 11.0 or greater. // [C] // 13, 14 - Diagnostic(ErrorCode.ERR_FeatureInPreview, "C").WithArguments("generic attributes").WithLocation(11, 2), + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "C").WithArguments("generic attributes", "11.0").WithLocation(11, 2), // (12,2): error CS7003: Unexpected use of an unbound generic name // [C<,>] // 15, 16 Diagnostic(ErrorCode.ERR_UnexpectedUnboundGenericName, "C<,>").WithLocation(12, 2), - // (12,2): error CS8652: The feature 'generic attributes' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // (12,2): error CS8936: Feature 'generic attributes' is not available in C# 10.0. Please use language version 11.0 or greater. // [C<,>] // 15, 16 - Diagnostic(ErrorCode.ERR_FeatureInPreview, "C<,>").WithArguments("generic attributes").WithLocation(12, 2), - // (13,2): error CS8652: The feature 'generic attributes' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "C<,>").WithArguments("generic attributes", "11.0").WithLocation(12, 2), + // (13,2): error CS8936: Feature 'generic attributes' is not available in C# 10.0. Please use language version 11.0 or greater. // [C] // 17, 18 - Diagnostic(ErrorCode.ERR_FeatureInPreview, "C").WithArguments("generic attributes").WithLocation(13, 2), + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "C").WithArguments("generic attributes", "11.0").WithLocation(13, 2), // (13,2): error CS0579: Duplicate 'C<,>' attribute // [C] // 17, 18 Diagnostic(ErrorCode.ERR_DuplicateAttribute, "C").WithArguments("C<,>").WithLocation(13, 2), - // (22,21): error CS8652: The feature 'generic attributes' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // (22,21): error CS8936: Feature 'generic attributes' is not available in C# 10.0. Please use language version 11.0 or greater. // public class B : Attribute // 19 - Diagnostic(ErrorCode.ERR_FeatureInPreview, "Attribute").WithArguments("generic attributes").WithLocation(22, 21), - // (26,24): error CS8652: The feature 'generic attributes' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "Attribute").WithArguments("generic attributes", "11.0").WithLocation(22, 21), + // (26,24): error CS8936: Feature 'generic attributes' is not available in C# 10.0. Please use language version 11.0 or greater. // public class C : Attribute // 20 - Diagnostic(ErrorCode.ERR_FeatureInPreview, "Attribute").WithArguments("generic attributes").WithLocation(26, 24)); + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "Attribute").WithArguments("generic attributes", "11.0").WithLocation(26, 24)); comp = CreateCompilation(source); comp.VerifyDiagnostics( @@ -8523,26 +8523,26 @@ public class C : Attribute } "; - var comp = CreateCompilation(source, parseOptions: TestOptions.Regular9); + var comp = CreateCompilation(source, parseOptions: TestOptions.Regular10); comp.VerifyDiagnostics( - // (12,21): error CS8652: The feature 'generic attributes' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // (12,21): error CS8936: Feature 'generic attributes' is not available in C# 10.0. Please use language version 11.0 or greater. // public class C : Attribute - Diagnostic(ErrorCode.ERR_FeatureInPreview, "Attribute").WithArguments("generic attributes").WithLocation(12, 21), + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "Attribute").WithArguments("generic attributes", "11.0").WithLocation(12, 21), // (6,2): error CS0307: The using alias 'Alias' cannot be used with type arguments // [Alias<>] Diagnostic(ErrorCode.ERR_TypeArgsNotAllowed, "Alias<>").WithArguments("Alias", "using alias").WithLocation(6, 2), // (7,2): error CS0307: The using alias 'Alias' cannot be used with type arguments // [Alias] Diagnostic(ErrorCode.ERR_TypeArgsNotAllowed, "Alias").WithArguments("Alias", "using alias").WithLocation(7, 2), - // (5,2): error CS8652: The feature 'generic attributes' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // (5,2): error CS8936: Feature 'generic attributes' is not available in C# 10.0. Please use language version 11.0 or greater. // [Alias] - Diagnostic(ErrorCode.ERR_FeatureInPreview, "Alias").WithArguments("generic attributes").WithLocation(5, 2), - // (6,2): error CS8652: The feature 'generic attributes' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "Alias").WithArguments("generic attributes", "11.0").WithLocation(5, 2), + // (6,2): error CS8936: Feature 'generic attributes' is not available in C# 10.0. Please use language version 11.0 or greater. // [Alias<>] - Diagnostic(ErrorCode.ERR_FeatureInPreview, "Alias<>").WithArguments("generic attributes").WithLocation(6, 2), - // (7,2): error CS8652: The feature 'generic attributes' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "Alias<>").WithArguments("generic attributes", "11.0").WithLocation(6, 2), + // (7,2): error CS8936: Feature 'generic attributes' is not available in C# 10.0. Please use language version 11.0 or greater. // [Alias] - Diagnostic(ErrorCode.ERR_FeatureInPreview, "Alias").WithArguments("generic attributes").WithLocation(7, 2)); + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "Alias").WithArguments("generic attributes", "11.0").WithLocation(7, 2)); comp = CreateCompilation(source, parseOptions: TestOptions.RegularPreview); comp.VerifyDiagnostics( @@ -8585,23 +8585,23 @@ class Test // NOTE: Dev11 does not give an error for "[Alias]" - it just silently drops the // attribute at emit-time. - var comp = CreateCompilationWithILAndMscorlib40(source, il, parseOptions: TestOptions.Regular9); + var comp = CreateCompilationWithILAndMscorlib40(source, il, parseOptions: TestOptions.Regular10); comp.VerifyDiagnostics( - // (4,2): error CS8652: The feature 'generic attributes' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // (4,2): error CS8936: Feature 'generic attributes' is not available in C# 10.0. Please use language version 11.0 or greater. // [Alias] - Diagnostic(ErrorCode.ERR_FeatureInPreview, "Alias").WithArguments("generic attributes").WithLocation(4, 2), + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "Alias").WithArguments("generic attributes", "11.0").WithLocation(4, 2), // (5,2): error CS0307: The using alias 'Alias' cannot be used with type arguments // [Alias<>] Diagnostic(ErrorCode.ERR_TypeArgsNotAllowed, "Alias<>").WithArguments("Alias", "using alias").WithLocation(5, 2), - // (5,2): error CS8652: The feature 'generic attributes' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // (5,2): error CS8936: Feature 'generic attributes' is not available in C# 10.0. Please use language version 11.0 or greater. // [Alias<>] - Diagnostic(ErrorCode.ERR_FeatureInPreview, "Alias<>").WithArguments("generic attributes").WithLocation(5, 2), + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "Alias<>").WithArguments("generic attributes", "11.0").WithLocation(5, 2), // (6,2): error CS0307: The using alias 'Alias' cannot be used with type arguments // [Alias] Diagnostic(ErrorCode.ERR_TypeArgsNotAllowed, "Alias").WithArguments("Alias", "using alias").WithLocation(6, 2), - // (6,2): error CS8652: The feature 'generic attributes' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // (6,2): error CS8936: Feature 'generic attributes' is not available in C# 10.0. Please use language version 11.0 or greater. // [Alias] - Diagnostic(ErrorCode.ERR_FeatureInPreview, "Alias").WithArguments("generic attributes").WithLocation(6, 2)); + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "Alias").WithArguments("generic attributes", "11.0").WithLocation(6, 2)); // NOTE: Dev11 does not give an error for "[Alias]" - it just silently drops the // attribute at emit-time. @@ -8640,20 +8640,20 @@ public class Inner } "; - var comp = CreateCompilation(source, parseOptions: TestOptions.Regular9); + var comp = CreateCompilation(source, parseOptions: TestOptions.Regular10); comp.VerifyDiagnostics( // (5,2): error CS0616: 'Outer.Inner' is not an attribute class // [InnerAlias] Diagnostic(ErrorCode.ERR_NotAnAttributeClass, "InnerAlias").WithArguments("Outer.Inner").WithLocation(5, 2), - // (5,2): error CS8652: The feature 'generic attributes' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // (5,2): error CS8936: Feature 'generic attributes' is not available in C# 10.0. Please use language version 11.0 or greater. // [InnerAlias] - Diagnostic(ErrorCode.ERR_FeatureInPreview, "InnerAlias").WithArguments("generic attributes").WithLocation(5, 2), + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "InnerAlias").WithArguments("generic attributes", "11.0").WithLocation(5, 2), // (8,17): error CS0616: 'Outer.Inner' is not an attribute class // [OuterAlias.Inner] Diagnostic(ErrorCode.ERR_NotAnAttributeClass, "Inner").WithArguments("Outer.Inner").WithLocation(8, 17), - // (8,6): error CS8652: The feature 'generic attributes' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // (8,6): error CS8936: Feature 'generic attributes' is not available in C# 10.0. Please use language version 11.0 or greater. // [OuterAlias.Inner] - Diagnostic(ErrorCode.ERR_FeatureInPreview, "OuterAlias.Inner").WithArguments("generic attributes").WithLocation(8, 6)); + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "OuterAlias.Inner").WithArguments("generic attributes", "11.0").WithLocation(8, 6)); comp = CreateCompilation(source, parseOptions: TestOptions.RegularPreview); comp.VerifyDiagnostics( @@ -9777,11 +9777,11 @@ public class C comp.VerifyDiagnostics(); Assert.False(comp.GlobalNamespace.GetTypeMember("C").GetAttributes().Single().AttributeClass.IsGenericType); - comp = CreateCompilation(source, parseOptions: TestOptions.Regular9); + comp = CreateCompilation(source, parseOptions: TestOptions.Regular10); comp.VerifyDiagnostics( - // (2,14): error CS8652: The feature 'generic attributes' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // (2,14): error CS8936: Feature 'generic attributes' is not available in C# 10.0. Please use language version 11.0 or greater. // class A : System.Attribute {} - Diagnostic(ErrorCode.ERR_FeatureInPreview, "System.Attribute").WithArguments("generic attributes").WithLocation(2, 14) + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "System.Attribute").WithArguments("generic attributes", "11.0").WithLocation(2, 14) ); Assert.False(comp.GlobalNamespace.GetTypeMember("C").GetAttributes().Single().AttributeClass.IsGenericType); } @@ -9906,20 +9906,20 @@ public class C Diagnostic(ErrorCode.ERR_AmbiguousAttribute, "A").WithArguments("A<>", "A", "AAttribute").WithLocation(5, 2) ); - comp = CreateCompilation(source, parseOptions: TestOptions.Regular9); + comp = CreateCompilation(source, parseOptions: TestOptions.Regular10); comp.VerifyDiagnostics( - // (2,30): error CS8652: The feature 'generic attributes' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // (2,30): error CS8936: Feature 'generic attributes' is not available in C# 10.0. Please use language version 11.0 or greater. // public class AAttribute : System.Attribute {} - Diagnostic(ErrorCode.ERR_FeatureInPreview, "System.Attribute").WithArguments("generic attributes").WithLocation(2, 30), - // (3,21): error CS8652: The feature 'generic attributes' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "System.Attribute").WithArguments("generic attributes", "11.0").WithLocation(2, 30), + // (3,21): error CS8936: Feature 'generic attributes' is not available in C# 10.0. Please use language version 11.0 or greater. // public class A : System.Attribute {} - Diagnostic(ErrorCode.ERR_FeatureInPreview, "System.Attribute").WithArguments("generic attributes").WithLocation(3, 21), + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "System.Attribute").WithArguments("generic attributes", "11.0").WithLocation(3, 21), // (5,2): error CS1614: 'A<>' is ambiguous between 'A' and 'AAttribute'. Either use '@A<>' or explicitly include the 'Attribute' suffix. // [A] Diagnostic(ErrorCode.ERR_AmbiguousAttribute, "A").WithArguments("A<>", "A", "AAttribute").WithLocation(5, 2), - // (5,2): error CS8652: The feature 'generic attributes' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // (5,2): error CS8936: Feature 'generic attributes' is not available in C# 10.0. Please use language version 11.0 or greater. // [A] - Diagnostic(ErrorCode.ERR_FeatureInPreview, "A").WithArguments("generic attributes").WithLocation(5, 2)); + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "A").WithArguments("generic attributes", "11.0").WithLocation(5, 2)); } [Fact, WorkItem(54772, "https://github.com/dotnet/roslyn/issues/54772")] @@ -9942,23 +9942,23 @@ public class C Diagnostic(ErrorCode.ERR_AmbiguousAttribute, "@A").WithArguments("A<>", "A", "AAttribute").WithLocation(5, 2) ); - comp = CreateCompilation(source, parseOptions: TestOptions.Regular9); + comp = CreateCompilation(source, parseOptions: TestOptions.Regular10); comp.VerifyDiagnostics( - // (2,30): error CS8652: The feature 'generic attributes' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // (2,30): error CS8936: Feature 'generic attributes' is not available in C# 10.0. Please use language version 11.0 or greater. // public class AAttribute : System.Attribute {} - Diagnostic(ErrorCode.ERR_FeatureInPreview, "System.Attribute").WithArguments("generic attributes").WithLocation(2, 30), - // (3,21): error CS8652: The feature 'generic attributes' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "System.Attribute").WithArguments("generic attributes", "11.0").WithLocation(2, 30), + // (3,21): error CS8936: Feature 'generic attributes' is not available in C# 10.0. Please use language version 11.0 or greater. // public class A : System.Attribute {} - Diagnostic(ErrorCode.ERR_FeatureInPreview, "System.Attribute").WithArguments("generic attributes").WithLocation(3, 21), + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "System.Attribute").WithArguments("generic attributes", "11.0").WithLocation(3, 21), // (5,2): error CS1614: 'A<>' is ambiguous between 'A' and 'AAttribute'. Either use '@A<>' or explicitly include the 'Attribute' suffix. // [@A] Diagnostic(ErrorCode.ERR_AmbiguousAttribute, "@A").WithArguments("A<>", "A", "AAttribute").WithLocation(5, 2), - // (5,2): error CS8652: The feature 'generic attributes' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // (5,2): error CS8936: Feature 'generic attributes' is not available in C# 10.0. Please use language version 11.0 or greater. // [@A] - Diagnostic(ErrorCode.ERR_FeatureInPreview, "@A").WithArguments("generic attributes").WithLocation(5, 2), - // (6,2): error CS8652: The feature 'generic attributes' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "@A").WithArguments("generic attributes", "11.0").WithLocation(5, 2), + // (6,2): error CS8936: Feature 'generic attributes' is not available in C# 10.0. Please use language version 11.0 or greater. // [AAttribute] - Diagnostic(ErrorCode.ERR_FeatureInPreview, "AAttribute").WithArguments("generic attributes").WithLocation(6, 2)); + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "AAttribute").WithArguments("generic attributes", "11.0").WithLocation(6, 2)); } [Fact] @@ -9973,11 +9973,11 @@ public class D : C { } [D] public class Program { } "; - var comp = CreateCompilation(new[] { source1, source2 }, parseOptions: TestOptions.Regular9); + var comp = CreateCompilation(new[] { source1, source2 }, parseOptions: TestOptions.Regular10); comp.VerifyDiagnostics( - // (2,21): error CS8652: The feature 'generic attributes' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // (2,21): error CS8936: Feature 'generic attributes' is not available in C# 10.0. Please use language version 11.0 or greater. // public class C : System.Attribute { } - Diagnostic(ErrorCode.ERR_FeatureInPreview, "System.Attribute").WithArguments("generic attributes").WithLocation(2, 21)); + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "System.Attribute").WithArguments("generic attributes", "11.0").WithLocation(2, 21)); var comp1 = CreateCompilation(source1); var comp2 = CreateCompilation(source2, references: new[] { comp1.ToMetadataReference() }, parseOptions: TestOptions.Regular9); @@ -10044,11 +10044,11 @@ public class D : C.Inner { } [D] public class Program { } "; - var comp = CreateCompilation(new[] { source1, source2 }, parseOptions: TestOptions.Regular9); + var comp = CreateCompilation(new[] { source1, source2 }, parseOptions: TestOptions.Regular10); comp.VerifyDiagnostics( - // (4,26): error CS8652: The feature 'generic attributes' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // (4,26): error CS8936: Feature 'generic attributes' is not available in C# 10.0. Please use language version 11.0 or greater. // public class Inner : System.Attribute { } - Diagnostic(ErrorCode.ERR_FeatureInPreview, "System.Attribute").WithArguments("generic attributes").WithLocation(4, 26)); + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "System.Attribute").WithArguments("generic attributes", "11.0").WithLocation(4, 26)); var comp1 = CreateCompilation(source1); var comp2 = CreateCompilation(source2, references: new[] { comp1.ToMetadataReference() }, parseOptions: TestOptions.Regular9); @@ -10088,20 +10088,20 @@ public class C : System.Attribute { } [C<>] public class Program { } "; - var comp = CreateCompilation(source, parseOptions: TestOptions.Regular9); + var comp = CreateCompilation(source, parseOptions: TestOptions.Regular10); comp.VerifyDiagnostics( - // (2,21): error CS8652: The feature 'generic attributes' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // (2,21): error CS8936: Feature 'generic attributes' is not available in C# 10.0. Please use language version 11.0 or greater. // public class C : System.Attribute { } - Diagnostic(ErrorCode.ERR_FeatureInPreview, "System.Attribute").WithArguments("generic attributes").WithLocation(2, 21), - // (4,2): error CS8652: The feature 'generic attributes' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "System.Attribute").WithArguments("generic attributes", "11.0").WithLocation(2, 21), + // (4,2): error CS8936: Feature 'generic attributes' is not available in C# 10.0. Please use language version 11.0 or greater. // [C] - Diagnostic(ErrorCode.ERR_FeatureInPreview, "C").WithArguments("generic attributes").WithLocation(4, 2), + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "C").WithArguments("generic attributes", "11.0").WithLocation(4, 2), // (4,4): error CS0246: The type or namespace name 'ERROR' could not be found (are you missing a using directive or an assembly reference?) // [C] Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "ERROR").WithArguments("ERROR").WithLocation(4, 4), - // (5,2): error CS8652: The feature 'generic attributes' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // (5,2): error CS8936: Feature 'generic attributes' is not available in C# 10.0. Please use language version 11.0 or greater. // [C] - Diagnostic(ErrorCode.ERR_FeatureInPreview, "C").WithArguments("generic attributes").WithLocation(5, 2), + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "C").WithArguments("generic attributes", "11.0").WithLocation(5, 2), // (5,2): error CS0579: Duplicate 'C<>' attribute // [C] Diagnostic(ErrorCode.ERR_DuplicateAttribute, "C").WithArguments("C<>").WithLocation(5, 2), @@ -10111,9 +10111,9 @@ public class Program { } // (6,2): error CS7003: Unexpected use of an unbound generic name // [C<>] Diagnostic(ErrorCode.ERR_UnexpectedUnboundGenericName, "C<>").WithLocation(6, 2), - // (6,2): error CS8652: The feature 'generic attributes' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // (6,2): error CS8936: Feature 'generic attributes' is not available in C# 10.0. Please use language version 11.0 or greater. // [C<>] - Diagnostic(ErrorCode.ERR_FeatureInPreview, "C<>").WithArguments("generic attributes").WithLocation(6, 2), + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "C<>").WithArguments("generic attributes", "11.0").WithLocation(6, 2), // (6,2): error CS0579: Duplicate 'C<>' attribute // [C<>] Diagnostic(ErrorCode.ERR_DuplicateAttribute, "C<>").WithArguments("C<>").WithLocation(6, 2)); diff --git a/src/Compilers/CSharp/Test/Emit2/Attributes/AttributeTests_CallerInfoAttributes.cs b/src/Compilers/CSharp/Test/Emit2/Attributes/AttributeTests_CallerInfoAttributes.cs index f9f3b86e81005..e1b0cf7967028 100644 --- a/src/Compilers/CSharp/Test/Emit2/Attributes/AttributeTests_CallerInfoAttributes.cs +++ b/src/Compilers/CSharp/Test/Emit2/Attributes/AttributeTests_CallerInfoAttributes.cs @@ -5818,5 +5818,27 @@ void M(int i, [CallerArgumentExpression(""i"")] in string s = ""default value"") CompileAndVerify(comp, expectedOutput: "1 + 1").VerifyDiagnostics(); } + + [Fact] + public void CallerArgumentExpression_Cycle() + { + string source = +@"namespace System.Runtime.CompilerServices +{ + public sealed class CallerArgumentExpressionAttribute : Attribute + { + public CallerArgumentExpressionAttribute([CallerArgumentExpression(nameof(parameterName))] string parameterName) + { + ParameterName = parameterName; + } + public string ParameterName { get; } + } +}"; + var comp = CreateCompilation(source); + comp.VerifyDiagnostics( + // (5,51): error CS8964: The CallerArgumentExpressionAttribute may only be applied to parameters with default values + // public CallerArgumentExpressionAttribute([CallerArgumentExpression(nameof(parameterName))] string parameterName) + Diagnostic(ErrorCode.ERR_BadCallerArgumentExpressionParamWithoutDefaultValue, "CallerArgumentExpression").WithLocation(5, 51)); + } } } diff --git a/src/Compilers/CSharp/Test/Emit2/Attributes/AttributeTests_LifetimeAnnotation.cs b/src/Compilers/CSharp/Test/Emit2/Attributes/AttributeTests_LifetimeAnnotation.cs index f151d5b930a3c..3e14d626c7172 100644 --- a/src/Compilers/CSharp/Test/Emit2/Attributes/AttributeTests_LifetimeAnnotation.cs +++ b/src/Compilers/CSharp/Test/Emit2/Attributes/AttributeTests_LifetimeAnnotation.cs @@ -17,21 +17,14 @@ namespace Microsoft.CodeAnalysis.CSharp.UnitTests { - public class AttributeTests_LifetimeAnnotation : CSharpTestBase + public class AttributeTests_ScopedRef : CSharpTestBase { - private const string LifetimeAnnotationAttributeDefinition = + private const string ScopedRefAttributeDefinition = @"namespace System.Runtime.CompilerServices { - [AttributeUsage(AttributeTargets.All, AllowMultiple = false, Inherited = false)] - public sealed class LifetimeAnnotationAttribute : Attribute + [AttributeUsage(AttributeTargets.Parameter, AllowMultiple = false, Inherited = false)] + public sealed class ScopedRefAttribute : Attribute { - public LifetimeAnnotationAttribute(bool isRefScoped, bool isValueScoped) - { - IsRefScoped = isRefScoped; - IsValueScoped = isValueScoped; - } - public bool IsRefScoped { get; } - public bool IsValueScoped { get; } } }"; @@ -43,22 +36,22 @@ public void ExplicitAttribute_FromSource() { public static void F(scoped ref int i) { } }"; - var comp = CreateCompilation(new[] { LifetimeAnnotationAttributeDefinition, source }); + var comp = CreateCompilation(new[] { ScopedRefAttributeDefinition, source }); var expected = -@" void Program.F(ref System.Int32 i) - [LifetimeAnnotation(True, False)] ref System.Int32 i +@"void Program.F(ref System.Int32 i) + [ScopedRef] ref System.Int32 i "; CompileAndVerify(comp, symbolValidator: module => { - Assert.Equal("System.Runtime.CompilerServices.LifetimeAnnotationAttribute", GetLifetimeAnnotationType(module).ToTestDisplayString()); - AssertLifetimeAnnotationAttributes(module, expected); + Assert.Equal("System.Runtime.CompilerServices.ScopedRefAttribute", GetScopedRefType(module).ToTestDisplayString()); + AssertScopedRefAttributes(module, expected); }); } [Fact] public void ExplicitAttribute_FromMetadata() { - var comp = CreateCompilation(LifetimeAnnotationAttributeDefinition); + var comp = CreateCompilation(ScopedRefAttributeDefinition); comp.VerifyDiagnostics(); var ref0 = comp.EmitToImageReference(); @@ -70,12 +63,12 @@ public static void F(scoped ref int i) { } comp = CreateCompilation(source, references: new[] { ref0 }); var expected = @"void Program.F(ref System.Int32 i) - [LifetimeAnnotation(True, False)] ref System.Int32 i + [ScopedRef] ref System.Int32 i "; CompileAndVerify(comp, symbolValidator: module => { - Assert.Null(GetLifetimeAnnotationType(module)); - AssertLifetimeAnnotationAttributes(module, expected); + Assert.Null(GetScopedRefType(module)); + AssertScopedRefAttributes(module, expected); }); } @@ -85,11 +78,9 @@ public void ExplicitAttribute_MissingConstructor() var source1 = @"namespace System.Runtime.CompilerServices { - public sealed class LifetimeAnnotationAttribute : Attribute + public sealed class ScopedRefAttribute : Attribute { - public LifetimeAnnotationAttribute() { } - public bool IsRefScoped { get; } - public bool IsValueScoped { get; } + public ScopedRefAttribute(int i) { } } }"; var source2 = @@ -99,9 +90,9 @@ public static void F(scoped ref int i) { } }"; var comp = CreateCompilation(new[] { source1, source2 }); comp.VerifyEmitDiagnostics( - // (3,26): error CS0656: Missing compiler required member 'System.Runtime.CompilerServices.LifetimeAnnotationAttribute..ctor' + // (3,26): error CS0656: Missing compiler required member 'System.Runtime.CompilerServices.ScopedRefAttribute..ctor' // public static void F(scoped ref int i) { } - Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "scoped ref int i").WithArguments("System.Runtime.CompilerServices.LifetimeAnnotationAttribute", ".ctor").WithLocation(3, 26)); + Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "scoped ref int i").WithArguments("System.Runtime.CompilerServices.ScopedRefAttribute", ".ctor").WithLocation(3, 26)); } [WorkItem(62124, "https://github.com/dotnet/roslyn/issues/62124")] @@ -110,17 +101,26 @@ public void ExplicitAttribute_ReferencedInSource_01() { var source = @"using System.Runtime.CompilerServices; -delegate void D([LifetimeAnnotation(true, false)] ref int i); +delegate void D([ScopedRef] ref int i); class Program { - public static void Main([LifetimeAnnotation(false, true)] string[] args) + public static void Main([ScopedRef] string[] args) { - D d = ([LifetimeAnnotation(true, false)] ref int i) => { }; + D d = ([ScopedRef] ref int i) => { }; } }"; - var comp = CreateCompilation(new[] { LifetimeAnnotationAttributeDefinition, source }); - // https://github.com/dotnet/roslyn/issues/62124: Re-enable check for LifetimeAnnotationAttribute in ReportExplicitUseOfReservedAttributes. - comp.VerifyDiagnostics(); + var comp = CreateCompilation(new[] { ScopedRefAttributeDefinition, source }); + comp.VerifyDiagnostics( + // (2,18): error CS9065: Do not use 'System.Runtime.CompilerServices.ScopedRefAttribute'. Use the 'scoped' keyword instead. + // delegate void D([ScopedRef] ref int i); + Diagnostic(ErrorCode.ERR_ExplicitScopedRef, "ScopedRef").WithLocation(2, 18), + // (5,30): error CS9065: Do not use 'System.Runtime.CompilerServices.ScopedRefAttribute'. Use the 'scoped' keyword instead. + // public static void Main([ScopedRef] string[] args) + Diagnostic(ErrorCode.ERR_ExplicitScopedRef, "ScopedRef").WithLocation(5, 30), + // (7,17): error CS9065: Do not use 'System.Runtime.CompilerServices.ScopedRefAttribute'. Use the 'scoped' keyword instead. + // D d = ([ScopedRef] ref int i) => { }; + Diagnostic(ErrorCode.ERR_ExplicitScopedRef, "ScopedRef").WithLocation(7, 17) + ); } [WorkItem(62124, "https://github.com/dotnet/roslyn/issues/62124")] @@ -130,34 +130,68 @@ public void ExplicitAttribute_ReferencedInSource_02() var source = @"using System; using System.Runtime.CompilerServices; -[module: LifetimeAnnotation(false, true)] -[LifetimeAnnotation(false, true)] class Program +[module: ScopedRef] +[ScopedRef] class Program { - [LifetimeAnnotation(false, true)] object F; - [LifetimeAnnotation(false, true)] event EventHandler E; - [LifetimeAnnotation(false, true)] object P { get; } - [LifetimeAnnotation(false, true)] static object M1() => throw null; - [return: LifetimeAnnotation(false, true)] static object M2() => throw null; - static void M3<[LifetimeAnnotation(false, true)] T>() { } -}"; - var comp = CreateCompilation(new[] { LifetimeAnnotationAttributeDefinition, source }); - // https://github.com/dotnet/roslyn/issues/62124: Re-enable check for LifetimeAnnotationAttribute in ReportExplicitUseOfReservedAttributes. + [ScopedRef] object F; + [ScopedRef] event EventHandler E; + [ScopedRef] object P { get; } + [ScopedRef] static object M1() => throw null; + [return: ScopedRef] static object M2() => throw null; + static void M3<[ScopedRef] T>() { } +} +namespace System.Runtime.CompilerServices +{ + [AttributeUsage(AttributeTargets.All, AllowMultiple = false, Inherited = false)] + public sealed class ScopedRefAttribute : Attribute + { + } +} +"; + var comp = CreateCompilation(source); comp.VerifyDiagnostics( - // (6,46): warning CS0169: The field 'Program.F' is never used - // [LifetimeAnnotation(false, true)] object F; - Diagnostic(ErrorCode.WRN_UnreferencedField, "F").WithArguments("Program.F").WithLocation(6, 46), - // (7,58): warning CS0067: The event 'Program.E' is never used - // [LifetimeAnnotation(false, true)] event EventHandler E; - Diagnostic(ErrorCode.WRN_UnreferencedEvent, "E").WithArguments("Program.E").WithLocation(7, 58)); + // (6,24): warning CS0169: The field 'Program.F' is never used + // [ScopedRef] object F; + Diagnostic(ErrorCode.WRN_UnreferencedField, "F").WithArguments("Program.F").WithLocation(6, 24), + // (7,36): warning CS0067: The event 'Program.E' is never used + // [ScopedRef] event EventHandler E; + Diagnostic(ErrorCode.WRN_UnreferencedEvent, "E").WithArguments("Program.E").WithLocation(7, 36)); + } + + [WorkItem(62124, "https://github.com/dotnet/roslyn/issues/62124")] + [Fact] + public void ExplicitAttribute_ReferencedInSource_03() + { + var source = @" +using System.Runtime.CompilerServices; +record struct R1([ScopedRef] ref int i); +record struct R2([ScopedRef] R i); +ref struct R { } +"; + var comp = CreateCompilation(new[] { ScopedRefAttributeDefinition, source }); + comp.VerifyDiagnostics( + // (3,19): error CS9065: Do not use 'System.Runtime.CompilerServices.ScopedRefAttribute'. Use the 'scoped' keyword instead. + // record struct R1([ScopedRef] ref int i); + Diagnostic(ErrorCode.ERR_ExplicitScopedRef, "ScopedRef").WithLocation(3, 19), + // (3,30): error CS0631: ref and out are not valid in this context + // record struct R1([ScopedRef] ref int i); + Diagnostic(ErrorCode.ERR_IllegalRefParam, "ref").WithLocation(3, 30), + // (4,19): error CS9065: Do not use 'System.Runtime.CompilerServices.ScopedRefAttribute'. Use the 'scoped' keyword instead. + // record struct R2([ScopedRef] R i); + Diagnostic(ErrorCode.ERR_ExplicitScopedRef, "ScopedRef").WithLocation(4, 19), + // (4,30): error CS8345: Field or auto-implemented property cannot be of type 'R' unless it is an instance member of a ref struct. + // record struct R2([ScopedRef] R i); + Diagnostic(ErrorCode.ERR_FieldAutoPropCantBeByRefLike, "R").WithArguments("R").WithLocation(4, 30) + ); } [Fact] public void ExplicitAttribute_UnexpectedParameterTargets() { var source0 = -@".class private System.Runtime.CompilerServices.LifetimeAnnotationAttribute extends [mscorlib]System.Attribute +@".class private System.Runtime.CompilerServices.ScopedRefAttribute extends [mscorlib]System.Attribute { - .method public hidebysig specialname rtspecialname instance void .ctor(bool isRefScoped, bool isValueScoped) cil managed { ret } + .method public hidebysig specialname rtspecialname instance void .ctor() cil managed { ret } } .class public sealed R extends [mscorlib]System.ValueType { @@ -169,25 +203,25 @@ .class public A .method public static void F1(valuetype R r) { .param [1] - .custom instance void System.Runtime.CompilerServices.LifetimeAnnotationAttribute::.ctor(bool, bool) = ( 01 00 01 00 00 00 ) // LifetimeAnnotationAttribute(isRefScoped: true, isValueScoped: false) + .custom instance void System.Runtime.CompilerServices.ScopedRefAttribute::.ctor() = ( 01 00 00 00 ) // ScopedRefAttribute() ret } .method public static void F2(int32 y) { .param [1] - .custom instance void System.Runtime.CompilerServices.LifetimeAnnotationAttribute::.ctor(bool, bool) = ( 01 00 00 01 00 00 ) // LifetimeAnnotationAttribute(isRefScoped: false, isValueScoped: true) + .custom instance void System.Runtime.CompilerServices.ScopedRefAttribute::.ctor() = ( 01 00 00 00 ) // ScopedRefAttribute() ret } .method public static void F3(object x, int32& y) { .param [2] - .custom instance void System.Runtime.CompilerServices.LifetimeAnnotationAttribute::.ctor(bool, bool) = ( 01 00 00 01 00 00 ) // LifetimeAnnotationAttribute(isRefScoped: false, isValueScoped: true) + .custom instance void System.Runtime.CompilerServices.ScopedRefAttribute::.ctor() = ( 01 00 00 00 ) // ScopedRefAttribute() ret } .method public static void F4(valuetype R& r) { .param [1] - .custom instance void System.Runtime.CompilerServices.LifetimeAnnotationAttribute::.ctor(bool, bool) = ( 01 00 01 01 00 00 ) // LifetimeAnnotationAttribute(isRefScoped: true, isValueScoped: true) + .custom instance void System.Runtime.CompilerServices.ScopedRefAttribute::.ctor() = ( 01 00 00 00 ) // ScopedRefAttribute() ret } } @@ -210,29 +244,38 @@ static void Main() }"; var comp = CreateCompilation(source1, references: new[] { ref0 }); comp.VerifyDiagnostics( - // (6,11): error CS0570: 'A.F1(R)' is not supported by the language - // A.F1(r); - Diagnostic(ErrorCode.ERR_BindToBogus, "F1").WithArguments("A.F1(R)").WithLocation(6, 11), // (7,11): error CS0570: 'A.F2(int)' is not supported by the language // A.F2(2); - Diagnostic(ErrorCode.ERR_BindToBogus, "F2").WithArguments("A.F2(int)").WithLocation(7, 11), - // (10,11): error CS0570: 'A.F3(object, ref int)' is not supported by the language - // A.F3(x, ref y); - Diagnostic(ErrorCode.ERR_BindToBogus, "F3").WithArguments("A.F3(object, ref int)").WithLocation(10, 11)); + Diagnostic(ErrorCode.ERR_BindToBogus, "F2").WithArguments("A.F2(int)").WithLocation(7, 11)); - var method = comp.GetMember("A.F4"); - Assert.Equal("void A.F4(ref scoped R r)", method.ToDisplayString(SymbolDisplayFormat.TestFormat.WithCompilerInternalOptions(SymbolDisplayCompilerInternalOptions.IncludeScoped))); + var method = comp.GetMember("A.F1"); + Assert.Equal("void A.F1(scoped R r)", method.ToDisplayString(SymbolDisplayFormat.TestFormat.WithCompilerInternalOptions(SymbolDisplayCompilerInternalOptions.IncludeScoped))); var parameter = method.Parameters[0]; - Assert.Equal(DeclarationScope.ValueScoped, parameter.Scope); + Assert.Equal(DeclarationScope.ValueScoped, parameter.DeclaredScope); + + method = comp.GetMember("A.F2"); + Assert.Equal("void A.F2(System.Int32 y)", method.ToDisplayString(SymbolDisplayFormat.TestFormat.WithCompilerInternalOptions(SymbolDisplayCompilerInternalOptions.IncludeScoped))); + parameter = method.Parameters[0]; + Assert.Equal(DeclarationScope.Unscoped, parameter.DeclaredScope); + + method = comp.GetMember("A.F3"); + Assert.Equal("void A.F3(System.Object x, scoped ref System.Int32 y)", method.ToDisplayString(SymbolDisplayFormat.TestFormat.WithCompilerInternalOptions(SymbolDisplayCompilerInternalOptions.IncludeScoped))); + parameter = method.Parameters[1]; + Assert.Equal(DeclarationScope.RefScoped, parameter.DeclaredScope); + + method = comp.GetMember("A.F4"); + Assert.Equal("void A.F4(ref R r)", method.ToDisplayString(SymbolDisplayFormat.TestFormat.WithCompilerInternalOptions(SymbolDisplayCompilerInternalOptions.IncludeScoped))); + parameter = method.Parameters[0]; + Assert.Equal(DeclarationScope.RefScoped, parameter.DeclaredScope); } [Fact] public void ExplicitAttribute_UnexpectedAttributeConstructor() { var source0 = -@".class private System.Runtime.CompilerServices.LifetimeAnnotationAttribute extends [mscorlib]System.Attribute +@".class private System.Runtime.CompilerServices.ScopedRefAttribute extends [mscorlib]System.Attribute { - .method public hidebysig specialname rtspecialname instance void .ctor() cil managed { ret } + .method public hidebysig specialname rtspecialname instance void .ctor(bool isRefScoped, bool isValueScoped) cil managed { ret } } .class public sealed R extends [mscorlib]System.ValueType { @@ -244,13 +287,13 @@ .class public A .method public static void F1(valuetype R r) { .param [1] - .custom instance void System.Runtime.CompilerServices.LifetimeAnnotationAttribute::.ctor() = ( 01 00 00 00 ) // LifetimeAnnotationAttribute() + .custom instance void System.Runtime.CompilerServices.ScopedRefAttribute::.ctor(bool, bool) = ( 01 00 00 01 00 00 ) // ScopedRefAttribute(isRefScoped: false, isValueScoped: true) ret } .method public static void F2(object x, int32& y) { .param [2] - .custom instance void System.Runtime.CompilerServices.LifetimeAnnotationAttribute::.ctor() = ( 01 00 00 00 ) // LifetimeAnnotationAttribute() + .custom instance void System.Runtime.CompilerServices.ScopedRefAttribute::.ctor(bool, bool) = ( 01 00 01 00 00 00 ) // ScopedRefAttribute(isRefScoped: true, isValueScoped: false) ret } } @@ -269,7 +312,7 @@ static void Main() } }"; var comp = CreateCompilation(source1, references: new[] { ref0 }); - // https://github.com/dotnet/roslyn/issues/61647: If the [LifetimeAnnotation] scoped value is an int + // https://github.com/dotnet/roslyn/issues/61647: If the [ScopedRef] scoped value is an int // rather than a pair of bools, the compiler should reject attribute values that it does not recognize. comp.VerifyDiagnostics(); } @@ -284,24 +327,21 @@ struct S public S(scoped ref int i) { } public static void F(scoped R r) { } public object this[scoped in int i] => null; - public static S operator+(S a, in scoped R b) => a; + public static S operator+(S a, scoped in R b) => a; }"; var comp = CreateCompilation(source); var expected = @"S..ctor(ref System.Int32 i) - [LifetimeAnnotation(True, False)] ref System.Int32 i + [ScopedRef] ref System.Int32 i void S.F(R r) - [LifetimeAnnotation(False, True)] R r -S S.op_Addition(S a, in R b) - S a - [LifetimeAnnotation(False, True)] in R b + [ScopedRef] R r System.Object S.this[in System.Int32 i].get - [LifetimeAnnotation(True, False)] in System.Int32 i + [ScopedRef] in System.Int32 i "; CompileAndVerify(comp, symbolValidator: module => { - Assert.Equal("System.Runtime.CompilerServices.LifetimeAnnotationAttribute", GetLifetimeAnnotationType(module).ToTestDisplayString()); - AssertLifetimeAnnotationAttributes(module, expected); + Assert.Equal("System.Runtime.CompilerServices.ScopedRefAttribute", GetScopedRefType(module).ToTestDisplayString()); + AssertScopedRefAttributes(module, expected); }); } @@ -321,8 +361,8 @@ public static void F(out int x, out R y) var comp = CreateCompilation(source); CompileAndVerify(comp, symbolValidator: module => { - Assert.Null(GetLifetimeAnnotationType(module)); - AssertLifetimeAnnotationAttributes(module, ""); + Assert.Null(GetScopedRefType(module)); + AssertScopedRefAttributes(module, ""); }); } @@ -342,30 +382,36 @@ public static void F(scoped out int x, scoped out R y) var comp = CreateCompilation(source); CompileAndVerify(comp, symbolValidator: module => { - Assert.Null(GetLifetimeAnnotationType(module)); - AssertLifetimeAnnotationAttributes(module, ""); + Assert.Null(GetScopedRefType(module)); + AssertScopedRefAttributes(module, ""); }); } [Fact] - public void EmitAttribute_OutParameters_03() + public void EmitAttribute_RefToRefStructParameters() { var source = @"ref struct R { } class Program { - public static void F(out scoped R r) { r = default; } + public static void F0(R r) { } + public static void F1(ref R r) { } + public static void F2(in R r) { } + public static void F3(out R r) { r = default; } + public static void F4(scoped ref R r) { } + public static void F5(scoped in R r) { } + public static void F6(scoped out R r) { r = default; } }"; var comp = CreateCompilation(source); var expected = -@" void Program.F(out R r) - [LifetimeAnnotation(False, True)] out R r -"; +@""; CompileAndVerify(comp, symbolValidator: module => { - Assert.Equal("System.Runtime.CompilerServices.LifetimeAnnotationAttribute", GetLifetimeAnnotationType(module).ToTestDisplayString()); - AssertLifetimeAnnotationAttributes(module, expected); + Assert.Null(GetScopedRefType(module)); + AssertScopedRefAttributes(module, expected); }); + + // https://github.com/dotnet/roslyn/issues/62780: Test additional cases with [UnscopedRef]. } [Fact] @@ -378,15 +424,15 @@ public void EmitAttribute_DelegateParameters() var comp = CreateCompilation(source); var expected = @"void D.Invoke(in modreq(System.Runtime.InteropServices.InAttribute) System.Int32 x, R y) - [LifetimeAnnotation(True, False)] in modreq(System.Runtime.InteropServices.InAttribute) System.Int32 x - [LifetimeAnnotation(False, True)] R y + [ScopedRef] in modreq(System.Runtime.InteropServices.InAttribute) System.Int32 x + [ScopedRef] R y System.IAsyncResult D.BeginInvoke(in modreq(System.Runtime.InteropServices.InAttribute) System.Int32 x, R y, System.AsyncCallback callback, System.Object @object) - [LifetimeAnnotation(True, False)] in modreq(System.Runtime.InteropServices.InAttribute) System.Int32 x - [LifetimeAnnotation(False, True)] R y + [ScopedRef] in modreq(System.Runtime.InteropServices.InAttribute) System.Int32 x + [ScopedRef] R y System.AsyncCallback callback System.Object @object void D.EndInvoke(in modreq(System.Runtime.InteropServices.InAttribute) System.Int32 x, System.IAsyncResult result) - [LifetimeAnnotation(True, False)] in modreq(System.Runtime.InteropServices.InAttribute) System.Int32 x + [ScopedRef] in modreq(System.Runtime.InteropServices.InAttribute) System.Int32 x System.IAsyncResult result "; CompileAndVerify( @@ -394,8 +440,8 @@ System.IAsyncResult result options: TestOptions.DebugDll.WithMetadataImportOptions(MetadataImportOptions.All), symbolValidator: module => { - Assert.Equal("System.Runtime.CompilerServices.LifetimeAnnotationAttribute", GetLifetimeAnnotationType(module).ToTestDisplayString()); - AssertLifetimeAnnotationAttributes(module, expected); + Assert.Equal("System.Runtime.CompilerServices.ScopedRefAttribute", GetScopedRefType(module).ToTestDisplayString()); + AssertScopedRefAttributes(module, expected); }); } @@ -415,25 +461,24 @@ static void Main() var comp = CreateCompilation(source); var expected = @"void D.Invoke(in modreq(System.Runtime.InteropServices.InAttribute) System.Int32 i) - [LifetimeAnnotation(True, False)] in modreq(System.Runtime.InteropServices.InAttribute) System.Int32 i + [ScopedRef] in modreq(System.Runtime.InteropServices.InAttribute) System.Int32 i System.IAsyncResult D.BeginInvoke(in modreq(System.Runtime.InteropServices.InAttribute) System.Int32 i, System.AsyncCallback callback, System.Object @object) - [LifetimeAnnotation(True, False)] in modreq(System.Runtime.InteropServices.InAttribute) System.Int32 i + [ScopedRef] in modreq(System.Runtime.InteropServices.InAttribute) System.Int32 i System.AsyncCallback callback System.Object @object void D.EndInvoke(in modreq(System.Runtime.InteropServices.InAttribute) System.Int32 i, System.IAsyncResult result) - [LifetimeAnnotation(True, False)] in modreq(System.Runtime.InteropServices.InAttribute) System.Int32 i + [ScopedRef] in modreq(System.Runtime.InteropServices.InAttribute) System.Int32 i System.IAsyncResult result void Program.<>c.
b__0_0(in System.Int32 i) - [LifetimeAnnotation(True, False)] in System.Int32 i - + [ScopedRef] in System.Int32 i "; CompileAndVerify( source, options: TestOptions.DebugDll.WithMetadataImportOptions(MetadataImportOptions.All), symbolValidator: module => { - Assert.Equal("System.Runtime.CompilerServices.LifetimeAnnotationAttribute", GetLifetimeAnnotationType(module).ToTestDisplayString()); - AssertLifetimeAnnotationAttributes(module, expected); + Assert.Equal("System.Runtime.CompilerServices.ScopedRefAttribute", GetScopedRefType(module).ToTestDisplayString()); + AssertScopedRefAttributes(module, expected); }); } @@ -452,15 +497,15 @@ void L(scoped in int i) { } var comp = CreateCompilation(source); var expected = @"void Program.g__L|0_0(in System.Int32 i) - [LifetimeAnnotation(True, False)] in System.Int32 i + [ScopedRef] in System.Int32 i "; CompileAndVerify( source, options: TestOptions.DebugDll.WithMetadataImportOptions(MetadataImportOptions.All), symbolValidator: module => { - Assert.Equal("System.Runtime.CompilerServices.LifetimeAnnotationAttribute", GetLifetimeAnnotationType(module).ToTestDisplayString()); - AssertLifetimeAnnotationAttributes(module, expected); + Assert.Equal("System.Runtime.CompilerServices.ScopedRefAttribute", GetScopedRefType(module).ToTestDisplayString()); + AssertScopedRefAttributes(module, expected); }); } @@ -482,13 +527,13 @@ static void Main() var comp = CreateCompilation(source); var expected = @"void <>f__AnonymousDelegate0.Invoke(in System.Int32 value) - [LifetimeAnnotation(True, False)] in System.Int32 value + [ScopedRef] in System.Int32 value R <>f__AnonymousDelegate1.Invoke(R value) - [LifetimeAnnotation(False, True)] R value + [ScopedRef] R value void Program.<>c.
b__0_0(in System.Int32 i) - [LifetimeAnnotation(True, False)] in System.Int32 i + [ScopedRef] in System.Int32 i R Program.<>c.
b__0_1(R r) - [LifetimeAnnotation(False, True)] R r + [ScopedRef] R r "; CompileAndVerify( source, @@ -496,20 +541,20 @@ static void Main() verify: Verification.Skipped, symbolValidator: module => { - Assert.Equal("System.Runtime.CompilerServices.LifetimeAnnotationAttribute", GetLifetimeAnnotationType(module).ToTestDisplayString()); - AssertLifetimeAnnotationAttributes(module, expected); + Assert.Equal("System.Runtime.CompilerServices.ScopedRefAttribute", GetScopedRefType(module).ToTestDisplayString()); + AssertScopedRefAttributes(module, expected); }); } - private static void AssertLifetimeAnnotationAttributes(ModuleSymbol module, string expected) + private static void AssertScopedRefAttributes(ModuleSymbol module, string expected) { - var actual = LifetimeAnnotationAttributesVisitor.GetString((PEModuleSymbol)module); + var actual = ScopedRefAttributesVisitor.GetString((PEModuleSymbol)module); AssertEx.AssertEqualToleratingWhitespaceDifferences(expected, actual); } - private static NamedTypeSymbol GetLifetimeAnnotationType(ModuleSymbol module) + private static NamedTypeSymbol GetScopedRefType(ModuleSymbol module) { - return module.GlobalNamespace.GetMember("System.Runtime.CompilerServices.LifetimeAnnotationAttribute"); + return module.GlobalNamespace.GetMember("System.Runtime.CompilerServices.ScopedRefAttribute"); } } } diff --git a/src/Compilers/CSharp/Test/Emit2/CodeGen/CodeGenMethodGroupConversionCachingTests.cs b/src/Compilers/CSharp/Test/Emit2/CodeGen/CodeGenMethodGroupConversionCachingTests.cs index 3952de8208ec4..063bddaf56951 100644 --- a/src/Compilers/CSharp/Test/Emit2/CodeGen/CodeGenMethodGroupConversionCachingTests.cs +++ b/src/Compilers/CSharp/Test/Emit2/CodeGen/CodeGenMethodGroupConversionCachingTests.cs @@ -5620,7 +5620,7 @@ static int M() return 0; } }"; - var comp = CompileAndVerify(source, parseOptions: TestOptions.RegularNext); + var comp = CompileAndVerify(source, parseOptions: TestOptions.Regular11); comp.VerifyDiagnostics(); comp.VerifyIL("C.Main", @" { @@ -5703,7 +5703,7 @@ static void Action() } } "; - var verifier = CompileAndVerifyWithWinRt(source, parseOptions: TestOptions.RegularNext, options: TestOptions.ReleaseWinMD); + var verifier = CompileAndVerifyWithWinRt(source, parseOptions: TestOptions.Regular11, options: TestOptions.ReleaseWinMD); verifier.VerifyIL("D.InstanceAdd", @" { @@ -5820,7 +5820,7 @@ static void Action() } } "; - var verifier = CompileAndVerifyWithWinRt(source, parseOptions: TestOptions.RegularNext, options: TestOptions.ReleaseWinMD); + var verifier = CompileAndVerifyWithWinRt(source, parseOptions: TestOptions.Regular11, options: TestOptions.ReleaseWinMD); verifier.VerifyIL("C.InstanceAssign", @" { @@ -5901,7 +5901,7 @@ static partial void PM(string p2) } "; - CompileAndVerify(text, parseOptions: TestOptions.RegularNext, expectedOutput: PASS).VerifyIL("Test.Main", @" + CompileAndVerify(text, parseOptions: TestOptions.Regular11, expectedOutput: PASS).VerifyIL("Test.Main", @" { // Code size 64 (0x40) .maxstack 2 @@ -5960,7 +5960,7 @@ public static void Main() } static void TestMethod() => Console.WriteLine(""In TestMethod""); } -", parseOptions: TestOptions.RegularNext, expectedOutput: @" +", parseOptions: TestOptions.Regular11, expectedOutput: @" In TestMethod In TestMethod ").VerifyIL("C.Main()", @" @@ -6025,7 +6025,7 @@ static void Main() static void Report(Delegate d) => Console.WriteLine($""{d.GetType().Namespace}.{d.GetType().Name}""); }"; - var comp = CreateCompilation(source, parseOptions: TestOptions.RegularNext, options: TestOptions.DebugExe); + var comp = CreateCompilation(source, parseOptions: TestOptions.Regular11, options: TestOptions.DebugExe); comp.VerifyDiagnostics(); var verifier = CompileAndVerify(comp, expectedOutput: diff --git a/src/Compilers/CSharp/Test/Emit2/Diagnostics/DiagnosticAnalyzerTests.cs b/src/Compilers/CSharp/Test/Emit2/Diagnostics/DiagnosticAnalyzerTests.cs index 9b61d8c724784..31879182e3d37 100644 --- a/src/Compilers/CSharp/Test/Emit2/Diagnostics/DiagnosticAnalyzerTests.cs +++ b/src/Compilers/CSharp/Test/Emit2/Diagnostics/DiagnosticAnalyzerTests.cs @@ -3570,6 +3570,153 @@ await compilationWithAnalyzers.GetAnalysisResultAsync(tree1, CancellationToken.N } } + [Theory, WorkItem(63205, "https://github.com/dotnet/roslyn/issues/63205")] + [CombinatorialData] + public async Task TestGetAnalysisResultWithFilterSpanAsync(bool testSyntaxNodeAction) + { + string source = @" +class B +{ + void M1() + { + int local1 = 1; + } + + void M2() + { + int local2 = 1; + } +}"; + + var compilation = CreateCompilationWithMscorlib45(new[] { source }); + var tree = compilation.SyntaxTrees[0]; + var localDecl1 = tree.GetRoot().DescendantNodes().OfType().First(); + var semanticModel = compilation.GetSemanticModel(tree); + var analyzer1 = new VariableDeclarationAnalyzer("ID0001", testSyntaxNodeAction); + var analyzer2 = new CSharpCompilerDiagnosticAnalyzer(); + var allAnalyzers = ImmutableArray.Create(analyzer1, analyzer2); + var compilationWithAnalyzers = compilation.WithAnalyzers(allAnalyzers); + + // Invoke "GetAnalysisResultAsync" for a a sub-span and then + // for the entire tree span and verify no duplicate diagnostics. + + var analysisResult = await compilationWithAnalyzers.GetAnalysisResultAsync( + semanticModel, + filterSpan: localDecl1.FullSpan, + CancellationToken.None); + + var diagnostics1 = analysisResult.SemanticDiagnostics[tree][analyzer1]; + diagnostics1.Verify( + Diagnostic("ID0001", "int local1 = 1").WithLocation(6, 9)); + + var diagnostics2 = analysisResult.SemanticDiagnostics[tree][analyzer2]; + diagnostics2.Verify( + // (6,13): warning CS0219: The variable 'local1' is assigned but its value is never used + // int local1 = 1; + Diagnostic(ErrorCode.WRN_UnreferencedVarAssg, "local1").WithArguments("local1").WithLocation(6, 13)); + + analysisResult = await compilationWithAnalyzers.GetAnalysisResultAsync( + semanticModel, + filterSpan: null, + CancellationToken.None); + + diagnostics1 = analysisResult.SemanticDiagnostics[tree][analyzer1]; + diagnostics1.Verify( + Diagnostic("ID0001", "int local1 = 1").WithLocation(6, 9), + Diagnostic("ID0001", "int local2 = 1").WithLocation(11, 9)); + + diagnostics2 = analysisResult.SemanticDiagnostics[tree][analyzer2]; + diagnostics2.Verify( + // (6,13): warning CS0219: The variable 'local1' is assigned but its value is never used + // int local1 = 1; + Diagnostic(ErrorCode.WRN_UnreferencedVarAssg, "local1").WithArguments("local1").WithLocation(6, 13), + // (11,13): warning CS0219: The variable 'local2' is assigned but its value is never used + // int local2 = 1; + Diagnostic(ErrorCode.WRN_UnreferencedVarAssg, "local2").WithArguments("local2").WithLocation(11, 13)); + } + + [Theory, CombinatorialData] + [WorkItem(63466, "https://github.com/dotnet/roslyn/issues/63466")] + public async Task TestAnalyzerWithActionsRegisteredAtDifferentScopesAsync(bool testSyntaxNodeAction) + { + string source = @" +public class C +{ + void M() + { + System.Console.WriteLine(1 + 1); + } +} +"; + var compilation = CreateCompilation(source) + .VerifyDiagnostics(); + + var tree = compilation.SyntaxTrees[0]; + var semanticModel = compilation.GetSemanticModel(tree); + var analyzer = new ActionsRegisteredAtDifferentScopesAnalyzer(testSyntaxNodeAction); + var analyzers = ImmutableArray.Create(analyzer); + var compilationWithAnalyzers = compilation.WithAnalyzers(analyzers); + var analysisResult = await compilationWithAnalyzers.GetAnalysisResultAsync( + semanticModel, + filterSpan: null, + CancellationToken.None); + + var diagnostics1 = analysisResult.SemanticDiagnostics[tree][analyzer]; + diagnostics1.Verify( + Diagnostic("MyDiagnostic", "System.Console.WriteLine(1 + 1)").WithLocation(6, 9), + Diagnostic("MyDiagnostic", "1 + 1").WithLocation(6, 34)); + } + + [DiagnosticAnalyzer(LanguageNames.CSharp)] + public class ActionsRegisteredAtDifferentScopesAnalyzer : DiagnosticAnalyzer + { + public const string DiagnosticId = "MyDiagnostic"; + internal const string Title = "MyDiagnostic"; + internal const string MessageFormat = "MyDiagnostic"; + internal const string Category = "Category"; + + private readonly bool _testSyntaxNodeAction; + + public ActionsRegisteredAtDifferentScopesAnalyzer(bool testSyntaxNodeAction) + { + _testSyntaxNodeAction = testSyntaxNodeAction; + } + + internal static DiagnosticDescriptor Rule = new(DiagnosticId, Title, MessageFormat, Category, DiagnosticSeverity.Warning, isEnabledByDefault: true); + + public override ImmutableArray SupportedDiagnostics { get { return ImmutableArray.Create(Rule); } } + + public override void Initialize(AnalysisContext context) + { + if (_testSyntaxNodeAction) + { + context.RegisterSyntaxNodeAction( + context => context.ReportDiagnostic(CodeAnalysis.Diagnostic.Create(Rule, context.Node.GetLocation())), + SyntaxKind.InvocationExpression); + + context.RegisterCodeBlockStartAction(context => + { + context.RegisterSyntaxNodeAction( + context => context.ReportDiagnostic(CodeAnalysis.Diagnostic.Create(Rule, context.Node.GetLocation())), + SyntaxKind.AddExpression); + }); + } + else + { + context.RegisterOperationAction( + context => context.ReportDiagnostic(CodeAnalysis.Diagnostic.Create(Rule, context.Operation.Syntax.GetLocation())), + OperationKind.Invocation); + + context.RegisterOperationBlockStartAction(context => + { + context.RegisterOperationAction( + context => context.ReportDiagnostic(CodeAnalysis.Diagnostic.Create(Rule, context.Operation.Syntax.GetLocation())), + OperationKind.Binary); + }); + } + } + } + [Theory, CombinatorialData] public async Task TestAdditionalFileAnalyzer(bool registerFromInitialize) { diff --git a/src/Compilers/CSharp/Test/Emit2/Diagnostics/OperationAnalyzerTests.cs b/src/Compilers/CSharp/Test/Emit2/Diagnostics/OperationAnalyzerTests.cs index faf119b347e7e..a5f46893e3e8a 100644 --- a/src/Compilers/CSharp/Test/Emit2/Diagnostics/OperationAnalyzerTests.cs +++ b/src/Compilers/CSharp/Test/Emit2/Diagnostics/OperationAnalyzerTests.cs @@ -1328,7 +1328,7 @@ class Test public static long Calculate1(long[] f) { long x; -" + $" x = { buildSequenceOfBinaryExpressions(8192) };" + @" +" + $" x = {buildSequenceOfBinaryExpressions(8192)};" + @" return x; } }"; @@ -1336,8 +1336,8 @@ public static long Calculate1(long[] f) CreateCompilationWithMscorlib45(source) .VerifyDiagnostics() .VerifyAnalyzerDiagnostics(new DiagnosticAnalyzer[] { new AssignmentOperationSyntaxTestAnalyzer() }, null, null, - Diagnostic(AssignmentOperationSyntaxTestAnalyzer.AssignmentOperationDescriptor.Id, $"x = { buildSequenceOfBinaryExpressions(8192) }").WithLocation(7, 9), - Diagnostic(AssignmentOperationSyntaxTestAnalyzer.AssignmentSyntaxDescriptor.Id, $"x = { buildSequenceOfBinaryExpressions(8192) }").WithLocation(7, 9)); + Diagnostic(AssignmentOperationSyntaxTestAnalyzer.AssignmentOperationDescriptor.Id, $"x = {buildSequenceOfBinaryExpressions(8192)}").WithLocation(7, 9), + Diagnostic(AssignmentOperationSyntaxTestAnalyzer.AssignmentSyntaxDescriptor.Id, $"x = {buildSequenceOfBinaryExpressions(8192)}").WithLocation(7, 9)); } [WorkItem(9020, "https://github.com/dotnet/roslyn/issues/9020")] diff --git a/src/Compilers/CSharp/Test/Emit2/Emit/NumericIntPtrTests.cs b/src/Compilers/CSharp/Test/Emit2/Emit/NumericIntPtrTests.cs index e9d2dc566359a..3f2ec933a77d7 100644 --- a/src/Compilers/CSharp/Test/Emit2/Emit/NumericIntPtrTests.cs +++ b/src/Compilers/CSharp/Test/Emit2/Emit/NumericIntPtrTests.cs @@ -875,18 +875,19 @@ class A4 : IA void IA.F1(System.IntPtr x, nuint y) { } }"; - var comp = CreateNumericIntPtrCompilation(new[] { sourceA, sourceB }, references: new[] { MscorlibRefWithoutSharingCachedSymbols }, parseOptions: TestOptions.Regular9); + var mscorlibRefWithoutSharing = MscorlibRefWithoutSharingCachedSymbols; + var comp = CreateNumericIntPtrCompilation(new[] { sourceA, sourceB }, references: new[] { mscorlibRefWithoutSharing }, parseOptions: TestOptions.Regular9); comp.VerifyDiagnostics(); - comp = CreateNumericIntPtrCompilation(sourceA, references: new[] { MscorlibRefWithoutSharingCachedSymbols }, parseOptions: TestOptions.Regular9); + comp = CreateEmptyCompilation(sourceA, references: new[] { mscorlibRefWithoutSharing }, parseOptions: TestOptions.Regular9); comp.VerifyDiagnostics(); var ref1 = comp.ToMetadataReference(); var ref2 = comp.EmitToImageReference(); - comp = CreateNumericIntPtrCompilation(sourceB, references: new[] { ref1, MscorlibRefWithoutSharingCachedSymbols }, parseOptions: TestOptions.Regular9); + comp = CreateEmptyCompilation(sourceB, references: new[] { ref1, mscorlibRefWithoutSharing }, parseOptions: TestOptions.Regular9); comp.VerifyDiagnostics(); - comp = CreateNumericIntPtrCompilation(sourceB, references: new[] { ref2, MscorlibRefWithoutSharingCachedSymbols }, parseOptions: TestOptions.Regular9); + comp = CreateEmptyCompilation(sourceB, references: new[] { ref2, mscorlibRefWithoutSharing }, parseOptions: TestOptions.Regular9); comp.VerifyDiagnostics(); } @@ -937,18 +938,19 @@ class B4 : A Diagnostic(ErrorCode.WRN_NewNotRequired, "F2").WithArguments("B3.F2(nint)").WithLocation(14, 21) }; - var comp = CreateNumericIntPtrCompilation(new[] { sourceA, sourceB }, references: new[] { MscorlibRefWithoutSharingCachedSymbols }, parseOptions: TestOptions.Regular9); + var mscorlibRefWithoutSharing = MscorlibRefWithoutSharingCachedSymbols; + var comp = CreateNumericIntPtrCompilation(new[] { sourceA, sourceB }, references: new[] { mscorlibRefWithoutSharing }, parseOptions: TestOptions.Regular9); comp.VerifyDiagnostics(diagnostics); - comp = CreateNumericIntPtrCompilation(sourceA, references: new[] { MscorlibRefWithoutSharingCachedSymbols }, parseOptions: TestOptions.Regular9); + comp = CreateEmptyCompilation(sourceA, references: new[] { mscorlibRefWithoutSharing }, parseOptions: TestOptions.Regular9); comp.VerifyDiagnostics(); var ref1 = comp.ToMetadataReference(); var ref2 = comp.EmitToImageReference(); - comp = CreateNumericIntPtrCompilation(sourceB, references: new[] { ref1, MscorlibRefWithoutSharingCachedSymbols }, parseOptions: TestOptions.Regular9); + comp = CreateEmptyCompilation(sourceB, references: new[] { ref1, mscorlibRefWithoutSharing }, parseOptions: TestOptions.Regular9); comp.VerifyDiagnostics(diagnostics); - comp = CreateNumericIntPtrCompilation(sourceB, references: new[] { ref2, MscorlibRefWithoutSharingCachedSymbols }, parseOptions: TestOptions.Regular9); + comp = CreateEmptyCompilation(sourceB, references: new[] { ref2, mscorlibRefWithoutSharing }, parseOptions: TestOptions.Regular9); comp.VerifyDiagnostics(diagnostics); } @@ -995,18 +997,19 @@ static void Main() } }"; - var comp = CreateNumericIntPtrCompilation(new[] { sourceA, sourceB }, references: new[] { MscorlibRefWithoutSharingCachedSymbols }, parseOptions: TestOptions.Regular9); + var mscorlibRefWithoutSharing = MscorlibRefWithoutSharingCachedSymbols; + var comp = CreateNumericIntPtrCompilation(new[] { sourceA, sourceB }, references: new[] { mscorlibRefWithoutSharing }, parseOptions: TestOptions.Regular9); comp.VerifyDiagnostics(); - comp = CreateNumericIntPtrCompilation(sourceA, references: new[] { MscorlibRefWithoutSharingCachedSymbols }, parseOptions: TestOptions.Regular9); + comp = CreateEmptyCompilation(sourceA, references: new[] { mscorlibRefWithoutSharing }, parseOptions: TestOptions.Regular9); comp.VerifyDiagnostics(); var ref1 = comp.ToMetadataReference(); var ref2 = comp.EmitToImageReference(); - comp = CreateNumericIntPtrCompilation(sourceB, references: new[] { ref1, MscorlibRefWithoutSharingCachedSymbols }, parseOptions: TestOptions.Regular9); + comp = CreateEmptyCompilation(sourceB, references: new[] { ref1, mscorlibRefWithoutSharing }, parseOptions: TestOptions.Regular9); comp.VerifyDiagnostics(); - comp = CreateNumericIntPtrCompilation(sourceB, references: new[] { ref2, MscorlibRefWithoutSharingCachedSymbols }, parseOptions: TestOptions.Regular9); + comp = CreateEmptyCompilation(sourceB, references: new[] { ref2, mscorlibRefWithoutSharing }, parseOptions: TestOptions.Regular9); comp.VerifyDiagnostics(); } @@ -1234,15 +1237,14 @@ static void Main() var verifier = CompileAndVerify(comp, expectedOutput: @"1"); verifier.VerifyIL("Program.F", @"{ - // Code size 17 (0x11) + // Code size 16 (0x10) .maxstack 2 IL_0000: volatile. IL_0002: ldsfld ""nint Program.F1"" IL_0007: volatile. IL_0009: ldsfld ""nuint Program.F2"" - IL_000e: conv.i - IL_000f: add - IL_0010: ret + IL_000e: add + IL_000f: ret }"); } @@ -1400,7 +1402,8 @@ public class A public static {{nuintType}}? F4; } """; - var comp = CreateNumericIntPtrCompilation(sourceA, references: new[] { MscorlibRefWithoutSharingCachedSymbols }, parseOptions: TestOptions.Regular9); + var mscorlibRefWithoutSharing = MscorlibRefWithoutSharingCachedSymbols; + var comp = CreateNumericIntPtrCompilation(sourceA, references: new[] { mscorlibRefWithoutSharing }, parseOptions: TestOptions.Regular9); comp.VerifyDiagnostics(); var sourceB = @@ -1421,7 +1424,7 @@ static void M2(int x, uint y, int? z, uint? w) F4 = w; } }"; - comp = CreateNumericIntPtrCompilation(sourceB, references: new[] { AsReference(comp, useCompilationReference), MscorlibRefWithoutSharingCachedSymbols }, parseOptions: useLatest ? TestOptions.Regular9 : TestOptions.Regular8); + comp = CreateEmptyCompilation(sourceB, references: new[] { AsReference(comp, useCompilationReference), mscorlibRefWithoutSharing }, parseOptions: useLatest ? TestOptions.Regular9 : TestOptions.Regular8); comp.VerifyDiagnostics(); var verifier = CompileAndVerify(comp); verifier.VerifyIL("B.M1", @@ -1513,7 +1516,8 @@ public class A public static {{nuintType}}? F4; } """; - var comp = CreateNumericIntPtrCompilation(sourceA, references: new[] { MscorlibRefWithoutSharingCachedSymbols }, parseOptions: TestOptions.Regular9); + var mscorlibRefWithoutSharing = MscorlibRefWithoutSharingCachedSymbols; + var comp = CreateNumericIntPtrCompilation(sourceA, references: new[] { mscorlibRefWithoutSharing }, parseOptions: TestOptions.Regular9); comp.VerifyDiagnostics(); var refA = AsReference(comp, useCompilationReference); @@ -1532,7 +1536,7 @@ static void Main() F4 = F4 / F2; } }"; - comp = CreateNumericIntPtrCompilation(sourceB, references: new[] { refA, MscorlibRefWithoutSharingCachedSymbols }, parseOptions: TestOptions.Regular9); + comp = CreateEmptyCompilation(sourceB, references: new[] { refA, mscorlibRefWithoutSharing }, parseOptions: TestOptions.Regular9); comp.VerifyDiagnostics(); var verifier = CompileAndVerify(comp); verifier.VerifyIL("B.Main", @@ -1622,7 +1626,7 @@ .locals init (nint? V_0, IL_00f6: ret }"); - comp = CreateNumericIntPtrCompilation(sourceB, references: new[] { refA, MscorlibRefWithoutSharingCachedSymbols }, parseOptions: TestOptions.Regular8); + comp = CreateEmptyCompilation(sourceB, references: new[] { refA, mscorlibRefWithoutSharing }, parseOptions: TestOptions.Regular8); comp.VerifyDiagnostics( // (5,14): error CS8400: Feature 'native-sized integers' is not available in C# 8.0. Please use language version 9.0 or greater. // F1 = -F1; @@ -2565,7 +2569,8 @@ public void Constants_Fields_02() public const nint C1 = -42; public const nuint C2 = 42; }"; - var comp = CreateNumericIntPtrCompilation(source0, references: new[] { MscorlibRefWithoutSharingCachedSymbols }, parseOptions: TestOptions.Regular9); + var mscorlibRefWithoutSharing = MscorlibRefWithoutSharingCachedSymbols; + var comp = CreateNumericIntPtrCompilation(source0, references: new[] { mscorlibRefWithoutSharing }, parseOptions: TestOptions.Regular9); var ref0 = comp.EmitToImageReference(); var source1 = @"using System; @@ -2577,7 +2582,7 @@ static void Main() Console.WriteLine(A.C2); } }"; - comp = CreateNumericIntPtrCompilation(source1, references: new[] { ref0, MscorlibRefWithoutSharingCachedSymbols }, parseOptions: TestOptions.Regular9, options: TestOptions.ReleaseExe); + comp = CreateEmptyCompilation(source1, references: new[] { ref0, mscorlibRefWithoutSharing }, parseOptions: TestOptions.Regular9, options: TestOptions.ReleaseExe); CompileAndVerify(comp, expectedOutput: @"-42 42"); @@ -2594,7 +2599,8 @@ public void Constants_ParameterDefaults() public static System.UIntPtr F3(System.UIntPtr u = 42) => u; public static nuint F4(nuint u = 42) => u; }"; - var comp = CreateNumericIntPtrCompilation(source0, references: new[] { MscorlibRefWithoutSharingCachedSymbols }, parseOptions: TestOptions.Regular9); + var mscorlibRefWithoutSharing = MscorlibRefWithoutSharingCachedSymbols; + var comp = CreateNumericIntPtrCompilation(source0, references: new[] { mscorlibRefWithoutSharing }, parseOptions: TestOptions.Regular9); var ref0 = comp.EmitToImageReference(); var source1 = @@ -2609,7 +2615,7 @@ static void Main() Console.WriteLine(A.F4()); } }"; - comp = CreateNumericIntPtrCompilation(source1, references: new[] { ref0, MscorlibRefWithoutSharingCachedSymbols }, parseOptions: TestOptions.Regular9, options: TestOptions.ReleaseExe); + comp = CreateEmptyCompilation(source1, references: new[] { ref0, mscorlibRefWithoutSharing }, parseOptions: TestOptions.Regular9, options: TestOptions.ReleaseExe); CompileAndVerify(comp, expectedOutput: @"-42 @@ -2806,23 +2812,24 @@ static void Main() -3 4"; - var comp = CreateNumericIntPtrCompilation(new[] { sourceA, sourceB }, references: new[] { MscorlibRefWithoutSharingCachedSymbols }, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular9); + var mscorlibRefWithoutSharing = MscorlibRefWithoutSharingCachedSymbols; + var comp = CreateNumericIntPtrCompilation(new[] { sourceA, sourceB }, references: new[] { mscorlibRefWithoutSharing }, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular9); CompileAndVerify(comp, expectedOutput: expectedOutput); - comp = CreateNumericIntPtrCompilation(sourceA, references: new[] { MscorlibRefWithoutSharingCachedSymbols }, parseOptions: TestOptions.Regular9); + comp = CreateEmptyCompilation(sourceA, references: new[] { mscorlibRefWithoutSharing }, parseOptions: TestOptions.Regular9); var ref1 = comp.ToMetadataReference(); var ref2 = comp.EmitToImageReference(); - comp = CreateNumericIntPtrCompilation(sourceB, references: new[] { ref1, MscorlibRefWithoutSharingCachedSymbols }, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular9); + comp = CreateEmptyCompilation(sourceB, references: new[] { ref1, mscorlibRefWithoutSharing }, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular9); CompileAndVerify(comp, expectedOutput: expectedOutput); - comp = CreateNumericIntPtrCompilation(sourceB, references: new[] { ref2, MscorlibRefWithoutSharingCachedSymbols }, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular9); + comp = CreateEmptyCompilation(sourceB, references: new[] { ref2, mscorlibRefWithoutSharing }, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular9); CompileAndVerify(comp, expectedOutput: expectedOutput); - comp = CreateNumericIntPtrCompilation(sourceB, references: new[] { ref1, MscorlibRefWithoutSharingCachedSymbols }, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular8); + comp = CreateEmptyCompilation(sourceB, references: new[] { ref1, mscorlibRefWithoutSharing }, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular8); CompileAndVerify(comp, expectedOutput: expectedOutput); - comp = CreateNumericIntPtrCompilation(sourceB, references: new[] { ref2, MscorlibRefWithoutSharingCachedSymbols }, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular8); + comp = CreateEmptyCompilation(sourceB, references: new[] { ref2, mscorlibRefWithoutSharing }, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular8); CompileAndVerify(comp, expectedOutput: expectedOutput); } @@ -3348,7 +3355,7 @@ .maxstack 1 conversions(sourceType: "long", destType: "nint", ExplicitNumeric, expectedImplicitIL: null, expectedExplicitIL: conv("conv.i"), expectedCheckedIL: conv("conv.ovf.i")); conversions(sourceType: "ulong", destType: "nint", ExplicitNumeric, expectedImplicitIL: null, expectedExplicitIL: conv("conv.i"), expectedCheckedIL: conv("conv.ovf.i.un")); conversions(sourceType: "nint", destType: "nint", Identity, expectedImplicitIL: convNone, expectedExplicitIL: convNone); - conversions(sourceType: "nuint", destType: "nint", ExplicitNumeric, expectedImplicitIL: null, expectedExplicitIL: conv("conv.i"), expectedCheckedIL: conv("conv.ovf.i.un")); + conversions(sourceType: "nuint", destType: "nint", ExplicitNumeric, expectedImplicitIL: null, expectedExplicitIL: convNone, expectedCheckedIL: conv("conv.ovf.i.un")); conversions(sourceType: "float", destType: "nint", ExplicitNumeric, expectedImplicitIL: null, expectedExplicitIL: conv("conv.i"), expectedCheckedIL: conv("conv.ovf.i")); conversions(sourceType: "double", destType: "nint", ExplicitNumeric, expectedImplicitIL: null, expectedExplicitIL: conv("conv.i"), expectedCheckedIL: conv("conv.ovf.i")); conversions(sourceType: "decimal", destType: "nint", ExplicitNumeric, expectedImplicitIL: null, @@ -3369,7 +3376,7 @@ .maxstack 1 IL_0007: ret }"); conversions(sourceType: "System.IntPtr", destType: "nint", Identity, expectedImplicitIL: convNone, expectedExplicitIL: convNone); - conversions(sourceType: "System.UIntPtr", destType: "nint", ExplicitNumeric, expectedImplicitIL: null, expectedExplicitIL: conv("conv.i"), expectedCheckedIL: conv("conv.ovf.i.un")); + conversions(sourceType: "System.UIntPtr", destType: "nint", ExplicitNumeric, expectedImplicitIL: null, expectedExplicitIL: convNone, expectedCheckedIL: conv("conv.ovf.i.un")); // nullable type to nint conversions(sourceType: "E?", destType: "nint", ExplicitNullableEnumeration, expectedImplicitIL: null, expectedExplicitIL: convFromNullableT("conv.i", "E")); @@ -3391,7 +3398,17 @@ .maxstack 1 IL_0002: call ""nint nint?.Value.get"" IL_0007: ret }"); - conversions(sourceType: "nuint?", destType: "nint", ExplicitNullableNumeric, expectedImplicitIL: null, expectedExplicitIL: convFromNullableT("conv.i", "nuint"), expectedCheckedIL: convFromNullableT("conv.ovf.i.un", "nuint")); + conversions(sourceType: "nuint?", destType: "nint", ExplicitNullableNumeric, expectedImplicitIL: null, expectedExplicitIL: +@" +{ + // Code size 8 (0x8) + .maxstack 1 + IL_0000: ldarga.s V_0 + IL_0002: call ""nuint nuint?.Value.get"" + IL_0007: ret +} +", + expectedCheckedIL: convFromNullableT("conv.ovf.i.un", "nuint")); conversions(sourceType: "float?", destType: "nint", ExplicitNullableNumeric, expectedImplicitIL: null, expectedExplicitIL: convFromNullableT("conv.i", "float"), expectedCheckedIL: convFromNullableT("conv.ovf.i", "float")); conversions(sourceType: "double?", destType: "nint", ExplicitNullableNumeric, expectedImplicitIL: null, expectedExplicitIL: convFromNullableT("conv.i", "double"), expectedCheckedIL: convFromNullableT("conv.ovf.i", "double")); conversions(sourceType: "decimal?", destType: "nint", ExplicitNullableNumeric, expectedImplicitIL: null, @@ -3421,7 +3438,17 @@ .maxstack 1 IL_0002: call ""nint nint?.Value.get"" IL_0007: ret }"); - conversions(sourceType: "System.UIntPtr?", destType: "nint", ExplicitNullableNumeric, expectedImplicitIL: null, expectedExplicitIL: convFromNullableT("conv.i", "nuint"), expectedCheckedIL: convFromNullableT("conv.ovf.i.un", "nuint")); + conversions(sourceType: "System.UIntPtr?", destType: "nint", ExplicitNullableNumeric, expectedImplicitIL: null, expectedExplicitIL: +@" +{ + // Code size 8 (0x8) + .maxstack 1 + IL_0000: ldarga.s V_0 + IL_0002: call ""nuint nuint?.Value.get"" + IL_0007: ret +} +", + expectedCheckedIL: convFromNullableT("conv.ovf.i.un", "nuint")); // type to nullable nint conversions(sourceType: "object", destType: "nint?", Unboxing, expectedImplicitIL: null, @@ -3491,7 +3518,17 @@ .maxstack 1 IL_0001: newobj ""nint?..ctor(nint)"" IL_0006: ret }"); - conversions(sourceType: "nuint", destType: "nint?", ExplicitNullableNumeric, expectedImplicitIL: null, expectedExplicitIL: convToNullableT("conv.i", "nint"), expectedCheckedIL: convToNullableT("conv.ovf.i.un", "nint")); + conversions(sourceType: "nuint", destType: "nint?", ExplicitNullableNumeric, expectedImplicitIL: null, expectedExplicitIL: +@" +{ + // Code size 7 (0x7) + .maxstack 1 + IL_0000: ldarg.0 + IL_0001: newobj ""nint?..ctor(nint)"" + IL_0006: ret +} +", + expectedCheckedIL: convToNullableT("conv.ovf.i.un", "nint")); conversions(sourceType: "float", destType: "nint?", ExplicitNullableNumeric, expectedImplicitIL: null, expectedExplicitIL: convToNullableT("conv.i", "nint"), expectedCheckedIL: convToNullableT("conv.ovf.i", "nint")); conversions(sourceType: "double", destType: "nint?", ExplicitNullableNumeric, expectedImplicitIL: null, expectedExplicitIL: convToNullableT("conv.i", "nint"), expectedCheckedIL: convToNullableT("conv.ovf.i", "nint")); conversions(sourceType: "decimal", destType: "nint?", ExplicitNullableNumeric, expectedImplicitIL: null, @@ -3528,7 +3565,17 @@ .maxstack 1 IL_0001: newobj ""nint?..ctor(nint)"" IL_0006: ret }"); - conversions(sourceType: "System.UIntPtr", destType: "nint?", ExplicitNullableNumeric, expectedImplicitIL: null, expectedExplicitIL: convToNullableT("conv.i", "nint"), expectedCheckedIL: convToNullableT("conv.ovf.i.un", "nint")); + conversions(sourceType: "System.UIntPtr", destType: "nint?", ExplicitNullableNumeric, expectedImplicitIL: null, expectedExplicitIL: +@" +{ + // Code size 7 (0x7) + .maxstack 1 + IL_0000: ldarg.0 + IL_0001: newobj ""nint?..ctor(nint)"" + IL_0006: ret +} +", + expectedCheckedIL: convToNullableT("conv.ovf.i.un", "nint")); // nullable type to nullable nint conversions(sourceType: "E?", destType: "nint?", ExplicitNullableEnumeration, expectedImplicitIL: null, expectedExplicitIL: convFromToNullableT("conv.i", "E", "nint")); @@ -3543,7 +3590,29 @@ .maxstack 1 conversions(sourceType: "long?", destType: "nint?", ExplicitNullableNumeric, expectedImplicitIL: null, expectedExplicitIL: convFromToNullableT("conv.i", "long", "nint"), expectedCheckedIL: convFromToNullableT("conv.ovf.i", "long", "nint")); conversions(sourceType: "ulong?", destType: "nint?", ExplicitNullableNumeric, expectedImplicitIL: null, expectedExplicitIL: convFromToNullableT("conv.i", "ulong", "nint"), expectedCheckedIL: convFromToNullableT("conv.ovf.i.un", "ulong", "nint")); conversions(sourceType: "nint?", destType: "nint?", Identity, expectedImplicitIL: convNone, expectedExplicitIL: convNone); - conversions(sourceType: "nuint?", destType: "nint?", ExplicitNullableNumeric, expectedImplicitIL: null, expectedExplicitIL: convFromToNullableT("conv.i", "nuint", "nint"), expectedCheckedIL: convFromToNullableT("conv.ovf.i.un", "nuint", "nint")); + conversions(sourceType: "nuint?", destType: "nint?", ExplicitNullableNumeric, expectedImplicitIL: null, expectedExplicitIL: +@" +{ + // Code size 34 (0x22) + .maxstack 1 + .locals init (nuint? V_0, + nint? V_1) + IL_0000: ldarg.0 + IL_0001: stloc.0 + IL_0002: ldloca.s V_0 + IL_0004: call ""bool nuint?.HasValue.get"" + IL_0009: brtrue.s IL_0015 + IL_000b: ldloca.s V_1 + IL_000d: initobj ""nint?"" + IL_0013: ldloc.1 + IL_0014: ret + IL_0015: ldloca.s V_0 + IL_0017: call ""nuint nuint?.GetValueOrDefault()"" + IL_001c: newobj ""nint?..ctor(nint)"" + IL_0021: ret +} +", + expectedCheckedIL: convFromToNullableT("conv.ovf.i.un", "nuint", "nint")); conversions(sourceType: "float?", destType: "nint?", ExplicitNullableNumeric, expectedImplicitIL: null, expectedExplicitIL: convFromToNullableT("conv.i", "float", "nint"), expectedCheckedIL: convFromToNullableT("conv.ovf.i", "float", "nint")); conversions(sourceType: "double?", destType: "nint?", ExplicitNullableNumeric, expectedImplicitIL: null, expectedExplicitIL: convFromToNullableT("conv.i", "double", "nint"), expectedCheckedIL: convFromToNullableT("conv.ovf.i", "double", "nint")); conversions(sourceType: "decimal?", destType: "nint?", ExplicitNullableNumeric, null, @@ -3590,7 +3659,29 @@ .locals init (decimal? V_0, IL_0027: ret }"); conversions(sourceType: "System.IntPtr?", destType: "nint?", Identity, expectedImplicitIL: convNone, expectedExplicitIL: convNone); - conversions(sourceType: "System.UIntPtr?", destType: "nint?", ExplicitNullableNumeric, expectedImplicitIL: null, expectedExplicitIL: convFromToNullableT("conv.i", "nuint", "nint"), expectedCheckedIL: convFromToNullableT("conv.ovf.i.un", "nuint", "nint")); + conversions(sourceType: "System.UIntPtr?", destType: "nint?", ExplicitNullableNumeric, expectedImplicitIL: null, expectedExplicitIL: +@" +{ + // Code size 34 (0x22) + .maxstack 1 + .locals init (nuint? V_0, + nint? V_1) + IL_0000: ldarg.0 + IL_0001: stloc.0 + IL_0002: ldloca.s V_0 + IL_0004: call ""bool nuint?.HasValue.get"" + IL_0009: brtrue.s IL_0015 + IL_000b: ldloca.s V_1 + IL_000d: initobj ""nint?"" + IL_0013: ldloc.1 + IL_0014: ret + IL_0015: ldloca.s V_0 + IL_0017: call ""nuint nuint?.GetValueOrDefault()"" + IL_001c: newobj ""nint?..ctor(nint)"" + IL_0021: ret +} +", + expectedCheckedIL: convFromToNullableT("conv.ovf.i.un", "nuint", "nint")); // nint to type conversions(sourceType: "nint", destType: "object", Boxing, @@ -3642,7 +3733,7 @@ .maxstack 1 IL_0007: ret }"); conversions(sourceType: "nint", destType: "System.IntPtr", Identity, expectedImplicitIL: convNone, expectedExplicitIL: convNone); - conversions(sourceType: "nint", destType: "System.UIntPtr", ExplicitNumeric, expectedImplicitIL: null, expectedExplicitIL: conv("conv.u"), expectedCheckedIL: conv("conv.ovf.u")); + conversions(sourceType: "nint", destType: "System.UIntPtr", ExplicitNumeric, expectedImplicitIL: null, expectedExplicitIL: convNone, expectedCheckedIL: conv("conv.ovf.u")); // nint to nullable type conversions(sourceType: "nint", destType: "E?", ExplicitNullableEnumeration, expectedImplicitIL: null, expectedExplicitIL: convToNullableT("conv.i4", "E"), expectedCheckedIL: convToNullableT("conv.ovf.i4", "E")); @@ -3692,7 +3783,17 @@ .maxstack 1 IL_0001: newobj ""nint?..ctor(nint)"" IL_0006: ret }"); - conversions(sourceType: "nint", destType: "System.UIntPtr?", ExplicitNullableNumeric, expectedImplicitIL: null, expectedExplicitIL: convToNullableT("conv.u", "nuint"), expectedCheckedIL: convToNullableT("conv.ovf.u", "nuint")); + conversions(sourceType: "nint", destType: "System.UIntPtr?", ExplicitNullableNumeric, expectedImplicitIL: null, expectedExplicitIL: +@" +{ + // Code size 7 (0x7) + .maxstack 1 + IL_0000: ldarg.0 + IL_0001: newobj ""nuint?..ctor(nuint)"" + IL_0006: ret +} +", + expectedCheckedIL: convToNullableT("conv.ovf.u", "nuint")); // nullable nint to type conversions(sourceType: "nint?", destType: "object", Boxing, @@ -3744,7 +3845,17 @@ .maxstack 1 IL_0002: call ""nint nint?.Value.get"" IL_0007: ret }"); - conversions(sourceType: "nint?", destType: "System.UIntPtr", ExplicitNullableNumeric, expectedImplicitIL: null, expectedExplicitIL: convFromNullableT("conv.u", "nint"), expectedCheckedIL: convFromNullableT("conv.ovf.u", "nint")); + conversions(sourceType: "nint?", destType: "System.UIntPtr", ExplicitNullableNumeric, expectedImplicitIL: null, expectedExplicitIL: +@" +{ + // Code size 8 (0x8) + .maxstack 1 + IL_0000: ldarga.s V_0 + IL_0002: call ""nint nint?.Value.get"" + IL_0007: ret +} +", + expectedCheckedIL: convFromNullableT("conv.ovf.u", "nint")); // nullable nint to nullable type conversions(sourceType: "nint?", destType: "E?", ExplicitNullableEnumeration, expectedImplicitIL: null, expectedExplicitIL: convFromToNullableT("conv.i4", "nint", "E"), expectedCheckedIL: convFromToNullableT("conv.ovf.i4", "nint", "E")); @@ -3804,7 +3915,29 @@ .locals init (nint? V_0, IL_0027: ret }"); conversions(sourceType: "nint?", destType: "System.IntPtr?", Identity, expectedImplicitIL: convNone, expectedExplicitIL: convNone); - conversions(sourceType: "nint?", destType: "System.UIntPtr?", ExplicitNullableNumeric, expectedImplicitIL: null, expectedExplicitIL: convFromToNullableT("conv.u", "nint", "nuint"), expectedCheckedIL: convFromToNullableT("conv.ovf.u", "nint", "nuint")); + conversions(sourceType: "nint?", destType: "System.UIntPtr?", ExplicitNullableNumeric, expectedImplicitIL: null, expectedExplicitIL: +@" +{ + // Code size 34 (0x22) + .maxstack 1 + .locals init (nint? V_0, + nuint? V_1) + IL_0000: ldarg.0 + IL_0001: stloc.0 + IL_0002: ldloca.s V_0 + IL_0004: call ""bool nint?.HasValue.get"" + IL_0009: brtrue.s IL_0015 + IL_000b: ldloca.s V_1 + IL_000d: initobj ""nuint?"" + IL_0013: ldloc.1 + IL_0014: ret + IL_0015: ldloca.s V_0 + IL_0017: call ""nint nint?.GetValueOrDefault()"" + IL_001c: newobj ""nuint?..ctor(nuint)"" + IL_0021: ret +} +", + expectedCheckedIL: convFromToNullableT("conv.ovf.u", "nint", "nuint")); // type to nuint conversions(sourceType: "object", destType: "nuint", Unboxing, expectedImplicitIL: null, @@ -3829,7 +3962,7 @@ .maxstack 1 conversions(sourceType: "uint", destType: "nuint", ImplicitNumeric, expectedImplicitIL: conv("conv.u"), expectedExplicitIL: conv("conv.u")); conversions(sourceType: "long", destType: "nuint", ExplicitNumeric, expectedImplicitIL: null, expectedExplicitIL: conv("conv.u"), expectedCheckedIL: conv("conv.ovf.u")); conversions(sourceType: "ulong", destType: "nuint", ExplicitNumeric, expectedImplicitIL: null, expectedExplicitIL: conv("conv.u"), expectedCheckedIL: conv("conv.ovf.u.un")); - conversions(sourceType: "nint", destType: "nuint", ExplicitNumeric, expectedImplicitIL: null, expectedExplicitIL: conv("conv.u"), expectedCheckedIL: conv("conv.ovf.u")); + conversions(sourceType: "nint", destType: "nuint", ExplicitNumeric, expectedImplicitIL: null, expectedExplicitIL: convNone, expectedCheckedIL: conv("conv.ovf.u")); conversions(sourceType: "nuint", destType: "nuint", Identity, expectedImplicitIL: convNone, expectedExplicitIL: convNone); conversions(sourceType: "float", destType: "nuint", ExplicitNumeric, expectedImplicitIL: null, expectedExplicitIL: conv("conv.u"), expectedCheckedIL: conv("conv.ovf.u")); conversions(sourceType: "double", destType: "nuint", ExplicitNumeric, expectedImplicitIL: null, expectedExplicitIL: conv("conv.u"), expectedCheckedIL: conv("conv.ovf.u")); @@ -3850,7 +3983,7 @@ .maxstack 1 IL_0006: conv.ovf.u.un IL_0007: ret }"); - conversions(sourceType: "System.IntPtr", destType: "nuint", ExplicitNumeric, expectedImplicitIL: null, expectedExplicitIL: conv("conv.u"), expectedCheckedIL: conv("conv.ovf.u")); + conversions(sourceType: "System.IntPtr", destType: "nuint", ExplicitNumeric, expectedImplicitIL: null, expectedExplicitIL: convNone, expectedCheckedIL: conv("conv.ovf.u")); conversions(sourceType: "System.UIntPtr", destType: "nuint", Identity, expectedImplicitIL: convNone, expectedExplicitIL: convNone); // nullable type to nuint @@ -3865,7 +3998,17 @@ .maxstack 1 conversions(sourceType: "uint?", destType: "nuint", ExplicitNullableImplicitNumeric, expectedImplicitIL: null, expectedExplicitIL: convFromNullableT("conv.u", "uint")); conversions(sourceType: "long?", destType: "nuint", ExplicitNullableNumeric, expectedImplicitIL: null, expectedExplicitIL: convFromNullableT("conv.u", "long"), expectedCheckedIL: convFromNullableT("conv.ovf.u", "long")); conversions(sourceType: "ulong?", destType: "nuint", ExplicitNullableNumeric, expectedImplicitIL: null, expectedExplicitIL: convFromNullableT("conv.u", "ulong"), expectedCheckedIL: convFromNullableT("conv.ovf.u.un", "ulong")); - conversions(sourceType: "nint?", destType: "nuint", ExplicitNullableNumeric, expectedImplicitIL: null, expectedExplicitIL: convFromNullableT("conv.u", "nint"), expectedCheckedIL: convFromNullableT("conv.ovf.u", "nint")); + conversions(sourceType: "nint?", destType: "nuint", ExplicitNullableNumeric, expectedImplicitIL: null, expectedExplicitIL: +@" +{ + // Code size 8 (0x8) + .maxstack 1 + IL_0000: ldarga.s V_0 + IL_0002: call ""nint nint?.Value.get"" + IL_0007: ret +} +", + expectedCheckedIL: convFromNullableT("conv.ovf.u", "nint")); conversions(sourceType: "nuint?", destType: "nuint", ExplicitNullableIdentity, expectedImplicitIL: null, @"{ // Code size 8 (0x8) @@ -3895,7 +4038,15 @@ .maxstack 1 IL_000c: conv.ovf.u.un IL_000d: ret }"); - conversions(sourceType: "System.IntPtr?", destType: "nuint", ExplicitNullableNumeric, expectedImplicitIL: null, expectedExplicitIL: convFromNullableT("conv.u", "nint"), expectedCheckedIL: convFromNullableT("conv.ovf.u", "nint")); + conversions(sourceType: "System.IntPtr?", destType: "nuint", ExplicitNullableNumeric, expectedImplicitIL: null, expectedExplicitIL: +@"{ + // Code size 8 (0x8) + .maxstack 1 + IL_0000: ldarga.s V_0 + IL_0002: call ""nint nint?.Value.get"" + IL_0007: ret +}", + expectedCheckedIL: convFromNullableT("conv.ovf.u", "nint")); conversions(sourceType: "System.UIntPtr?", destType: "nuint", ExplicitNullableIdentity, expectedImplicitIL: null, @"{ // Code size 8 (0x8) @@ -3942,7 +4093,17 @@ .maxstack 1 conversions(sourceType: "uint", destType: "nuint?", ImplicitNullableNumeric, expectedImplicitIL: convToNullableT("conv.u", "nuint"), expectedExplicitIL: convToNullableT("conv.u", "nuint")); conversions(sourceType: "long", destType: "nuint?", ExplicitNullableNumeric, expectedImplicitIL: null, expectedExplicitIL: convToNullableT("conv.u", "nuint"), expectedCheckedIL: convToNullableT("conv.ovf.u", "nuint")); conversions(sourceType: "ulong", destType: "nuint?", ExplicitNullableNumeric, expectedImplicitIL: null, expectedExplicitIL: convToNullableT("conv.u", "nuint"), expectedCheckedIL: convToNullableT("conv.ovf.u.un", "nuint")); - conversions(sourceType: "nint", destType: "nuint?", ExplicitNullableNumeric, expectedImplicitIL: null, expectedExplicitIL: convToNullableT("conv.u", "nuint"), expectedCheckedIL: convToNullableT("conv.ovf.u", "nuint")); + conversions(sourceType: "nint", destType: "nuint?", ExplicitNullableNumeric, expectedImplicitIL: null, expectedExplicitIL: +@" +{ + // Code size 7 (0x7) + .maxstack 1 + IL_0000: ldarg.0 + IL_0001: newobj ""nuint?..ctor(nuint)"" + IL_0006: ret +} +", + expectedCheckedIL: convToNullableT("conv.ovf.u", "nuint")); conversions(sourceType: "nuint", destType: "nuint?", ImplicitNullableIdentity, @"{ // Code size 7 (0x7) @@ -3979,7 +4140,17 @@ .maxstack 1 IL_0007: newobj ""nuint?..ctor(nuint)"" IL_000c: ret }"); - conversions(sourceType: "System.IntPtr", destType: "nuint?", ExplicitNullableNumeric, expectedImplicitIL: null, expectedExplicitIL: convToNullableT("conv.u", "nuint"), expectedCheckedIL: convToNullableT("conv.ovf.u", "nuint")); + conversions(sourceType: "System.IntPtr", destType: "nuint?", ExplicitNullableNumeric, expectedImplicitIL: null, expectedExplicitIL: +@" +{ + // Code size 7 (0x7) + .maxstack 1 + IL_0000: ldarg.0 + IL_0001: newobj ""nuint?..ctor(nuint)"" + IL_0006: ret +} +", + expectedCheckedIL: convToNullableT("conv.ovf.u", "nuint")); conversions(sourceType: "System.UIntPtr", destType: "nuint?", ImplicitNullableIdentity, @"{ // Code size 7 (0x7) @@ -4008,7 +4179,29 @@ .maxstack 1 conversions(sourceType: "uint?", destType: "nuint?", ImplicitNullableNumeric, expectedImplicitIL: convFromToNullableT("conv.u", "uint", "nuint"), expectedExplicitIL: convFromToNullableT("conv.u", "uint", "nuint")); conversions(sourceType: "long?", destType: "nuint?", ExplicitNullableNumeric, expectedImplicitIL: null, expectedExplicitIL: convFromToNullableT("conv.u", "long", "nuint"), expectedCheckedIL: convFromToNullableT("conv.ovf.u", "long", "nuint")); conversions(sourceType: "ulong?", destType: "nuint?", ExplicitNullableNumeric, expectedImplicitIL: null, expectedExplicitIL: convFromToNullableT("conv.u", "ulong", "nuint"), expectedCheckedIL: convFromToNullableT("conv.ovf.u.un", "ulong", "nuint")); - conversions(sourceType: "nint?", destType: "nuint?", ExplicitNullableNumeric, expectedImplicitIL: null, expectedExplicitIL: convFromToNullableT("conv.u", "nint", "nuint"), expectedCheckedIL: convFromToNullableT("conv.ovf.u", "nint", "nuint")); + conversions(sourceType: "nint?", destType: "nuint?", ExplicitNullableNumeric, expectedImplicitIL: null, expectedExplicitIL: +@" +{ + // Code size 34 (0x22) + .maxstack 1 + .locals init (nint? V_0, + nuint? V_1) + IL_0000: ldarg.0 + IL_0001: stloc.0 + IL_0002: ldloca.s V_0 + IL_0004: call ""bool nint?.HasValue.get"" + IL_0009: brtrue.s IL_0015 + IL_000b: ldloca.s V_1 + IL_000d: initobj ""nuint?"" + IL_0013: ldloc.1 + IL_0014: ret + IL_0015: ldloca.s V_0 + IL_0017: call ""nint nint?.GetValueOrDefault()"" + IL_001c: newobj ""nuint?..ctor(nuint)"" + IL_0021: ret +} +", + expectedCheckedIL: convFromToNullableT("conv.ovf.u", "nint", "nuint")); conversions(sourceType: "nuint?", destType: "nuint?", Identity, expectedImplicitIL: convNone, expectedExplicitIL: convNone); conversions(sourceType: "float?", destType: "nuint?", ExplicitNullableNumeric, expectedImplicitIL: null, expectedExplicitIL: convFromToNullableT("conv.u", "float", "nuint"), expectedCheckedIL: convFromToNullableT("conv.ovf.u", "float", "nuint")); conversions(sourceType: "double?", destType: "nuint?", ExplicitNullableNumeric, expectedImplicitIL: null, expectedExplicitIL: convFromToNullableT("conv.u", "double", "nuint"), expectedCheckedIL: convFromToNullableT("conv.ovf.u", "double", "nuint")); @@ -4055,7 +4248,29 @@ .locals init (decimal? V_0, IL_0022: newobj ""nuint?..ctor(nuint)"" IL_0027: ret }"); - conversions(sourceType: "System.IntPtr?", destType: "nuint?", ExplicitNullableNumeric, expectedImplicitIL: null, expectedExplicitIL: convFromToNullableT("conv.u", "nint", "nuint"), expectedCheckedIL: convFromToNullableT("conv.ovf.u", "nint", "nuint")); + conversions(sourceType: "System.IntPtr?", destType: "nuint?", ExplicitNullableNumeric, expectedImplicitIL: null, expectedExplicitIL: +@" +{ + // Code size 34 (0x22) + .maxstack 1 + .locals init (nint? V_0, + nuint? V_1) + IL_0000: ldarg.0 + IL_0001: stloc.0 + IL_0002: ldloca.s V_0 + IL_0004: call ""bool nint?.HasValue.get"" + IL_0009: brtrue.s IL_0015 + IL_000b: ldloca.s V_1 + IL_000d: initobj ""nuint?"" + IL_0013: ldloc.1 + IL_0014: ret + IL_0015: ldloca.s V_0 + IL_0017: call ""nint nint?.GetValueOrDefault()"" + IL_001c: newobj ""nuint?..ctor(nuint)"" + IL_0021: ret +} +", + expectedCheckedIL: convFromToNullableT("conv.ovf.u", "nint", "nuint")); conversions(sourceType: "System.UIntPtr?", destType: "nuint?", Identity, expectedImplicitIL: convNone, expectedExplicitIL: convNone); // nuint to type @@ -4107,7 +4322,7 @@ .maxstack 1 IL_0002: call ""decimal decimal.op_Implicit(ulong)"" IL_0007: ret }"); - conversions(sourceType: "nuint", destType: "System.IntPtr", ExplicitNumeric, expectedImplicitIL: null, expectedExplicitIL: conv("conv.i"), expectedCheckedIL: conv("conv.ovf.i.un")); + conversions(sourceType: "nuint", destType: "System.IntPtr", ExplicitNumeric, expectedImplicitIL: null, expectedExplicitIL: convNone, expectedCheckedIL: conv("conv.ovf.i.un")); conversions(sourceType: "nuint", destType: "System.UIntPtr", Identity, expectedImplicitIL: convNone, expectedExplicitIL: convNone); // nuint to nullable type @@ -4143,7 +4358,17 @@ .maxstack 1 IL_0007: newobj ""decimal?..ctor(decimal)"" IL_000c: ret }"); - conversions(sourceType: "nuint", destType: "System.IntPtr?", ExplicitNullableNumeric, expectedImplicitIL: null, expectedExplicitIL: convToNullableT("conv.i", "nint"), expectedCheckedIL: convToNullableT("conv.ovf.i.un", "nint")); + conversions(sourceType: "nuint", destType: "System.IntPtr?", ExplicitNullableNumeric, expectedImplicitIL: null, expectedExplicitIL: +@" +{ + // Code size 7 (0x7) + .maxstack 1 + IL_0000: ldarg.0 + IL_0001: newobj ""nint?..ctor(nint)"" + IL_0006: ret +} +", + expectedCheckedIL: convToNullableT("conv.ovf.i.un", "nint")); conversions(sourceType: "nuint", destType: "System.UIntPtr?", ImplicitNullableIdentity, @"{ // Code size 7 (0x7) @@ -4202,7 +4427,17 @@ .maxstack 1 IL_0008: call ""decimal decimal.op_Implicit(ulong)"" IL_000d: ret }"); - conversions(sourceType: "nuint?", destType: "System.IntPtr", ExplicitNullableNumeric, expectedImplicitIL: null, expectedExplicitIL: convFromNullableT("conv.i", "nuint"), expectedCheckedIL: convFromNullableT("conv.ovf.i.un", "nuint")); + conversions(sourceType: "nuint?", destType: "System.IntPtr", ExplicitNullableNumeric, expectedImplicitIL: null, expectedExplicitIL: +@" +{ + // Code size 8 (0x8) + .maxstack 1 + IL_0000: ldarga.s V_0 + IL_0002: call ""nuint nuint?.Value.get"" + IL_0007: ret +} +", + expectedCheckedIL: convFromNullableT("conv.ovf.i.un", "nuint")); conversions(sourceType: "nuint?", destType: "System.UIntPtr", ExplicitNullableIdentity, expectedImplicitIL: null, @"{ // Code size 8 (0x8) @@ -4269,7 +4504,29 @@ .locals init (nuint? V_0, IL_0022: newobj ""decimal?..ctor(decimal)"" IL_0027: ret }"); - conversions(sourceType: "nuint?", destType: "System.IntPtr?", ExplicitNullableNumeric, expectedImplicitIL: null, expectedExplicitIL: convFromToNullableT("conv.i", "nuint", "nint"), expectedCheckedIL: convFromToNullableT("conv.ovf.i.un", "nuint", "nint")); + conversions(sourceType: "nuint?", destType: "System.IntPtr?", ExplicitNullableNumeric, expectedImplicitIL: null, expectedExplicitIL: +@" +{ + // Code size 34 (0x22) + .maxstack 1 + .locals init (nuint? V_0, + nint? V_1) + IL_0000: ldarg.0 + IL_0001: stloc.0 + IL_0002: ldloca.s V_0 + IL_0004: call ""bool nuint?.HasValue.get"" + IL_0009: brtrue.s IL_0015 + IL_000b: ldloca.s V_1 + IL_000d: initobj ""nint?"" + IL_0013: ldloc.1 + IL_0014: ret + IL_0015: ldloca.s V_0 + IL_0017: call ""nuint nuint?.GetValueOrDefault()"" + IL_001c: newobj ""nint?..ctor(nint)"" + IL_0021: ret +} +", + expectedCheckedIL: convFromToNullableT("conv.ovf.i.un", "nuint", "nint")); conversions(sourceType: "nuint?", destType: "System.UIntPtr?", Identity, expectedImplicitIL: convNone, expectedExplicitIL: convNone); // System.IntPtr to type @@ -4325,7 +4582,7 @@ .maxstack 1 IL_0007: ret }"); conversions(sourceType: "System.IntPtr", destType: "System.IntPtr", Identity, expectedImplicitIL: convNone, expectedExplicitIL: convNone); - conversions(sourceType: "System.IntPtr", destType: "System.UIntPtr", ExplicitNumeric, expectedImplicitIL: null, expectedExplicitIL: conv("conv.u"), expectedCheckedIL: conv("conv.ovf.u")); + conversions(sourceType: "System.IntPtr", destType: "System.UIntPtr", ExplicitNumeric, expectedImplicitIL: null, expectedExplicitIL: convNone, expectedCheckedIL: conv("conv.ovf.u")); // System.IntPtr to nullable type conversions(sourceType: "System.IntPtr", destType: "E?", ExplicitNullableEnumeration, expectedImplicitIL: null, expectedExplicitIL: convToNullableT("conv.i4", "E"), expectedCheckedIL: convToNullableT("conv.ovf.i4", "E")); @@ -4375,7 +4632,17 @@ .maxstack 1 IL_0001: newobj ""nint?..ctor(nint)"" IL_0006: ret }"); - conversions(sourceType: "System.IntPtr", destType: "System.UIntPtr?", ExplicitNullableNumeric, expectedImplicitIL: null, expectedExplicitIL: convToNullableT("conv.u", "nuint"), expectedCheckedIL: convToNullableT("conv.ovf.u", "nuint")); + conversions(sourceType: "System.IntPtr", destType: "System.UIntPtr?", ExplicitNullableNumeric, expectedImplicitIL: null, expectedExplicitIL: +@" +{ + // Code size 7 (0x7) + .maxstack 1 + IL_0000: ldarg.0 + IL_0001: newobj ""nuint?..ctor(nuint)"" + IL_0006: ret +} +", + expectedCheckedIL: convToNullableT("conv.ovf.u", "nuint")); // nullable System.IntPtr to type conversions(sourceType: "System.IntPtr?", destType: "object", Boxing, @@ -4427,7 +4694,17 @@ .maxstack 1 IL_0002: call ""nint nint?.Value.get"" IL_0007: ret }"); - conversions(sourceType: "System.IntPtr?", destType: "System.UIntPtr", ExplicitNullableNumeric, expectedImplicitIL: null, expectedExplicitIL: convFromNullableT("conv.u", "nint"), expectedCheckedIL: convFromNullableT("conv.ovf.u", "nint")); + conversions(sourceType: "System.IntPtr?", destType: "System.UIntPtr", ExplicitNullableNumeric, expectedImplicitIL: null, expectedExplicitIL: +@" +{ + // Code size 8 (0x8) + .maxstack 1 + IL_0000: ldarga.s V_0 + IL_0002: call ""nint nint?.Value.get"" + IL_0007: ret +} +", + expectedCheckedIL: convFromNullableT("conv.ovf.u", "nint")); // nullable System.IntPtr to nullable type conversions(sourceType: "System.IntPtr?", destType: "E?", ExplicitNullableEnumeration, expectedImplicitIL: null, expectedExplicitIL: convFromToNullableT("conv.i4", "nint", "E"), expectedCheckedIL: convFromToNullableT("conv.ovf.i4", "nint", "E")); @@ -4487,7 +4764,29 @@ .locals init (nint? V_0, IL_0027: ret }"); conversions(sourceType: "System.IntPtr?", destType: "System.IntPtr?", Identity, expectedImplicitIL: convNone, expectedExplicitIL: convNone); - conversions(sourceType: "System.IntPtr?", destType: "System.UIntPtr?", ExplicitNullableNumeric, expectedImplicitIL: null, expectedExplicitIL: convFromToNullableT("conv.u", "nint", "nuint"), expectedCheckedIL: convFromToNullableT("conv.ovf.u", "nint", "nuint")); + conversions(sourceType: "System.IntPtr?", destType: "System.UIntPtr?", ExplicitNullableNumeric, expectedImplicitIL: null, expectedExplicitIL: +@" +{ + // Code size 34 (0x22) + .maxstack 1 + .locals init (nint? V_0, + nuint? V_1) + IL_0000: ldarg.0 + IL_0001: stloc.0 + IL_0002: ldloca.s V_0 + IL_0004: call ""bool nint?.HasValue.get"" + IL_0009: brtrue.s IL_0015 + IL_000b: ldloca.s V_1 + IL_000d: initobj ""nuint?"" + IL_0013: ldloc.1 + IL_0014: ret + IL_0015: ldloca.s V_0 + IL_0017: call ""nint nint?.GetValueOrDefault()"" + IL_001c: newobj ""nuint?..ctor(nuint)"" + IL_0021: ret +} +", + expectedCheckedIL: convFromToNullableT("conv.ovf.u", "nint", "nuint")); // type to System.IntPtr conversions(sourceType: "object", destType: "System.IntPtr", Unboxing, expectedImplicitIL: null, @@ -4513,7 +4812,7 @@ .maxstack 1 conversions(sourceType: "long", destType: "System.IntPtr", ExplicitNumeric, expectedImplicitIL: null, expectedExplicitIL: conv("conv.i"), expectedCheckedIL: conv("conv.ovf.i")); conversions(sourceType: "ulong", destType: "System.IntPtr", ExplicitNumeric, expectedImplicitIL: null, expectedExplicitIL: conv("conv.i"), expectedCheckedIL: conv("conv.ovf.i.un")); conversions(sourceType: "nint", destType: "System.IntPtr", Identity, expectedImplicitIL: convNone, expectedExplicitIL: convNone); - conversions(sourceType: "nuint", destType: "System.IntPtr", ExplicitNumeric, expectedImplicitIL: null, expectedExplicitIL: conv("conv.i"), expectedCheckedIL: conv("conv.ovf.i.un")); + conversions(sourceType: "nuint", destType: "System.IntPtr", ExplicitNumeric, expectedImplicitIL: null, expectedExplicitIL: convNone, expectedCheckedIL: conv("conv.ovf.i.un")); conversions(sourceType: "float", destType: "System.IntPtr", ExplicitNumeric, expectedImplicitIL: null, expectedExplicitIL: conv("conv.i"), expectedCheckedIL: conv("conv.ovf.i")); conversions(sourceType: "double", destType: "System.IntPtr", ExplicitNumeric, expectedImplicitIL: null, expectedExplicitIL: conv("conv.i"), expectedCheckedIL: conv("conv.ovf.i")); conversions(sourceType: "decimal", destType: "System.IntPtr", ExplicitNumeric, expectedImplicitIL: null, @@ -4533,7 +4832,7 @@ .maxstack 1 IL_0006: conv.ovf.i IL_0007: ret }"); - conversions(sourceType: "System.UIntPtr", destType: "System.IntPtr", ExplicitNumeric, expectedImplicitIL: null, expectedExplicitIL: conv("conv.i"), expectedCheckedIL: conv("conv.ovf.i.un")); + conversions(sourceType: "System.UIntPtr", destType: "System.IntPtr", ExplicitNumeric, expectedImplicitIL: null, expectedExplicitIL: convNone, expectedCheckedIL: conv("conv.ovf.i.un")); // type to nullable System.IntPtr conversions(sourceType: "object", destType: "System.IntPtr?", Unboxing, expectedImplicitIL: null, @@ -4603,7 +4902,17 @@ .maxstack 1 IL_0001: newobj ""nint?..ctor(nint)"" IL_0006: ret }"); - conversions(sourceType: "nuint", destType: "System.IntPtr?", ExplicitNullableNumeric, expectedImplicitIL: null, expectedExplicitIL: convToNullableT("conv.i", "nint"), expectedCheckedIL: convToNullableT("conv.ovf.i.un", "nint")); + conversions(sourceType: "nuint", destType: "System.IntPtr?", ExplicitNullableNumeric, expectedImplicitIL: null, expectedExplicitIL: +@" +{ + // Code size 7 (0x7) + .maxstack 1 + IL_0000: ldarg.0 + IL_0001: newobj ""nint?..ctor(nint)"" + IL_0006: ret +} +", + expectedCheckedIL: convToNullableT("conv.ovf.i.un", "nint")); conversions(sourceType: "float", destType: "System.IntPtr?", ExplicitNullableNumeric, expectedImplicitIL: null, expectedExplicitIL: convToNullableT("conv.i", "nint"), expectedCheckedIL: convToNullableT("conv.ovf.i", "nint")); conversions(sourceType: "double", destType: "System.IntPtr?", ExplicitNullableNumeric, expectedImplicitIL: null, expectedExplicitIL: convToNullableT("conv.i", "nint"), expectedCheckedIL: convToNullableT("conv.ovf.i", "nint")); conversions(sourceType: "decimal", destType: "System.IntPtr?", ExplicitNullableNumeric, expectedImplicitIL: null, @@ -4640,7 +4949,17 @@ .maxstack 1 IL_0001: newobj ""nint?..ctor(nint)"" IL_0006: ret }"); - conversions(sourceType: "System.UIntPtr", destType: "System.IntPtr?", ExplicitNullableNumeric, expectedImplicitIL: null, expectedExplicitIL: convToNullableT("conv.i", "nint"), expectedCheckedIL: convToNullableT("conv.ovf.i.un", "nint")); + conversions(sourceType: "System.UIntPtr", destType: "System.IntPtr?", ExplicitNullableNumeric, expectedImplicitIL: null, expectedExplicitIL: +@" +{ + // Code size 7 (0x7) + .maxstack 1 + IL_0000: ldarg.0 + IL_0001: newobj ""nint?..ctor(nint)"" + IL_0006: ret +} +", + expectedCheckedIL: convToNullableT("conv.ovf.i.un", "nint")); // nullable type to System.IntPtr conversions(sourceType: "E?", destType: "System.IntPtr", ExplicitNullableEnumeration, expectedImplicitIL: null, expectedExplicitIL: convFromNullableT("conv.i", "E")); @@ -4662,7 +4981,17 @@ .maxstack 1 IL_0002: call ""nint nint?.Value.get"" IL_0007: ret }"); - conversions(sourceType: "nuint?", destType: "System.IntPtr", ExplicitNullableNumeric, expectedImplicitIL: null, expectedExplicitIL: convFromNullableT("conv.i", "nuint"), expectedCheckedIL: convFromNullableT("conv.ovf.i.un", "nuint")); + conversions(sourceType: "nuint?", destType: "System.IntPtr", ExplicitNullableNumeric, expectedImplicitIL: null, expectedExplicitIL: +@" +{ + // Code size 8 (0x8) + .maxstack 1 + IL_0000: ldarga.s V_0 + IL_0002: call ""nuint nuint?.Value.get"" + IL_0007: ret +} +", + expectedCheckedIL: convFromNullableT("conv.ovf.i.un", "nuint")); conversions(sourceType: "float?", destType: "System.IntPtr", ExplicitNullableNumeric, expectedImplicitIL: null, expectedExplicitIL: convFromNullableT("conv.i", "float"), expectedCheckedIL: convFromNullableT("conv.ovf.i", "float")); conversions(sourceType: "double?", destType: "System.IntPtr", ExplicitNullableNumeric, expectedImplicitIL: null, expectedExplicitIL: convFromNullableT("conv.i", "double"), expectedCheckedIL: convFromNullableT("conv.ovf.i", "double")); conversions(sourceType: "decimal?", destType: "System.IntPtr", ExplicitNullableNumeric, expectedImplicitIL: null, @@ -4692,7 +5021,17 @@ .maxstack 1 IL_0002: call ""nint nint?.Value.get"" IL_0007: ret }"); - conversions(sourceType: "System.UIntPtr?", destType: "System.IntPtr", ExplicitNullableNumeric, expectedImplicitIL: null, expectedExplicitIL: convFromNullableT("conv.i", "nuint"), expectedCheckedIL: convFromNullableT("conv.ovf.i.un", "nuint")); + conversions(sourceType: "System.UIntPtr?", destType: "System.IntPtr", ExplicitNullableNumeric, expectedImplicitIL: null, expectedExplicitIL: +@" +{ + // Code size 8 (0x8) + .maxstack 1 + IL_0000: ldarga.s V_0 + IL_0002: call ""nuint nuint?.Value.get"" + IL_0007: ret +} +", + expectedCheckedIL: convFromNullableT("conv.ovf.i.un", "nuint")); // nullable type to nullable System.IntPtr conversions(sourceType: "E?", destType: "System.IntPtr?", ExplicitNullableEnumeration, expectedImplicitIL: null, expectedExplicitIL: convFromToNullableT("conv.i", "E", "nint")); @@ -4707,7 +5046,29 @@ .maxstack 1 conversions(sourceType: "long?", destType: "System.IntPtr?", ExplicitNullableNumeric, expectedImplicitIL: null, expectedExplicitIL: convFromToNullableT("conv.i", "long", "nint"), expectedCheckedIL: convFromToNullableT("conv.ovf.i", "long", "nint")); conversions(sourceType: "ulong?", destType: "System.IntPtr?", ExplicitNullableNumeric, expectedImplicitIL: null, expectedExplicitIL: convFromToNullableT("conv.i", "ulong", "nint"), expectedCheckedIL: convFromToNullableT("conv.ovf.i.un", "ulong", "nint")); conversions(sourceType: "nint?", destType: "System.IntPtr?", Identity, expectedImplicitIL: convNone, expectedExplicitIL: convNone); - conversions(sourceType: "nuint?", destType: "System.IntPtr?", ExplicitNullableNumeric, expectedImplicitIL: null, expectedExplicitIL: convFromToNullableT("conv.i", "nuint", "nint"), expectedCheckedIL: convFromToNullableT("conv.ovf.i.un", "nuint", "nint")); + conversions(sourceType: "nuint?", destType: "System.IntPtr?", ExplicitNullableNumeric, expectedImplicitIL: null, expectedExplicitIL: +@" +{ + // Code size 34 (0x22) + .maxstack 1 + .locals init (nuint? V_0, + nint? V_1) + IL_0000: ldarg.0 + IL_0001: stloc.0 + IL_0002: ldloca.s V_0 + IL_0004: call ""bool nuint?.HasValue.get"" + IL_0009: brtrue.s IL_0015 + IL_000b: ldloca.s V_1 + IL_000d: initobj ""nint?"" + IL_0013: ldloc.1 + IL_0014: ret + IL_0015: ldloca.s V_0 + IL_0017: call ""nuint nuint?.GetValueOrDefault()"" + IL_001c: newobj ""nint?..ctor(nint)"" + IL_0021: ret +} +", + expectedCheckedIL: convFromToNullableT("conv.ovf.i.un", "nuint", "nint")); conversions(sourceType: "float?", destType: "System.IntPtr?", ExplicitNullableNumeric, expectedImplicitIL: null, expectedExplicitIL: convFromToNullableT("conv.i", "float", "nint"), expectedCheckedIL: convFromToNullableT("conv.ovf.i", "float", "nint")); conversions(sourceType: "double?", destType: "System.IntPtr?", ExplicitNullableNumeric, expectedImplicitIL: null, expectedExplicitIL: convFromToNullableT("conv.i", "double", "nint"), expectedCheckedIL: convFromToNullableT("conv.ovf.i", "double", "nint")); conversions(sourceType: "decimal?", destType: "System.IntPtr?", ExplicitNullableNumeric, null, @@ -4754,7 +5115,29 @@ .locals init (decimal? V_0, IL_0027: ret }"); conversions(sourceType: "System.IntPtr?", destType: "System.IntPtr?", Identity, expectedImplicitIL: convNone, expectedExplicitIL: convNone); - conversions(sourceType: "System.UIntPtr?", destType: "System.IntPtr?", ExplicitNullableNumeric, expectedImplicitIL: null, expectedExplicitIL: convFromToNullableT("conv.i", "nuint", "nint"), expectedCheckedIL: convFromToNullableT("conv.ovf.i.un", "nuint", "nint")); + conversions(sourceType: "System.UIntPtr?", destType: "System.IntPtr?", ExplicitNullableNumeric, expectedImplicitIL: null, expectedExplicitIL: +@" +{ + // Code size 34 (0x22) + .maxstack 1 + .locals init (nuint? V_0, + nint? V_1) + IL_0000: ldarg.0 + IL_0001: stloc.0 + IL_0002: ldloca.s V_0 + IL_0004: call ""bool nuint?.HasValue.get"" + IL_0009: brtrue.s IL_0015 + IL_000b: ldloca.s V_1 + IL_000d: initobj ""nint?"" + IL_0013: ldloc.1 + IL_0014: ret + IL_0015: ldloca.s V_0 + IL_0017: call ""nuint nuint?.GetValueOrDefault()"" + IL_001c: newobj ""nint?..ctor(nint)"" + IL_0021: ret +} +", + expectedCheckedIL: convFromToNullableT("conv.ovf.i.un", "nuint", "nint")); // System.UIntPtr to type conversions(sourceType: "System.UIntPtr", destType: "object", Boxing, @@ -4805,7 +5188,7 @@ .maxstack 1 IL_0002: call ""decimal decimal.op_Implicit(ulong)"" IL_0007: ret }"); - conversions(sourceType: "System.UIntPtr", destType: "System.IntPtr", ExplicitNumeric, expectedImplicitIL: null, expectedExplicitIL: conv("conv.i"), expectedCheckedIL: conv("conv.ovf.i.un")); + conversions(sourceType: "System.UIntPtr", destType: "System.IntPtr", ExplicitNumeric, expectedImplicitIL: null, expectedExplicitIL: convNone, expectedCheckedIL: conv("conv.ovf.i.un")); conversions(sourceType: "System.UIntPtr", destType: "System.UIntPtr", Identity, expectedImplicitIL: convNone, expectedExplicitIL: convNone); // System.UIntPtr to nullable type @@ -4841,7 +5224,17 @@ .maxstack 1 IL_0007: newobj ""decimal?..ctor(decimal)"" IL_000c: ret }"); - conversions(sourceType: "System.UIntPtr", destType: "System.IntPtr?", ExplicitNullableNumeric, expectedImplicitIL: null, expectedExplicitIL: convToNullableT("conv.i", "nint"), expectedCheckedIL: convToNullableT("conv.ovf.i.un", "nint")); + conversions(sourceType: "System.UIntPtr", destType: "System.IntPtr?", ExplicitNullableNumeric, expectedImplicitIL: null, expectedExplicitIL: +@" +{ + // Code size 7 (0x7) + .maxstack 1 + IL_0000: ldarg.0 + IL_0001: newobj ""nint?..ctor(nint)"" + IL_0006: ret +} +", + expectedCheckedIL: convToNullableT("conv.ovf.i.un", "nint")); conversions(sourceType: "System.UIntPtr", destType: "System.UIntPtr?", ImplicitNullableIdentity, @"{ // Code size 7 (0x7) @@ -4900,7 +5293,17 @@ .maxstack 1 IL_0008: call ""decimal decimal.op_Implicit(ulong)"" IL_000d: ret }"); - conversions(sourceType: "System.UIntPtr?", destType: "System.IntPtr", ExplicitNullableNumeric, expectedImplicitIL: null, expectedExplicitIL: convFromNullableT("conv.i", "nuint"), expectedCheckedIL: convFromNullableT("conv.ovf.i.un", "nuint")); + conversions(sourceType: "System.UIntPtr?", destType: "System.IntPtr", ExplicitNullableNumeric, expectedImplicitIL: null, expectedExplicitIL: +@" +{ + // Code size 8 (0x8) + .maxstack 1 + IL_0000: ldarga.s V_0 + IL_0002: call ""nuint nuint?.Value.get"" + IL_0007: ret +} +", + expectedCheckedIL: convFromNullableT("conv.ovf.i.un", "nuint")); conversions(sourceType: "System.UIntPtr?", destType: "System.UIntPtr", ExplicitNullableIdentity, expectedImplicitIL: null, @"{ // Code size 8 (0x8) @@ -4967,7 +5370,29 @@ .locals init (nuint? V_0, IL_0022: newobj ""decimal?..ctor(decimal)"" IL_0027: ret }"); - conversions(sourceType: "System.UIntPtr?", destType: "System.IntPtr?", ExplicitNullableNumeric, expectedImplicitIL: null, expectedExplicitIL: convFromToNullableT("conv.i", "nuint", "nint"), expectedCheckedIL: convFromToNullableT("conv.ovf.i.un", "nuint", "nint")); + conversions(sourceType: "System.UIntPtr?", destType: "System.IntPtr?", ExplicitNullableNumeric, expectedImplicitIL: null, expectedExplicitIL: +@" +{ + // Code size 34 (0x22) + .maxstack 1 + .locals init (nuint? V_0, + nint? V_1) + IL_0000: ldarg.0 + IL_0001: stloc.0 + IL_0002: ldloca.s V_0 + IL_0004: call ""bool nuint?.HasValue.get"" + IL_0009: brtrue.s IL_0015 + IL_000b: ldloca.s V_1 + IL_000d: initobj ""nint?"" + IL_0013: ldloc.1 + IL_0014: ret + IL_0015: ldloca.s V_0 + IL_0017: call ""nuint nuint?.GetValueOrDefault()"" + IL_001c: newobj ""nint?..ctor(nint)"" + IL_0021: ret +} +", + expectedCheckedIL: convFromToNullableT("conv.ovf.i.un", "nuint", "nint")); conversions(sourceType: "System.UIntPtr?", destType: "System.UIntPtr?", Identity, expectedImplicitIL: convNone, expectedExplicitIL: convNone); // type to System.UIntPtr @@ -4993,7 +5418,7 @@ .maxstack 1 conversions(sourceType: "uint", destType: "System.UIntPtr", ImplicitNumeric, expectedImplicitIL: conv("conv.u"), expectedExplicitIL: conv("conv.u")); conversions(sourceType: "long", destType: "System.UIntPtr", ExplicitNumeric, expectedImplicitIL: null, expectedExplicitIL: conv("conv.u"), expectedCheckedIL: conv("conv.ovf.u")); conversions(sourceType: "ulong", destType: "System.UIntPtr", ExplicitNumeric, expectedImplicitIL: null, expectedExplicitIL: conv("conv.u"), expectedCheckedIL: conv("conv.ovf.u.un")); - conversions(sourceType: "nint", destType: "System.UIntPtr", ExplicitNumeric, expectedImplicitIL: null, expectedExplicitIL: conv("conv.u"), expectedCheckedIL: conv("conv.ovf.u")); + conversions(sourceType: "nint", destType: "System.UIntPtr", ExplicitNumeric, expectedImplicitIL: null, expectedExplicitIL: convNone, expectedCheckedIL: conv("conv.ovf.u")); conversions(sourceType: "nuint", destType: "System.UIntPtr", Identity, expectedImplicitIL: convNone, expectedExplicitIL: convNone); conversions(sourceType: "float", destType: "System.UIntPtr", ExplicitNumeric, expectedImplicitIL: null, expectedExplicitIL: conv("conv.u"), expectedCheckedIL: conv("conv.ovf.u")); conversions(sourceType: "double", destType: "System.UIntPtr", ExplicitNumeric, expectedImplicitIL: null, expectedExplicitIL: conv("conv.u"), expectedCheckedIL: conv("conv.ovf.u")); @@ -5014,7 +5439,7 @@ .maxstack 1 IL_0006: conv.ovf.u.un IL_0007: ret }"); - conversions(sourceType: "System.IntPtr", destType: "System.UIntPtr", ExplicitNumeric, expectedImplicitIL: null, expectedExplicitIL: conv("conv.u"), expectedCheckedIL: conv("conv.ovf.u")); + conversions(sourceType: "System.IntPtr", destType: "System.UIntPtr", ExplicitNumeric, expectedImplicitIL: null, expectedExplicitIL: convNone, expectedCheckedIL: conv("conv.ovf.u")); conversions(sourceType: "System.UIntPtr", destType: "System.UIntPtr", Identity, expectedImplicitIL: convNone, expectedExplicitIL: convNone); // type to nullable System.UIntPtr @@ -5054,7 +5479,17 @@ .maxstack 1 conversions(sourceType: "uint", destType: "System.UIntPtr?", ImplicitNullableNumeric, expectedImplicitIL: convToNullableT("conv.u", "nuint"), expectedExplicitIL: convToNullableT("conv.u", "nuint")); conversions(sourceType: "long", destType: "System.UIntPtr?", ExplicitNullableNumeric, expectedImplicitIL: null, expectedExplicitIL: convToNullableT("conv.u", "nuint"), expectedCheckedIL: convToNullableT("conv.ovf.u", "nuint")); conversions(sourceType: "ulong", destType: "System.UIntPtr?", ExplicitNullableNumeric, expectedImplicitIL: null, expectedExplicitIL: convToNullableT("conv.u", "nuint"), expectedCheckedIL: convToNullableT("conv.ovf.u.un", "nuint")); - conversions(sourceType: "nint", destType: "System.UIntPtr?", ExplicitNullableNumeric, expectedImplicitIL: null, expectedExplicitIL: convToNullableT("conv.u", "nuint"), expectedCheckedIL: convToNullableT("conv.ovf.u", "nuint")); + conversions(sourceType: "nint", destType: "System.UIntPtr?", ExplicitNullableNumeric, expectedImplicitIL: null, expectedExplicitIL: +@" +{ + // Code size 7 (0x7) + .maxstack 1 + IL_0000: ldarg.0 + IL_0001: newobj ""nuint?..ctor(nuint)"" + IL_0006: ret +} +", + expectedCheckedIL: convToNullableT("conv.ovf.u", "nuint")); conversions(sourceType: "nuint", destType: "System.UIntPtr?", ImplicitNullableIdentity, @"{ // Code size 7 (0x7) @@ -5091,7 +5526,17 @@ .maxstack 1 IL_0007: newobj ""nuint?..ctor(nuint)"" IL_000c: ret }"); - conversions(sourceType: "System.IntPtr", destType: "System.UIntPtr?", ExplicitNullableNumeric, expectedImplicitIL: null, expectedExplicitIL: convToNullableT("conv.u", "nuint"), expectedCheckedIL: convToNullableT("conv.ovf.u", "nuint")); + conversions(sourceType: "System.IntPtr", destType: "System.UIntPtr?", ExplicitNullableNumeric, expectedImplicitIL: null, expectedExplicitIL: +@" +{ + // Code size 7 (0x7) + .maxstack 1 + IL_0000: ldarg.0 + IL_0001: newobj ""nuint?..ctor(nuint)"" + IL_0006: ret +} +", + expectedCheckedIL: convToNullableT("conv.ovf.u", "nuint")); conversions(sourceType: "System.UIntPtr", destType: "System.UIntPtr?", ImplicitNullableIdentity, @"{ // Code size 7 (0x7) @@ -5120,7 +5565,17 @@ .maxstack 1 conversions(sourceType: "uint?", destType: "System.UIntPtr", ExplicitNullableImplicitNumeric, expectedImplicitIL: null, expectedExplicitIL: convFromNullableT("conv.u", "uint")); conversions(sourceType: "long?", destType: "System.UIntPtr", ExplicitNullableNumeric, expectedImplicitIL: null, expectedExplicitIL: convFromNullableT("conv.u", "long"), expectedCheckedIL: convFromNullableT("conv.ovf.u", "long")); conversions(sourceType: "ulong?", destType: "System.UIntPtr", ExplicitNullableNumeric, expectedImplicitIL: null, expectedExplicitIL: convFromNullableT("conv.u", "ulong"), expectedCheckedIL: convFromNullableT("conv.ovf.u.un", "ulong")); - conversions(sourceType: "nint?", destType: "System.UIntPtr", ExplicitNullableNumeric, expectedImplicitIL: null, expectedExplicitIL: convFromNullableT("conv.u", "nint"), expectedCheckedIL: convFromNullableT("conv.ovf.u", "nint")); + conversions(sourceType: "nint?", destType: "System.UIntPtr", ExplicitNullableNumeric, expectedImplicitIL: null, expectedExplicitIL: +@" +{ + // Code size 8 (0x8) + .maxstack 1 + IL_0000: ldarga.s V_0 + IL_0002: call ""nint nint?.Value.get"" + IL_0007: ret +} +", + expectedCheckedIL: convFromNullableT("conv.ovf.u", "nint")); conversions(sourceType: "nuint?", destType: "System.UIntPtr", ExplicitNullableIdentity, expectedImplicitIL: null, @"{ // Code size 8 (0x8) @@ -5150,7 +5605,17 @@ .maxstack 1 IL_000c: conv.ovf.u.un IL_000d: ret }"); - conversions(sourceType: "System.IntPtr?", destType: "System.UIntPtr", ExplicitNullableNumeric, expectedImplicitIL: null, expectedExplicitIL: convFromNullableT("conv.u", "nint"), expectedCheckedIL: convFromNullableT("conv.ovf.u", "nint")); + conversions(sourceType: "System.IntPtr?", destType: "System.UIntPtr", ExplicitNullableNumeric, expectedImplicitIL: null, expectedExplicitIL: +@" +{ + // Code size 8 (0x8) + .maxstack 1 + IL_0000: ldarga.s V_0 + IL_0002: call ""nint nint?.Value.get"" + IL_0007: ret +} +", + expectedCheckedIL: convFromNullableT("conv.ovf.u", "nint")); conversions(sourceType: "System.UIntPtr?", destType: "System.UIntPtr", ExplicitNullableIdentity, expectedImplicitIL: null, @"{ // Code size 8 (0x8) @@ -5172,7 +5637,29 @@ .maxstack 1 conversions(sourceType: "uint?", destType: "System.UIntPtr?", ImplicitNullableNumeric, expectedImplicitIL: convFromToNullableT("conv.u", "uint", "nuint"), expectedExplicitIL: convFromToNullableT("conv.u", "uint", "nuint")); conversions(sourceType: "long?", destType: "System.UIntPtr?", ExplicitNullableNumeric, expectedImplicitIL: null, expectedExplicitIL: convFromToNullableT("conv.u", "long", "nuint"), expectedCheckedIL: convFromToNullableT("conv.ovf.u", "long", "nuint")); conversions(sourceType: "ulong?", destType: "System.UIntPtr?", ExplicitNullableNumeric, expectedImplicitIL: null, expectedExplicitIL: convFromToNullableT("conv.u", "ulong", "nuint"), expectedCheckedIL: convFromToNullableT("conv.ovf.u.un", "ulong", "nuint")); - conversions(sourceType: "nint?", destType: "System.UIntPtr?", ExplicitNullableNumeric, expectedImplicitIL: null, expectedExplicitIL: convFromToNullableT("conv.u", "nint", "nuint"), expectedCheckedIL: convFromToNullableT("conv.ovf.u", "nint", "nuint")); + conversions(sourceType: "nint?", destType: "System.UIntPtr?", ExplicitNullableNumeric, expectedImplicitIL: null, expectedExplicitIL: +@" +{ + // Code size 34 (0x22) + .maxstack 1 + .locals init (nint? V_0, + nuint? V_1) + IL_0000: ldarg.0 + IL_0001: stloc.0 + IL_0002: ldloca.s V_0 + IL_0004: call ""bool nint?.HasValue.get"" + IL_0009: brtrue.s IL_0015 + IL_000b: ldloca.s V_1 + IL_000d: initobj ""nuint?"" + IL_0013: ldloc.1 + IL_0014: ret + IL_0015: ldloca.s V_0 + IL_0017: call ""nint nint?.GetValueOrDefault()"" + IL_001c: newobj ""nuint?..ctor(nuint)"" + IL_0021: ret +} +", + expectedCheckedIL: convFromToNullableT("conv.ovf.u", "nint", "nuint")); conversions(sourceType: "nuint?", destType: "System.UIntPtr?", Identity, expectedImplicitIL: convNone, expectedExplicitIL: convNone); conversions(sourceType: "float?", destType: "System.UIntPtr?", ExplicitNullableNumeric, expectedImplicitIL: null, expectedExplicitIL: convFromToNullableT("conv.u", "float", "nuint"), expectedCheckedIL: convFromToNullableT("conv.ovf.u", "float", "nuint")); conversions(sourceType: "double?", destType: "System.UIntPtr?", ExplicitNullableNumeric, expectedImplicitIL: null, expectedExplicitIL: convFromToNullableT("conv.u", "double", "nuint"), expectedCheckedIL: convFromToNullableT("conv.ovf.u", "double", "nuint")); @@ -5219,7 +5706,29 @@ .locals init (decimal? V_0, IL_0022: newobj ""nuint?..ctor(nuint)"" IL_0027: ret }"); - conversions(sourceType: "System.IntPtr?", destType: "System.UIntPtr?", ExplicitNullableNumeric, expectedImplicitIL: null, expectedExplicitIL: convFromToNullableT("conv.u", "nint", "nuint"), expectedCheckedIL: convFromToNullableT("conv.ovf.u", "nint", "nuint")); + conversions(sourceType: "System.IntPtr?", destType: "System.UIntPtr?", ExplicitNullableNumeric, expectedImplicitIL: null, expectedExplicitIL: +@" +{ + // Code size 34 (0x22) + .maxstack 1 + .locals init (nint? V_0, + nuint? V_1) + IL_0000: ldarg.0 + IL_0001: stloc.0 + IL_0002: ldloca.s V_0 + IL_0004: call ""bool nint?.HasValue.get"" + IL_0009: brtrue.s IL_0015 + IL_000b: ldloca.s V_1 + IL_000d: initobj ""nuint?"" + IL_0013: ldloc.1 + IL_0014: ret + IL_0015: ldloca.s V_0 + IL_0017: call ""nint nint?.GetValueOrDefault()"" + IL_001c: newobj ""nuint?..ctor(nuint)"" + IL_0021: ret +} +", + expectedCheckedIL: convFromToNullableT("conv.ovf.u", "nint", "nuint")); conversions(sourceType: "System.UIntPtr?", destType: "System.UIntPtr?", Identity, expectedImplicitIL: convNone, expectedExplicitIL: convNone); return; @@ -8265,7 +8774,8 @@ void constantDeclaration(string opType, string declarations, string expr, string {declarations} public const {opType} F = {expr}; }}"; - var comp = CreateNumericIntPtrCompilation(sourceA, references: new[] { MscorlibRefWithoutSharingCachedSymbols }, parseOptions: TestOptions.Regular9); + var mscorlibRefWithoutSharing = MscorlibRefWithoutSharingCachedSymbols; + var comp = CreateNumericIntPtrCompilation(sourceA, references: new[] { mscorlibRefWithoutSharing }, parseOptions: TestOptions.Regular9); comp.VerifyDiagnostics(expectedDiagnostics); @@ -8284,7 +8794,7 @@ static void Main() } }"; var refA = comp.EmitToImageReference(); - comp = CreateNumericIntPtrCompilation(sourceB, references: new[] { refA, MscorlibRefWithoutSharingCachedSymbols }, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular9); + comp = CreateEmptyCompilation(sourceB, references: new[] { refA, mscorlibRefWithoutSharing }, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular9); CompileAndVerify(comp, expectedOutput: expectedResult); Assert.NotNull(expectedResult); @@ -8633,11 +9143,11 @@ public void Int64Conversions() { convert(fromType: "nint", toType: "ulong", "int.MinValue", "18446744071562067968", "conv.i8", "System.OverflowException", "conv.ovf.u8"); convert(fromType: "nint", toType: "ulong", "int.MaxValue", "2147483647", "conv.i8", "2147483647", "conv.ovf.u8"); - convert(fromType: "nint", toType: "nuint", "int.MinValue", IntPtr.Size == 4 ? "2147483648" : "18446744071562067968", "conv.u", "System.OverflowException", "conv.ovf.u"); - convert(fromType: "nint", toType: "nuint", "int.MaxValue", "2147483647", "conv.u", "2147483647", "conv.ovf.u"); + convert(fromType: "nint", toType: "nuint", "int.MinValue", IntPtr.Size == 4 ? "2147483648" : "18446744071562067968", null, "System.OverflowException", "conv.ovf.u"); + convert(fromType: "nint", toType: "nuint", "int.MaxValue", "2147483647", null, "2147483647", "conv.ovf.u"); convert(fromType: "nuint", toType: "long", "uint.MaxValue", "4294967295", "conv.u8", "4294967295", "conv.ovf.i8.un"); - convert(fromType: "nuint", toType: "nint", "uint.MaxValue", IntPtr.Size == 4 ? "-1" : "4294967295", "conv.i", IntPtr.Size == 4 ? "System.OverflowException" : "4294967295", "conv.ovf.i.un"); + convert(fromType: "nuint", toType: "nint", "uint.MaxValue", IntPtr.Size == 4 ? "-1" : "4294967295", null, IntPtr.Size == 4 ? "System.OverflowException" : "4294967295", "conv.ovf.i.un"); string nintMinValue = IntPtr.Size == 4 ? int.MinValue.ToString() : long.MinValue.ToString(); string nintMaxValue = IntPtr.Size == 4 ? int.MaxValue.ToString() : long.MaxValue.ToString(); @@ -8645,11 +9155,11 @@ public void Int64Conversions() convert(fromType: "nint", toType: "ulong", nintMinValue, IntPtr.Size == 4 ? "18446744071562067968" : "9223372036854775808", "conv.i8", "System.OverflowException", "conv.ovf.u8"); convert(fromType: "nint", toType: "ulong", nintMaxValue, IntPtr.Size == 4 ? "2147483647" : "9223372036854775807", "conv.i8", IntPtr.Size == 4 ? "2147483647" : "9223372036854775807", "conv.ovf.u8"); - convert(fromType: "nint", toType: "nuint", nintMinValue, IntPtr.Size == 4 ? "2147483648" : "9223372036854775808", "conv.u", "System.OverflowException", "conv.ovf.u"); - convert(fromType: "nint", toType: "nuint", nintMaxValue, IntPtr.Size == 4 ? "2147483647" : "9223372036854775807", "conv.u", IntPtr.Size == 4 ? "2147483647" : "9223372036854775807", "conv.ovf.u"); + convert(fromType: "nint", toType: "nuint", nintMinValue, IntPtr.Size == 4 ? "2147483648" : "9223372036854775808", null, "System.OverflowException", "conv.ovf.u"); + convert(fromType: "nint", toType: "nuint", nintMaxValue, IntPtr.Size == 4 ? "2147483647" : "9223372036854775807", null, IntPtr.Size == 4 ? "2147483647" : "9223372036854775807", "conv.ovf.u"); convert(fromType: "nuint", toType: "long", nuintMaxValue, IntPtr.Size == 4 ? "4294967295" : "-1", "conv.u8", IntPtr.Size == 4 ? "4294967295" : "System.OverflowException", "conv.ovf.i8.un"); - convert(fromType: "nuint", toType: "nint", nuintMaxValue, "-1", "conv.i", "System.OverflowException", "conv.ovf.i.un"); + convert(fromType: "nuint", toType: "nint", nuintMaxValue, "-1", null, "System.OverflowException", "conv.ovf.i.un"); void convert(string fromType, string toType, string fromValue, string toValueUnchecked, string toConvUnchecked, string toValueChecked, string toConvChecked) { @@ -8683,7 +9193,14 @@ static void Main() $@"{toValueUnchecked} {toValueChecked}"); - verifier.VerifyIL("Program.Convert", + verifier.VerifyIL("Program.Convert", toConvUnchecked is null ? +@" +{ + // Code size 2 (0x2) + .maxstack 1 + IL_0000: ldarg.0 + IL_0001: ret +}" : $@"{{ // Code size 3 (0x3) .maxstack 1 @@ -9269,6 +9786,13 @@ public void SignedToUnsignedConversions_Explicit(string type) }}"; var comp = CreateNumericIntPtrCompilation(source, references: new[] { MscorlibRefWithoutSharingCachedSymbols }); var verifier = CompileAndVerify(comp); + string expectedExplicitILNop = +@"{ + // Code size 2 (0x2) + .maxstack 1 + IL_0000: ldarg.0 + IL_0001: ret +}"; string expectedExplicitILA = @"{ // Code size 3 (0x3) @@ -9297,7 +9821,7 @@ .maxstack 1 verifier.VerifyIL("NativeInts.Explicit2", expectedExplicitILA); verifier.VerifyIL("NativeInts.Explicit3", expectedExplicitILA); verifier.VerifyIL("NativeInts.Explicit4", expectedExplicitILB); - verifier.VerifyIL("NativeInts.Explicit5", expectedExplicitILB); + verifier.VerifyIL("NativeInts.Explicit5", expectedExplicitILNop); verifier.VerifyIL("NativeInts.Checked1", expectedCheckedIL); verifier.VerifyIL("NativeInts.Checked2", expectedCheckedIL); verifier.VerifyIL("NativeInts.Checked3", expectedCheckedIL); @@ -9562,7 +10086,7 @@ interface I void M(nint x1, System.IntPtr x2, nuint x3, System.UIntPtr x4); } "; - var parseOptions = useCSharp11 ? TestOptions.RegularNext : TestOptions.Regular10; + var parseOptions = useCSharp11 ? TestOptions.Regular11 : TestOptions.Regular10; var comp = CreateEmptyCompilation(new[] { source, corlib_cs }, parseOptions: parseOptions); verify(comp); @@ -10960,6 +11484,75 @@ .maxstack 4 "); } + [WorkItem(63348, "https://github.com/dotnet/roslyn/issues/63348")] + [Fact] + public void ConditionalStackalloc() + { + var source = +@"using System; +class Program +{ + static int F(int n) + { + Span s = n < 10 ? stackalloc char[n] : new char[n]; + return s[n - 1]; + } + static void Main() + { + Console.Write(F(1)); + Console.Write(F(11)); + } +}"; + + var comp = CreateCompilation(new[] { SpanSource, source }, options: TestOptions.UnsafeReleaseExe); + verify(comp); + + comp = CreateNumericIntPtrCompilation(new[] { SpanSource, source }, references: new[] { MscorlibRefWithoutSharingCachedSymbols }, options: TestOptions.UnsafeReleaseExe); + verify(comp); + + void verify(CSharpCompilation comp) + { + comp.VerifyEmitDiagnostics(); + var verifier = CompileAndVerify(comp, verify: Verification.Skipped, expectedOutput: "00"); + verifier.VerifyIL("Program.F", """ +{ + // Code size 48 (0x30) + .maxstack 3 + .locals init (System.Span V_0, //s + System.Span V_1, + int V_2) + IL_0000: ldarg.0 + IL_0001: ldc.i4.s 10 + IL_0003: bge.s IL_0016 + IL_0005: ldarg.0 + IL_0006: stloc.2 + IL_0007: ldloc.2 + IL_0008: conv.u + IL_0009: ldc.i4.2 + IL_000a: mul.ovf.un + IL_000b: localloc + IL_000d: ldloc.2 + IL_000e: newobj "System.Span..ctor(void*, int)" + IL_0013: stloc.1 + IL_0014: br.s IL_0022 + IL_0016: ldarg.0 + IL_0017: newarr "char" + IL_001c: call "System.Span System.Span.op_Implicit(char[])" + IL_0021: stloc.1 + IL_0022: ldloc.1 + IL_0023: stloc.0 + IL_0024: ldloca.s V_0 + IL_0026: ldarg.0 + IL_0027: ldc.i4.1 + IL_0028: sub + IL_0029: call "ref char System.Span.this[int].get" + IL_002e: ldind.u2 + IL_002f: ret +} +"""); + } + } + private void VerifyNoNativeIntegerAttributeEmitted(CSharpCompilation comp) { // PEVerify is skipped because it reports "Type load failed" because of the above corlib, diff --git a/src/Compilers/CSharp/Test/Emit2/FlowAnalysis/FlowDiagnosticTests.cs b/src/Compilers/CSharp/Test/Emit2/FlowAnalysis/FlowDiagnosticTests.cs index a1e1a3f2a1c12..2833ce13f2b4e 100644 --- a/src/Compilers/CSharp/Test/Emit2/FlowAnalysis/FlowDiagnosticTests.cs +++ b/src/Compilers/CSharp/Test/Emit2/FlowAnalysis/FlowDiagnosticTests.cs @@ -1209,15 +1209,15 @@ struct S }"; CreateCompilation(program, parseOptions: TestOptions.Regular10) .VerifyDiagnostics( - // (5,5): error CS0171: Field 'S.y' must be fully assigned before control is returned to the caller. Consider updating to language version 'preview' to auto-default the field. + // (5,5): error CS0171: Field 'S.y' must be fully assigned before control is returned to the caller. Consider updating to language version '11.0' to auto-default the field. // S(int x) { this.x = x; } - Diagnostic(ErrorCode.ERR_UnassignedThisUnsupportedVersion, "S").WithArguments("S.y", "preview").WithLocation(5, 5), + Diagnostic(ErrorCode.ERR_UnassignedThisUnsupportedVersion, "S").WithArguments("S.y", "11.0").WithLocation(5, 5), // (4,12): warning CS0169: The field 'S.y' is never used // int x, y; Diagnostic(ErrorCode.WRN_UnreferencedField, "y").WithArguments("S.y").WithLocation(4, 12) ); - var verifier = CompileAndVerify(program, parseOptions: TestOptions.RegularNext); + var verifier = CompileAndVerify(program, parseOptions: TestOptions.Regular11); verifier.VerifyDiagnostics( // (4,12): warning CS0169: The field 'S.y' is never used // int x, y; @@ -1273,11 +1273,11 @@ public static void Main(string[] args) }"; CreateCompilation(program, parseOptions: TestOptions.Regular10) .VerifyDiagnostics( - // (5,12): error CS0843: Auto-implemented property 'Program.X' must be fully assigned before control is returned to the caller. Consider updating to language version 'preview' to auto-default the property. + // (5,12): error CS0843: Auto-implemented property 'Program.X' must be fully assigned before control is returned to the caller. Consider updating to language version '11.0' to auto-default the property. // public Program(int x) - Diagnostic(ErrorCode.ERR_UnassignedThisAutoPropertyUnsupportedVersion, "Program").WithArguments("Program.X", "preview").WithLocation(5, 12)); + Diagnostic(ErrorCode.ERR_UnassignedThisAutoPropertyUnsupportedVersion, "Program").WithArguments("Program.X", "11.0").WithLocation(5, 12)); - var verifier = CompileAndVerify(program, parseOptions: TestOptions.RegularNext); + var verifier = CompileAndVerify(program, parseOptions: TestOptions.Regular11); verifier.VerifyDiagnostics(); verifier.VerifyIL("Program..ctor", @" { @@ -1377,20 +1377,20 @@ static void Main(string[] args) // (16,9): error CS1612: Cannot modify the return value of 'Program.x' because it is not a variable // x.i = 1; Diagnostic(ErrorCode.ERR_ReturnNotLValue, "x").WithArguments("Program.x").WithLocation(16, 9), - // (16,9): error CS9014: Use of possibly unassigned field 'i'. Consider updating to language version 'preview' to auto-default the field. + // (16,9): error CS9015: Use of possibly unassigned field 'i'. Consider updating to language version '11.0' to auto-default the field. // x.i = 1; - Diagnostic(ErrorCode.ERR_UseDefViolationFieldUnsupportedVersion, "x.i").WithArguments("i", "preview").WithLocation(16, 9), - // (17,34): error CS9013: Use of possibly unassigned auto-implemented property 'x2'. Consider updating to language version 'preview' to auto-default the property. + Diagnostic(ErrorCode.ERR_UseDefViolationFieldUnsupportedVersion, "x.i").WithArguments("i", "11.0").WithLocation(16, 9), + // (17,34): error CS9014: Use of possibly unassigned auto-implemented property 'x2'. Consider updating to language version '11.0' to auto-default the property. // System.Console.WriteLine(x2.ii); - Diagnostic(ErrorCode.ERR_UseDefViolationPropertyUnsupportedVersion, "x2").WithArguments("x2", "preview").WithLocation(17, 34), - // (14,12): error CS0843: Auto-implemented property 'Program.x' must be fully assigned before control is returned to the caller. Consider updating to language version 'preview' to auto-default the property. + Diagnostic(ErrorCode.ERR_UseDefViolationPropertyUnsupportedVersion, "x2").WithArguments("x2", "11.0").WithLocation(17, 34), + // (14,12): error CS0843: Auto-implemented property 'Program.x' must be fully assigned before control is returned to the caller. Consider updating to language version '11.0' to auto-default the property. // public Program(int dummy) - Diagnostic(ErrorCode.ERR_UnassignedThisAutoPropertyUnsupportedVersion, "Program").WithArguments("Program.x", "preview").WithLocation(14, 12), - // (14,12): error CS0843: Auto-implemented property 'Program.x2' must be fully assigned before control is returned to the caller. Consider updating to language version 'preview' to auto-default the property. + Diagnostic(ErrorCode.ERR_UnassignedThisAutoPropertyUnsupportedVersion, "Program").WithArguments("Program.x", "11.0").WithLocation(14, 12), + // (14,12): error CS0843: Auto-implemented property 'Program.x2' must be fully assigned before control is returned to the caller. Consider updating to language version '11.0' to auto-default the property. // public Program(int dummy) - Diagnostic(ErrorCode.ERR_UnassignedThisAutoPropertyUnsupportedVersion, "Program").WithArguments("Program.x2", "preview").WithLocation(14, 12)); + Diagnostic(ErrorCode.ERR_UnassignedThisAutoPropertyUnsupportedVersion, "Program").WithArguments("Program.x2", "11.0").WithLocation(14, 12)); - comp = CreateCompilation(text, parseOptions: TestOptions.RegularNext); + comp = CreateCompilation(text, parseOptions: TestOptions.Regular11); comp.VerifyDiagnostics( // (16,9): error CS1612: Cannot modify the return value of 'Program.x' because it is not a variable // x.i = 1; @@ -1434,20 +1434,20 @@ static void Main(string[] args) // (16,9): error CS1612: Cannot modify the return value of 'Program.x' because it is not a variable // x.i = 1; Diagnostic(ErrorCode.ERR_ReturnNotLValue, "x").WithArguments("Program.x").WithLocation(16, 9), - // (16,9): error CS9014: Use of possibly unassigned field 'i'. Consider updating to language version 'preview' to auto-default the field. + // (16,9): error CS9015: Use of possibly unassigned field 'i'. Consider updating to language version '11.0' to auto-default the field. // x.i = 1; - Diagnostic(ErrorCode.ERR_UseDefViolationFieldUnsupportedVersion, "x.i").WithArguments("i", "preview").WithLocation(16, 9), - // (17,34): error CS9013: Use of possibly unassigned auto-implemented property 'x2'. Consider updating to language version 'preview' to auto-default the property. + Diagnostic(ErrorCode.ERR_UseDefViolationFieldUnsupportedVersion, "x.i").WithArguments("i", "11.0").WithLocation(16, 9), + // (17,34): error CS9014: Use of possibly unassigned auto-implemented property 'x2'. Consider updating to language version '11.0' to auto-default the property. // System.Console.WriteLine(x2.ii); - Diagnostic(ErrorCode.ERR_UseDefViolationPropertyUnsupportedVersion, "x2").WithArguments("x2", "preview").WithLocation(17, 34), - // (14,12): error CS0843: Auto-implemented property 'Program.x' must be fully assigned before control is returned to the caller. Consider updating to language version 'preview' to auto-default the property. + Diagnostic(ErrorCode.ERR_UseDefViolationPropertyUnsupportedVersion, "x2").WithArguments("x2", "11.0").WithLocation(17, 34), + // (14,12): error CS0843: Auto-implemented property 'Program.x' must be fully assigned before control is returned to the caller. Consider updating to language version '11.0' to auto-default the property. // public Program(int dummy) - Diagnostic(ErrorCode.ERR_UnassignedThisAutoPropertyUnsupportedVersion, "Program").WithArguments("Program.x", "preview").WithLocation(14, 12), - // (14,12): error CS0843: Auto-implemented property 'Program.x2' must be fully assigned before control is returned to the caller. Consider updating to language version 'preview' to auto-default the property. + Diagnostic(ErrorCode.ERR_UnassignedThisAutoPropertyUnsupportedVersion, "Program").WithArguments("Program.x", "11.0").WithLocation(14, 12), + // (14,12): error CS0843: Auto-implemented property 'Program.x2' must be fully assigned before control is returned to the caller. Consider updating to language version '11.0' to auto-default the property. // public Program(int dummy) - Diagnostic(ErrorCode.ERR_UnassignedThisAutoPropertyUnsupportedVersion, "Program").WithArguments("Program.x2", "preview").WithLocation(14, 12)); + Diagnostic(ErrorCode.ERR_UnassignedThisAutoPropertyUnsupportedVersion, "Program").WithArguments("Program.x2", "11.0").WithLocation(14, 12)); - comp = CreateCompilation(text, options: TestOptions.DebugDll.WithSpecificDiagnosticOptions(ReportStructInitializationWarnings), parseOptions: TestOptions.RegularNext); + comp = CreateCompilation(text, options: TestOptions.DebugDll.WithSpecificDiagnosticOptions(ReportStructInitializationWarnings), parseOptions: TestOptions.Regular11); comp.VerifyDiagnostics( // (14,12): warning CS9020: Control is returned to caller before auto-implemented property 'Program.x' is explicitly assigned, causing a preceding implicit assignment of 'default'. // public Program(int dummy) @@ -1465,7 +1465,7 @@ static void Main(string[] args) // System.Console.WriteLine(x2.ii); Diagnostic(ErrorCode.WRN_UseDefViolationPropertySupportedVersion, "x2").WithArguments("x2").WithLocation(17, 34)); - comp = CreateCompilation(text, parseOptions: TestOptions.RegularNext); + comp = CreateCompilation(text, parseOptions: TestOptions.Regular11); comp.VerifyDiagnostics( // (16,9): error CS1612: Cannot modify the return value of 'Program.x' because it is not a variable // x.i = 1; @@ -1754,21 +1754,21 @@ static void Main(string[] args) // (20,17): error CS1620: Argument 1 must be passed with the 'out' keyword // Goo(ref x3); Diagnostic(ErrorCode.ERR_BadArgRef, "x3").WithArguments("1", "out").WithLocation(20, 17), - // (15,17): error CS9014: Use of possibly unassigned auto-implemented property 'x1'. Consider updating to language version 'preview' to auto-default the property. + // (15,17): error CS9014: Use of possibly unassigned auto-implemented property 'x1'. Consider updating to language version '11.0' to auto-default the property. // Goo(out x1); - Diagnostic(ErrorCode.ERR_UseDefViolationPropertyUnsupportedVersion, "x1").WithArguments("x1", "preview").WithLocation(15, 17), - // (16,9): error CS0188: The 'this' object cannot be used before all of its fields have been assigned. Consider updating to language version 'preview' to auto-default the unassigned fields. + Diagnostic(ErrorCode.ERR_UseDefViolationPropertyUnsupportedVersion, "x1").WithArguments("x1", "11.0").WithLocation(15, 17), + // (16,9): error CS0188: The 'this' object cannot be used before all of its fields have been assigned. Consider updating to language version '11.0' to auto-default the unassigned fields. // Goo(ref x1); - Diagnostic(ErrorCode.ERR_UseDefViolationThisUnsupportedVersion, "Goo").WithArguments("preview").WithLocation(16, 9), - // (17,17): error CS9014: Use of possibly unassigned auto-implemented property 'x2'. Consider updating to language version 'preview' to auto-default the property. + Diagnostic(ErrorCode.ERR_UseDefViolationThisUnsupportedVersion, "Goo").WithArguments("11.0").WithLocation(16, 9), + // (17,17): error CS9014: Use of possibly unassigned auto-implemented property 'x2'. Consider updating to language version '11.0' to auto-default the property. // Goo(out x2); - Diagnostic(ErrorCode.ERR_UseDefViolationPropertyUnsupportedVersion, "x2").WithArguments("x2", "preview").WithLocation(17, 17), + Diagnostic(ErrorCode.ERR_UseDefViolationPropertyUnsupportedVersion, "x2").WithArguments("x2", "11.0").WithLocation(17, 17), // (6,20): warning CS0649: Field 'Program.S1.x' is never assigned to, and will always have its default value 0 // public int x; Diagnostic(ErrorCode.WRN_UnassignedInternalField, "x").WithArguments("Program.S1.x", "0").WithLocation(6, 20) ); - comp = CreateCompilation(text, parseOptions: TestOptions.RegularNext); + comp = CreateCompilation(text, parseOptions: TestOptions.Regular11); comp.VerifyDiagnostics( // (15,17): error CS0206: A property or indexer may not be passed as an out or ref parameter // Goo(out x1); @@ -2399,15 +2399,15 @@ static void Goo(int y) // (8,13): error CS1501: No overload for method 'Goo' takes 2 arguments // Goo(y, null); Diagnostic(ErrorCode.ERR_BadArgCount, "Goo").WithArguments("Goo", "2").WithLocation(8, 13), - // (6,9): error CS0171: Field 'C.S.x' must be fully assigned before control is returned to the caller. Consider updating to language version 'preview' to auto-default the field. + // (6,9): error CS0171: Field 'C.S.x' must be fully assigned before control is returned to the caller. Consider updating to language version '11.0' to auto-default the field. // S(dynamic y) - Diagnostic(ErrorCode.ERR_UnassignedThisUnsupportedVersion, "S").WithArguments("C.S.x", "preview").WithLocation(6, 9), + Diagnostic(ErrorCode.ERR_UnassignedThisUnsupportedVersion, "S").WithArguments("C.S.x", "11.0").WithLocation(6, 9), // (5,13): warning CS0169: The field 'C.S.x' is never used // int x; Diagnostic(ErrorCode.WRN_UnreferencedField, "x").WithArguments("C.S.x").WithLocation(5, 13) ); - comp = CreateCompilationWithMscorlib40AndSystemCore(source, parseOptions: TestOptions.RegularNext); + comp = CreateCompilationWithMscorlib40AndSystemCore(source, parseOptions: TestOptions.Regular11); comp.VerifyDiagnostics( // (8,13): error CS1501: No overload for method 'Goo' takes 2 arguments // Goo(y, null); @@ -2553,9 +2553,9 @@ public void RegressionTest949324() }"; CSharpCompilation comp = CreateCompilationWithMscorlib40AndSystemCore(source, parseOptions: TestOptions.Regular10); comp.VerifyDiagnostics( - // (3,5): error CS0171: Field 'Derived.x' must be fully assigned before control is returned to the caller. Consider updating to language version 'preview' to auto-default the field. + // (3,5): error CS0171: Field 'Derived.x' must be fully assigned before control is returned to the caller. Consider updating to language version '11.0' to auto-default the field. // Derived(int x) { } - Diagnostic(ErrorCode.ERR_UnassignedThisUnsupportedVersion, "Derived").WithArguments("Derived.x", "preview").WithLocation(3, 5), + Diagnostic(ErrorCode.ERR_UnassignedThisUnsupportedVersion, "Derived").WithArguments("Derived.x", "11.0").WithLocation(3, 5), // (4,28): error CS0103: The name 'p2' does not exist in the current context // Derived(long x) : this(p2) // error CS0188: The 'this' object cannot be used before all of its fields are assigned to Diagnostic(ErrorCode.ERR_NameNotInContext, "p2").WithArguments("p2").WithLocation(4, 28), @@ -2564,7 +2564,7 @@ public void RegressionTest949324() Diagnostic(ErrorCode.WRN_UnreferencedField, "x").WithArguments("Derived.x").WithLocation(8, 17) ); - comp = CreateCompilationWithMscorlib40AndSystemCore(source, parseOptions: TestOptions.RegularNext); + comp = CreateCompilationWithMscorlib40AndSystemCore(source, parseOptions: TestOptions.Regular11); comp.VerifyDiagnostics( // (4,28): error CS0103: The name 'p2' does not exist in the current context // Derived(long x) : this(p2) // error CS0188: The 'this' object cannot be used before all of its fields are assigned to @@ -2684,14 +2684,14 @@ public S(object x, object y) }"; var comp = CreateCompilation(source, parseOptions: TestOptions.Regular10); comp.VerifyDiagnostics( - // (6,12): error CS0171: Field 'S.F' must be fully assigned before control is returned to the caller. Consider updating to language version 'preview' to auto-default the field. + // (6,12): error CS0171: Field 'S.F' must be fully assigned before control is returned to the caller. Consider updating to language version '11.0' to auto-default the field. // public S(object x, object y) - Diagnostic(ErrorCode.ERR_UnassignedThisUnsupportedVersion, "S").WithArguments("S.F", "preview").WithLocation(6, 12), + Diagnostic(ErrorCode.ERR_UnassignedThisUnsupportedVersion, "S").WithArguments("S.F", "11.0").WithLocation(6, 12), // (8,28): error CS1673: Anonymous methods, lambda expressions, query expressions, and local functions inside structs cannot access instance members of 'this'. Consider copying 'this' to a local variable outside the anonymous method, lambda expression, query expression, or local function and using the local instead. // Action a = () => { F = x; }; Diagnostic(ErrorCode.ERR_ThisStructNotInAnonMeth, "F").WithLocation(8, 28)); - comp = CreateCompilation(source, parseOptions: TestOptions.RegularNext); + comp = CreateCompilation(source, parseOptions: TestOptions.Regular11); comp.VerifyDiagnostics( // (8,28): error CS1673: Anonymous methods, lambda expressions, query expressions, and local functions inside structs cannot access instance members of 'this'. Consider copying 'this' to a local variable outside the anonymous method, lambda expression, query expression, or local function and using the local instead. // Action a = () => { F = x; }; @@ -2714,9 +2714,9 @@ public S(object x, object y) }"; var comp = CreateCompilation(source, parseOptions: TestOptions.Regular10); comp.VerifyDiagnostics( - // (5,12): error CS0171: Field 'S.F' must be fully assigned before control is returned to the caller. Consider updating to language version 'preview' to auto-default the field. + // (5,12): error CS0171: Field 'S.F' must be fully assigned before control is returned to the caller. Consider updating to language version '11.0' to auto-default the field. // public S(object x, object y) - Diagnostic(ErrorCode.ERR_UnassignedThisUnsupportedVersion, "S").WithArguments("S.F", "preview").WithLocation(5, 12), + Diagnostic(ErrorCode.ERR_UnassignedThisUnsupportedVersion, "S").WithArguments("S.F", "11.0").WithLocation(5, 12), // (7,14): warning CS8321: The local function 'f' is declared but never used // void f() { F = x; } Diagnostic(ErrorCode.WRN_UnreferencedLocalFunction, "f").WithArguments("f").WithLocation(7, 14), @@ -2724,7 +2724,7 @@ public S(object x, object y) // void f() { F = x; } Diagnostic(ErrorCode.ERR_ThisStructNotInAnonMeth, "F").WithLocation(7, 20)); - comp = CreateCompilation(source, parseOptions: TestOptions.RegularNext); + comp = CreateCompilation(source, parseOptions: TestOptions.Regular11); comp.VerifyDiagnostics( // (7,14): warning CS8321: The local function 'f' is declared but never used // void f() { F = x; } diff --git a/src/Compilers/CSharp/Test/Emit2/FlowAnalysis/LocalFunctions.cs b/src/Compilers/CSharp/Test/Emit2/FlowAnalysis/LocalFunctions.cs index 23b14c6a89cad..2a374ace2b087 100644 --- a/src/Compilers/CSharp/Test/Emit2/FlowAnalysis/LocalFunctions.cs +++ b/src/Compilers/CSharp/Test/Emit2/FlowAnalysis/LocalFunctions.cs @@ -724,17 +724,17 @@ void Local() // (10,20): error CS1673: Anonymous methods, lambda expressions, query expressions, and local functions inside structs cannot access instance members of 'this'. Consider copying 'this' to a local variable outside the anonymous method, lambda expression, query expression, or local function and using the local instead. // s._x = _x; Diagnostic(ErrorCode.ERR_ThisStructNotInAnonMeth, "_x").WithLocation(10, 20), - // (7,17): error CS0188: The 'this' object cannot be used before all of its fields have been assigned. Consider updating to language version 'preview' to auto-default the unassigned fields. + // (7,17): error CS0188: The 'this' object cannot be used before all of its fields have been assigned. Consider updating to language version '11.0' to auto-default the unassigned fields. // var s = this; - Diagnostic(ErrorCode.ERR_UseDefViolationThisUnsupportedVersion, "this").WithArguments("preview").WithLocation(7, 17), - // (12,9): error CS9015: Use of possibly unassigned field '_x'. Consider updating to language version 'preview' to auto-default the field. + Diagnostic(ErrorCode.ERR_UseDefViolationThisUnsupportedVersion, "this").WithArguments("11.0").WithLocation(7, 17), + // (12,9): error CS9015: Use of possibly unassigned field '_x'. Consider updating to language version '11.0' to auto-default the field. // Local(); - Diagnostic(ErrorCode.ERR_UseDefViolationFieldUnsupportedVersion, "Local()").WithArguments("_x", "preview").WithLocation(12, 9), - // (5,12): error CS0171: Field 'S._x' must be fully assigned before control is returned to the caller. Consider updating to language version 'preview' to auto-default the field. + Diagnostic(ErrorCode.ERR_UseDefViolationFieldUnsupportedVersion, "Local()").WithArguments("_x", "11.0").WithLocation(12, 9), + // (5,12): error CS0171: Field 'S._x' must be fully assigned before control is returned to the caller. Consider updating to language version '11.0' to auto-default the field. // public S(int x) - Diagnostic(ErrorCode.ERR_UnassignedThisUnsupportedVersion, "S").WithArguments("S._x", "preview").WithLocation(5, 12)); + Diagnostic(ErrorCode.ERR_UnassignedThisUnsupportedVersion, "S").WithArguments("S._x", "11.0").WithLocation(5, 12)); - comp = CreateCompilation(source, parseOptions: TestOptions.RegularNext); + comp = CreateCompilation(source, parseOptions: TestOptions.Regular11); comp.VerifyDiagnostics( // (10,20): error CS1673: Anonymous methods, lambda expressions, query expressions, and local functions inside structs cannot access instance members of 'this'. Consider copying 'this' to a local variable outside the anonymous method, lambda expression, query expression, or local function and using the local instead. // s._x = _x; @@ -1500,11 +1500,11 @@ void Local() // (12,20): error CS1673: Anonymous methods, lambda expressions, query expressions, and local functions inside structs cannot access instance members of 'this'. Consider copying 'this' to a local variable outside the anonymous method, lambda expression, query expression, or local function and using the local instead. // S s2 = this; Diagnostic(ErrorCode.ERR_ThisStructNotInAnonMeth, "this").WithLocation(12, 20), - // (14,9): error CS9014: Use of possibly unassigned field '_x'. Consider updating to language version 'preview' to auto-default the field. + // (14,9): error CS9015: Use of possibly unassigned field '_x'. Consider updating to language version '11.0' to auto-default the field. // Local(); - Diagnostic(ErrorCode.ERR_UseDefViolationFieldUnsupportedVersion, "Local()").WithArguments("_x", "preview").WithLocation(14, 9)); + Diagnostic(ErrorCode.ERR_UseDefViolationFieldUnsupportedVersion, "Local()").WithArguments("_x", "11.0").WithLocation(14, 9)); - comp = CreateCompilation(source, parseOptions: TestOptions.RegularNext); + comp = CreateCompilation(source, parseOptions: TestOptions.Regular11); comp.VerifyDiagnostics( // (12,20): error CS1673: Anonymous methods, lambda expressions, query expressions, and local functions inside structs cannot access instance members of 'this'. Consider copying 'this' to a local variable outside the anonymous method, lambda expression, query expression, or local function and using the local instead. // S s2 = this; diff --git a/src/Compilers/CSharp/Test/Emit2/FlowAnalysis/RegionAnalysisTests.cs b/src/Compilers/CSharp/Test/Emit2/FlowAnalysis/RegionAnalysisTests.cs index 128f14009c14a..f82fbc86818a4 100644 --- a/src/Compilers/CSharp/Test/Emit2/FlowAnalysis/RegionAnalysisTests.cs +++ b/src/Compilers/CSharp/Test/Emit2/FlowAnalysis/RegionAnalysisTests.cs @@ -6429,13 +6429,13 @@ public void FieldBeforeAssignedInStructCtor() }"; var compilation = CreateCompilation(source, parseOptions: TestOptions.Regular10); compilation.VerifyDiagnostics( - // (6,18): error CS9014: Use of possibly unassigned field 'value'. Consider updating to language version 'preview' to auto-default the field. + // (6,18): error CS9015: Use of possibly unassigned field 'value'. Consider updating to language version '11.0' to auto-default the field. // S.Equals(value , value); - Diagnostic(ErrorCode.ERR_UseDefViolationFieldUnsupportedVersion, "value").WithArguments("value", "preview").WithLocation(6, 18) + Diagnostic(ErrorCode.ERR_UseDefViolationFieldUnsupportedVersion, "value").WithArguments("value", "11.0").WithLocation(6, 18) ); verify(); - compilation = CreateCompilation(source, parseOptions: TestOptions.RegularNext); + compilation = CreateCompilation(source, parseOptions: TestOptions.Regular11); compilation.VerifyDiagnostics(); verify(); diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/PatternMatchingTestBase.cs b/src/Compilers/CSharp/Test/Emit2/Semantics/PatternMatchingTestBase.cs similarity index 100% rename from src/Compilers/CSharp/Test/Semantic/Semantics/PatternMatchingTestBase.cs rename to src/Compilers/CSharp/Test/Emit2/Semantics/PatternMatchingTestBase.cs diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/PatternMatchingTests.cs b/src/Compilers/CSharp/Test/Emit2/Semantics/PatternMatchingTests.cs similarity index 99% rename from src/Compilers/CSharp/Test/Semantic/Semantics/PatternMatchingTests.cs rename to src/Compilers/CSharp/Test/Emit2/Semantics/PatternMatchingTests.cs index 595b76dd2a960..935b6e6708b06 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/PatternMatchingTests.cs +++ b/src/Compilers/CSharp/Test/Emit2/Semantics/PatternMatchingTests.cs @@ -8349,11 +8349,11 @@ static void Main() "; var comp = CreateCompilationWithSpanAndMemoryExtensions(source, parseOptions: TestOptions.Regular10); comp.VerifyDiagnostics( - // (5,57): error CS8652: The feature 'pattern matching ReadOnly/Span on constant string' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // (5,57): error CS8936: Feature 'pattern matching ReadOnly/Span on constant string' is not available in C# 10.0. Please use language version 11.0 or greater. // static bool M(ReadOnlySpan chars) => chars is ""; - Diagnostic(ErrorCode.ERR_FeatureInPreview, @"""""").WithArguments("pattern matching ReadOnly/Span on constant string").WithLocation(5, 57)); + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, @"""""").WithArguments("pattern matching ReadOnly/Span on constant string", "11.0").WithLocation(5, 57)); - comp = CreateCompilationWithSpanAndMemoryExtensions(source, options: TestOptions.ReleaseExe, parseOptions: TestOptions.RegularNext); + comp = CreateCompilationWithSpanAndMemoryExtensions(source, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular11); comp.VerifyEmitDiagnostics(); var verifier = CompileAndVerify(comp, expectedOutput: @"True @@ -8391,11 +8391,11 @@ static void Main() "; var comp = CreateCompilationWithSpanAndMemoryExtensions(source, parseOptions: TestOptions.Regular10); comp.VerifyDiagnostics( - // (4,63): error CS8652: The feature 'pattern matching ReadOnly/Span on constant string' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // (4,63): error CS8936: Feature 'pattern matching ReadOnly/Span on constant string' is not available in C# 10.0. Please use language version 11.0 or greater. // static bool M(ReadOnlySpan chars) => chars switch { "" => true, _ => false }; - Diagnostic(ErrorCode.ERR_FeatureInPreview, @"""""").WithArguments("pattern matching ReadOnly/Span on constant string").WithLocation(4, 63)); + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, @"""""").WithArguments("pattern matching ReadOnly/Span on constant string", "11.0").WithLocation(4, 63)); - comp = CreateCompilationWithSpanAndMemoryExtensions(source, options: TestOptions.ReleaseExe, parseOptions: TestOptions.RegularNext); + comp = CreateCompilationWithSpanAndMemoryExtensions(source, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular11); comp.VerifyEmitDiagnostics(); var verifier = CompileAndVerify(comp, expectedOutput: @"True @@ -9703,11 +9703,11 @@ static void Main() "; var comp = CreateCompilationWithSpanAndMemoryExtensions(source, parseOptions: TestOptions.Regular10); comp.VerifyDiagnostics( - // (5,49): error CS8652: The feature 'pattern matching ReadOnly/Span on constant string' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // (5,49): error CS8936: Feature 'pattern matching ReadOnly/Span on constant string' is not available in C# 10.0. Please use language version 11.0 or greater. // static bool M(Span chars) => chars is ""; - Diagnostic(ErrorCode.ERR_FeatureInPreview, @"""""").WithArguments("pattern matching ReadOnly/Span on constant string").WithLocation(5, 49)); + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, @"""""").WithArguments("pattern matching ReadOnly/Span on constant string", "11.0").WithLocation(5, 49)); - comp = CreateCompilationWithSpanAndMemoryExtensions(source, options: TestOptions.ReleaseExe, parseOptions: TestOptions.RegularNext); + comp = CreateCompilationWithSpanAndMemoryExtensions(source, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular11); comp.VerifyEmitDiagnostics(); var verifier = CompileAndVerify(comp, expectedOutput: @"True @@ -9744,11 +9744,11 @@ static void Main() "; var comp = CreateCompilationWithSpanAndMemoryExtensions(source, parseOptions: TestOptions.Regular10); comp.VerifyDiagnostics( - // (5,55): error CS8652: The feature 'pattern matching ReadOnly/Span on constant string' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // (5,55): error CS8936: Feature 'pattern matching ReadOnly/Span on constant string' is not available in C# 10.0. Please use language version 11.0 or greater. // static bool M(Span chars) => chars switch { "" => true, _ => false }; - Diagnostic(ErrorCode.ERR_FeatureInPreview, @"""""").WithArguments("pattern matching ReadOnly/Span on constant string").WithLocation(5, 55)); + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, @"""""").WithArguments("pattern matching ReadOnly/Span on constant string", "11.0").WithLocation(5, 55)); - comp = CreateCompilationWithSpanAndMemoryExtensions(source, options: TestOptions.ReleaseExe, parseOptions: TestOptions.RegularNext); + comp = CreateCompilationWithSpanAndMemoryExtensions(source, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular11); comp.VerifyEmitDiagnostics(); var verifier = CompileAndVerify(comp, expectedOutput: @"True @@ -10066,7 +10066,7 @@ class Program static bool F1(ReadOnlySpan span) => span is """"; static bool F2(Span span) => span is """"; }"; - var comp = CreateCompilationWithSpanAndMemoryExtensions(source, parseOptions: TestOptions.RegularNext); + var comp = CreateCompilationWithSpanAndMemoryExtensions(source, parseOptions: TestOptions.Regular11); comp.VerifyDiagnostics( // (4,56): error CS8121: An expression of type 'ReadOnlySpan' cannot be handled by a pattern of type 'string'. // static bool F1(ReadOnlySpan span) => span is ""; @@ -10097,7 +10097,7 @@ static void Main() F(new Span(new int[] { '1', '2', '3' })); } }"; - var comp = CreateCompilationWithSpanAndMemoryExtensions(source, parseOptions: TestOptions.RegularNext); + var comp = CreateCompilationWithSpanAndMemoryExtensions(source, parseOptions: TestOptions.Regular11); comp.VerifyEmitDiagnostics( // (5,56): error CS8121: An expression of type 'ReadOnlySpan' cannot be handled by a pattern of type 'ReadOnlySpan'. // static bool F1(ReadOnlySpan span) => span is ReadOnlySpan _; @@ -10117,7 +10117,7 @@ class Program static bool F1(ReadOnlySpan span) => span is ReadOnlySpan and ""ABC""; static bool F2(Span span) => span is Span and ""123""; }"; - var comp = CreateCompilationWithSpanAndMemoryExtensions(source, parseOptions: TestOptions.RegularNext); + var comp = CreateCompilationWithSpanAndMemoryExtensions(source, parseOptions: TestOptions.Regular11); comp.VerifyEmitDiagnostics( // (4,56): error CS8121: An expression of type 'ReadOnlySpan' cannot be handled by a pattern of type 'ReadOnlySpan'. // static bool F1(ReadOnlySpan span) => span is ReadOnlySpan and "ABC"; @@ -10139,7 +10139,7 @@ class Program static bool F3(ValueType v) => v is ReadOnlySpan _; static bool F4(ValueType v) => v is Span _; }"; - var comp = CreateCompilationWithSpanAndMemoryExtensions(source, parseOptions: TestOptions.RegularNext); + var comp = CreateCompilationWithSpanAndMemoryExtensions(source, parseOptions: TestOptions.Regular11); comp.VerifyEmitDiagnostics( // (4,41): error CS8121: An expression of type 'object' cannot be handled by a pattern of type 'ReadOnlySpan'. // static bool F1(object o) => o is ReadOnlySpan _; @@ -10167,7 +10167,7 @@ class Program static bool F3(ValueType v) => v is ReadOnlySpan and ""ABC""; static bool F4(ValueType v) => v is Span and ""123""; }"; - var comp = CreateCompilationWithSpanAndMemoryExtensions(source, parseOptions: TestOptions.RegularNext); + var comp = CreateCompilationWithSpanAndMemoryExtensions(source, parseOptions: TestOptions.Regular11); comp.VerifyEmitDiagnostics( // (4,41): error CS8121: An expression of type 'object' cannot be handled by a pattern of type 'ReadOnlySpan'. // static bool F1(object o) => o is ReadOnlySpan and "ABC"; @@ -10194,7 +10194,7 @@ class Program static bool F1(ReadOnlySpan span) => span is $""{123}""; static bool F2(Span span) => span is $""{n}""; }"; - var comp = CreateCompilationWithSpanAndMemoryExtensions(source, parseOptions: TestOptions.RegularNext); + var comp = CreateCompilationWithSpanAndMemoryExtensions(source, parseOptions: TestOptions.Regular11); comp.VerifyEmitDiagnostics( // (5,56): error CS0150: A constant value is expected // static bool F1(ReadOnlySpan span) => span is $"{123}"; @@ -10225,7 +10225,7 @@ static void Main() F(""123"".ToArray()); } }"; - var comp = CreateCompilationWithSpanAndMemoryExtensions(source, options: TestOptions.ReleaseExe, parseOptions: TestOptions.RegularNext); + var comp = CreateCompilationWithSpanAndMemoryExtensions(source, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular11); comp.VerifyEmitDiagnostics(); CompileAndVerify(comp, expectedOutput: @"(True, False) @@ -10243,7 +10243,7 @@ class Program static bool F1(ReadOnlySpan span, bool b) => span is (b ? """" : ""ABC""); static bool F2(Span span, bool b) => span is (b ? """" : ""123""); }"; - var comp = CreateCompilationWithSpanAndMemoryExtensions(source, parseOptions: TestOptions.RegularNext); + var comp = CreateCompilationWithSpanAndMemoryExtensions(source, parseOptions: TestOptions.Regular11); comp.VerifyEmitDiagnostics( // (4,65): error CS0150: A constant value is expected // static bool F1(ReadOnlySpan span, bool b) => span is (b ? "" : "ABC"); @@ -10273,7 +10273,7 @@ static void Main() F(""123"".ToArray()); } }"; - var comp = CreateCompilationWithSpanAndMemoryExtensions(source, options: TestOptions.ReleaseExe, parseOptions: TestOptions.RegularNext); + var comp = CreateCompilationWithSpanAndMemoryExtensions(source, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular11); comp.VerifyEmitDiagnostics(); CompileAndVerify(comp, expectedOutput: @"(True, False) @@ -10291,7 +10291,7 @@ class Program static bool F1(ReadOnlySpan span, bool b) => span is b switch { true => """", false => ""ABC"" }; static bool F2(Span span, bool b) => span is b switch { false => """", true => ""123"" }; }"; - var comp = CreateCompilationWithSpanAndMemoryExtensions(source, parseOptions: TestOptions.RegularNext); + var comp = CreateCompilationWithSpanAndMemoryExtensions(source, parseOptions: TestOptions.Regular11); comp.VerifyEmitDiagnostics( // (4,64): error CS0150: A constant value is expected // static bool F1(ReadOnlySpan span, bool b) => span is b switch { true => "", false => "ABC" }; @@ -10315,7 +10315,7 @@ static void Main() Expression> e2 = () => new Span(null) is ""ABC""; } }"; - var comp = CreateCompilationWithSpanAndMemoryExtensions(source, parseOptions: TestOptions.RegularNext); + var comp = CreateCompilationWithSpanAndMemoryExtensions(source, parseOptions: TestOptions.Regular11); comp.VerifyEmitDiagnostics( // (7,43): error CS8122: An expression tree may not contain an 'is' pattern-matching operator. // Expression> e1 = () => new ReadOnlySpan(null) is "123"; @@ -10345,7 +10345,7 @@ static void Main() Expression> e2 = () => new Span(null) switch { ""ABC"" => true, _ => false }; } }"; - var comp = CreateCompilationWithSpanAndMemoryExtensions(source, parseOptions: TestOptions.RegularNext); + var comp = CreateCompilationWithSpanAndMemoryExtensions(source, parseOptions: TestOptions.Regular11); comp.VerifyEmitDiagnostics( // (7,43): error CS8514: An expression tree may not contain a switch expression. // Expression> e1 = () => new ReadOnlySpan(null) switch { "123" => true, _ => false }; @@ -10401,7 +10401,7 @@ static int F2(Span span) }; } }"; - var comp = CreateCompilationWithSpanAndMemoryExtensions(source, parseOptions: TestOptions.RegularNext); + var comp = CreateCompilationWithSpanAndMemoryExtensions(source, parseOptions: TestOptions.Regular11); comp.VerifyEmitDiagnostics( // (8,13): error CS9013: A string 'null' constant is not supported as a pattern for 'ReadOnlySpan'. Use an empty string instead. // (string)null => 0, @@ -10672,7 +10672,7 @@ static int F2(Span span) }; } }"; - var comp = CreateCompilationWithSpanAndMemoryExtensions(source, options: TestOptions.ReleaseExe, parseOptions: TestOptions.RegularNext); + var comp = CreateCompilationWithSpanAndMemoryExtensions(source, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular11); comp.VerifyEmitDiagnostics(); var verifier = CompileAndVerify(comp, expectedOutput: @"0 @@ -10852,7 +10852,7 @@ class Program static bool F1(ReadOnlySpan span) => span is ""123""; static bool F2(Span span) => span is ""ABC""; }"; - var comp = CreateCompilationWithSpanAndMemoryExtensions(source, parseOptions: TestOptions.RegularNext); + var comp = CreateCompilationWithSpanAndMemoryExtensions(source, parseOptions: TestOptions.Regular11); comp.VerifyEmitDiagnostics(); var tree = comp.SyntaxTrees.Single(); var model = comp.GetSemanticModel(tree); @@ -10876,7 +10876,7 @@ class Program static bool F1(ReadOnlySpan span) => span is ""123"" and var r; static bool F2(Span span) => span is ""ABC"" and var s; }"; - var comp = CreateCompilationWithSpanAndMemoryExtensions(source, parseOptions: TestOptions.RegularNext); + var comp = CreateCompilationWithSpanAndMemoryExtensions(source, parseOptions: TestOptions.Regular11); comp.VerifyEmitDiagnostics(); var tree = comp.SyntaxTrees.Single(); var model = comp.GetSemanticModel(tree); @@ -10897,7 +10897,7 @@ static bool F(ReadOnlySpan span) return span is ""123""; } }"; - var comp = CreateCompilationWithSpanAndMemoryExtensions(source, parseOptions: TestOptions.RegularNext); + var comp = CreateCompilationWithSpanAndMemoryExtensions(source, parseOptions: TestOptions.Regular11); comp.VerifyEmitDiagnostics(); var tree = comp.SyntaxTrees.Single(); var model = comp.GetSemanticModel(tree); @@ -10954,7 +10954,7 @@ static bool F(Span span) return span is ""ABC""; } }"; - var comp = CreateCompilationWithSpanAndMemoryExtensions(source, parseOptions: TestOptions.RegularNext); + var comp = CreateCompilationWithSpanAndMemoryExtensions(source, parseOptions: TestOptions.Regular11); comp.VerifyEmitDiagnostics(); var tree = comp.SyntaxTrees.Single(); var model = comp.GetSemanticModel(tree); diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/PatternMatchingTests2.cs b/src/Compilers/CSharp/Test/Emit2/Semantics/PatternMatchingTests2.cs similarity index 100% rename from src/Compilers/CSharp/Test/Semantic/Semantics/PatternMatchingTests2.cs rename to src/Compilers/CSharp/Test/Emit2/Semantics/PatternMatchingTests2.cs diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/PatternMatchingTests3.cs b/src/Compilers/CSharp/Test/Emit2/Semantics/PatternMatchingTests3.cs similarity index 100% rename from src/Compilers/CSharp/Test/Semantic/Semantics/PatternMatchingTests3.cs rename to src/Compilers/CSharp/Test/Emit2/Semantics/PatternMatchingTests3.cs diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/PatternMatchingTests4.cs b/src/Compilers/CSharp/Test/Emit2/Semantics/PatternMatchingTests4.cs similarity index 90% rename from src/Compilers/CSharp/Test/Semantic/Semantics/PatternMatchingTests4.cs rename to src/Compilers/CSharp/Test/Emit2/Semantics/PatternMatchingTests4.cs index fcfd622eaf39e..2dd6e1e04efeb 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/PatternMatchingTests4.cs +++ b/src/Compilers/CSharp/Test/Emit2/Semantics/PatternMatchingTests4.cs @@ -4240,6 +4240,513 @@ void M(object obj) [11]: leaf `_ => 4` ", boundSwitch.ReachabilityDecisionDag.Dump()); } + + [Fact, WorkItem(62241, "https://github.com/dotnet/roslyn/issues/62241")] + public void DisableBalancedSwitchDispatchOptimization_Double() + { + var source = """ +C.M(double.NaN); + +public class C +{ + public static void M(double x) + { + string msg = x switch + { + < -40.0 => "Too low", + >= -40.0 and < 0 => "Low", + >= 0 and < 10.0 => "Acceptable", + >= 10.0 => "High", + double.NaN => "NaN", + }; + System.Console.Write(msg); + } +} +"""; + var comp = CreateCompilation(source); + comp.VerifyDiagnostics(); + var verifier = CompileAndVerify(comp, expectedOutput: "NaN"); + + var tree = comp.SyntaxTrees.First(); + var @switch = tree.GetRoot().DescendantNodes().OfType().Single(); + var model = (CSharpSemanticModel)comp.GetSemanticModel(tree); + var binder = model.GetEnclosingBinder(@switch.SpanStart); + var boundSwitch = (BoundSwitchExpression)binder.BindExpression(@switch, BindingDiagnosticBag.Discarded); + AssertEx.AssertEqualToleratingWhitespaceDifferences(""" +[0]: t0 < -40 ? [1] : [2] +[1]: leaf `< -40.0 => "Too low"` +[2]: t0 >= -40 ? [3] : [8] +[3]: t0 < 0 ? [4] : [5] +[4]: leaf `>= -40.0 and < 0 => "Low"` +[5]: t0 < 10 ? [6] : [7] +[6]: leaf `>= 0 and < 10.0 => "Acceptable"` +[7]: leaf `>= 10.0 => "High"` +[8]: leaf `double.NaN => "NaN"` +""", boundSwitch.ReachabilityDecisionDag.Dump()); + + verifier.VerifyIL("C.M", """ +{ + // Code size 95 (0x5f) + .maxstack 2 + .locals init (string V_0) + IL_0000: ldarg.0 + IL_0001: ldc.r8 -40 + IL_000a: blt.s IL_0032 + IL_000c: ldarg.0 + IL_000d: ldc.r8 -40 + IL_0016: blt.un.s IL_0052 + IL_0018: ldarg.0 + IL_0019: ldc.r8 0 + IL_0022: blt.s IL_003a + IL_0024: ldarg.0 + IL_0025: ldc.r8 10 + IL_002e: blt.s IL_0042 + IL_0030: br.s IL_004a + IL_0032: ldstr "Too low" + IL_0037: stloc.0 + IL_0038: br.s IL_0058 + IL_003a: ldstr "Low" + IL_003f: stloc.0 + IL_0040: br.s IL_0058 + IL_0042: ldstr "Acceptable" + IL_0047: stloc.0 + IL_0048: br.s IL_0058 + IL_004a: ldstr "High" + IL_004f: stloc.0 + IL_0050: br.s IL_0058 + IL_0052: ldstr "NaN" + IL_0057: stloc.0 + IL_0058: ldloc.0 + IL_0059: call "void System.Console.Write(string)" + IL_005e: ret +} +"""); + } + + [Fact, WorkItem(62241, "https://github.com/dotnet/roslyn/issues/62241")] + public void DisableBalancedSwitchDispatchOptimization_Single() + { + var source = """ +C.M(float.NaN); + +public class C +{ + public static void M(float x) + { + string msg = x switch + { + < -40.0f => "Too low", + >= -40.0f and < 0f => "Low", + >= 0f and < 10.0f => "Acceptable", + >= 10.0f => "High", + float.NaN => "NaN", + }; + System.Console.Write(msg); + } +} +"""; + var comp = CreateCompilation(source); + comp.VerifyDiagnostics(); + var verifier = CompileAndVerify(comp, expectedOutput: "NaN"); + + var tree = comp.SyntaxTrees.First(); + var @switch = tree.GetRoot().DescendantNodes().OfType().Single(); + var model = (CSharpSemanticModel)comp.GetSemanticModel(tree); + var binder = model.GetEnclosingBinder(@switch.SpanStart); + var boundSwitch = (BoundSwitchExpression)binder.BindExpression(@switch, BindingDiagnosticBag.Discarded); + AssertEx.AssertEqualToleratingWhitespaceDifferences(""" +[0]: t0 < -40 ? [1] : [2] +[1]: leaf `< -40.0f => "Too low"` +[2]: t0 >= -40 ? [3] : [8] +[3]: t0 < 0 ? [4] : [5] +[4]: leaf `>= -40.0f and < 0f => "Low"` +[5]: t0 < 10 ? [6] : [7] +[6]: leaf `>= 0f and < 10.0f => "Acceptable"` +[7]: leaf `>= 10.0f => "High"` +[8]: leaf `float.NaN => "NaN"` +""", boundSwitch.ReachabilityDecisionDag.Dump()); + + verifier.VerifyIL("C.M", """ +{ + // Code size 79 (0x4f) + .maxstack 2 + .locals init (string V_0) + IL_0000: ldarg.0 + IL_0001: ldc.r4 -40 + IL_0006: blt.s IL_0022 + IL_0008: ldarg.0 + IL_0009: ldc.r4 -40 + IL_000e: blt.un.s IL_0042 + IL_0010: ldarg.0 + IL_0011: ldc.r4 0 + IL_0016: blt.s IL_002a + IL_0018: ldarg.0 + IL_0019: ldc.r4 10 + IL_001e: blt.s IL_0032 + IL_0020: br.s IL_003a + IL_0022: ldstr "Too low" + IL_0027: stloc.0 + IL_0028: br.s IL_0048 + IL_002a: ldstr "Low" + IL_002f: stloc.0 + IL_0030: br.s IL_0048 + IL_0032: ldstr "Acceptable" + IL_0037: stloc.0 + IL_0038: br.s IL_0048 + IL_003a: ldstr "High" + IL_003f: stloc.0 + IL_0040: br.s IL_0048 + IL_0042: ldstr "NaN" + IL_0047: stloc.0 + IL_0048: ldloc.0 + IL_0049: call "void System.Console.Write(string)" + IL_004e: ret +} +"""); + } + + [Fact, WorkItem(62241, "https://github.com/dotnet/roslyn/issues/62241")] + public void DisableBalancedSwitchDispatchOptimization_Double_StartingWithHigh() + { + var source = """ +C.M(double.NaN); + +public class C +{ + public static void M(double x) + { + string msg = x switch + { + >= 10.0 => "High", + >= 0 and < 10.0 => "Acceptable", + >= -40.0 and < 0 => "Low", + < -40.0 => "Too low", + double.NaN => "NaN", + }; + System.Console.Write(msg); + } +} +"""; + var comp = CreateCompilation(source); + comp.VerifyDiagnostics(); + var verifier = CompileAndVerify(comp, expectedOutput: "NaN"); + + var tree = comp.SyntaxTrees.First(); + var @switch = tree.GetRoot().DescendantNodes().OfType().Single(); + var model = (CSharpSemanticModel)comp.GetSemanticModel(tree); + var binder = model.GetEnclosingBinder(@switch.SpanStart); + var boundSwitch = (BoundSwitchExpression)binder.BindExpression(@switch, BindingDiagnosticBag.Discarded); + AssertEx.AssertEqualToleratingWhitespaceDifferences(""" +[0]: t0 >= 10 ? [1] : [2] +[1]: leaf `>= 10.0 => "High"` +[2]: t0 >= 0 ? [3] : [4] +[3]: leaf `>= 0 and < 10.0 => "Acceptable"` +[4]: t0 >= -40 ? [5] : [6] +[5]: leaf `>= -40.0 and < 0 => "Low"` +[6]: t0 < -40 ? [7] : [8] +[7]: leaf `< -40.0 => "Too low"` +[8]: leaf `double.NaN => "NaN"` +""", boundSwitch.ReachabilityDecisionDag.Dump()); + + verifier.VerifyIL("C.M", """ +{ + // Code size 95 (0x5f) + .maxstack 2 + .locals init (string V_0) + IL_0000: ldarg.0 + IL_0001: ldc.r8 10 + IL_000a: bge.s IL_0032 + IL_000c: ldarg.0 + IL_000d: ldc.r8 0 + IL_0016: bge.s IL_003a + IL_0018: ldarg.0 + IL_0019: ldc.r8 -40 + IL_0022: bge.s IL_0042 + IL_0024: ldarg.0 + IL_0025: ldc.r8 -40 + IL_002e: blt.s IL_004a + IL_0030: br.s IL_0052 + IL_0032: ldstr "High" + IL_0037: stloc.0 + IL_0038: br.s IL_0058 + IL_003a: ldstr "Acceptable" + IL_003f: stloc.0 + IL_0040: br.s IL_0058 + IL_0042: ldstr "Low" + IL_0047: stloc.0 + IL_0048: br.s IL_0058 + IL_004a: ldstr "Too low" + IL_004f: stloc.0 + IL_0050: br.s IL_0058 + IL_0052: ldstr "NaN" + IL_0057: stloc.0 + IL_0058: ldloc.0 + IL_0059: call "void System.Console.Write(string)" + IL_005e: ret +} +"""); + } + + [Fact, WorkItem(62241, "https://github.com/dotnet/roslyn/issues/62241")] + public void DisableBalancedSwitchDispatchOptimization_Double_StartingWithNaN() + { + var source = """ +C.M(double.NaN); + +public class C +{ + public static void M(double x) + { + string msg = x switch + { + double.NaN => "NaN", + < -40.0 => "Too low", + >= -40.0 and < 0 => "Low", + >= 0 and < 10.0 => "Acceptable", + >= 10.0 => "High", + }; + System.Console.Write(msg); + } +} +"""; + var comp = CreateCompilation(source); + comp.VerifyDiagnostics(); + var verifier = CompileAndVerify(comp, expectedOutput: "NaN"); + + var tree = comp.SyntaxTrees.First(); + var @switch = tree.GetRoot().DescendantNodes().OfType().Single(); + var model = (CSharpSemanticModel)comp.GetSemanticModel(tree); + var binder = model.GetEnclosingBinder(@switch.SpanStart); + var boundSwitch = (BoundSwitchExpression)binder.BindExpression(@switch, BindingDiagnosticBag.Discarded); + AssertEx.AssertEqualToleratingWhitespaceDifferences(""" +[0]: t0 == NaN ? [1] : [2] +[1]: leaf `double.NaN => "NaN"` +[2]: t0 < -40 ? [3] : [4] +[3]: leaf `< -40.0 => "Too low"` +[4]: t0 < 0 ? [5] : [6] +[5]: leaf `>= -40.0 and < 0 => "Low"` +[6]: t0 < 10 ? [7] : [8] +[7]: leaf `>= 0 and < 10.0 => "Acceptable"` +[8]: leaf `>= 10.0 => "High"` +""", boundSwitch.ReachabilityDecisionDag.Dump()); + + verifier.VerifyIL("C.M", """ +{ + // Code size 91 (0x5b) + .maxstack 2 + .locals init (string V_0) + IL_0000: ldarg.0 + IL_0001: call "bool double.IsNaN(double)" + IL_0006: brtrue.s IL_002e + IL_0008: ldarg.0 + IL_0009: ldc.r8 -40 + IL_0012: blt.s IL_0036 + IL_0014: ldarg.0 + IL_0015: ldc.r8 0 + IL_001e: blt.s IL_003e + IL_0020: ldarg.0 + IL_0021: ldc.r8 10 + IL_002a: blt.s IL_0046 + IL_002c: br.s IL_004e + IL_002e: ldstr "NaN" + IL_0033: stloc.0 + IL_0034: br.s IL_0054 + IL_0036: ldstr "Too low" + IL_003b: stloc.0 + IL_003c: br.s IL_0054 + IL_003e: ldstr "Low" + IL_0043: stloc.0 + IL_0044: br.s IL_0054 + IL_0046: ldstr "Acceptable" + IL_004b: stloc.0 + IL_004c: br.s IL_0054 + IL_004e: ldstr "High" + IL_0053: stloc.0 + IL_0054: ldloc.0 + IL_0055: call "void System.Console.Write(string)" + IL_005a: ret +} +"""); + } + + [Fact, WorkItem(62241, "https://github.com/dotnet/roslyn/issues/62241")] + public void DisableBalancedSwitchDispatchOptimization_Double_DefaultCase() + { + var source = """ +C.M(double.NaN); + +public class C +{ + public static void M(double x) + { + string msg = x switch + { + < -40.0 => "Too low", + >= -40.0 and < 0 => "Low", + >= 0 and < 10.0 => "Acceptable", + >= 10.0 => "High", + _ => "NaN", + }; + System.Console.Write(msg); + } +} +"""; + var comp = CreateCompilation(source); + comp.VerifyDiagnostics(); + var verifier = CompileAndVerify(comp, expectedOutput: "NaN"); + + var tree = comp.SyntaxTrees.First(); + var @switch = tree.GetRoot().DescendantNodes().OfType().Single(); + var model = (CSharpSemanticModel)comp.GetSemanticModel(tree); + var binder = model.GetEnclosingBinder(@switch.SpanStart); + var boundSwitch = (BoundSwitchExpression)binder.BindExpression(@switch, BindingDiagnosticBag.Discarded); + AssertEx.AssertEqualToleratingWhitespaceDifferences(""" +[0]: t0 < -40 ? [1] : [2] +[1]: leaf `< -40.0 => "Too low"` +[2]: t0 >= -40 ? [3] : [8] +[3]: t0 < 0 ? [4] : [5] +[4]: leaf `>= -40.0 and < 0 => "Low"` +[5]: t0 < 10 ? [6] : [7] +[6]: leaf `>= 0 and < 10.0 => "Acceptable"` +[7]: leaf `>= 10.0 => "High"` +[8]: leaf `_ => "NaN"` +""", boundSwitch.ReachabilityDecisionDag.Dump()); + + verifier.VerifyIL("C.M", """ +{ + // Code size 95 (0x5f) + .maxstack 2 + .locals init (string V_0) + IL_0000: ldarg.0 + IL_0001: ldc.r8 -40 + IL_000a: blt.s IL_0032 + IL_000c: ldarg.0 + IL_000d: ldc.r8 -40 + IL_0016: blt.un.s IL_0052 + IL_0018: ldarg.0 + IL_0019: ldc.r8 0 + IL_0022: blt.s IL_003a + IL_0024: ldarg.0 + IL_0025: ldc.r8 10 + IL_002e: blt.s IL_0042 + IL_0030: br.s IL_004a + IL_0032: ldstr "Too low" + IL_0037: stloc.0 + IL_0038: br.s IL_0058 + IL_003a: ldstr "Low" + IL_003f: stloc.0 + IL_0040: br.s IL_0058 + IL_0042: ldstr "Acceptable" + IL_0047: stloc.0 + IL_0048: br.s IL_0058 + IL_004a: ldstr "High" + IL_004f: stloc.0 + IL_0050: br.s IL_0058 + IL_0052: ldstr "NaN" + IL_0057: stloc.0 + IL_0058: ldloc.0 + IL_0059: call "void System.Console.Write(string)" + IL_005e: ret +} +"""); + } + + [Fact, WorkItem(62241, "https://github.com/dotnet/roslyn/issues/62241")] + public void DisableBalancedSwitchDispatchOptimization_Double_WhenClause() + { + var source = """ +C.M(double.NaN); + +public class C +{ + public static void M(double x) + { + bool b = true; + string msg = x switch + { + < -40.0 => "Too low", + >= -40.0 and < 0 => "Low", + >= 0 and < 10.0 => "Acceptable", + >= 10.0 => "High", + double.NaN when b => "NaN", + _ => "Other", + }; + System.Console.Write(msg); + } +} +"""; + var comp = CreateCompilation(source); + comp.VerifyDiagnostics(); + var verifier = CompileAndVerify(comp, expectedOutput: "NaN"); + + var tree = comp.SyntaxTrees.First(); + var @switch = tree.GetRoot().DescendantNodes().OfType().Single(); + var model = (CSharpSemanticModel)comp.GetSemanticModel(tree); + var binder = model.GetEnclosingBinder(@switch.SpanStart); + var boundSwitch = (BoundSwitchExpression)binder.BindExpression(@switch, BindingDiagnosticBag.Discarded); + AssertEx.AssertEqualToleratingWhitespaceDifferences(""" +[0]: t0 < -40 ? [1] : [2] +[1]: leaf `< -40.0 => "Too low"` +[2]: t0 >= -40 ? [3] : [8] +[3]: t0 < 0 ? [4] : [5] +[4]: leaf `>= -40.0 and < 0 => "Low"` +[5]: t0 < 10 ? [6] : [7] +[6]: leaf `>= 0 and < 10.0 => "Acceptable"` +[7]: leaf `>= 10.0 => "High"` +[8]: when (b) ? [10] : [9] +[9]: leaf `_ => "Other"` +[10]: leaf `double.NaN when b => "NaN"` +""", boundSwitch.ReachabilityDecisionDag.Dump()); + + verifier.VerifyIL("C.M", """ +{ + // Code size 110 (0x6e) + .maxstack 2 + .locals init (bool V_0, //b + string V_1, + double V_2) + IL_0000: ldc.i4.1 + IL_0001: stloc.0 + IL_0002: ldarg.0 + IL_0003: stloc.2 + IL_0004: ldloc.2 + IL_0005: ldc.r8 -40 + IL_000e: blt.s IL_0036 + IL_0010: ldloc.2 + IL_0011: ldc.r8 -40 + IL_001a: blt.un.s IL_0056 + IL_001c: ldloc.2 + IL_001d: ldc.r8 0 + IL_0026: blt.s IL_003e + IL_0028: ldloc.2 + IL_0029: ldc.r8 10 + IL_0032: blt.s IL_0046 + IL_0034: br.s IL_004e + IL_0036: ldstr "Too low" + IL_003b: stloc.1 + IL_003c: br.s IL_0067 + IL_003e: ldstr "Low" + IL_0043: stloc.1 + IL_0044: br.s IL_0067 + IL_0046: ldstr "Acceptable" + IL_004b: stloc.1 + IL_004c: br.s IL_0067 + IL_004e: ldstr "High" + IL_0053: stloc.1 + IL_0054: br.s IL_0067 + IL_0056: ldloc.0 + IL_0057: brfalse.s IL_0061 + IL_0059: ldstr "NaN" + IL_005e: stloc.1 + IL_005f: br.s IL_0067 + IL_0061: ldstr "Other" + IL_0066: stloc.1 + IL_0067: ldloc.1 + IL_0068: call "void System.Console.Write(string)" + IL_006d: ret +} +"""); + } #endif } } diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/PatternMatchingTests5.cs b/src/Compilers/CSharp/Test/Emit2/Semantics/PatternMatchingTests5.cs similarity index 74% rename from src/Compilers/CSharp/Test/Semantic/Semantics/PatternMatchingTests5.cs rename to src/Compilers/CSharp/Test/Emit2/Semantics/PatternMatchingTests5.cs index 2eb874bb6b89b..4cca81c72e802 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/PatternMatchingTests5.cs +++ b/src/Compilers/CSharp/Test/Emit2/Semantics/PatternMatchingTests5.cs @@ -4,6 +4,7 @@ #nullable disable +using System.Collections.Immutable; using System.Linq; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.CSharp.Test.Utilities; @@ -1949,5 +1950,668 @@ public void Repro55184() Diagnostic(ErrorCode.ERR_NoSuchMember, "Error").WithArguments("int", "Error").WithLocation(7, 19) ); } + + private const string INumberBaseDefinition = """ + namespace System.Numerics; + public interface INumberBase where T : INumberBase {} + """; + + [Fact] + public void ForbiddenOnTypeParametersConstrainedToINumberBase_01() + { + var source = """ + #pragma warning disable 8321 // Unused local function + using System.Numerics; + + void M(T t) where T : INumberBase + { + int o = t switch + { + 1 => 1, // 1 + > 1 => 2, // 2 + int => 3, // OK + [] => 4, // 3 + (_) => 5, // OK + "" => 6, // OK + { } => 7, // OK + var x => 8, // OK + _ => 9 // Ok + }; + } + """; + + 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. + // 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. + // > 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. + // [] => 4, // 3 + Diagnostic(ErrorCode.ERR_ListPatternRequiresLength, "[]").WithArguments("T").WithLocation(11, 9), + // (11,9): error CS0518: Predefined type 'System.Index' is not defined or imported + // [] => 4, // 3 + Diagnostic(ErrorCode.ERR_PredefinedTypeNotFound, "[]").WithArguments("System.Index").WithLocation(11, 9), + // (11,9): error CS0021: Cannot apply indexing with [] to an expression of type 'T' + // [] => 4, // 3 + Diagnostic(ErrorCode.ERR_BadIndexLHS, "[]").WithArguments("T").WithLocation(11, 9) + ); + } + + [Fact] + public void ForbiddenOnTypeParametersConstrainedToINumberBase_02() + { + var source = """ + #pragma warning disable 8321 // Unused local function + using System.Numerics; + + void M(T t) where T : struct, INumberBase + { + int o = t switch + { + 1 => 1, // 1 + > 1 => 2, // 2 + int => 3, // OK + [] => 4, // 3 + (_) => 5, // OK + "" => 6, // 4 + { } => 7, // OK + var x => 8, // OK + _ => 9 // Ok + }; + } + """; + + 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. + // 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. + // > 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. + // [] => 4, // 3 + Diagnostic(ErrorCode.ERR_ListPatternRequiresLength, "[]").WithArguments("T").WithLocation(11, 9), + // (11,9): error CS0518: Predefined type 'System.Index' is not defined or imported + // [] => 4, // 3 + Diagnostic(ErrorCode.ERR_PredefinedTypeNotFound, "[]").WithArguments("System.Index").WithLocation(11, 9), + // (11,9): error CS0021: Cannot apply indexing with [] to an expression of type 'T' + // [] => 4, // 3 + Diagnostic(ErrorCode.ERR_BadIndexLHS, "[]").WithArguments("T").WithLocation(11, 9), + // (13,9): error CS8121: An expression of type 'T' cannot be handled by a pattern of type 'string'. + // "" => 6, // 4 + Diagnostic(ErrorCode.ERR_PatternWrongType, @"""""").WithArguments("T", "string").WithLocation(13, 9) + ); + } + + [Fact] + public void ForbiddenOnTypeParametersConstrainedToINumberBase_MultipleReferences_01() + { + var source = """ + #pragma warning disable 8321 // Unused local function + using System.Numerics; + + void M(T t) where T : struct, INumberBase + { + int o = t switch + { + 1 => 1, // 1 + > 1 => 2, // 2 + int => 3, // OK + [] => 4, // 3 + (_) => 5, // OK + "" => 6, // 4 + { } => 7, // OK + var x => 8, // OK + _ => 9 // Ok + }; + } + """; + + var ref1 = CreateCompilation(INumberBaseDefinition, assemblyName: "A").EmitToImageReference(); + var ref2 = CreateCompilation(INumberBaseDefinition, assemblyName: "B").EmitToImageReference(); + + var comp = CreateCompilation(new[] { source }, references: new[] { ref1, ref2 }); + comp.VerifyDiagnostics( + // (4,34): error CS0433: The type 'INumberBase' exists in both 'A, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null' and 'B, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null' + // void M(T t) where T : struct, INumberBase + Diagnostic(ErrorCode.ERR_SameFullNameAggAgg, "INumberBase").WithArguments("A, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null", "System.Numerics.INumberBase", "B, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null").WithLocation(4, 34), + // (11,9): error CS8985: List patterns may not be used for a value of type 'T'. No suitable 'Length' or 'Count' property was found. + // [] => 4, // 3 + Diagnostic(ErrorCode.ERR_ListPatternRequiresLength, "[]").WithArguments("T").WithLocation(11, 9), + // (11,9): error CS0518: Predefined type 'System.Index' is not defined or imported + // [] => 4, // 3 + Diagnostic(ErrorCode.ERR_PredefinedTypeNotFound, "[]").WithArguments("System.Index").WithLocation(11, 9), + // (11,9): error CS0021: Cannot apply indexing with [] to an expression of type 'T' + // [] => 4, // 3 + Diagnostic(ErrorCode.ERR_BadIndexLHS, "[]").WithArguments("T").WithLocation(11, 9), + // (13,9): error CS8121: An expression of type 'T' cannot be handled by a pattern of type 'string'. + // "" => 6, // 4 + Diagnostic(ErrorCode.ERR_PatternWrongType, @"""""").WithArguments("T", "string").WithLocation(13, 9) + ); + } + + [Fact] + public void ForbiddenOnTypeParametersConstrainedToINumberBase_MultipleReferences_02() + { + var source = """ + extern alias A; + #pragma warning disable 8321 // Unused local function + + void M(T t) where T : struct, A::System.Numerics.INumberBase + { + int o = t switch + { + 1 => 1, // 1 + > 1 => 2, // 2 + int => 3, // OK + [] => 4, // 3 + (_) => 5, // OK + "" => 6, // 4 + { } => 7, // OK + var x => 8, // OK + _ => 9 // Ok + }; + } + """; + + var ref1 = CreateCompilation(INumberBaseDefinition, assemblyName: "A").EmitToImageReference(aliases: ImmutableArray.Create("A")); + var ref2 = CreateCompilation(INumberBaseDefinition, assemblyName: "B").EmitToImageReference(); + + 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. + // 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. + // > 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. + // [] => 4, // 3 + Diagnostic(ErrorCode.ERR_ListPatternRequiresLength, "[]").WithArguments("T").WithLocation(11, 9), + // (11,9): error CS0518: Predefined type 'System.Index' is not defined or imported + // [] => 4, // 3 + Diagnostic(ErrorCode.ERR_PredefinedTypeNotFound, "[]").WithArguments("System.Index").WithLocation(11, 9), + // (11,9): error CS0021: Cannot apply indexing with [] to an expression of type 'T' + // [] => 4, // 3 + Diagnostic(ErrorCode.ERR_BadIndexLHS, "[]").WithArguments("T").WithLocation(11, 9), + // (13,9): error CS8121: An expression of type 'T' cannot be handled by a pattern of type 'string'. + // "" => 6, // 4 + Diagnostic(ErrorCode.ERR_PatternWrongType, @"""""").WithArguments("T", "string").WithLocation(13, 9) + ); + } + + [Theory] + [InlineData("class")] + [InlineData("struct")] + [InlineData("interface")] + public void ForbiddenOnTypesInheritingFromINumberBase(string type) + { + var source = $$""" + #pragma warning disable 8321 // Unused local function + using System.Numerics; + + C c = default(C); + int o = c switch + { + 1 => 1, // 1 + > 1 => 2, // 2 + int => 3, // 3 + [] => 4, // 4 + (_) => 5, // OK + "" => 6, // 5 + { } => 7, // OK + var x => 8, // OK + _ => 9 // Ok + }; + + {{type}} C : INumberBase + { + } + """; + + var comp = CreateCompilation(new[] { source, INumberBaseDefinition }); + comp.VerifyDiagnostics( + // (7,5): error CS0029: Cannot implicitly convert type 'int' to 'C' + // 1 => 1, // 1 + Diagnostic(ErrorCode.ERR_NoImplicitConv, "1").WithArguments("int", "C").WithLocation(7, 5), + // (8,5): error CS8781: Relational patterns may not be used for a value of type 'C'. + // > 1 => 2, // 2 + Diagnostic(ErrorCode.ERR_UnsupportedTypeForRelationalPattern, "> 1").WithArguments("C").WithLocation(8, 5), + // (8,7): error CS0029: Cannot implicitly convert type 'int' to 'C' + // > 1 => 2, // 2 + Diagnostic(ErrorCode.ERR_NoImplicitConv, "1").WithArguments("int", "C").WithLocation(8, 7), + // (9,5): error CS8121: An expression of type 'C' cannot be handled by a pattern of type 'int'. + // int => 3, // 3 + Diagnostic(ErrorCode.ERR_PatternWrongType, "int").WithArguments("C", "int").WithLocation(9, 5), + // (10,5): error CS8985: List patterns may not be used for a value of type 'C'. No suitable 'Length' or 'Count' property was found. + // [] => 4, // 4 + Diagnostic(ErrorCode.ERR_ListPatternRequiresLength, "[]").WithArguments("C").WithLocation(10, 5), + // (10,5): error CS0518: Predefined type 'System.Index' is not defined or imported + // [] => 4, // 4 + Diagnostic(ErrorCode.ERR_PredefinedTypeNotFound, "[]").WithArguments("System.Index").WithLocation(10, 5), + // (10,5): error CS0021: Cannot apply indexing with [] to an expression of type 'C' + // [] => 4, // 4 + Diagnostic(ErrorCode.ERR_BadIndexLHS, "[]").WithArguments("C").WithLocation(10, 5), + // (12,5): error CS0029: Cannot implicitly convert type 'string' to 'C' + // "" => 6, // 5 + Diagnostic(ErrorCode.ERR_NoImplicitConv, @"""""").WithArguments("string", "C").WithLocation(12, 5) + ); + } + + [Theory] + [InlineData("class")] + [InlineData("struct")] + [InlineData("interface")] + public void ForbiddenOnTypesInheritingFromINumberBase_MultipleReferences01(string type) + { + var source = $$""" + #pragma warning disable 8321 // Unused local function + using System.Numerics; + + C c = default(C); + int o = c switch + { + 1 => 1, // 1 + > 1 => 2, // 2 + int => 3, // 3 + [] => 4, // 4 + (_) => 5, // OK + "" => 6, // 5 + { } => 7, // OK + var x => 8, // OK + _ => 9 // Ok + }; + + {{type}} C : + INumberBase + { + } + """; + + var ref1 = CreateCompilation(INumberBaseDefinition, assemblyName: "A").EmitToImageReference(); + var ref2 = CreateCompilation(INumberBaseDefinition, assemblyName: "B").EmitToImageReference(); + + var comp = CreateCompilation(new[] { source }, references: new[] { ref1, ref2 }); + comp.VerifyDiagnostics( + // (7,5): error CS0029: Cannot implicitly convert type 'int' to 'C' + // 1 => 1, // 1 + Diagnostic(ErrorCode.ERR_NoImplicitConv, "1").WithArguments("int", "C").WithLocation(7, 5), + // (8,5): error CS8781: Relational patterns may not be used for a value of type 'C'. + // > 1 => 2, // 2 + Diagnostic(ErrorCode.ERR_UnsupportedTypeForRelationalPattern, "> 1").WithArguments("C").WithLocation(8, 5), + // (8,7): error CS0029: Cannot implicitly convert type 'int' to 'C' + // > 1 => 2, // 2 + Diagnostic(ErrorCode.ERR_NoImplicitConv, "1").WithArguments("int", "C").WithLocation(8, 7), + // (9,5): error CS8121: An expression of type 'C' cannot be handled by a pattern of type 'int'. + // int => 3, // 3 + Diagnostic(ErrorCode.ERR_PatternWrongType, "int").WithArguments("C", "int").WithLocation(9, 5), + // (10,5): error CS8985: List patterns may not be used for a value of type 'C'. No suitable 'Length' or 'Count' property was found. + // [] => 4, // 4 + Diagnostic(ErrorCode.ERR_ListPatternRequiresLength, "[]").WithArguments("C").WithLocation(10, 5), + // (10,5): error CS0518: Predefined type 'System.Index' is not defined or imported + // [] => 4, // 4 + Diagnostic(ErrorCode.ERR_PredefinedTypeNotFound, "[]").WithArguments("System.Index").WithLocation(10, 5), + // (10,5): error CS0021: Cannot apply indexing with [] to an expression of type 'C' + // [] => 4, // 4 + Diagnostic(ErrorCode.ERR_BadIndexLHS, "[]").WithArguments("C").WithLocation(10, 5), + // (12,5): error CS0029: Cannot implicitly convert type 'string' to 'C' + // "" => 6, // 5 + Diagnostic(ErrorCode.ERR_NoImplicitConv, @"""""").WithArguments("string", "C").WithLocation(12, 5), + // (19,5): error CS0433: The type 'INumberBase' exists in both 'A, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null' and 'B, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null' + // INumberBase + Diagnostic(ErrorCode.ERR_SameFullNameAggAgg, "INumberBase").WithArguments("A, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null", "System.Numerics.INumberBase", "B, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null").WithLocation(19, 5) + ); + } + + [Theory] + [InlineData("class")] + [InlineData("struct")] + [InlineData("interface")] + public void ForbiddenOnTypeParametersInheritingFromINumberBase_MultipleReferences02(string type) + { + var source = $$""" + extern alias A; + #pragma warning disable 8321 // Unused local function + + C c = default(C); + int o = c switch + { + 1 => 1, // 1 + > 1 => 2, // 2 + int => 3, // 3 + [] => 4, // 4 + (_) => 5, // OK + "" => 6, // 5 + { } => 7, // OK + var x => 8, // OK + _ => 9 // Ok + }; + + {{type}} C : A::System.Numerics.INumberBase + { + } + """; + + var ref1 = CreateCompilation(INumberBaseDefinition).EmitToImageReference(aliases: ImmutableArray.Create("A")); + var ref2 = CreateCompilation(INumberBaseDefinition).EmitToImageReference(); + + var comp = CreateCompilation(new[] { source }, references: new[] { ref1, ref2 }); + comp.VerifyDiagnostics( + // (7,5): error CS0029: Cannot implicitly convert type 'int' to 'C' + // 1 => 1, // 1 + Diagnostic(ErrorCode.ERR_NoImplicitConv, "1").WithArguments("int", "C").WithLocation(7, 5), + // (8,5): error CS8781: Relational patterns may not be used for a value of type 'C'. + // > 1 => 2, // 2 + Diagnostic(ErrorCode.ERR_UnsupportedTypeForRelationalPattern, "> 1").WithArguments("C").WithLocation(8, 5), + // (8,7): error CS0029: Cannot implicitly convert type 'int' to 'C' + // > 1 => 2, // 2 + Diagnostic(ErrorCode.ERR_NoImplicitConv, "1").WithArguments("int", "C").WithLocation(8, 7), + // (9,5): error CS8121: An expression of type 'C' cannot be handled by a pattern of type 'int'. + // int => 3, // 3 + Diagnostic(ErrorCode.ERR_PatternWrongType, "int").WithArguments("C", "int").WithLocation(9, 5), + // (10,5): error CS8985: List patterns may not be used for a value of type 'C'. No suitable 'Length' or 'Count' property was found. + // [] => 4, // 4 + Diagnostic(ErrorCode.ERR_ListPatternRequiresLength, "[]").WithArguments("C").WithLocation(10, 5), + // (10,5): error CS0518: Predefined type 'System.Index' is not defined or imported + // [] => 4, // 4 + Diagnostic(ErrorCode.ERR_PredefinedTypeNotFound, "[]").WithArguments("System.Index").WithLocation(10, 5), + // (10,5): error CS0021: Cannot apply indexing with [] to an expression of type 'C' + // [] => 4, // 4 + Diagnostic(ErrorCode.ERR_BadIndexLHS, "[]").WithArguments("C").WithLocation(10, 5), + // (12,5): error CS0029: Cannot implicitly convert type 'string' to 'C' + // "" => 6, // 5 + Diagnostic(ErrorCode.ERR_NoImplicitConv, @"""""").WithArguments("string", "C").WithLocation(12, 5) + ); + } + + private const string INumberBaseBCL = """ + namespace System + { + using System.Numerics; + + public class Object {} + public class Void {} + public class ValueType {} + public class String {} + public class Enum {} + public struct Nullable where T : struct {} + public struct Byte : INumberBase {} + public struct SByte : INumberBase {} + public struct Int16 : INumberBase {} + public struct Char : INumberBase {} + public struct UInt16 : INumberBase {} + public struct Int32 : INumberBase {} + public struct UInt32 : INumberBase {} + public struct Int64 : INumberBase {} + public struct UInt64 : INumberBase {} + public struct Single : INumberBase {} + public struct Double : INumberBase {} + public struct Decimal : INumberBase { public Decimal(int value) {} } + public struct IntPtr : INumberBase {} + public struct UIntPtr : INumberBase {} + } + """; + + [Theory] + [InlineData("byte")] + [InlineData("sbyte")] + [InlineData("short")] + [InlineData("ushort")] + [InlineData("int")] + [InlineData("uint")] + [InlineData("nint")] + [InlineData("nuint")] + [InlineData("long")] + [InlineData("ulong")] + [InlineData("float")] + [InlineData("double")] + [InlineData("decimal")] + public void MatchingOnConstantConversionsWithINumberBaseIsAllowed(string inputType) + { + var source = $$""" + {{inputType}} i = 1; + _ = i switch + { + 1 => 1, + > 1 => 2, + _ => 3 + }; + """; + + var comp = CreateEmptyCompilation(new[] { source, INumberBaseBCL, INumberBaseDefinition }); + comp.VerifyDiagnostics(); + } + + [Theory] + [InlineData("byte")] + [InlineData("sbyte")] + [InlineData("short")] + [InlineData("ushort")] + [InlineData("int")] + [InlineData("uint")] + [InlineData("nint")] + [InlineData("nuint")] + [InlineData("long")] + [InlineData("ulong")] + [InlineData("float")] + [InlineData("double")] + [InlineData("decimal")] + public void MatchingOnConstantConversionsWithINumberBaseIsAllowed_Nullable(string inputType) + { + var source = $$""" + {{inputType}}? i = 1; + _ = i switch + { + 1 => 1, + > 1 => 2, + _ => 3 + }; + """; + + var comp = CreateEmptyCompilation(new[] { source, INumberBaseBCL, INumberBaseDefinition }); + comp.VerifyDiagnostics(); + } + + [Fact] + public void MatchingOnConstantConversionsWithINumberBaseIsDisallowed_TypePatternToINumberBaseInt() + { + var source = """ + using System.Numerics; + int i = 1; + _ = ((INumberBase)i) switch + { + 1 => 1, + > 1 => 2, + _ => 3 + }; + """; + + 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. + // 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. + // > 1 => 2, + Diagnostic(ErrorCode.ERR_CannotMatchOnINumberBase, "> 1").WithArguments("System.Numerics.INumberBase").WithLocation(6, 5) + ); + } + + [Theory] + [InlineData("byte")] + [InlineData("sbyte")] + [InlineData("short")] + [InlineData("ushort")] + [InlineData("uint")] + [InlineData("nint")] + [InlineData("nuint")] + [InlineData("long")] + [InlineData("ulong")] + [InlineData("float")] + [InlineData("double")] + [InlineData("decimal")] + public void MatchingOnConstantConversionsWithINumberBaseIsAllowed_TypePatternToINumberBaseT(string inputType) + { + var source = $$""" + using System.Numerics; + {{inputType}} i = 1; + _ = ((INumberBase<{{inputType}}>)i) switch + { + 1 => 1, + > 1 => 2, + _ => 3 + }; + """; + + var comp = CreateEmptyCompilation(new[] { source, INumberBaseBCL, INumberBaseDefinition }); + comp.VerifyDiagnostics( + // (5,5): error CS0029: Cannot implicitly convert type 'int' to 'System.Numerics.INumberBase' + // 1 => 1, + Diagnostic(ErrorCode.ERR_NoImplicitConv, "1").WithArguments("int", $"System.Numerics.INumberBase<{inputType}>").WithLocation(5, 5), + // (6,5): error CS8781: Relational patterns may not be used for a value of type 'System.Numerics.INumberBase'. + // > 1 => 2, + Diagnostic(ErrorCode.ERR_UnsupportedTypeForRelationalPattern, "> 1").WithArguments($"System.Numerics.INumberBase<{inputType}>").WithLocation(6, 5), + // (6,7): error CS0029: Cannot implicitly convert type 'int' to 'System.Numerics.INumberBase' + // > 1 => 2, + Diagnostic(ErrorCode.ERR_NoImplicitConv, "1").WithArguments("int", $"System.Numerics.INumberBase<{inputType}>").WithLocation(6, 7) + ); + } + + [Fact] + public void MatchingOnINumberBaseIsAllowed_ClassNotInterface() + { + var source = """ + #pragma warning disable 8321 // Unused local function + using System.Numerics; + + void M(T t) where T : INumberBase + { + int o = t switch + { + 1 => 1, + > 1 => 2, + _ => 3 + }; + } + + namespace System.Numerics + { + public class INumberBase where T : INumberBase + { + } + } + """; + + var comp = CreateCompilation(source); + comp.VerifyDiagnostics(); + } + + [Fact] + public void MatchingOnINumberBaseIsAllowed_WrongArity() + { + var source = """ + #pragma warning disable 8321 // Unused local function + using System.Numerics; + + void M1(T1 t) where T1 : INumberBase + { + int o = t switch + { + 1 => 1, + > 1 => 2, + _ => 3 + }; + } + + void M2(T t) where T : INumberBase + { + int o = t switch + { + 1 => 1, + > 1 => 2, + _ => 3 + }; + } + + namespace System.Numerics + { + public interface INumberBase where T1 : INumberBase + { + } + + public interface INumberBase + { + } + } + """; + + var comp = CreateCompilation(source); + comp.VerifyDiagnostics(); + } + + [Fact] + public void MatchingOnINumberBaseIsAllowed_WrongNamespace() + { + var source = """ + #pragma warning disable 8321 // Unused local function + using System; + + void M(T t) where T : INumberBase + { + int o = t switch + { + 1 => 1, + > 1 => 2, + _ => 3 + }; + } + + namespace System + { + public interface INumberBase where T : INumberBase + { + } + } + """; + + var comp = CreateCompilation(source); + comp.VerifyDiagnostics(); + } + + [Fact] + public void MatchingOnINumberBaseIsAllowed_NestedType() + { + var source = """ + #pragma warning disable 8321 // Unused local function + using static System.Numerics.Outer; + + void M(T t) where T : INumberBase + { + int o = t switch + { + 1 => 1, + > 1 => 2, + _ => 3 + }; + } + + namespace System.Numerics + { + public interface Outer + { + public interface INumberBase where T : INumberBase + { + } + } + } + """; + + var comp = CreateCompilation(source); + comp.VerifyDiagnostics(); + } } } diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/PatternMatchingTests_Global.cs b/src/Compilers/CSharp/Test/Emit2/Semantics/PatternMatchingTests_Global.cs similarity index 100% rename from src/Compilers/CSharp/Test/Semantic/Semantics/PatternMatchingTests_Global.cs rename to src/Compilers/CSharp/Test/Emit2/Semantics/PatternMatchingTests_Global.cs diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/PatternMatchingTests_ListPatterns.cs b/src/Compilers/CSharp/Test/Emit2/Semantics/PatternMatchingTests_ListPatterns.cs similarity index 99% rename from src/Compilers/CSharp/Test/Semantic/Semantics/PatternMatchingTests_ListPatterns.cs rename to src/Compilers/CSharp/Test/Emit2/Semantics/PatternMatchingTests_ListPatterns.cs index 2f96e69ec5d32..2078ea76d3e0b 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/PatternMatchingTests_ListPatterns.cs +++ b/src/Compilers/CSharp/Test/Emit2/Semantics/PatternMatchingTests_ListPatterns.cs @@ -451,18 +451,18 @@ class C "; var compilation = CreateCompilationWithIndexAndRange(source, parseOptions: TestOptions.Regular10); compilation.VerifyDiagnostics( - // (2,16): error CS8652: The feature 'list pattern' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // (2,16): error CS8936: Feature 'list pattern' is not available in C# 10.0. Please use language version 11.0 or greater. // _ = new C() is []; - Diagnostic(ErrorCode.ERR_FeatureInPreview, "[]").WithArguments("list pattern").WithLocation(2, 16), - // (3,16): error CS8652: The feature 'list pattern' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "[]").WithArguments("list pattern", "11.0").WithLocation(2, 16), + // (3,16): error CS8936: Feature 'list pattern' is not available in C# 10.0. Please use language version 11.0 or greater. // _ = new C() is [.. var x]; - Diagnostic(ErrorCode.ERR_FeatureInPreview, "[.. var x]").WithArguments("list pattern").WithLocation(3, 16), - // (4,16): error CS9002: Slice patterns may only be used once and directly inside a list pattern. + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "[.. var x]").WithArguments("list pattern", "11.0").WithLocation(3, 16), + // (4,16): error CS8980: Slice patterns may only be used once and directly inside a list pattern. // _ = new C() is .. var y; Diagnostic(ErrorCode.ERR_MisplacedSlicePattern, ".. var y").WithLocation(4, 16) ); - compilation = CreateCompilationWithIndexAndRange(source, parseOptions: TestOptions.RegularNext); + compilation = CreateCompilationWithIndexAndRange(source, parseOptions: TestOptions.Regular11); compilation.VerifyDiagnostics( // (4,16): error CS9002: Slice patterns may only be used once and directly inside a list pattern. // _ = new C() is .. var y; diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/PatternMatchingTests_Scope.cs b/src/Compilers/CSharp/Test/Emit2/Semantics/PatternMatchingTests_Scope.cs similarity index 100% rename from src/Compilers/CSharp/Test/Semantic/Semantics/PatternMatchingTests_Scope.cs rename to src/Compilers/CSharp/Test/Emit2/Semantics/PatternMatchingTests_Scope.cs diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/PatternSwitchTests.cs b/src/Compilers/CSharp/Test/Emit2/Semantics/PatternSwitchTests.cs similarity index 100% rename from src/Compilers/CSharp/Test/Semantic/Semantics/PatternSwitchTests.cs rename to src/Compilers/CSharp/Test/Emit2/Semantics/PatternSwitchTests.cs diff --git a/src/Compilers/CSharp/Test/Emit/Emit/EndToEndTests.cs b/src/Compilers/CSharp/Test/EndToEnd/EndToEndTests.cs similarity index 98% rename from src/Compilers/CSharp/Test/Emit/Emit/EndToEndTests.cs rename to src/Compilers/CSharp/Test/EndToEnd/EndToEndTests.cs index d5ad6749052ad..6a2d416a0ed35 100644 --- a/src/Compilers/CSharp/Test/Emit/Emit/EndToEndTests.cs +++ b/src/Compilers/CSharp/Test/EndToEnd/EndToEndTests.cs @@ -13,8 +13,9 @@ using Microsoft.CodeAnalysis.CSharp.Symbols; using Microsoft.CodeAnalysis.PooledObjects; -namespace Microsoft.CodeAnalysis.CSharp.UnitTests.Emit +namespace Microsoft.CodeAnalysis.CSharp.UnitTests.EndToEnd { + [TestCaseOrderer("XUnit.Project.Orderers.AlphabeticalOrderer", "XUnit.Project")] public class EndToEndTests : EmitMetadataTestBase { /// diff --git a/src/Compilers/CSharp/Test/EndToEnd/Microsoft.CodeAnalysis.CSharp.EndToEnd.UnitTests.csproj b/src/Compilers/CSharp/Test/EndToEnd/Microsoft.CodeAnalysis.CSharp.EndToEnd.UnitTests.csproj new file mode 100644 index 0000000000000..d14796cc26fd9 --- /dev/null +++ b/src/Compilers/CSharp/Test/EndToEnd/Microsoft.CodeAnalysis.CSharp.EndToEnd.UnitTests.csproj @@ -0,0 +1,28 @@ + + + + + Library + Microsoft.CodeAnalysis.CSharp.UnitTests + net6.0;net472 + true + + + + + + + + + + + + + Emit\MvidReader.cs + + + + + + + \ No newline at end of file diff --git a/src/Compilers/CSharp/Test/EndToEnd/README.md b/src/Compilers/CSharp/Test/EndToEnd/README.md new file mode 100644 index 0000000000000..0fe86cec1e3ac --- /dev/null +++ b/src/Compilers/CSharp/Test/EndToEnd/README.md @@ -0,0 +1,9 @@ +The EndToEnd tests are isolated from other compiler test to reduce variability. + +Specifically, other tests could: +1. affect JIT ordering, +2. cause GC side-effects, +3. affect implicit caching, +4. change the starting stack size. + +Because EndToEnd tests are in a single test class, they also don't get parallelized. diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/BindingTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/BindingTests.cs index 277a713c918f0..12fce53df8849 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/BindingTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/BindingTests.cs @@ -2152,13 +2152,13 @@ public void GenericAttributeClassWithMultipleParts() var source = @"class C { } class C : System.Attribute { }"; - CreateCompilation(source, parseOptions: TestOptions.Regular9).VerifyDiagnostics( + CreateCompilation(source, parseOptions: TestOptions.Regular10).VerifyDiagnostics( // (2,7): error CS0101: The namespace '' already contains a definition for 'C' // class C : System.Attribute { } Diagnostic(ErrorCode.ERR_DuplicateNameInNS, "C").WithArguments("C", "").WithLocation(2, 7), - // (2,14): error CS8652: The feature 'generic attributes' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // (2,14): error CS8936: Feature 'generic attributes' is not available in C# 10.0. Please use language version 11.0 or greater. // class C : System.Attribute { } - Diagnostic(ErrorCode.ERR_FeatureInPreview, "System.Attribute").WithArguments("generic attributes").WithLocation(2, 14) + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "System.Attribute").WithArguments("generic attributes", "11.0").WithLocation(2, 14) ); CreateCompilation(source).VerifyDiagnostics( diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/DeconstructionTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/DeconstructionTests.cs index d677a49d84fb5..6bc67da45aff6 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/DeconstructionTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/DeconstructionTests.cs @@ -4269,11 +4269,15 @@ private static void StandAlone_01_VerifySemanticModel(CSharpCompilation comp, Lo Assert.Empty(symbolInfo.CandidateSymbols); Assert.Equal(CandidateReason.None, symbolInfo.CandidateReason); typeInfo = model.GetTypeInfo(declarations[0].Type); - Assert.Null(typeInfo.Type); - Assert.Null(typeInfo.ConvertedType); + Assert.Equal("(var a, var b)", typeInfo.Type.ToTestDisplayString()); + Assert.Equal("(var a, var b)", typeInfo.ConvertedType.ToTestDisplayString()); + Assert.Equal(typeInfo.Type, typeInfo.ConvertedType); + Assert.Equal(TypeKind.Struct, typeInfo.Type.TypeKind); + Assert.Equal(TypeKind.Error, ((INamedTypeSymbol)typeInfo.Type).TypeArguments[0].TypeKind); + Assert.Equal(TypeKind.Error, ((INamedTypeSymbol)typeInfo.Type).TypeArguments[1].TypeKind); Assert.True(model.GetConversion(declarations[0].Type).IsIdentity); symbolInfo = model.GetSymbolInfo(declarations[0].Type); - Assert.Null(symbolInfo.Symbol); + Assert.Equal("(var a, var b)", symbolInfo.Symbol.ToTestDisplayString()); Assert.Empty(symbolInfo.CandidateSymbols); Assert.Equal(CandidateReason.None, symbolInfo.CandidateReason); Assert.Null(model.GetAliasInfo(declarations[0].Type)); @@ -4400,11 +4404,11 @@ private static void StandAlone_02_VerifySemanticModel(CSharpCompilation comp) Assert.Empty(symbolInfo.CandidateSymbols); Assert.Equal(CandidateReason.None, symbolInfo.CandidateReason); typeInfo = model.GetTypeInfo(declarations[0].Type); - Assert.Null(typeInfo.Type); - Assert.Null(typeInfo.ConvertedType); + Assert.Equal("(var a, var b)", typeInfo.Type.ToTestDisplayString()); + Assert.Equal("(var a, var b)", typeInfo.ConvertedType.ToTestDisplayString()); Assert.True(model.GetConversion(declarations[0].Type).IsIdentity); symbolInfo = model.GetSymbolInfo(declarations[0].Type); - Assert.Null(symbolInfo.Symbol); + Assert.Equal("(var a, var b)", symbolInfo.Symbol.ToTestDisplayString()); Assert.Empty(symbolInfo.CandidateSymbols); Assert.Equal(CandidateReason.None, symbolInfo.CandidateReason); Assert.Null(model.GetAliasInfo(declarations[0].Type)); @@ -4524,11 +4528,15 @@ private static void StandAlone_03_VerifySemanticModel(CSharpCompilation comp) Assert.Empty(symbolInfo.CandidateSymbols); Assert.Equal(CandidateReason.None, symbolInfo.CandidateReason); typeInfo = model.GetTypeInfo(declarations[0].Type); - Assert.Null(typeInfo.Type); - Assert.Null(typeInfo.ConvertedType); + Assert.Equal("(var, var)", typeInfo.Type.ToTestDisplayString()); + Assert.Equal("(var, var)", typeInfo.ConvertedType.ToTestDisplayString()); + Assert.Equal(typeInfo.Type, typeInfo.ConvertedType); + Assert.Equal(TypeKind.Struct, typeInfo.Type.TypeKind); + Assert.Equal(TypeKind.Error, ((INamedTypeSymbol)typeInfo.Type).TypeArguments[0].TypeKind); + Assert.Equal(TypeKind.Error, ((INamedTypeSymbol)typeInfo.Type).TypeArguments[1].TypeKind); Assert.True(model.GetConversion(declarations[0].Type).IsIdentity); symbolInfo = model.GetSymbolInfo(declarations[0].Type); - Assert.Null(symbolInfo.Symbol); + Assert.Equal("(var, var)", symbolInfo.Symbol.ToTestDisplayString()); Assert.Empty(symbolInfo.CandidateSymbols); Assert.Equal(CandidateReason.None, symbolInfo.CandidateReason); Assert.Null(model.GetAliasInfo(declarations[0].Type)); @@ -4670,11 +4678,11 @@ private static void StandAlone_05_VerifySemanticModel(CSharpCompilation comp) Assert.Empty(symbolInfo.CandidateSymbols); Assert.Equal(CandidateReason.None, symbolInfo.CandidateReason); typeInfo = model.GetTypeInfo(declarations[0].Type); - Assert.Null(typeInfo.Type); - Assert.Null(typeInfo.ConvertedType); + Assert.Equal("System.Int32", typeInfo.Type.ToTestDisplayString()); + Assert.Equal("System.Int32", typeInfo.ConvertedType.ToTestDisplayString()); Assert.True(model.GetConversion(declarations[0].Type).IsIdentity); symbolInfo = model.GetSymbolInfo(declarations[0].Type); - Assert.Null(symbolInfo.Symbol); + Assert.Equal("System.Int32", symbolInfo.Symbol.ToTestDisplayString()); Assert.Empty(symbolInfo.CandidateSymbols); Assert.Equal(CandidateReason.None, symbolInfo.CandidateReason); Assert.Equal("var=System.Int32", model.GetAliasInfo(declarations[0].Type).ToTestDisplayString()); @@ -4764,11 +4772,11 @@ private static void StandAlone_06_VerifySemanticModel(CSharpCompilation comp) Assert.Empty(symbolInfo.CandidateSymbols); Assert.Equal(CandidateReason.None, symbolInfo.CandidateReason); typeInfo = model.GetTypeInfo(declarations[0].Type); - Assert.Null(typeInfo.Type); - Assert.Null(typeInfo.ConvertedType); + Assert.Equal("System.Int32", typeInfo.Type.ToTestDisplayString()); + Assert.Equal("System.Int32", typeInfo.ConvertedType.ToTestDisplayString()); Assert.True(model.GetConversion(declarations[0].Type).IsIdentity); symbolInfo = model.GetSymbolInfo(declarations[0].Type); - Assert.Null(symbolInfo.Symbol); + Assert.Equal("System.Int32", symbolInfo.Symbol.ToTestDisplayString()); Assert.Empty(symbolInfo.CandidateSymbols); Assert.Equal(CandidateReason.None, symbolInfo.CandidateReason); Assert.Equal("var=System.Int32", model.GetAliasInfo(declarations[0].Type).ToTestDisplayString()); @@ -4842,11 +4850,11 @@ private static void StandAlone_07_VerifySemanticModel(CSharpCompilation comp) Assert.Empty(symbolInfo.CandidateSymbols); Assert.Equal(CandidateReason.None, symbolInfo.CandidateReason); typeInfo = model.GetTypeInfo(declarations[0].Type); - Assert.Null(typeInfo.Type); - Assert.Null(typeInfo.ConvertedType); + Assert.Equal("System.Int32", typeInfo.Type.ToTestDisplayString()); + Assert.Equal("System.Int32", typeInfo.ConvertedType.ToTestDisplayString()); Assert.True(model.GetConversion(declarations[0].Type).IsIdentity); symbolInfo = model.GetSymbolInfo(declarations[0].Type); - Assert.Null(symbolInfo.Symbol); + Assert.Equal("System.Int32", symbolInfo.Symbol.ToTestDisplayString()); Assert.Empty(symbolInfo.CandidateSymbols); Assert.Equal(CandidateReason.None, symbolInfo.CandidateReason); Assert.Equal("var=System.Int32", model.GetAliasInfo(declarations[0].Type).ToTestDisplayString()); @@ -5210,11 +5218,11 @@ private static void StandAlone_14_VerifySemanticModel(CSharpCompilation comp, Lo Assert.Empty(symbolInfo.CandidateSymbols); Assert.Equal(CandidateReason.None, symbolInfo.CandidateReason); typeInfo = model.GetTypeInfo(declarations[0].Type); - Assert.Null(typeInfo.Type); - Assert.Null(typeInfo.ConvertedType); + Assert.Equal("(var a, var b)", typeInfo.Type.ToTestDisplayString()); + Assert.Equal("(var a, var b)", typeInfo.ConvertedType.ToTestDisplayString()); Assert.True(model.GetConversion(declarations[0].Type).IsIdentity); symbolInfo = model.GetSymbolInfo(declarations[0].Type); - Assert.Null(symbolInfo.Symbol); + Assert.Equal("(var a, var b)", symbolInfo.Symbol.ToTestDisplayString()); Assert.Empty(symbolInfo.CandidateSymbols); Assert.Equal(CandidateReason.None, symbolInfo.CandidateReason); Assert.Null(model.GetAliasInfo(declarations[0].Type)); @@ -5355,11 +5363,11 @@ private static void StandAlone_15_VerifySemanticModel(CSharpCompilation comp) Assert.Empty(symbolInfo.CandidateSymbols); Assert.Equal(CandidateReason.None, symbolInfo.CandidateReason); typeInfo = model.GetTypeInfo(declarations[0].Type); - Assert.Null(typeInfo.Type); - Assert.Null(typeInfo.ConvertedType); + Assert.Equal("(var a, var b)", typeInfo.Type.ToTestDisplayString()); + Assert.Equal("(var a, var b)", typeInfo.ConvertedType.ToTestDisplayString()); Assert.True(model.GetConversion(declarations[0].Type).IsIdentity); symbolInfo = model.GetSymbolInfo(declarations[0].Type); - Assert.Null(symbolInfo.Symbol); + Assert.Equal("(var a, var b)", symbolInfo.Symbol.ToTestDisplayString()); Assert.Empty(symbolInfo.CandidateSymbols); Assert.Equal(CandidateReason.None, symbolInfo.CandidateReason); Assert.Null(model.GetAliasInfo(declarations[0].Type)); @@ -5492,11 +5500,11 @@ private static void StandAlone_16_VerifySemanticModel(CSharpCompilation comp) Assert.Empty(symbolInfo.CandidateSymbols); Assert.Equal(CandidateReason.None, symbolInfo.CandidateReason); typeInfo = model.GetTypeInfo(declarations[0].Type); - Assert.Null(typeInfo.Type); - Assert.Null(typeInfo.ConvertedType); + Assert.Equal("(var, var)", typeInfo.Type.ToTestDisplayString()); + Assert.Equal("(var, var)", typeInfo.ConvertedType.ToTestDisplayString()); Assert.True(model.GetConversion(declarations[0].Type).IsIdentity); symbolInfo = model.GetSymbolInfo(declarations[0].Type); - Assert.Null(symbolInfo.Symbol); + Assert.Equal("(var, var)", symbolInfo.Symbol.ToTestDisplayString()); Assert.Empty(symbolInfo.CandidateSymbols); Assert.Equal(CandidateReason.None, symbolInfo.CandidateReason); Assert.Null(model.GetAliasInfo(declarations[0].Type)); @@ -5679,11 +5687,11 @@ private static void StandAlone_18_VerifySemanticModel(CSharpCompilation comp, Lo Assert.Empty(symbolInfo.CandidateSymbols); Assert.Equal(CandidateReason.None, symbolInfo.CandidateReason); typeInfo = model.GetTypeInfo(declarations[0].Type); - Assert.Null(typeInfo.Type); - Assert.Null(typeInfo.ConvertedType); + Assert.Equal("((var a, var b), var c)", typeInfo.Type.ToTestDisplayString()); + Assert.Equal("((var a, var b), var c)", typeInfo.ConvertedType.ToTestDisplayString()); Assert.True(model.GetConversion(declarations[0].Type).IsIdentity); symbolInfo = model.GetSymbolInfo(declarations[0].Type); - Assert.Null(symbolInfo.Symbol); + Assert.Equal("((var a, var b), var c)", symbolInfo.Symbol.ToTestDisplayString()); Assert.Empty(symbolInfo.CandidateSymbols); Assert.Equal(CandidateReason.None, symbolInfo.CandidateReason); Assert.Null(model.GetAliasInfo(declarations[0].Type)); @@ -5789,11 +5797,11 @@ private static void StandAlone_19_VerifySemanticModel(CSharpCompilation comp) Assert.Empty(symbolInfo.CandidateSymbols); Assert.Equal(CandidateReason.None, symbolInfo.CandidateReason); typeInfo = model.GetTypeInfo(declarations[0].Type); - Assert.Null(typeInfo.Type); - Assert.Null(typeInfo.ConvertedType); + Assert.Equal("((var a, var b), var c)", typeInfo.Type.ToTestDisplayString()); + Assert.Equal("((var a, var b), var c)", typeInfo.ConvertedType.ToTestDisplayString()); Assert.True(model.GetConversion(declarations[0].Type).IsIdentity); symbolInfo = model.GetSymbolInfo(declarations[0].Type); - Assert.Null(symbolInfo.Symbol); + Assert.Equal("((var a, var b), var c)", symbolInfo.Symbol.ToTestDisplayString()); Assert.Empty(symbolInfo.CandidateSymbols); Assert.Equal(CandidateReason.None, symbolInfo.CandidateReason); Assert.Null(model.GetAliasInfo(declarations[0].Type)); @@ -5892,11 +5900,11 @@ private static void StandAlone_20_VerifySemanticModel(CSharpCompilation comp) Assert.Empty(symbolInfo.CandidateSymbols); Assert.Equal(CandidateReason.None, symbolInfo.CandidateReason); typeInfo = model.GetTypeInfo(declarations[0].Type); - Assert.Null(typeInfo.Type); - Assert.Null(typeInfo.ConvertedType); + Assert.Equal("((var, var), var)", typeInfo.Type.ToTestDisplayString()); + Assert.Equal("((var, var), var)", typeInfo.ConvertedType.ToTestDisplayString()); Assert.True(model.GetConversion(declarations[0].Type).IsIdentity); symbolInfo = model.GetSymbolInfo(declarations[0].Type); - Assert.Null(symbolInfo.Symbol); + Assert.Equal("((var, var), var)", symbolInfo.Symbol.ToTestDisplayString()); Assert.Empty(symbolInfo.CandidateSymbols); Assert.Equal(CandidateReason.None, symbolInfo.CandidateReason); Assert.Null(model.GetAliasInfo(declarations[0].Type)); @@ -6531,5 +6539,27 @@ .locals init (int& V_0) } "); } + + [Fact, WorkItem(61332, "https://github.com/dotnet/roslyn/issues/61332")] + public void NestedNullableConversions() + { + var code = """ + float? _startScrollPosition, _endScrollPosition; + (_startScrollPosition, _endScrollPosition) = GetScrollPositions(); + + (float, float) GetScrollPositions() => (0, 0); + """; + + var comp = CreateCompilation(code); + comp.VerifyDiagnostics(); + + var tree = comp.SyntaxTrees[0]; + var model = comp.GetSemanticModel(tree); + var assignment = tree.GetRoot().DescendantNodes().OfType().Single(); + var deconstructionInfo = model.GetDeconstructionInfo(assignment); + var nestedConversions = deconstructionInfo.Nested; + Assert.Equal(2, nestedConversions.Length); + Assert.All(nestedConversions, n => Assert.Empty(n.Nested)); + } } } diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/DelegateTypeTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/DelegateTypeTests.cs index 084c9b0f393d9..17b9cb4b7112b 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/DelegateTypeTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/DelegateTypeTests.cs @@ -10088,8 +10088,10 @@ class Program { static R F1(ref R r) { Console.WriteLine(r._i); return new R(); } static R F2(scoped ref R r) { Console.WriteLine(r._i); return new R(); } - static R F3(ref scoped R r) { Console.WriteLine(r._i); return new R(); } - static R F4(scoped ref R r) { Console.WriteLine(r._i); return new R(); } + static R F3(in R r) { Console.WriteLine(r._i); return new R(); } + static R F4(scoped in R r) { Console.WriteLine(r._i); return new R(); } + static R F5(out R r) { r = new R(-5); Console.WriteLine(r._i); return new R(); } + static R F6(scoped out R r) { r = new R(-6); Console.WriteLine(r._i); return new R(); } static void Main() { var d1 = F1; @@ -10102,12 +10104,20 @@ static void Main() Report(d2); var d3 = F3; var r3 = new R(3); - d3(ref r3); + d3(r3); Report(d3); var d4 = F4; var r4 = new R(4); - d4(ref r4); + d4(r4); Report(d4); + var d5 = F5; + var r5 = new R(5); + d5(out r5); + Report(d5); + var d6 = F6; + var r6 = new R(6); + d6(out r6); + Report(d6); } static void Report(Delegate d) => Console.WriteLine(d.GetType()); }"; @@ -10115,12 +10125,18 @@ static void Main() @"1 <>f__AnonymousDelegate0 2 -<>f__AnonymousDelegate1 +<>f__AnonymousDelegate0 3 -<>f__AnonymousDelegate2 +<>f__AnonymousDelegate1 4 <>f__AnonymousDelegate1 +-5 +<>f__AnonymousDelegate2 +-6 +<>f__AnonymousDelegate2 "); + + // https://github.com/dotnet/roslyn/issues/62780: Test with [UnscopedRef]. } [Fact] diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/InheritanceBindingTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/InheritanceBindingTests.cs index 7028526674248..d312e75f67938 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/InheritanceBindingTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/InheritanceBindingTests.cs @@ -99,9 +99,9 @@ private protected void IGoo.Method14() { } // (34,23): error CS0106: The modifier 'private' is not valid for this item // private void IGoo.Method10() { } Diagnostic(ErrorCode.ERR_BadMemberFlag, "Method10").WithArguments("private").WithLocation(34, 23), - // (37,22): error CS8703: The modifier 'static' is not valid for this item in C# 9.0. Please use language version 'preview' or greater. + // (37,22): error CS8703: The modifier 'static' is not valid for this item in C# 9.0. Please use language version '11.0' or greater. // static void IGoo.Method12() { } - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "Method12").WithArguments("static", "9.0", "preview").WithLocation(37, 22), + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "Method12").WithArguments("static", "9.0", "11.0").WithLocation(37, 22), // (40,33): error CS0106: The modifier 'private protected' is not valid for this item // private protected void IGoo.Method14() { } Diagnostic(ErrorCode.ERR_BadMemberFlag, "Method14").WithArguments("private protected").WithLocation(40, 33), @@ -162,28 +162,38 @@ static int IGoo.Property12 { set { } } CreateCompilation(text, parseOptions: TestOptions.Regular9).VerifyDiagnostics( // (20,23): error CS0106: The modifier 'abstract' is not valid for this item - Diagnostic(ErrorCode.ERR_BadMemberFlag, "Property1").WithArguments("abstract"), + // abstract int IGoo.Property1 { set { } } + Diagnostic(ErrorCode.ERR_BadMemberFlag, "Property1").WithArguments("abstract").WithLocation(20, 23), // (21,22): error CS0106: The modifier 'virtual' is not valid for this item - Diagnostic(ErrorCode.ERR_BadMemberFlag, "Property2").WithArguments("virtual"), + // virtual int IGoo.Property2 { set { } } + Diagnostic(ErrorCode.ERR_BadMemberFlag, "Property2").WithArguments("virtual").WithLocation(21, 22), // (22,23): error CS0106: The modifier 'override' is not valid for this item - Diagnostic(ErrorCode.ERR_BadMemberFlag, "Property3").WithArguments("override"), + // override int IGoo.Property3 { set { } } + Diagnostic(ErrorCode.ERR_BadMemberFlag, "Property3").WithArguments("override").WithLocation(22, 23), // (24,21): error CS0106: The modifier 'sealed' is not valid for this item - Diagnostic(ErrorCode.ERR_BadMemberFlag, "Property4").WithArguments("sealed"), + // sealed int IGoo.Property4 { set { } } + Diagnostic(ErrorCode.ERR_BadMemberFlag, "Property4").WithArguments("sealed").WithLocation(24, 21), // (26,18): error CS0106: The modifier 'new' is not valid for this item - Diagnostic(ErrorCode.ERR_BadMemberFlag, "Property5").WithArguments("new"), + // new int IGoo.Property5 { set { } } + Diagnostic(ErrorCode.ERR_BadMemberFlag, "Property5").WithArguments("new").WithLocation(26, 18), // (28,21): error CS0106: The modifier 'public' is not valid for this item - Diagnostic(ErrorCode.ERR_BadMemberFlag, "Property6").WithArguments("public"), + // public int IGoo.Property6 { set { } } + Diagnostic(ErrorCode.ERR_BadMemberFlag, "Property6").WithArguments("public").WithLocation(28, 21), // (29,24): error CS0106: The modifier 'protected' is not valid for this item - Diagnostic(ErrorCode.ERR_BadMemberFlag, "Property7").WithArguments("protected"), + // protected int IGoo.Property7 { set { } } + Diagnostic(ErrorCode.ERR_BadMemberFlag, "Property7").WithArguments("protected").WithLocation(29, 24), // (30,23): error CS0106: The modifier 'internal' is not valid for this item - Diagnostic(ErrorCode.ERR_BadMemberFlag, "Property8").WithArguments("internal"), + // internal int IGoo.Property8 { set { } } + Diagnostic(ErrorCode.ERR_BadMemberFlag, "Property8").WithArguments("internal").WithLocation(30, 23), // (31,33): error CS0106: The modifier 'protected internal' is not valid for this item - Diagnostic(ErrorCode.ERR_BadMemberFlag, "Property9").WithArguments("protected internal"), + // protected internal int IGoo.Property9 { set { } } //roslyn considers 'protected internal' one modifier (two in dev10) + Diagnostic(ErrorCode.ERR_BadMemberFlag, "Property9").WithArguments("protected internal").WithLocation(31, 33), // (32,22): error CS0106: The modifier 'private' is not valid for this item - Diagnostic(ErrorCode.ERR_BadMemberFlag, "Property10").WithArguments("private"), - // (35,21): error CS8703: The modifier 'static' is not valid for this item in C# 9.0. Please use language version 'preview' or greater. + // private int IGoo.Property10 { set { } } + Diagnostic(ErrorCode.ERR_BadMemberFlag, "Property10").WithArguments("private").WithLocation(32, 22), + // (35,21): error CS8703: The modifier 'static' is not valid for this item in C# 9.0. Please use language version '11.0' or greater. // static int IGoo.Property12 { set { } } - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "Property12").WithArguments("static", "9.0", "preview").WithLocation(35, 21), + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "Property12").WithArguments("static", "9.0", "11.0").WithLocation(35, 21), // (35,21): error CS0539: 'AbstractGoo.Property12' in explicit interface declaration is not found among members of the interface that can be implemented // static int IGoo.Property12 { set { } } Diagnostic(ErrorCode.ERR_InterfaceMemberNotFound, "Property12").WithArguments("AbstractGoo.Property12").WithLocation(35, 21), @@ -191,7 +201,8 @@ static int IGoo.Property12 { set { } } // abstract class AbstractGoo : IGoo Diagnostic(ErrorCode.ERR_UnimplementedInterfaceMember, "IGoo").WithArguments("AbstractGoo", "IGoo.Property12").WithLocation(18, 30), // (34,34): warning CS0626: Method, operator, or accessor 'AbstractGoo.IGoo.Property11.set' is marked external and has no attributes on it. Consider adding a DllImport attribute to specify the external implementation. - Diagnostic(ErrorCode.WRN_ExternMethodNoImplementation, "set").WithArguments("AbstractGoo.IGoo.Property11.set")); + // extern int IGoo.Property11 { set; } //not an error (in dev10 or roslyn) + Diagnostic(ErrorCode.WRN_ExternMethodNoImplementation, "set").WithArguments("AbstractGoo.IGoo.Property11.set").WithLocation(34, 34)); } [Fact] @@ -308,43 +319,43 @@ static event System.Action IGoo.Event12 { add { } remove { } } CreateCompilation(text, parseOptions: TestOptions.Regular9).VerifyDiagnostics( // (20,39): error CS0106: The modifier 'abstract' is not valid for this item // abstract event System.Action IGoo.Event1 { add { } remove { } } - Diagnostic(ErrorCode.ERR_BadMemberFlag, "Event1").WithArguments("abstract"), + Diagnostic(ErrorCode.ERR_BadMemberFlag, "Event1").WithArguments("abstract").WithLocation(20, 39), // (21,38): error CS0106: The modifier 'virtual' is not valid for this item // virtual event System.Action IGoo.Event2 { add { } remove { } } - Diagnostic(ErrorCode.ERR_BadMemberFlag, "Event2").WithArguments("virtual"), + Diagnostic(ErrorCode.ERR_BadMemberFlag, "Event2").WithArguments("virtual").WithLocation(21, 38), // (22,39): error CS0106: The modifier 'override' is not valid for this item // override event System.Action IGoo.Event3 { add { } remove { } } - Diagnostic(ErrorCode.ERR_BadMemberFlag, "Event3").WithArguments("override"), + Diagnostic(ErrorCode.ERR_BadMemberFlag, "Event3").WithArguments("override").WithLocation(22, 39), // (24,37): error CS0106: The modifier 'sealed' is not valid for this item // sealed event System.Action IGoo.Event4 { add { } remove { } } - Diagnostic(ErrorCode.ERR_BadMemberFlag, "Event4").WithArguments("sealed"), + Diagnostic(ErrorCode.ERR_BadMemberFlag, "Event4").WithArguments("sealed").WithLocation(24, 37), // (26,34): error CS0106: The modifier 'new' is not valid for this item // new event System.Action IGoo.Event5 { add { } remove { } } - Diagnostic(ErrorCode.ERR_BadMemberFlag, "Event5").WithArguments("new"), + Diagnostic(ErrorCode.ERR_BadMemberFlag, "Event5").WithArguments("new").WithLocation(26, 34), // (28,37): error CS0106: The modifier 'public' is not valid for this item // public event System.Action IGoo.Event6 { add { } remove { } } - Diagnostic(ErrorCode.ERR_BadMemberFlag, "Event6").WithArguments("public"), + Diagnostic(ErrorCode.ERR_BadMemberFlag, "Event6").WithArguments("public").WithLocation(28, 37), // (29,40): error CS0106: The modifier 'protected' is not valid for this item // protected event System.Action IGoo.Event7 { add { } remove { } } - Diagnostic(ErrorCode.ERR_BadMemberFlag, "Event7").WithArguments("protected"), + Diagnostic(ErrorCode.ERR_BadMemberFlag, "Event7").WithArguments("protected").WithLocation(29, 40), // (30,39): error CS0106: The modifier 'internal' is not valid for this item // internal event System.Action IGoo.Event8 { add { } remove { } } - Diagnostic(ErrorCode.ERR_BadMemberFlag, "Event8").WithArguments("internal"), + Diagnostic(ErrorCode.ERR_BadMemberFlag, "Event8").WithArguments("internal").WithLocation(30, 39), // (31,49): error CS0106: The modifier 'protected internal' is not valid for this item // protected internal event System.Action IGoo.Event9 { add { } remove { } } //roslyn considers 'protected internal' one modifier (two in dev10) - Diagnostic(ErrorCode.ERR_BadMemberFlag, "Event9").WithArguments("protected internal"), + Diagnostic(ErrorCode.ERR_BadMemberFlag, "Event9").WithArguments("protected internal").WithLocation(31, 49), // (32,38): error CS0106: The modifier 'private' is not valid for this item // private event System.Action IGoo.Event10 { add { } remove { } } - Diagnostic(ErrorCode.ERR_BadMemberFlag, "Event10").WithArguments("private"), + Diagnostic(ErrorCode.ERR_BadMemberFlag, "Event10").WithArguments("private").WithLocation(32, 38), // (34,47): error CS0179: 'AbstractGoo.IGoo.Event11.add' cannot be extern and declare a body // extern event System.Action IGoo.Event11 { add { } remove { } } - Diagnostic(ErrorCode.ERR_ExternHasBody, "add").WithArguments("AbstractGoo.IGoo.Event11.add"), + Diagnostic(ErrorCode.ERR_ExternHasBody, "add").WithArguments("AbstractGoo.IGoo.Event11.add").WithLocation(34, 47), // (34,55): error CS0179: 'AbstractGoo.IGoo.Event11.remove' cannot be extern and declare a body // extern event System.Action IGoo.Event11 { add { } remove { } } - Diagnostic(ErrorCode.ERR_ExternHasBody, "remove").WithArguments("AbstractGoo.IGoo.Event11.remove"), - // (35,37): error CS8703: The modifier 'static' is not valid for this item in C# 9.0. Please use language version 'preview' or greater. + Diagnostic(ErrorCode.ERR_ExternHasBody, "remove").WithArguments("AbstractGoo.IGoo.Event11.remove").WithLocation(34, 55), + // (35,37): error CS8703: The modifier 'static' is not valid for this item in C# 9.0. Please use language version '11.0' or greater. // static event System.Action IGoo.Event12 { add { } remove { } } - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "Event12").WithArguments("static", "9.0", "preview").WithLocation(35, 37), + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "Event12").WithArguments("static", "9.0", "11.0").WithLocation(35, 37), // (35,37): error CS0539: 'AbstractGoo.Event12' in explicit interface declaration is not found among members of the interface that can be implemented // static event System.Action IGoo.Event12 { add { } remove { } } Diagnostic(ErrorCode.ERR_InterfaceMemberNotFound, "Event12").WithArguments("AbstractGoo.Event12").WithLocation(35, 37), diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/InterpolationTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/InterpolationTests.cs index d6b0e44b41a4f..8a8bc0f815bf9 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/InterpolationTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/InterpolationTests.cs @@ -1261,7 +1261,7 @@ public static void Main(){ Console.WriteLine(str); } }"; - var parseOptions = TestOptions.RegularNext; + var parseOptions = TestOptions.Regular11; var compOptions = new CSharpCompilationOptions(OutputKind.ConsoleApplication); //string.Format was fixed in dotnet core 3 @@ -1422,7 +1422,7 @@ public static void Main(){ Console.WriteLine(str); } }"; - var parseOptions = TestOptions.RegularNext; + var parseOptions = TestOptions.Regular11; var compOptions = new CSharpCompilationOptions(OutputKind.ConsoleApplication); var expectedOutput = "Before {a} After"; @@ -13425,7 +13425,7 @@ .locals init (object V_0, //d [Theory] [InlineData(@"$""{s}""")] [InlineData(@"$""{s}"" + $""""")] - public void RefEscape_01(string expression) + public void RefEscape_01A(string expression) { var code = @" using System; @@ -13448,12 +13448,47 @@ public static CustomHandler M() } "; - var comp = CreateCompilation(new[] { code, InterpolatedStringHandlerAttribute }, targetFramework: TargetFramework.NetCoreApp); - comp.VerifyDiagnostics( + var expectedDiagnostics = new[] + { // (17,19): error CS8352: Cannot use variable 's' in this context because it may expose referenced variables outside of their declaration scope // return $"{s}"; Diagnostic(ErrorCode.ERR_EscapeVariable, "s").WithArguments("s").WithLocation(17, 19) - ); + }; + + var comp = CreateCompilation(new[] { code, InterpolatedStringHandlerAttribute }, parseOptions: TestOptions.Regular10, targetFramework: TargetFramework.NetCoreApp); + comp.VerifyDiagnostics(expectedDiagnostics); + + comp = CreateCompilation(new[] { code, InterpolatedStringHandlerAttribute }, targetFramework: TargetFramework.NetCoreApp); + comp.VerifyDiagnostics(expectedDiagnostics); + } + + // As above but with scoped parameter in AppendFormatted(). + [WorkItem(63262, "https://github.com/dotnet/roslyn/issues/63262")] + [Theory] + [InlineData(@"$""{s}""")] + [InlineData(@"$""{s}"" + $""""")] + public void RefEscape_01B(string expression) + { + var code = @" +using System; +using System.Runtime.CompilerServices; + +[InterpolatedStringHandler] +public ref struct CustomHandler +{ + public CustomHandler(int literalLength, int formattedCount) { } + + public void AppendFormatted(scoped Span s) { } + + public static CustomHandler M() + { + Span s = stackalloc char[10]; + return " + expression + @"; + } +} +"; + var comp = CreateCompilation(new[] { code, InterpolatedStringHandlerAttribute }, targetFramework: TargetFramework.NetCoreApp); + comp.VerifyDiagnostics(); } [Theory] @@ -13482,12 +13517,18 @@ public static ref CustomHandler M() } "; - var comp = CreateCompilation(new[] { code, InterpolatedStringHandlerAttribute }, targetFramework: TargetFramework.NetCoreApp); - comp.VerifyDiagnostics( + var expectedDiagnostics = new[] + { // (17,9): error CS8150: By-value returns may only be used in methods that return by value // return $"{s}"; Diagnostic(ErrorCode.ERR_MustHaveRefReturn, "return").WithLocation(17, 9) - ); + }; + + var comp = CreateCompilation(new[] { code, InterpolatedStringHandlerAttribute }, parseOptions: TestOptions.Regular10, targetFramework: TargetFramework.NetCoreApp); + comp.VerifyDiagnostics(expectedDiagnostics); + + comp = CreateCompilation(new[] { code, InterpolatedStringHandlerAttribute }, targetFramework: TargetFramework.NetCoreApp); + comp.VerifyDiagnostics(expectedDiagnostics); } [Theory] @@ -13516,12 +13557,18 @@ public static ref CustomHandler M() } "; - var comp = CreateCompilation(new[] { code, InterpolatedStringHandlerAttribute }, targetFramework: TargetFramework.NetCoreApp); - comp.VerifyDiagnostics( + var expectedDiagnostics = new[] + { // (17,20): error CS8156: An expression cannot be used in this context because it may not be passed or returned by reference // return ref $"{s}"; Diagnostic(ErrorCode.ERR_RefReturnLvalueExpected, expression).WithLocation(17, 20) - ); + }; + + var comp = CreateCompilation(new[] { code, InterpolatedStringHandlerAttribute }, parseOptions: TestOptions.Regular10, targetFramework: TargetFramework.NetCoreApp); + comp.VerifyDiagnostics(expectedDiagnostics); + + comp = CreateCompilation(new[] { code, InterpolatedStringHandlerAttribute }, targetFramework: TargetFramework.NetCoreApp); + comp.VerifyDiagnostics(expectedDiagnostics); } [Theory] @@ -13557,31 +13604,21 @@ public ref struct S1 } "; - var comp = CreateCompilation(new[] { code, InterpolatedStringHandlerAttribute, InterpolatedStringHandlerArgumentAttribute }, parseOptions: TestOptions.Regular10, targetFramework: TargetFramework.NetCoreApp); - comp.VerifyDiagnostics( + var expectedDiagnostics = new[] + { // (17,9): error CS8350: This combination of arguments to 'CustomHandler.M2(ref S1, ref CustomHandler)' is disallowed because it may expose variables referenced by parameter 'handler' outside of their declaration scope // M2(ref s1, $"{s}"); Diagnostic(ErrorCode.ERR_CallArgMixing, @"M2(ref s1, " + expression + @")").WithArguments("CustomHandler.M2(ref S1, ref CustomHandler)", "handler").WithLocation(17, 9), // (17,23): error CS8352: Cannot use variable 's' in this context because it may expose referenced variables outside of their declaration scope // M2(ref s1, $"{s}"); Diagnostic(ErrorCode.ERR_EscapeVariable, "s").WithArguments("s").WithLocation(17, 23) - ); + }; + + var comp = CreateCompilation(new[] { code, InterpolatedStringHandlerAttribute, InterpolatedStringHandlerArgumentAttribute }, parseOptions: TestOptions.Regular10, targetFramework: TargetFramework.NetCoreApp); + comp.VerifyDiagnostics(expectedDiagnostics); comp = CreateCompilation(new[] { code, InterpolatedStringHandlerAttribute, InterpolatedStringHandlerArgumentAttribute }, targetFramework: TargetFramework.NetCoreApp); - comp.VerifyDiagnostics( - // (17,9): error CS8350: This combination of arguments to 'CustomHandler.M2(ref S1, ref CustomHandler)' is disallowed because it may expose variables referenced by parameter 'handler' outside of their declaration scope - // M2(ref s1, $"{s}"); - Diagnostic(ErrorCode.ERR_CallArgMixing, @"M2(ref s1, " + expression + @")").WithArguments("CustomHandler.M2(ref S1, ref CustomHandler)", "handler").WithLocation(17, 9), - // (17,16): error CS8156: An expression cannot be used in this context because it may not be passed or returned by reference - // M2(ref s1, $"{s}"); - Diagnostic(ErrorCode.ERR_RefReturnLvalueExpected, "s1").WithLocation(17, 16), - // (17,20): error CS8347: Cannot use a result of 'CustomHandler.CustomHandler(int, int, ref S1)' in this context because it may expose variables referenced by parameter 's1' outside of their declaration scope - // M2(ref s1, $"{s}"); - Diagnostic(ErrorCode.ERR_EscapeCall, expression).WithArguments("CustomHandler.CustomHandler(int, int, ref S1)", "s1").WithLocation(17, 20), - // (17,23): error CS8352: Cannot use variable 's' in this context because it may expose referenced variables outside of their declaration scope - // M2(ref s1, $"{s}"); - Diagnostic(ErrorCode.ERR_EscapeVariable, "s").WithArguments("s").WithLocation(17, 23) - ); + comp.VerifyDiagnostics(expectedDiagnostics); } [Theory] @@ -13617,7 +13654,10 @@ public ref struct S1 } "; - var comp = CreateCompilation(new[] { code, InterpolatedStringHandlerAttribute, InterpolatedStringHandlerArgumentAttribute }, targetFramework: TargetFramework.NetCoreApp); + var comp = CreateCompilation(new[] { code, InterpolatedStringHandlerAttribute, InterpolatedStringHandlerArgumentAttribute }, parseOptions: TestOptions.Regular10, targetFramework: TargetFramework.NetCoreApp); + comp.VerifyDiagnostics(); + + comp = CreateCompilation(new[] { code, InterpolatedStringHandlerAttribute, InterpolatedStringHandlerArgumentAttribute }, targetFramework: TargetFramework.NetCoreApp); comp.VerifyDiagnostics(); } @@ -13648,7 +13688,10 @@ public CustomHandler(int literalLength, int formattedCount, Span s) : this } "; - var comp = CreateCompilation(new[] { code, InterpolatedStringHandlerAttribute, InterpolatedStringHandlerArgumentAttribute }, targetFramework: TargetFramework.NetCoreApp); + var comp = CreateCompilation(new[] { code, InterpolatedStringHandlerAttribute, InterpolatedStringHandlerArgumentAttribute }, parseOptions: TestOptions.Regular10, targetFramework: TargetFramework.NetCoreApp); + comp.VerifyDiagnostics(); + + comp = CreateCompilation(new[] { code, InterpolatedStringHandlerAttribute, InterpolatedStringHandlerArgumentAttribute }, targetFramework: TargetFramework.NetCoreApp); comp.VerifyDiagnostics(); } @@ -13679,7 +13722,10 @@ public CustomHandler(int literalLength, int formattedCount, Span s) : this } "; - var comp = CreateCompilation(new[] { code, InterpolatedStringHandlerAttribute, InterpolatedStringHandlerArgumentAttribute }, targetFramework: TargetFramework.NetCoreApp); + var comp = CreateCompilation(new[] { code, InterpolatedStringHandlerAttribute, InterpolatedStringHandlerArgumentAttribute }, parseOptions: TestOptions.Regular10, targetFramework: TargetFramework.NetCoreApp); + comp.VerifyDiagnostics(); + + comp = CreateCompilation(new[] { code, InterpolatedStringHandlerAttribute, InterpolatedStringHandlerArgumentAttribute }, targetFramework: TargetFramework.NetCoreApp); comp.VerifyDiagnostics(); } @@ -13711,16 +13757,28 @@ public static ref CustomHandler M2(ref Span s, [InterpolatedStringHandlerA } "; - var comp = CreateCompilation(new[] { code, InterpolatedStringHandlerAttribute, InterpolatedStringHandlerArgumentAttribute }, targetFramework: TargetFramework.NetCoreApp); + var comp = CreateCompilation(new[] { code, InterpolatedStringHandlerAttribute, InterpolatedStringHandlerArgumentAttribute }, parseOptions: TestOptions.Regular10, targetFramework: TargetFramework.NetCoreApp); comp.VerifyDiagnostics( // (16,16): error CS8352: Cannot use variable 'c' in this context because it may expose referenced variables outside of their declaration scope // return c; Diagnostic(ErrorCode.ERR_EscapeVariable, "c").WithArguments("c").WithLocation(16, 16) ); + + comp = CreateCompilation(new[] { code, InterpolatedStringHandlerAttribute, InterpolatedStringHandlerArgumentAttribute }, targetFramework: TargetFramework.NetCoreApp); + comp.VerifyDiagnostics( + // (16,16): error CS8352: Cannot use variable 'c' in this context because it may expose referenced variables outside of their declaration scope + // return c; + Diagnostic(ErrorCode.ERR_EscapeVariable, "c").WithArguments("c").WithLocation(16, 16), + // (21,20): error CS8166: Cannot return a parameter by reference 'handler' because it is not a ref parameter + // return ref handler; + Diagnostic(ErrorCode.ERR_RefReturnParameter, "handler").WithArguments("handler").WithLocation(21, 20) + ); } - [Fact] - public void RefEscape_09() + [Theory] + [InlineData(LanguageVersion.CSharp10)] + [InlineData(LanguageVersion.CSharp11)] + public void RefEscape_09(LanguageVersion languageVersion) { var code = @" using System; @@ -13749,36 +13807,21 @@ public ref struct S1 public CustomHandler Handler; } "; - - var comp = CreateCompilation(new[] { code, InterpolatedStringHandlerAttribute, InterpolatedStringHandlerArgumentAttribute }, parseOptions: TestOptions.Regular10, targetFramework: TargetFramework.NetCoreApp); - comp.VerifyDiagnostics( - // (15,9): error CS8350: This combination of arguments to 'CustomHandler.M2(ref S1, CustomHandler)' is disallowed because it may expose variables referenced by parameter 'handler' outside of their declaration scope - // M2(ref s1, $"{s2}"); - Diagnostic(ErrorCode.ERR_CallArgMixing, @"M2(ref s1, $""{s2}"")").WithArguments("CustomHandler.M2(ref S1, CustomHandler)", "handler").WithLocation(15, 9), - // (15,23): error CS8352: Cannot use variable 's2' in this context because it may expose referenced variables outside of their declaration scope - // M2(ref s1, $"{s2}"); - Diagnostic(ErrorCode.ERR_EscapeVariable, "s2").WithArguments("s2").WithLocation(15, 23) - ); - - comp = CreateCompilation(new[] { code, InterpolatedStringHandlerAttribute, InterpolatedStringHandlerArgumentAttribute }, targetFramework: TargetFramework.NetCoreApp); + var comp = CreateCompilation(new[] { code, InterpolatedStringHandlerAttribute, InterpolatedStringHandlerArgumentAttribute }, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion), targetFramework: TargetFramework.NetCoreApp); comp.VerifyDiagnostics( // (15,9): error CS8350: This combination of arguments to 'CustomHandler.M2(ref S1, CustomHandler)' is disallowed because it may expose variables referenced by parameter 'handler' outside of their declaration scope // M2(ref s1, $"{s2}"); Diagnostic(ErrorCode.ERR_CallArgMixing, @"M2(ref s1, $""{s2}"")").WithArguments("CustomHandler.M2(ref S1, CustomHandler)", "handler").WithLocation(15, 9), - // (15,16): error CS8156: An expression cannot be used in this context because it may not be passed or returned by reference - // M2(ref s1, $"{s2}"); - Diagnostic(ErrorCode.ERR_RefReturnLvalueExpected, "s1").WithLocation(15, 16), - // (15,20): error CS8347: Cannot use a result of 'CustomHandler.CustomHandler(int, int, ref S1)' in this context because it may expose variables referenced by parameter 's1' outside of their declaration scope - // M2(ref s1, $"{s2}"); - Diagnostic(ErrorCode.ERR_EscapeCall, @"$""{s2}""").WithArguments("CustomHandler.CustomHandler(int, int, ref S1)", "s1").WithLocation(15, 20), // (15,23): error CS8352: Cannot use variable 's2' in this context because it may expose referenced variables outside of their declaration scope // M2(ref s1, $"{s2}"); Diagnostic(ErrorCode.ERR_EscapeVariable, "s2").WithArguments("s2").WithLocation(15, 23) ); } - [Fact] - public void RefEscape_10() + [Theory] + [InlineData(LanguageVersion.CSharp10)] + [InlineData(LanguageVersion.CSharp11)] + public void RefEscape_10(LanguageVersion languageVersion) { var code = @"using System.Runtime.CompilerServices; @@ -13802,17 +13845,258 @@ static void Main() static void M(ref S s, [InterpolatedStringHandlerArgument(""s"")] CustomHandler handler) { } }"; - var comp = CreateCompilation(new[] { code, InterpolatedStringHandlerAttribute, InterpolatedStringHandlerArgumentAttribute }, parseOptions: TestOptions.Regular10, targetFramework: TargetFramework.NetCoreApp); + var comp = CreateCompilation(new[] { code, InterpolatedStringHandlerAttribute, InterpolatedStringHandlerArgumentAttribute }, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion), targetFramework: TargetFramework.NetCoreApp); comp.VerifyDiagnostics(); + } - comp = CreateCompilation(new[] { code, InterpolatedStringHandlerAttribute, InterpolatedStringHandlerArgumentAttribute }, targetFramework: TargetFramework.NetCoreApp); + [WorkItem(63262, "https://github.com/dotnet/roslyn/issues/63262")] + [Theory] + [InlineData(LanguageVersion.CSharp10)] + [InlineData(LanguageVersion.CSharp11)] + public void RefEscape_11A(LanguageVersion languageVersion) + { + var code = +@"using System; +using System.Runtime.CompilerServices; +[InterpolatedStringHandler] +ref struct CustomHandler +{ + public CustomHandler(int literalLength, int formattedCount) { } + public void AppendFormatted(Span s) { } +} +class Program +{ + static void F1() + { + Span s = stackalloc char[10]; + M($""{s}""); + } + static void F2() + { + Span s = stackalloc char[10]; + CustomHandler h2 = new CustomHandler(0, 1); + h2.AppendFormatted(s); // 1 + M(ref h2); + } + static void M(ref CustomHandler handler) { } +} +"; + var comp = CreateCompilation(new[] { code, InterpolatedStringHandlerAttribute }, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion), targetFramework: TargetFramework.NetCoreApp); comp.VerifyDiagnostics( - // (17,15): error CS8156: An expression cannot be used in this context because it may not be passed or returned by reference - // M(ref s, $"{1}"); - Diagnostic(ErrorCode.ERR_RefReturnLvalueExpected, "s").WithLocation(17, 15), - // (17,18): error CS8347: Cannot use a result of 'CustomHandler.CustomHandler(int, int, ref S)' in this context because it may expose variables referenced by parameter 's' outside of their declaration scope - // M(ref s, $"{1}"); - Diagnostic(ErrorCode.ERR_EscapeCall, @"$""{1}""").WithArguments("CustomHandler.CustomHandler(int, int, ref S)", "s").WithLocation(17, 18)); + // (20,9): error CS8350: This combination of arguments to 'CustomHandler.AppendFormatted(Span)' is disallowed because it may expose variables referenced by parameter 's' outside of their declaration scope + // h2.AppendFormatted(s); // 1 + Diagnostic(ErrorCode.ERR_CallArgMixing, "h2.AppendFormatted(s)").WithArguments("CustomHandler.AppendFormatted(System.Span)", "s").WithLocation(20, 9), + // (20,28): error CS8352: Cannot use variable 's' in this context because it may expose referenced variables outside of their declaration scope + // h2.AppendFormatted(s); // 1 + Diagnostic(ErrorCode.ERR_EscapeVariable, "s").WithArguments("s").WithLocation(20, 28)); + } + + // As above but with scoped parameter in AppendFormatted(). + [WorkItem(63262, "https://github.com/dotnet/roslyn/issues/63262")] + [Fact] + public void RefEscape_11B() + { + var code = +@"using System; +using System.Runtime.CompilerServices; +[InterpolatedStringHandler] +ref struct CustomHandler +{ + public CustomHandler(int literalLength, int formattedCount) { } + public void AppendFormatted(scoped Span s) { } +} +class Program +{ + static void F1() + { + Span s = stackalloc char[10]; + M($""{s}""); + } + static void F2() + { + Span s = stackalloc char[10]; + CustomHandler h2 = new CustomHandler(0, 1); + h2.AppendFormatted(s); + M(ref h2); + } + static void M(ref CustomHandler handler) { } +} +"; + var comp = CreateCompilation(new[] { code, InterpolatedStringHandlerAttribute }, targetFramework: TargetFramework.NetCoreApp); + comp.VerifyDiagnostics(); + } + + [WorkItem(63262, "https://github.com/dotnet/roslyn/issues/63262")] + [Theory] + [InlineData(LanguageVersion.CSharp10)] + [InlineData(LanguageVersion.CSharp11)] + public void RefEscape_12A(LanguageVersion languageVersion) + { + var code = +@"using System; +using System.Runtime.CompilerServices; +[InterpolatedStringHandler] +ref struct CustomHandler +{ + public CustomHandler(int literalLength, int formattedCount) { } + public void AppendFormatted(Span s) { } +} +class Program +{ + static CustomHandler F1() + { + Span s = stackalloc char[10]; + CustomHandler h1 = $""{s}""; + return h1; // 1 + } + static CustomHandler F2() + { + Span s = stackalloc char[10]; + CustomHandler h2 = new CustomHandler(0, 1); + h2.AppendFormatted(s); // 2 + return h2; + } +} +"; + var comp = CreateCompilation(new[] { code, InterpolatedStringHandlerAttribute }, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion), targetFramework: TargetFramework.NetCoreApp); + comp.VerifyDiagnostics( + // (15,16): error CS8352: Cannot use variable 'h1' in this context because it may expose referenced variables outside of their declaration scope + // return h1; // 1 + Diagnostic(ErrorCode.ERR_EscapeVariable, "h1").WithArguments("h1").WithLocation(15, 16), + // (21,9): error CS8350: This combination of arguments to 'CustomHandler.AppendFormatted(Span)' is disallowed because it may expose variables referenced by parameter 's' outside of their declaration scope + // h2.AppendFormatted(s); // 2 + Diagnostic(ErrorCode.ERR_CallArgMixing, "h2.AppendFormatted(s)").WithArguments("CustomHandler.AppendFormatted(System.Span)", "s").WithLocation(21, 9), + // (21,28): error CS8352: Cannot use variable 's' in this context because it may expose referenced variables outside of their declaration scope + // h2.AppendFormatted(s); // 2 + Diagnostic(ErrorCode.ERR_EscapeVariable, "s").WithArguments("s").WithLocation(21, 28)); + } + + // As above but with scoped parameter in AppendFormatted(). + [WorkItem(63262, "https://github.com/dotnet/roslyn/issues/63262")] + [Fact] + public void RefEscape_12B() + { + var code = +@"using System; +using System.Runtime.CompilerServices; +[InterpolatedStringHandler] +ref struct CustomHandler +{ + public CustomHandler(int literalLength, int formattedCount) { } + public void AppendFormatted(scoped Span s) { } +} +class Program +{ + static CustomHandler F1() + { + Span s = stackalloc char[10]; + CustomHandler h1 = $""{s}""; + return h1; + } + static CustomHandler F2() + { + Span s = stackalloc char[10]; + CustomHandler h2 = new CustomHandler(0, 1); + h2.AppendFormatted(s); + return h2; + } + static CustomHandler F3() + { + Span s = stackalloc char[10]; + scoped CustomHandler h3 = new CustomHandler(0, 1); + h3.AppendFormatted(s); + return h3; // 1 + } +} +"; + var comp = CreateCompilation(new[] { code, InterpolatedStringHandlerAttribute }, targetFramework: TargetFramework.NetCoreApp); + comp.VerifyDiagnostics( + // (29,16): error CS8352: Cannot use variable 'h3' in this context because it may expose referenced variables outside of their declaration scope + // return h3; // 1 + Diagnostic(ErrorCode.ERR_EscapeVariable, "h3").WithArguments("h3").WithLocation(29, 16)); + } + + [WorkItem(63306, "https://github.com/dotnet/roslyn/issues/63306")] + [Theory] + [InlineData(LanguageVersion.CSharp10)] + [InlineData(LanguageVersion.CSharp11)] + public void RefEscape_13A(LanguageVersion languageVersion) + { + var code = +@"using System.Runtime.CompilerServices; +[InterpolatedStringHandler] +ref struct CustomHandler +{ + public CustomHandler(int literalLength, int formattedCount) { } + public void AppendFormatted(in int i) { } +} +class Program +{ + static CustomHandler F1() + { + int i = 1; + return $""{i}""; // 1 + } + static CustomHandler F2() + { + return $""{2}""; // 2 + } + static CustomHandler F3() + { + int i = 3; + CustomHandler h3 = $""{i}""; // 3 + return h3; + } + static CustomHandler F4() + { + CustomHandler h4 = $""{4}""; // 4 + return h4; + } +} +"; + // https://github.com/dotnet/roslyn/issues/63306: Should report an error in each case. + var comp = CreateCompilation(new[] { code, InterpolatedStringHandlerAttribute }, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion), targetFramework: TargetFramework.NetCoreApp); + comp.VerifyDiagnostics(); + } + + // As above but with scoped parameter in AppendFormatted(). + [Fact] + public void RefEscape_13B() + { + var code = +@"using System.Runtime.CompilerServices; +[InterpolatedStringHandler] +ref struct CustomHandler +{ + public CustomHandler(int literalLength, int formattedCount) { } + public void AppendFormatted(scoped in int i) { } +} +class Program +{ + static CustomHandler F1() + { + int i = 1; + return $""{i}""; + } + static CustomHandler F2() + { + return $""{2}""; + } + static CustomHandler F3() + { + int i = 3; + CustomHandler h3 = $""{i}""; + return h3; + } + static CustomHandler F4() + { + CustomHandler h4 = $""{4}""; + return h4; + } +} +"; + var comp = CreateCompilation(new[] { code, InterpolatedStringHandlerAttribute }, targetFramework: TargetFramework.NetCoreApp); + comp.VerifyDiagnostics(); } [Theory, WorkItem(54703, "https://github.com/dotnet/roslyn/issues/54703")] @@ -15991,5 +16275,46 @@ string M() // return $"hello + {other}"; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion5, @"$""hello + {other}""").WithArguments("interpolated strings", "6").WithLocation(7, 16)); } + + [Fact, WorkItem(1566008, "https://devdiv.visualstudio.com/DevDiv/_workitems/edit/1566008")] + public void InterpolatedStringInForeach_HasErrors() + { + var text = """ + int i = 1; + /**/foreach (($"{i}") in new int[0]) {}/**/ + """; + + var comp = CreateCompilation(text).VerifyDiagnostics( + // (1,5): warning CS0219: The variable 'i' is assigned but its value is never used + // int i = 1; + Diagnostic(ErrorCode.WRN_UnreferencedVarAssg, "i").WithArguments("i").WithLocation(1, 5), + // (2,29): error CS0230: Type and identifier are both required in a foreach statement + // /**/foreach (($"{i}") in new int[0]) {}/**/ + Diagnostic(ErrorCode.ERR_BadForeachDecl, "in").WithLocation(2, 29) + ); + + VerifyOperationTreeForTest(comp, expectedOperationTree: """ + IForEachLoopOperation (LoopKind.ForEach, Continue Label Id: 0, Exit Label Id: 1) (OperationKind.Loop, Type: null, IsInvalid) (Syntax: 'foreach (($ ... int[0]) {}') + LoopControlVariable: + IInterpolatedStringOperation (OperationKind.InterpolatedString, Type: System.String) (Syntax: '$"{i}"') + Parts(1): + IInterpolationOperation (OperationKind.Interpolation, Type: null) (Syntax: '{i}') + Expression: + ILocalReferenceOperation: i (OperationKind.LocalReference, Type: System.Int32) (Syntax: 'i') + Alignment: + null + FormatString: + null + Collection: + IArrayCreationOperation (OperationKind.ArrayCreation, Type: System.Int32[]) (Syntax: 'new int[0]') + Dimension Sizes(1): + ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 0) (Syntax: '0') + Initializer: + null + Body: + IBlockOperation (0 statements) (OperationKind.Block, Type: null) (Syntax: '{}') + NextVariables(0) + """); + } } } diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/LambdaTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/LambdaTests.cs index 3d2966a9aacc0..8d107c0a61c3a 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/LambdaTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/LambdaTests.cs @@ -6782,5 +6782,117 @@ static void Main() Assert.Equal(RefKind.In, lambdas[1].Parameters[0].RefKind); Assert.Equal(RefKind.Out, lambdas[2].Parameters[0].RefKind); } + + [Fact] + public void StaticPartialLambda() + { + CreateCompilation(""" + class C + { + void M() + { + System.Action x = static partial () => { }; + } + } + """).VerifyDiagnostics( + // (5,27): error CS8934: Cannot convert lambda expression to type 'Action' because the return type does not match the delegate return type + // System.Action x = static partial () => { }; + Diagnostic(ErrorCode.ERR_CantConvAnonMethReturnType, "static partial () => { }").WithArguments("lambda expression", "System.Action").WithLocation(5, 27), + // (5,34): error CS0246: The type or namespace name 'partial' could not be found (are you missing a using directive or an assembly reference?) + // System.Action x = static partial () => { }; + Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "partial").WithArguments("partial").WithLocation(5, 34)); + } + + [Fact] + public void PartialStaticLambda() + { + CreateCompilation(""" + class C + { + void M() + { + System.Action x = partial static () => { }; + } + } + """).VerifyDiagnostics( + // (5,27): error CS0103: The name 'partial' does not exist in the current context + // System.Action x = partial static () => { }; + Diagnostic(ErrorCode.ERR_NameNotInContext, "partial").WithArguments("partial").WithLocation(5, 27), + // (5,35): error CS1002: ; expected + // System.Action x = partial static () => { }; + Diagnostic(ErrorCode.ERR_SemicolonExpected, "static").WithLocation(5, 35), + // (5,35): error CS0106: The modifier 'static' is not valid for this item + // System.Action x = partial static () => { }; + Diagnostic(ErrorCode.ERR_BadMemberFlag, "static").WithArguments("static").WithLocation(5, 35), + // (5,43): error CS8124: Tuple must contain at least two elements. + // System.Action x = partial static () => { }; + Diagnostic(ErrorCode.ERR_TupleTooFewElements, ")").WithLocation(5, 43), + // (5,45): error CS1001: Identifier expected + // System.Action x = partial static () => { }; + Diagnostic(ErrorCode.ERR_IdentifierExpected, "=>").WithLocation(5, 45), + // (5,45): error CS1003: Syntax error, ',' expected + // System.Action x = partial static () => { }; + Diagnostic(ErrorCode.ERR_SyntaxError, "=>").WithArguments(",").WithLocation(5, 45), + // (5,48): error CS1002: ; expected + // System.Action x = partial static () => { }; + Diagnostic(ErrorCode.ERR_SemicolonExpected, "{").WithLocation(5, 48)); + } + + [Fact] + public void PartialLambda() + { + CreateCompilation(""" + class C + { + void M() + { + System.Action x = partial () => { }; + } + } + """).VerifyDiagnostics( + // (5,27): error CS0246: The type or namespace name 'partial' could not be found (are you missing a using directive or an assembly reference?) + // System.Action x = partial () => { }; + Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "partial").WithArguments("partial").WithLocation(5, 27), + // (5,27): error CS8934: Cannot convert lambda expression to type 'Action' because the return type does not match the delegate return type + // System.Action x = partial () => { }; + Diagnostic(ErrorCode.ERR_CantConvAnonMethReturnType, "partial () => { }").WithArguments("lambda expression", "System.Action").WithLocation(5, 27)); + } + + [WorkItem(61013, "https://github.com/dotnet/roslyn/issues/61013")] + [Fact] + public void InvalidCast() + { + var source = """ + using System; + #nullable enable + internal class Program + { + void Main(string[] args) + { + Choice(args.Length > 0 + ? (Action)(() => DS1() + : () => DS2(args[0])); + } + + void DS1() + { } + + void DS2(string a) + { } + + void Choice(Action a) + { + a(); + } + } + """; + + var comp = CreateCompilation(source, parseOptions: TestOptions.Regular8); + + var syntaxTree = comp.SyntaxTrees[0]; + var action = syntaxTree.GetRoot().DescendantNodes().OfType().First(id => id.Identifier.ValueText == "Action"); + var model = comp.GetSemanticModel(syntaxTree); + AssertEx.Equal("System.Action", model.GetTypeInfo(action).Type.ToTestDisplayString()); + } } } diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/LocalFunctionTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/LocalFunctionTests.cs index df87ce161d64c..42ce8f871f1f9 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/LocalFunctionTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/LocalFunctionTests.cs @@ -7119,8 +7119,8 @@ async static void B4() { } Diagnostic(ErrorCode.WRN_LowerCaseTypeName, "await").WithArguments("await").WithLocation(23, 30)); } - [Fact, WorkItem(59775, "https://github.com/dotnet/roslyn/issues/59775")] - public void TypeParameterScope_InMethodAttributeNameOf() + [Theory, CombinatorialData, WorkItem(59775, "https://github.com/dotnet/roslyn/issues/59775")] + public void TypeParameterScope_InMethodAttributeNameOf(bool useCSharp10) { var source = @" class C @@ -7142,28 +7142,15 @@ public class MyAttribute : System.Attribute public MyAttribute(string name1) { } } "; - var comp = CreateCompilation(source, parseOptions: TestOptions.Regular10); - comp.VerifyDiagnostics( - // (8,20): error CS0103: The name 'TParameter' does not exist in the current context - // [My(nameof(TParameter))] // 1 - Diagnostic(ErrorCode.ERR_NameNotInContext, "TParameter").WithArguments("TParameter").WithLocation(8, 20), - // (12,16): error CS0103: The name 'TParameter' does not exist in the current context - // [My(nameof(TParameter))] // 2 - Diagnostic(ErrorCode.ERR_NameNotInContext, "TParameter").WithArguments("TParameter").WithLocation(12, 16) - ); - - VerifyTParameter(comp, 0, null); - VerifyTParameter(comp, 1, null); - - comp = CreateCompilation(source, parseOptions: TestOptions.RegularNext); + var comp = CreateCompilation(source, parseOptions: useCSharp10 ? TestOptions.Regular10 : TestOptions.Regular11); comp.VerifyDiagnostics(); VerifyTParameter(comp, 0, "void local()"); VerifyTParameter(comp, 1, "void C.M2()"); } - [Fact, WorkItem(59775, "https://github.com/dotnet/roslyn/issues/59775")] - public void TypeParameterScope_InMethodAttributeNameOfNameOf() + [Theory, CombinatorialData, WorkItem(59775, "https://github.com/dotnet/roslyn/issues/59775")] + public void TypeParameterScope_InMethodAttributeNameOfNameOf(bool useCSharp10) { var source = @" class C @@ -7185,20 +7172,7 @@ public class MyAttribute : System.Attribute public MyAttribute(string name1) { } } "; - var comp = CreateCompilation(source, parseOptions: TestOptions.Regular10); - comp.VerifyDiagnostics( - // (8,27): error CS0103: The name 'TParameter' does not exist in the current context - // [My(nameof(nameof(TParameter)))] // 1 - Diagnostic(ErrorCode.ERR_NameNotInContext, "TParameter").WithArguments("TParameter").WithLocation(8, 27), - // (12,23): error CS0103: The name 'TParameter' does not exist in the current context - // [My(nameof(nameof(TParameter)))] // 2 - Diagnostic(ErrorCode.ERR_NameNotInContext, "TParameter").WithArguments("TParameter").WithLocation(12, 23) - ); - - VerifyTParameter(comp, 0, null); - VerifyTParameter(comp, 1, null); - - comp = CreateCompilation(source, parseOptions: TestOptions.RegularNext); + var comp = CreateCompilation(source, parseOptions: useCSharp10 ? TestOptions.Regular10 : TestOptions.Regular11); comp.VerifyDiagnostics( // (8,20): error CS8081: Expression does not have a name. // [My(nameof(nameof(TParameter)))] // 1 @@ -7212,8 +7186,8 @@ public MyAttribute(string name1) { } VerifyTParameter(comp, 1, "void C.M2()"); } - [Fact, WorkItem(59775, "https://github.com/dotnet/roslyn/issues/59775")] - public void TypeParameterScope_InMethodAttributeNameOf_TopLevel() + [Theory, CombinatorialData, WorkItem(59775, "https://github.com/dotnet/roslyn/issues/59775")] + public void TypeParameterScope_InMethodAttributeNameOf_TopLevel(bool useCSharp10) { var source = @" local(); @@ -7226,23 +7200,14 @@ public class MyAttribute : System.Attribute public MyAttribute(string name1) { } } "; - var comp = CreateCompilation(source, parseOptions: TestOptions.Regular10); - comp.VerifyDiagnostics( - // (4,12): error CS0103: The name 'TParameter' does not exist in the current context - // [My(nameof(TParameter))] // 1 - Diagnostic(ErrorCode.ERR_NameNotInContext, "TParameter").WithArguments("TParameter").WithLocation(4, 12) - ); - - VerifyTParameter(comp, 0, null); - - comp = CreateCompilation(source, parseOptions: TestOptions.RegularNext); + var comp = CreateCompilation(source, parseOptions: useCSharp10 ? TestOptions.Regular10 : TestOptions.Regular11); comp.VerifyDiagnostics(); VerifyTParameter(comp, 0, "void local()"); } - [Fact] - public void TypeParameterScope_InMethodAttributeNameOf_SpeculatingWithNewAttribute() + [Theory, CombinatorialData] + public void TypeParameterScope_InMethodAttributeNameOf_SpeculatingWithNewAttribute(bool useCSharp10) { var source = @" class C @@ -7264,35 +7229,20 @@ public class MyAttribute : System.Attribute public MyAttribute(string name1) { } } "; - // C# 10 - var comp = CreateCompilation(source, parseOptions: TestOptions.Regular10); + var parseOptions = useCSharp10 ? TestOptions.Regular10 : TestOptions.Regular11; + var comp = CreateCompilation(source, parseOptions: parseOptions); comp.VerifyDiagnostics(); - var tree = comp.SyntaxTrees.Single(); - var parentModel = comp.GetSemanticModel(tree); // Note: offset by one to the left to get away from return type var localFuncPosition = tree.GetText().ToString().IndexOf("void local()", StringComparison.Ordinal) - 1; var methodPosition = tree.GetText().ToString().IndexOf("void M2()", StringComparison.Ordinal) - 1; + var parentModel = comp.GetSemanticModel(tree); - var attr = parseAttributeSyntax("[My(nameof(TParameter))]", TestOptions.Regular10); - VerifyTParameterSpeculation(parentModel, localFuncPosition, attr, found: false); - VerifyTParameterSpeculation(parentModel, methodPosition, attr, found: false); - - attr = parseAttributeSyntax("[My(TParameter)]", TestOptions.Regular10); - VerifyTParameterSpeculation(parentModel, localFuncPosition, attr, found: false); - VerifyTParameterSpeculation(parentModel, methodPosition, attr, found: false); - - // C# 11 - comp = CreateCompilation(source, parseOptions: TestOptions.RegularNext); - comp.VerifyDiagnostics(); - tree = comp.SyntaxTrees.Single(); - parentModel = comp.GetSemanticModel(tree); - - attr = parseAttributeSyntax("[My(nameof(TParameter))]", TestOptions.RegularNext); + var attr = parseAttributeSyntax("[My(nameof(TParameter))]", parseOptions); VerifyTParameterSpeculation(parentModel, localFuncPosition, attr, found: false); VerifyTParameterSpeculation(parentModel, methodPosition, attr, found: false); - attr = parseAttributeSyntax("[My(TParameter)]", TestOptions.RegularNext); + attr = parseAttributeSyntax("[My(TParameter)]", parseOptions); VerifyTParameterSpeculation(parentModel, localFuncPosition, attr, found: false); VerifyTParameterSpeculation(parentModel, methodPosition, attr, found: false); @@ -7327,8 +7277,8 @@ static IdentifierNameSyntax getTParameter(CSharpSyntaxNode node) } } - [Fact] - public void TypeParameterScope_InMethodAttributeNameOf_SpeculatingWithinAttribute() + [Theory, CombinatorialData] + public void TypeParameterScope_InMethodAttributeNameOf_SpeculatingWithinAttribute(bool useCSharp10) { var source = @" class C @@ -7352,8 +7302,9 @@ public class MyAttribute : System.Attribute public MyAttribute(string name1) { } } "; - // C# 10 - var comp = CreateCompilation(source, parseOptions: TestOptions.Regular10); + + var parseOptions = useCSharp10 ? TestOptions.Regular10 : TestOptions.Regular11; + var comp = CreateCompilation(source, parseOptions: parseOptions); comp.VerifyDiagnostics( // (8,13): error CS0103: The name 'a' does not exist in the current context // [My(a)] @@ -7373,51 +7324,17 @@ public MyAttribute(string name1) { } var parentModel = comp.GetSemanticModel(tree); var aPosition = getIdentifierPosition("a"); - var newNameOf = parseNameof("nameof(TParameter)", parseOptions: TestOptions.Regular10); + var newNameOf = parseNameof("nameof(TParameter)", parseOptions: parseOptions); Assert.Equal("System.String", parentModel.GetSpeculativeTypeInfo(aPosition, newNameOf, SpeculativeBindingOption.BindAsExpression).Type.ToTestDisplayString()); var bPosition = getIdentifierPosition("b"); - var newNameOfArgument = parseIdentifier("TParameter", parseOptions: TestOptions.Regular10); - Assert.True(parentModel.GetSpeculativeTypeInfo(bPosition, newNameOfArgument, SpeculativeBindingOption.BindAsExpression).Type.IsErrorType()); + var newNameOfArgument = parseIdentifier("TParameter", parseOptions: parseOptions); + Assert.Equal("TParameter", parentModel.GetSpeculativeTypeInfo(bPosition, newNameOfArgument, SpeculativeBindingOption.BindAsExpression).Type.ToTestDisplayString()); var cPosition = getIdentifierPosition("c"); Assert.Equal("System.String", parentModel.GetSpeculativeTypeInfo(cPosition, newNameOf, SpeculativeBindingOption.BindAsExpression).Type.ToTestDisplayString()); var dPosition = getIdentifierPosition("d"); - Assert.True(parentModel.GetSpeculativeTypeInfo(dPosition, newNameOfArgument, SpeculativeBindingOption.BindAsExpression).Type.IsErrorType()); - - // C# 11 - comp = CreateCompilation(source, parseOptions: TestOptions.RegularNext); - comp.VerifyDiagnostics( - // (8,13): error CS0103: The name 'a' does not exist in the current context - // [My(a)] - Diagnostic(ErrorCode.ERR_NameNotInContext, "a").WithArguments("a").WithLocation(8, 13), - // (9,20): error CS0103: The name 'b' does not exist in the current context - // [My(nameof(b))] - Diagnostic(ErrorCode.ERR_NameNotInContext, "b").WithArguments("b").WithLocation(9, 20), - // (13,9): error CS0103: The name 'c' does not exist in the current context - // [My(c)] - Diagnostic(ErrorCode.ERR_NameNotInContext, "c").WithArguments("c").WithLocation(13, 9), - // (14,16): error CS0103: The name 'd' does not exist in the current context - // [My(nameof(d))] - Diagnostic(ErrorCode.ERR_NameNotInContext, "d").WithArguments("d").WithLocation(14, 16) - ); - - tree = comp.SyntaxTrees.Single(); - parentModel = comp.GetSemanticModel(tree); - - aPosition = getIdentifierPosition("a"); - newNameOf = parseNameof("nameof(TParameter)", parseOptions: TestOptions.RegularNext); - Assert.Equal("System.String", parentModel.GetSpeculativeTypeInfo(aPosition, newNameOf, SpeculativeBindingOption.BindAsExpression).Type.ToTestDisplayString()); - - bPosition = getIdentifierPosition("b"); - newNameOfArgument = parseIdentifier("TParameter", parseOptions: TestOptions.RegularNext); - Assert.Equal("TParameter", parentModel.GetSpeculativeTypeInfo(bPosition, newNameOfArgument, SpeculativeBindingOption.BindAsExpression).Type.ToTestDisplayString()); - - cPosition = getIdentifierPosition("c"); - Assert.Equal("System.String", parentModel.GetSpeculativeTypeInfo(cPosition, newNameOf, SpeculativeBindingOption.BindAsExpression).Type.ToTestDisplayString()); - - dPosition = getIdentifierPosition("d"); Assert.Equal("TParameter", parentModel.GetSpeculativeTypeInfo(dPosition, newNameOfArgument, SpeculativeBindingOption.BindAsExpression).Type.ToTestDisplayString()); return; @@ -7482,7 +7399,7 @@ public MyAttribute(string name1) { } VerifyTParameterSpeculation(parentModel, methodPosition, attr, found: false); // C# 11 - comp = CreateCompilation(source, parseOptions: TestOptions.RegularNext); + comp = CreateCompilation(source, parseOptions: TestOptions.Regular11); comp.VerifyDiagnostics( // (8,13): error CS0103: The name 'a' does not exist in the current context // [My(a)] @@ -7508,8 +7425,8 @@ static AttributeSyntax parseAttributeSyntax(string source, CSharpParseOptions pa => SyntaxFactory.ParseCompilationUnit($@"class X {{ {source} void M() {{ }} }}", options: parseOptions).DescendantNodes().OfType().Single(); } - [Fact] - public void TypeParameterScope_InMethodAttributeNameOf_SpeculatingWithReplacementAttributeInsideExisting() + [Theory, CombinatorialData] + public void TypeParameterScope_InMethodAttributeNameOf_SpeculatingWithReplacementAttributeInsideExisting(bool useCSharp10) { var source = @" class C @@ -7531,8 +7448,8 @@ public class MyAttribute : System.Attribute public MyAttribute(string name1) { } } "; - // C# 10 - var comp = CreateCompilation(source, parseOptions: TestOptions.Regular10); + var parseOptions = useCSharp10 ? TestOptions.Regular10 : TestOptions.Regular11; + var comp = CreateCompilation(source, parseOptions: parseOptions); comp.VerifyDiagnostics( // (8,13): error CS0103: The name 'positionA' does not exist in the current context // [My(positionA)] @@ -7547,33 +7464,11 @@ public MyAttribute(string name1) { } var localFuncPosition = tree.GetText().ToString().IndexOf("positionA", StringComparison.Ordinal); var methodPosition = tree.GetText().ToString().IndexOf("positionB", StringComparison.Ordinal); - var attr = parseAttributeSyntax("[My(nameof(TParameter))]", TestOptions.Regular10); - VerifyTParameterSpeculation(parentModel, localFuncPosition, attr, found: false); - VerifyTParameterSpeculation(parentModel, methodPosition, attr, found: false); - - attr = parseAttributeSyntax("[My(TParameter)]", TestOptions.Regular10); - VerifyTParameterSpeculation(parentModel, localFuncPosition, attr, found: false); - VerifyTParameterSpeculation(parentModel, methodPosition, attr, found: false); - - // C# 11 - comp = CreateCompilation(source, parseOptions: TestOptions.RegularNext); - comp.VerifyDiagnostics( - // (8,13): error CS0103: The name 'positionA' does not exist in the current context - // [My(positionA)] - Diagnostic(ErrorCode.ERR_NameNotInContext, "positionA").WithArguments("positionA").WithLocation(8, 13), - // (12,9): error CS0103: The name 'positionB' does not exist in the current context - // [My(positionB)] - Diagnostic(ErrorCode.ERR_NameNotInContext, "positionB").WithArguments("positionB").WithLocation(12, 9) - ); - - tree = comp.SyntaxTrees.Single(); - parentModel = comp.GetSemanticModel(tree); - - attr = parseAttributeSyntax("[My(nameof(TParameter))]", TestOptions.Regular10); + var attr = parseAttributeSyntax("[My(nameof(TParameter))]", parseOptions); VerifyTParameterSpeculation(parentModel, localFuncPosition, attr); VerifyTParameterSpeculation(parentModel, methodPosition, attr); - attr = parseAttributeSyntax("[My(TParameter)]", TestOptions.Regular10); + attr = parseAttributeSyntax("[My(TParameter)]", parseOptions); VerifyTParameterSpeculation(parentModel, localFuncPosition, attr, found: false); VerifyTParameterSpeculation(parentModel, methodPosition, attr, found: false); @@ -7583,9 +7478,9 @@ static AttributeSyntax parseAttributeSyntax(string source, CSharpParseOptions pa => SyntaxFactory.ParseCompilationUnit($@"class X {{ {source} void M() {{ }} }}", options: parseOptions).DescendantNodes().OfType().Single(); } - [Fact, WorkItem(59775, "https://github.com/dotnet/roslyn/issues/59775")] + [Theory, CombinatorialData, WorkItem(59775, "https://github.com/dotnet/roslyn/issues/59775")] [WorkItem(60194, "https://github.com/dotnet/roslyn/issues/60194")] - public void TypeParameterScope_InMethodAttributeNameOf_CompatBreak() + public void TypeParameterScope_InMethodAttributeNameOf_CompatBreak(bool useCSharp10) { var source = @" class C @@ -7612,16 +7507,8 @@ public class MyAttribute : System.Attribute public MyAttribute(string name1) { } } "; - // The break will also apply to C# 10 and earlier when .NET 7 ships, - // but is currently scoped down to users of LangVer=preview. - // Tracked by https://github.com/dotnet/roslyn/issues/60640 - var comp = CreateCompilation(source, parseOptions: TestOptions.Regular10); - comp.VerifyDiagnostics(); - - VerifyTParameter(comp, 0, "C", symbolKind: SymbolKind.NamedType, lookupFinds: "C.TParameter"); - VerifyTParameter(comp, 1, "C", symbolKind: SymbolKind.NamedType, lookupFinds: "C.TParameter"); - comp = CreateCompilation(source, parseOptions: TestOptions.RegularNext); + var comp = CreateCompilation(source, parseOptions: useCSharp10 ? TestOptions.Regular10 : TestOptions.Regular11); comp.VerifyDiagnostics( // (13,20): error CS0704: Cannot do non-virtual member lookup in 'TParameter' because it is a type parameter // [My(nameof(TParameter.Constant))] // 1 @@ -8519,7 +8406,7 @@ public MyAttribute(string name1) { } comp.VerifyDiagnostics(); VerifyTParameter(comp, 0, "R"); - comp = CreateCompilation(source, parseOptions: TestOptions.RegularNext); + comp = CreateCompilation(source, parseOptions: TestOptions.Regular11); comp.VerifyDiagnostics(); VerifyTParameter(comp, 0, "R"); } @@ -8539,7 +8426,7 @@ public MyAttribute(string name1) { } comp.VerifyDiagnostics(); VerifyTParameter(comp, 0, "R"); - comp = CreateCompilation(new[] { source, IsExternalInitTypeDefinition }, parseOptions: TestOptions.RegularNext); + comp = CreateCompilation(new[] { source, IsExternalInitTypeDefinition }, parseOptions: TestOptions.Regular11); comp.VerifyDiagnostics(); VerifyTParameter(comp, 0, "R"); } @@ -8650,8 +8537,8 @@ public interface I VerifyTParameter(comp, 0, "R"); } - [Fact] - public void ParameterScope_InMethodAttributeNameOf() + [Theory, CombinatorialData] + public void ParameterScope_InMethodAttributeNameOf(bool useCSharp10) { var source = @" class C @@ -8673,20 +8560,7 @@ public class MyAttribute : System.Attribute public MyAttribute(string name1) { } } "; - var comp = CreateCompilation(source, parseOptions: TestOptions.Regular10); - comp.VerifyDiagnostics( - // (8,20): error CS0103: The name 'parameter' does not exist in the current context - // [My(nameof(parameter))] // 1 - Diagnostic(ErrorCode.ERR_NameNotInContext, "parameter").WithArguments("parameter").WithLocation(8, 20), - // (12,16): error CS0103: The name 'parameter' does not exist in the current context - // [My(nameof(parameter))] // 2 - Diagnostic(ErrorCode.ERR_NameNotInContext, "parameter").WithArguments("parameter").WithLocation(12, 16) - ); - - VerifyParameter(comp, 0, null); - VerifyParameter(comp, 1, null); - - comp = CreateCompilation(source, parseOptions: TestOptions.RegularNext); + var comp = CreateCompilation(source, parseOptions: useCSharp10 ? TestOptions.Regular10 : TestOptions.Regular11); comp.VerifyDiagnostics(); VerifyParameter(comp, 0, "void local(System.Int32 parameter)"); @@ -8743,7 +8617,7 @@ public MyAttribute(string name1) { } } "; - var comp = CreateCompilation(source, parseOptions: TestOptions.RegularNext); + var comp = CreateCompilation(source, parseOptions: TestOptions.Regular11); comp.VerifyDiagnostics( // (7,14): warning CS8321: The local function 'local' is declared but never used // void local(int parameter) { } @@ -8782,7 +8656,7 @@ public MyAttribute(string name1) { } } "; - var comp = CreateCompilation(source, parseOptions: TestOptions.RegularNext); + var comp = CreateCompilation(source, parseOptions: TestOptions.Regular11); comp.VerifyDiagnostics( // (6,13): error CS0103: The name 'nameof' does not exist in the current context // [My(nameof())] @@ -8800,8 +8674,8 @@ public MyAttribute(string name1) { } Assert.False(model.LookupSymbols(nameofExpression.ArgumentList.CloseParenToken.SpanStart).ToTestDisplayStrings().Contains("parameter")); } - [Fact] - public void ParameterScope_InMethodAttributeNameOf_ConflictingNames() + [Theory, CombinatorialData] + public void ParameterScope_InMethodAttributeNameOf_ConflictingNames(bool useCSharp10) { var source = @" class C @@ -8823,26 +8697,7 @@ public class MyAttribute : System.Attribute public MyAttribute(string name1) { } } "; - var comp = CreateCompilation(source, parseOptions: TestOptions.Regular10); - comp.VerifyDiagnostics( - // (8,20): error CS0103: The name 'parameter' does not exist in the current context - // [My(nameof(parameter))] - Diagnostic(ErrorCode.ERR_NameNotInContext, "parameter").WithArguments("parameter").WithLocation(8, 20), - // (9,36): error CS0412: 'parameter': a parameter, local variable, or local function cannot have the same name as a method type parameter - // void local<@parameter>(int parameter) => throw null; - Diagnostic(ErrorCode.ERR_LocalSameNameAsTypeParam, "parameter").WithArguments("parameter").WithLocation(9, 36), - // (12,16): error CS0103: The name 'parameter' does not exist in the current context - // [My(nameof(parameter))] - Diagnostic(ErrorCode.ERR_NameNotInContext, "parameter").WithArguments("parameter").WithLocation(12, 16), - // (13,29): error CS0412: 'parameter': a parameter, local variable, or local function cannot have the same name as a method type parameter - // void M2<@parameter>(int parameter) => throw null; - Diagnostic(ErrorCode.ERR_LocalSameNameAsTypeParam, "parameter").WithArguments("parameter").WithLocation(13, 29) - ); - - VerifyParameter(comp, 0, null); - VerifyParameter(comp, 1, null); - - comp = CreateCompilation(source, parseOptions: TestOptions.RegularNext); + var comp = CreateCompilation(source, parseOptions: useCSharp10 ? TestOptions.Regular10 : TestOptions.Regular11); comp.VerifyDiagnostics( // (9,36): error CS0412: 'parameter': a parameter, local variable, or local function cannot have the same name as a method type parameter // void local<@parameter>(int parameter) => throw null; @@ -8856,8 +8711,8 @@ public MyAttribute(string name1) { } VerifyParameter(comp, 1, "void C.M2(System.Int32 parameter)"); } - [Fact] - public void ParameterScope_InMethodAttributeNameOf_CompatBreak() + [Theory, CombinatorialData] + public void ParameterScope_InMethodAttributeNameOf_CompatBreak(bool useCSharp10) { var source = @" class C @@ -8884,13 +8739,7 @@ public class MyAttribute : System.Attribute public MyAttribute(string name1) { } } "; - // The break will also apply to C# 10 and earlier when .NET 7 ships, - // but is currently scoped down to users of LangVer=preview. - // Tracked by https://github.com/dotnet/roslyn/issues/60640 - var comp = CreateCompilation(source, parseOptions: TestOptions.Regular10); - comp.VerifyDiagnostics(); - - comp = CreateCompilation(source, parseOptions: TestOptions.RegularNext); + var comp = CreateCompilation(source, parseOptions: useCSharp10 ? TestOptions.Regular10 : TestOptions.Regular11); comp.VerifyDiagnostics( // (13,30): error CS1061: 'int' does not contain a definition for 'Constant' and no accessible extension method 'Constant' accepting a first argument of type 'int' could be found (are you missing a using directive or an assembly reference?) // [My(nameof(parameter.Constant))] // 1 @@ -8901,8 +8750,8 @@ public MyAttribute(string name1) { } ); } - [Fact] - public void ParameterScope_InMethodAttributeNameOf_WithReturnTarget() + [Theory, CombinatorialData] + public void ParameterScope_InMethodAttributeNameOf_WithReturnTarget(bool useCSharp10) { var source = @" class C @@ -8924,28 +8773,15 @@ public class MyAttribute : System.Attribute public MyAttribute(string name1) { } } "; - var comp = CreateCompilation(source, parseOptions: TestOptions.Regular10); - comp.VerifyDiagnostics( - // (8,28): error CS0103: The name 'parameter' does not exist in the current context - // [return: My(nameof(parameter))] // 1 - Diagnostic(ErrorCode.ERR_NameNotInContext, "parameter").WithArguments("parameter").WithLocation(8, 28), - // (12,24): error CS0103: The name 'parameter' does not exist in the current context - // [return: My(nameof(parameter))] // 2 - Diagnostic(ErrorCode.ERR_NameNotInContext, "parameter").WithArguments("parameter").WithLocation(12, 24) - ); - - VerifyParameter(comp, 0, null); - VerifyParameter(comp, 1, null); - - comp = CreateCompilation(source, parseOptions: TestOptions.RegularNext); + var comp = CreateCompilation(source, parseOptions: useCSharp10 ? TestOptions.Regular10 : TestOptions.Regular11); comp.VerifyDiagnostics(); VerifyParameter(comp, 0, "void local(System.Int32 parameter)"); VerifyParameter(comp, 1, "void C.M2(System.Int32 parameter)"); } - [Fact] - public void ParameterScope_InMethodAttributeNameOf_SpeculatingWithReplacementAttributeInsideExisting() + [Theory, CombinatorialData] + public void ParameterScope_InMethodAttributeNameOf_SpeculatingWithReplacementAttributeInsideExisting(bool useCSharp10) { var source = @" class C @@ -8967,8 +8803,8 @@ public class MyAttribute : System.Attribute public MyAttribute(string name1) { } } "; - // C# 10 - var comp = CreateCompilation(source, parseOptions: TestOptions.Regular10); + var parseOptions = useCSharp10 ? TestOptions.Regular10 : TestOptions.Regular11; + var comp = CreateCompilation(source, parseOptions: parseOptions); comp.VerifyDiagnostics( // (8,13): error CS0103: The name 'positionA' does not exist in the current context // [My(positionA)] @@ -8983,33 +8819,11 @@ public MyAttribute(string name1) { } var localFuncPosition = tree.GetText().ToString().IndexOf("positionA", StringComparison.Ordinal); var methodPosition = tree.GetText().ToString().IndexOf("positionB", StringComparison.Ordinal); - var attr = parseAttributeSyntax("[My(nameof(parameter))]", TestOptions.Regular10); - VerifyParameterSpeculation(parentModel, localFuncPosition, attr, found: false); - VerifyParameterSpeculation(parentModel, methodPosition, attr, found: false); - - attr = parseAttributeSyntax("[My(parameter)]", TestOptions.Regular10); - VerifyParameterSpeculation(parentModel, localFuncPosition, attr, found: false); - VerifyParameterSpeculation(parentModel, methodPosition, attr, found: false); - - // C# 11 - comp = CreateCompilation(source, parseOptions: TestOptions.RegularNext); - comp.VerifyDiagnostics( - // (8,13): error CS0103: The name 'positionA' does not exist in the current context - // [My(positionA)] - Diagnostic(ErrorCode.ERR_NameNotInContext, "positionA").WithArguments("positionA").WithLocation(8, 13), - // (12,9): error CS0103: The name 'positionB' does not exist in the current context - // [My(positionB)] - Diagnostic(ErrorCode.ERR_NameNotInContext, "positionB").WithArguments("positionB").WithLocation(12, 9) - ); - - tree = comp.SyntaxTrees.Single(); - parentModel = comp.GetSemanticModel(tree); - - attr = parseAttributeSyntax("[My(nameof(parameter))]", TestOptions.Regular10); + var attr = parseAttributeSyntax("[My(nameof(parameter))]", parseOptions); VerifyParameterSpeculation(parentModel, localFuncPosition, attr); VerifyParameterSpeculation(parentModel, methodPosition, attr); - attr = parseAttributeSyntax("[My(parameter)]", TestOptions.Regular10); + attr = parseAttributeSyntax("[My(parameter)]", parseOptions); VerifyParameterSpeculation(parentModel, localFuncPosition, attr, found: false); VerifyParameterSpeculation(parentModel, methodPosition, attr, found: false); @@ -9043,8 +8857,8 @@ static IdentifierNameSyntax getParameter(CSharpSyntaxNode node) } } - [Fact] - public void ParameterScope_InIndexerAttributeNameOf() + [Theory, CombinatorialData] + public void ParameterScope_InIndexerAttributeNameOf(bool useCSharp10) { var source = @" class C @@ -9058,23 +8872,14 @@ public class MyAttribute : System.Attribute public MyAttribute(string name1) { } } "; - var comp = CreateCompilation(source, parseOptions: TestOptions.Regular10); - comp.VerifyDiagnostics( - // (4,16): error CS0103: The name 'parameter' does not exist in the current context - // [My(nameof(parameter))] - Diagnostic(ErrorCode.ERR_NameNotInContext, "parameter").WithArguments("parameter").WithLocation(4, 16) - ); - - VerifyParameter(comp, 0, null); - - comp = CreateCompilation(source, parseOptions: TestOptions.RegularNext); + var comp = CreateCompilation(source, parseOptions: useCSharp10 ? TestOptions.Regular10 : TestOptions.Regular11); comp.VerifyDiagnostics(); VerifyParameter(comp, 0, "System.Int32 C.this[System.Int32 parameter] { get; }"); } - [Fact] - public void ParameterScope_InIndexerAttributeNameOf_SetterOnly() + [Theory, CombinatorialData] + public void ParameterScope_InIndexerAttributeNameOf_SetterOnly(bool useCSharp10) { var source = @" class C @@ -9088,23 +8893,14 @@ public class MyAttribute : System.Attribute public MyAttribute(string name1) { } } "; - var comp = CreateCompilation(source, parseOptions: TestOptions.Regular10); - comp.VerifyDiagnostics( - // (4,16): error CS0103: The name 'parameter' does not exist in the current context - // [My(nameof(parameter))] - Diagnostic(ErrorCode.ERR_NameNotInContext, "parameter").WithArguments("parameter").WithLocation(4, 16) - ); - - VerifyParameter(comp, 0, null); - - comp = CreateCompilation(source, parseOptions: TestOptions.RegularNext); + var comp = CreateCompilation(source, parseOptions: useCSharp10 ? TestOptions.Regular10 : TestOptions.Regular11); comp.VerifyDiagnostics(); VerifyParameter(comp, 0, "System.Int32 C.this[System.Int32 parameter] { set; }"); } - [Fact] - public void ParameterScope_InIndexerGetterAttributeNameOf() + [Theory, CombinatorialData] + public void ParameterScope_InIndexerGetterAttributeNameOf(bool useCSharp10) { var source = @" class C @@ -9121,23 +8917,14 @@ public class MyAttribute : System.Attribute public MyAttribute(string name1) { } } "; - var comp = CreateCompilation(source, parseOptions: TestOptions.Regular10); - comp.VerifyDiagnostics( - // (6,20): error CS0103: The name 'parameter' does not exist in the current context - // [My(nameof(parameter))] - Diagnostic(ErrorCode.ERR_NameNotInContext, "parameter").WithArguments("parameter").WithLocation(6, 20) - ); - - VerifyParameter(comp, 0, null); - - comp = CreateCompilation(source); + var comp = CreateCompilation(source, parseOptions: useCSharp10 ? TestOptions.Regular10 : TestOptions.Regular11); comp.VerifyDiagnostics(); VerifyParameter(comp, 0, "System.Int32 C.this[System.Int32 parameter].get"); } - [Fact] - public void ParameterScope_InIndexerSetterAttributeNameOf() + [Theory, CombinatorialData] + public void ParameterScope_InIndexerSetterAttributeNameOf(bool useCSharp10) { var source = @" class C @@ -9154,23 +8941,14 @@ public class MyAttribute : System.Attribute public MyAttribute(string name1) { } } "; - var comp = CreateCompilation(source, parseOptions: TestOptions.Regular10); - comp.VerifyDiagnostics( - // (6,20): error CS0103: The name 'parameter' does not exist in the current context - // [My(nameof(parameter))] - Diagnostic(ErrorCode.ERR_NameNotInContext, "parameter").WithArguments("parameter").WithLocation(6, 20) - ); - - VerifyParameter(comp, 0, null); - - comp = CreateCompilation(source, parseOptions: TestOptions.RegularNext); + var comp = CreateCompilation(source, parseOptions: useCSharp10 ? TestOptions.Regular10 : TestOptions.Regular11); comp.VerifyDiagnostics(); VerifyParameter(comp, 0, "void C.this[System.Int32 parameter].set"); } - [Fact] - public void ParameterScope_InIndexerInitSetterAttributeNameOf() + [Theory, CombinatorialData] + public void ParameterScope_InIndexerInitSetterAttributeNameOf(bool useCSharp10) { var source = @" class C @@ -9187,23 +8965,14 @@ public class MyAttribute : System.Attribute public MyAttribute(string name1) { } } "; - var comp = CreateCompilation(new[] { source, IsExternalInitTypeDefinition }, parseOptions: TestOptions.Regular10); - comp.VerifyDiagnostics( - // (6,20): error CS0103: The name 'parameter' does not exist in the current context - // [My(nameof(parameter))] - Diagnostic(ErrorCode.ERR_NameNotInContext, "parameter").WithArguments("parameter").WithLocation(6, 20) - ); - - VerifyParameter(comp, 0, null); - - comp = CreateCompilation(new[] { source, IsExternalInitTypeDefinition }, parseOptions: TestOptions.RegularNext); + var comp = CreateCompilation(new[] { source, IsExternalInitTypeDefinition }, parseOptions: useCSharp10 ? TestOptions.Regular10 : TestOptions.Regular11); comp.VerifyDiagnostics(); VerifyParameter(comp, 0, "void modreq(System.Runtime.CompilerServices.IsExternalInit) C.this[System.Int32 parameter].init"); } - [Fact] - public void ParameterScope_InMethodAttributeNameOf_Lambda() + [Theory, CombinatorialData] + public void ParameterScope_InMethodAttributeNameOf_Lambda(bool useCSharp10) { var source = @" class C @@ -9219,16 +8988,7 @@ public class MyAttribute : System.Attribute public MyAttribute(string name1) { } } "; - var comp = CreateCompilation(source, parseOptions: TestOptions.Regular10); - comp.VerifyDiagnostics( - // (6,28): error CS0103: The name 'parameter' does not exist in the current context - // var x = [My(nameof(parameter))] int (int parameter) => 0; - Diagnostic(ErrorCode.ERR_NameNotInContext, "parameter").WithArguments("parameter").WithLocation(6, 28) - ); - - VerifyParameter(comp, 0, null); - - comp = CreateCompilation(source, parseOptions: TestOptions.RegularNext); + var comp = CreateCompilation(source, parseOptions: useCSharp10 ? TestOptions.Regular10 : TestOptions.Regular11); comp.VerifyDiagnostics(); VerifyParameter(comp, 0, "lambda expression"); @@ -9271,8 +9031,8 @@ public MyAttribute(string name1) { } ); } - [Fact] - public void ParameterScope_InMethodAttributeNameOf_Delegate() + [Theory, CombinatorialData] + public void ParameterScope_InMethodAttributeNameOf_Delegate(bool useCSharp10) { var source = @" [My(nameof(parameter))] delegate int MyDelegate(int parameter); @@ -9282,23 +9042,14 @@ public class MyAttribute : System.Attribute public MyAttribute(string name1) { } } "; - var comp = CreateCompilation(source, parseOptions: TestOptions.Regular10); - comp.VerifyDiagnostics( - // (2,12): error CS0103: The name 'parameter' does not exist in the current context - // [My(nameof(parameter))] delegate int MyDelegate(int parameter); - Diagnostic(ErrorCode.ERR_NameNotInContext, "parameter").WithArguments("parameter").WithLocation(2, 12) - ); - - VerifyParameter(comp, 0, null); - - comp = CreateCompilation(source, parseOptions: TestOptions.RegularNext); + var comp = CreateCompilation(source, parseOptions: useCSharp10 ? TestOptions.Regular10 : TestOptions.Regular11); comp.VerifyDiagnostics(); VerifyParameter(comp, 0, "System.Int32 MyDelegate.Invoke(System.Int32 parameter)"); } - [Fact] - public void ParameterScope_InMethodAttributeNameOf_Delegate_ConflictingName() + [Theory, CombinatorialData] + public void ParameterScope_InMethodAttributeNameOf_Delegate_ConflictingName(bool useCSharp10) { var source = @" [My(nameof(TParameter))] delegate int MyDelegate(int TParameter); @@ -9308,19 +9059,14 @@ public class MyAttribute : System.Attribute public MyAttribute(string name1) { } } "; - var comp = CreateCompilation(source, parseOptions: TestOptions.Regular10); - comp.VerifyDiagnostics(); - - VerifyTParameter(comp, 0, "MyDelegate"); - - comp = CreateCompilation(source, parseOptions: TestOptions.RegularNext); + var comp = CreateCompilation(source, parseOptions: useCSharp10 ? TestOptions.Regular10 : TestOptions.Regular11); comp.VerifyDiagnostics(); VerifyParameter(comp, 0, "System.Int32 MyDelegate.Invoke(System.Int32 TParameter)", parameterName: "TParameter"); } - [Fact] - public void ParameterScope_InMethodAttributeNameOf_Constructor() + [Theory, CombinatorialData] + public void ParameterScope_InMethodAttributeNameOf_Constructor(bool useCSharp10) { var source = @" class C @@ -9333,16 +9079,7 @@ public class MyAttribute : System.Attribute public MyAttribute(string name1) { } } "; - var comp = CreateCompilation(source, parseOptions: TestOptions.Regular10); - comp.VerifyDiagnostics( - // (4,16): error CS0103: The name 'parameter' does not exist in the current context - // [My(nameof(parameter))] C(int parameter) { } - Diagnostic(ErrorCode.ERR_NameNotInContext, "parameter").WithArguments("parameter").WithLocation(4, 16) - ); - - VerifyParameter(comp, 0, null); - - comp = CreateCompilation(source, parseOptions: TestOptions.RegularNext); + var comp = CreateCompilation(source, parseOptions: useCSharp10 ? TestOptions.Regular10 : TestOptions.Regular11); comp.VerifyDiagnostics(); VerifyParameter(comp, 0, "C..ctor(System.Int32 parameter)"); @@ -9490,8 +9227,8 @@ public MyAttribute(string name1) { } VerifyParameter(comp, 1, null); } - [Fact] - public void ParameterScope_InParameterAttributeNameOf() + [Theory, CombinatorialData] + public void ParameterScope_InParameterAttributeNameOf(bool useCSharp10) { var source = @" class C @@ -9511,28 +9248,15 @@ public class MyAttribute : System.Attribute public MyAttribute(string name1) { } } "; - var comp = CreateCompilation(source, parseOptions: TestOptions.Regular10); - comp.VerifyDiagnostics( - // (8,31): error CS0103: The name 'parameter' does not exist in the current context - // void local([My(nameof(parameter))] int parameter) => throw null; - Diagnostic(ErrorCode.ERR_NameNotInContext, "parameter").WithArguments("parameter").WithLocation(8, 31), - // (11,24): error CS0103: The name 'parameter' does not exist in the current context - // void M2([My(nameof(parameter))] int parameter) => throw null; - Diagnostic(ErrorCode.ERR_NameNotInContext, "parameter").WithArguments("parameter").WithLocation(11, 24) - ); - - VerifyParameter(comp, 0, null); - VerifyParameter(comp, 1, null); - - comp = CreateCompilation(source, parseOptions: TestOptions.RegularNext); + var comp = CreateCompilation(source, parseOptions: useCSharp10 ? TestOptions.Regular10 : TestOptions.Regular11); comp.VerifyDiagnostics(); VerifyParameter(comp, 0, "void local(System.Int32 parameter)"); VerifyParameter(comp, 1, "void C.M2(System.Int32 parameter)"); } - [Fact] - public void ParameterScope_InParameterAttributeNameOf_ConflictingNames() + [Theory, CombinatorialData] + public void ParameterScope_InParameterAttributeNameOf_ConflictingNames(bool useCSharp10) { var source = @" class C @@ -9552,20 +9276,7 @@ public class MyAttribute : System.Attribute public MyAttribute(string name1) { } } "; - var comp = CreateCompilation(source, parseOptions: TestOptions.Regular10); - comp.VerifyDiagnostics( - // (8,61): error CS0412: 'TParameter': a parameter, local variable, or local function cannot have the same name as a method type parameter - // void local([My(nameof(TParameter))] int TParameter) => throw null; - Diagnostic(ErrorCode.ERR_LocalSameNameAsTypeParam, "TParameter").WithArguments("TParameter").WithLocation(8, 61), - // (11,54): error CS0412: 'TParameter': a parameter, local variable, or local function cannot have the same name as a method type parameter - // void M2([My(nameof(TParameter))] int TParameter) => throw null; - Diagnostic(ErrorCode.ERR_LocalSameNameAsTypeParam, "TParameter").WithArguments("TParameter").WithLocation(11, 54) - ); - - VerifyTParameter(comp, 0, "void local(System.Int32 TParameter)"); - VerifyTParameter(comp, 1, "void C.M2(System.Int32 TParameter)"); - - comp = CreateCompilation(source, parseOptions: TestOptions.RegularNext); + var comp = CreateCompilation(source, parseOptions: useCSharp10 ? TestOptions.Regular10 : TestOptions.Regular11); comp.VerifyDiagnostics( // (8,61): error CS0412: 'TParameter': a parameter, local variable, or local function cannot have the same name as a method type parameter // void local([My(nameof(TParameter))] int TParameter) => throw null; @@ -9579,8 +9290,8 @@ public MyAttribute(string name1) { } VerifyParameter(comp, 1, "void C.M2(System.Int32 TParameter)", parameterName: "TParameter"); } - [Fact] - public void ParameterScope_InParameterAttributeNameOf_SpeculatingWithReplacementAttributeInsideExisting() + [Theory, CombinatorialData] + public void ParameterScope_InParameterAttributeNameOf_SpeculatingWithReplacementAttributeInsideExisting(bool useCSharp10) { var source = @" class C @@ -9600,8 +9311,8 @@ public class MyAttribute : System.Attribute public MyAttribute(string name1) { } } "; - // C# 10 - var comp = CreateCompilation(source, parseOptions: TestOptions.Regular10); + var parseOptions = useCSharp10 ? TestOptions.Regular10 : TestOptions.Regular11; + var comp = CreateCompilation(source, parseOptions: parseOptions); comp.VerifyDiagnostics( // (8,24): error CS0103: The name 'positionA' does not exist in the current context // void local([My(positionA)] int parameter) { } @@ -9617,28 +9328,6 @@ public MyAttribute(string name1) { } var methodPosition = tree.GetText().ToString().IndexOf("positionB", StringComparison.Ordinal); var attr = parseAttributeSyntax("[My(nameof(parameter))]", TestOptions.Regular10); - VerifyParameterSpeculation(parentModel, localFuncPosition, attr, found: false); - VerifyParameterSpeculation(parentModel, methodPosition, attr, found: false); - - attr = parseAttributeSyntax("[My(parameter)]", TestOptions.Regular10); - VerifyParameterSpeculation(parentModel, localFuncPosition, attr, found: false); - VerifyParameterSpeculation(parentModel, methodPosition, attr, found: false); - - // C# 11 - comp = CreateCompilation(source, parseOptions: TestOptions.RegularNext); - comp.VerifyDiagnostics( - // (8,24): error CS0103: The name 'positionA' does not exist in the current context - // void local([My(positionA)] int parameter) { } - Diagnostic(ErrorCode.ERR_NameNotInContext, "positionA").WithArguments("positionA").WithLocation(8, 24), - // (11,17): error CS0103: The name 'positionB' does not exist in the current context - // void M2([My(positionB)] int parameter) { } - Diagnostic(ErrorCode.ERR_NameNotInContext, "positionB").WithArguments("positionB").WithLocation(11, 17) - ); - - tree = comp.SyntaxTrees.Single(); - parentModel = comp.GetSemanticModel(tree); - - attr = parseAttributeSyntax("[My(nameof(parameter))]", TestOptions.Regular10); VerifyParameterSpeculation(parentModel, localFuncPosition, attr); VerifyParameterSpeculation(parentModel, methodPosition, attr); @@ -9652,8 +9341,8 @@ static AttributeSyntax parseAttributeSyntax(string source, CSharpParseOptions pa => SyntaxFactory.ParseCompilationUnit($@"class X {{ {source} void M() {{ }} }}", options: parseOptions).DescendantNodes().OfType().Single(); } - [Fact] - public void ParameterScope_InParameterAttributeNameOf_Indexer() + [Theory, CombinatorialData] + public void ParameterScope_InParameterAttributeNameOf_Indexer(bool useCSharp10) { var source = @" class C @@ -9666,23 +9355,14 @@ public class MyAttribute : System.Attribute public MyAttribute(string name1) { } } "; - var comp = CreateCompilation(source, parseOptions: TestOptions.Regular10); - comp.VerifyDiagnostics( - // (4,25): error CS0103: The name 'parameter' does not exist in the current context - // int this[[My(nameof(parameter))] int parameter] => throw null; - Diagnostic(ErrorCode.ERR_NameNotInContext, "parameter").WithArguments("parameter").WithLocation(4, 25) - ); - - VerifyParameter(comp, 0, null); - - comp = CreateCompilation(source, parseOptions: TestOptions.RegularNext); + var comp = CreateCompilation(source, parseOptions: useCSharp10 ? TestOptions.Regular10 : TestOptions.Regular11); comp.VerifyDiagnostics(); VerifyParameter(comp, 0, "System.Int32 C.this[System.Int32 parameter] { get; }"); } - [Fact] - public void ParameterScope_InParameterAttributeNameOf_Indexer_SetterOnly() + [Theory, CombinatorialData] + public void ParameterScope_InParameterAttributeNameOf_Indexer_SetterOnly(bool useCSharp10) { var source = @" class C @@ -9695,16 +9375,7 @@ public class MyAttribute : System.Attribute public MyAttribute(string name1) { } } "; - var comp = CreateCompilation(source, parseOptions: TestOptions.Regular10); - comp.VerifyDiagnostics( - // (4,25): error CS0103: The name 'parameter' does not exist in the current context - // int this[[My(nameof(parameter))] int parameter] => throw null; - Diagnostic(ErrorCode.ERR_NameNotInContext, "parameter").WithArguments("parameter").WithLocation(4, 25) - ); - - VerifyParameter(comp, 0, null); - - comp = CreateCompilation(source, parseOptions: TestOptions.RegularNext); + var comp = CreateCompilation(source, parseOptions: useCSharp10 ? TestOptions.Regular10 : TestOptions.Regular11); comp.VerifyDiagnostics(); VerifyParameter(comp, 0, "System.Int32 C.this[System.Int32 parameter] { set; }"); @@ -9748,37 +9419,62 @@ public MyAttribute(string name1) { } ); } - [Fact] - public void ParameterScope_InParameterAttributeNameOf_Constructor() + [Fact, WorkItem(1556927, "https://devdiv.visualstudio.com/DevDiv/_workitems/edit/1556927")] + public void ParameterScope_ValueLocalNotInPropertyOrAccessorAttributeNameOf_UnknownAccessor() { var source = @" class C { - C([My(nameof(parameter))] int parameter) => throw null; + int Property4 { [My(nameof(value))] unknown => throw null; } } public class MyAttribute : System.Attribute { - public MyAttribute(string name1) { } + public MyAttribute(string name) { } } "; - var comp = CreateCompilation(source, parseOptions: TestOptions.Regular10); + var comp = CreateCompilation(new[] { source, IsExternalInitTypeDefinition }); comp.VerifyDiagnostics( - // (4,18): error CS0103: The name 'parameter' does not exist in the current context - // C([My(nameof(parameter))] int parameter) => throw null; - Diagnostic(ErrorCode.ERR_NameNotInContext, "parameter").WithArguments("parameter").WithLocation(4, 18) + // (4,9): error CS0548: 'C.Property4': property or indexer must have at least one accessor + // int Property4 { [My(nameof(value))] unknown => throw null; } + Diagnostic(ErrorCode.ERR_PropertyWithNoAccessors, "Property4").WithArguments("C.Property4").WithLocation(4, 9), + // (4,41): error CS1014: A get or set accessor expected + // int Property4 { [My(nameof(value))] unknown => throw null; } + Diagnostic(ErrorCode.ERR_GetOrSetExpected, "unknown").WithLocation(4, 41) ); - VerifyParameter(comp, 0, null); + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + var node = tree.GetRoot().DescendantNodes().OfType() + .Where(i => i.Identifier.ValueText == "value") + .Where(i => i.Ancestors().Any(a => a.IsKind(SyntaxKind.Attribute))) + .Single(); + + Assert.Null(model.GetSymbolInfo(node).Symbol); + } - comp = CreateCompilation(source, parseOptions: TestOptions.RegularNext); + [Theory, CombinatorialData] + public void ParameterScope_InParameterAttributeNameOf_Constructor(bool useCSharp10) + { + var source = @" +class C +{ + C([My(nameof(parameter))] int parameter) => throw null; +} + +public class MyAttribute : System.Attribute +{ + public MyAttribute(string name1) { } +} +"; + var comp = CreateCompilation(source, parseOptions: useCSharp10 ? TestOptions.Regular10 : TestOptions.Regular11); comp.VerifyDiagnostics(); VerifyParameter(comp, 0, "C..ctor(System.Int32 parameter)"); } - [Fact] - public void ParameterScope_InParameterAttributeNameOf_Delegate() + [Theory, CombinatorialData] + public void ParameterScope_InParameterAttributeNameOf_Delegate(bool useCSharp10) { var source = @" delegate void MyDelegate([My(nameof(parameter))] int parameter); @@ -9788,23 +9484,14 @@ public class MyAttribute : System.Attribute public MyAttribute(string name1) { } } "; - var comp = CreateCompilation(source, parseOptions: TestOptions.Regular10); - comp.VerifyDiagnostics( - // (2,37): error CS0103: The name 'parameter' does not exist in the current context - // delegate void MyDelegate([My(nameof(parameter))] int parameter); - Diagnostic(ErrorCode.ERR_NameNotInContext, "parameter").WithArguments("parameter").WithLocation(2, 37) - ); - - VerifyParameter(comp, 0, null); - - comp = CreateCompilation(source, parseOptions: TestOptions.RegularNext); + var comp = CreateCompilation(source, parseOptions: useCSharp10 ? TestOptions.Regular10 : TestOptions.Regular11); comp.VerifyDiagnostics(); VerifyParameter(comp, 0, "void MyDelegate.Invoke(System.Int32 parameter)"); } - [Fact] - public void ParameterScope_InParameterAttributeNameOf_ConversionOperator() + [Theory, CombinatorialData] + public void ParameterScope_InParameterAttributeNameOf_ConversionOperator(bool useCSharp10) { var source = @" class C @@ -9817,23 +9504,14 @@ public class MyAttribute : System.Attribute public MyAttribute(string name1) { } } "; - var comp = CreateCompilation(source, parseOptions: TestOptions.Regular10); - comp.VerifyDiagnostics( - // (4,50): error CS0103: The name 'parameter' does not exist in the current context - // public static implicit operator C([My(nameof(parameter))] int parameter) => throw null; - Diagnostic(ErrorCode.ERR_NameNotInContext, "parameter").WithArguments("parameter").WithLocation(4, 50) - ); - - VerifyParameter(comp, 0, null); - - comp = CreateCompilation(source, parseOptions: TestOptions.RegularNext); + var comp = CreateCompilation(source, parseOptions: useCSharp10 ? TestOptions.Regular10 : TestOptions.Regular11); comp.VerifyDiagnostics(); VerifyParameter(comp, 0, "C C.op_Implicit(System.Int32 parameter)"); } - [Fact] - public void ParameterScope_InParameterAttributeNameOf_Operator() + [Theory, CombinatorialData] + public void ParameterScope_InParameterAttributeNameOf_Operator(bool useCSharp10) { var source = @" class C @@ -9846,23 +9524,14 @@ public class MyAttribute : System.Attribute public MyAttribute(string name1) { } } "; - var comp = CreateCompilation(source, parseOptions: TestOptions.Regular10); - comp.VerifyDiagnostics( - // (4,43): error CS0103: The name 'parameter' does not exist in the current context - // public static C operator +([My(nameof(parameter))] int parameter, C other) => throw null; - Diagnostic(ErrorCode.ERR_NameNotInContext, "parameter").WithArguments("parameter").WithLocation(4, 43) - ); - - VerifyParameter(comp, 0, null); - - comp = CreateCompilation(source, parseOptions: TestOptions.RegularNext); + var comp = CreateCompilation(source, parseOptions: useCSharp10 ? TestOptions.Regular10 : TestOptions.Regular11); comp.VerifyDiagnostics(); VerifyParameter(comp, 0, "C C.op_Addition(System.Int32 parameter, C other)"); } - [Fact] - public void ParameterScope_InParameterAttributeNameOf_Lambda() + [Theory, CombinatorialData] + public void ParameterScope_InParameterAttributeNameOf_Lambda(bool useCSharp10) { var source = @" class C @@ -9878,16 +9547,7 @@ public class MyAttribute : System.Attribute public MyAttribute(string name1) { } } "; - var comp = CreateCompilation(source, parseOptions: TestOptions.Regular10); - comp.VerifyDiagnostics( - // (6,29): error CS0103: The name 'parameter' does not exist in the current context - // var x = ([My(nameof(parameter))] int parameter) => 0; - Diagnostic(ErrorCode.ERR_NameNotInContext, "parameter").WithArguments("parameter").WithLocation(6, 29) - ); - - VerifyParameter(comp, 0, null); - - comp = CreateCompilation(source, parseOptions: TestOptions.RegularNext); + var comp = CreateCompilation(source, parseOptions: useCSharp10 ? TestOptions.Regular10 : TestOptions.Regular11); comp.VerifyDiagnostics(); VerifyParameter(comp, 0, "lambda expression"); @@ -9920,8 +9580,8 @@ public MyAttribute(string name1) { } VerifyParameter(comp, 0, "lambda expression"); } - [Fact] - public void ParameterScope_InTypeParameterAttributeNameOf() + [Theory, CombinatorialData] + public void ParameterScope_InTypeParameterAttributeNameOf(bool useCSharp10) { var source = @" class C @@ -9941,28 +9601,15 @@ public class MyAttribute : System.Attribute public MyAttribute(string name1) { } } "; - var comp = CreateCompilation(source, parseOptions: TestOptions.Regular10); - comp.VerifyDiagnostics( - // (8,31): error CS0103: The name 'parameter' does not exist in the current context - // void local<[My(nameof(parameter))] T>(int parameter) { } - Diagnostic(ErrorCode.ERR_NameNotInContext, "parameter").WithArguments("parameter").WithLocation(8, 31), - // (11,24): error CS0103: The name 'parameter' does not exist in the current context - // void M2<[My(nameof(parameter))] T>(int parameter) { } - Diagnostic(ErrorCode.ERR_NameNotInContext, "parameter").WithArguments("parameter").WithLocation(11, 24) - ); - - VerifyParameter(comp, 0, null); - VerifyParameter(comp, 1, null); - - comp = CreateCompilation(source, parseOptions: TestOptions.RegularNext); + var comp = CreateCompilation(source, parseOptions: useCSharp10 ? TestOptions.Regular10 : TestOptions.Regular11); comp.VerifyDiagnostics(); VerifyParameter(comp, 0, "void local(System.Int32 parameter)"); VerifyParameter(comp, 1, "void C.M2(System.Int32 parameter)"); } - [Fact] - public void ParameterScope_InTypeParameterAttributeNameOf_SpeculatingWithReplacementAttributeInsideExisting() + [Theory, CombinatorialData] + public void ParameterScope_InTypeParameterAttributeNameOf_SpeculatingWithReplacementAttributeInsideExisting(bool useCSharp10) { var source = @" class C @@ -9982,8 +9629,8 @@ public class MyAttribute : System.Attribute public MyAttribute(string name1) { } } "; - // C# 10 - var comp = CreateCompilation(source, parseOptions: TestOptions.Regular10); + var parseOptions = useCSharp10 ? TestOptions.Regular10 : TestOptions.Regular11; + var comp = CreateCompilation(source, parseOptions: parseOptions); comp.VerifyDiagnostics( // (8,24): error CS0103: The name 'positionA' does not exist in the current context // void local([My(positionA)] int parameter) { } @@ -9999,28 +9646,6 @@ public MyAttribute(string name1) { } var methodPosition = tree.GetText().ToString().IndexOf("positionB", StringComparison.Ordinal); var attr = parseAttributeSyntax("[My(nameof(parameter))]", TestOptions.Regular10); - VerifyParameterSpeculation(parentModel, localFuncPosition, attr, found: false); - VerifyParameterSpeculation(parentModel, methodPosition, attr, found: false); - - attr = parseAttributeSyntax("[My(parameter)]", TestOptions.Regular10); - VerifyParameterSpeculation(parentModel, localFuncPosition, attr, found: false); - VerifyParameterSpeculation(parentModel, methodPosition, attr, found: false); - - // C# 11 - comp = CreateCompilation(source, parseOptions: TestOptions.RegularNext); - comp.VerifyDiagnostics( - // (8,24): error CS0103: The name 'positionA' does not exist in the current context - // void local([My(positionA)] int parameter) { } - Diagnostic(ErrorCode.ERR_NameNotInContext, "positionA").WithArguments("positionA").WithLocation(8, 24), - // (11,17): error CS0103: The name 'positionB' does not exist in the current context - // void M2([My(positionB)] int parameter) { } - Diagnostic(ErrorCode.ERR_NameNotInContext, "positionB").WithArguments("positionB").WithLocation(11, 17) - ); - - tree = comp.SyntaxTrees.Single(); - parentModel = comp.GetSemanticModel(tree); - - attr = parseAttributeSyntax("[My(nameof(parameter))]", TestOptions.Regular10); VerifyParameterSpeculation(parentModel, localFuncPosition, attr); VerifyParameterSpeculation(parentModel, methodPosition, attr); @@ -10034,8 +9659,8 @@ static AttributeSyntax parseAttributeSyntax(string source, CSharpParseOptions pa => SyntaxFactory.ParseCompilationUnit($@"class X {{ {source} void M() {{ }} }}", options: parseOptions).DescendantNodes().OfType().Single(); } - [Fact] - public void ParameterScope_InTypeParameterAttributeNameOf_Delegate() + [Theory, CombinatorialData] + public void ParameterScope_InTypeParameterAttributeNameOf_Delegate(bool useCSharp10) { var source = @" delegate int MyDelegate<[My(nameof(parameter))] T>(int parameter); @@ -10045,16 +9670,7 @@ public class MyAttribute : System.Attribute public MyAttribute(string name1) { } } "; - var comp = CreateCompilation(source, parseOptions: TestOptions.Regular10); - comp.VerifyDiagnostics( - // (2,36): error CS0103: The name 'parameter' does not exist in the current context - // delegate int MyDelegate<[My(nameof(parameter))] T>(int parameter); - Diagnostic(ErrorCode.ERR_NameNotInContext, "parameter").WithArguments("parameter").WithLocation(2, 36) - ); - - VerifyParameter(comp, 0, null); - - comp = CreateCompilation(source, parseOptions: TestOptions.RegularNext); + var comp = CreateCompilation(source, parseOptions: useCSharp10 ? TestOptions.Regular10 : TestOptions.Regular11); comp.VerifyDiagnostics(); VerifyParameter(comp, 0, "System.Int32 MyDelegate.Invoke(System.Int32 parameter)"); @@ -10429,5 +10045,32 @@ public MyAttribute(string name1) { } "); comp.VerifyDiagnostics(); } + + [Fact, WorkItem(1556927, "https://devdiv.visualstudio.com/DevDiv/_workitems/edit/1556927")] + public void LambdaOutsideMemberModel() + { + var text = @" +public class MyAttribute : System.Attribute +{ + public MyAttribute(string name1) { } +} + +int P +{ + badAccessorName + { + M([My(nameof(P))] env => env); +"; + var comp = CreateCompilation(text); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + var node = tree.GetRoot().DescendantNodes().OfType() + .Where(i => i.Identifier.ValueText == "P") + .Where(i => i.Ancestors().Any(a => a.IsKind(SyntaxKind.Attribute))) + .Single(); + + Assert.Null(model.GetSymbolInfo(node).Symbol); + } } } diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/NativeIntegerTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/NativeIntegerTests.cs index 7e6e68185b96c..cd55dd14b21f6 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/NativeIntegerTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/NativeIntegerTests.cs @@ -4286,15 +4286,14 @@ static void Main() var verifier = CompileAndVerify(source, expectedOutput: @"1"); verifier.VerifyIL("Program.F", @"{ - // Code size 17 (0x11) + // Code size 16 (0x10) .maxstack 2 IL_0000: volatile. IL_0002: ldsfld ""nint Program.F1"" IL_0007: volatile. IL_0009: ldsfld ""nuint Program.F2"" - IL_000e: conv.i - IL_000f: add - IL_0010: ret + IL_000e: add + IL_000f: ret }"); } @@ -7661,7 +7660,7 @@ .maxstack 1 conversions(sourceType: "long", destType: "nint", ExplicitNumeric, expectedImplicitIL: null, expectedExplicitIL: conv("conv.i"), expectedCheckedIL: conv("conv.ovf.i")); conversions(sourceType: "ulong", destType: "nint", ExplicitNumeric, expectedImplicitIL: null, expectedExplicitIL: conv("conv.i"), expectedCheckedIL: conv("conv.ovf.i.un")); conversions(sourceType: "nint", destType: "nint", Identity, expectedImplicitIL: convNone, expectedExplicitIL: convNone); - conversions(sourceType: "nuint", destType: "nint", ExplicitNumeric, expectedImplicitIL: null, expectedExplicitIL: conv("conv.i"), expectedCheckedIL: conv("conv.ovf.i.un")); + conversions(sourceType: "nuint", destType: "nint", ExplicitNumeric, expectedImplicitIL: null, expectedExplicitIL: convNone, expectedCheckedIL: conv("conv.ovf.i.un")); conversions(sourceType: "float", destType: "nint", ExplicitNumeric, expectedImplicitIL: null, expectedExplicitIL: conv("conv.i"), expectedCheckedIL: conv("conv.ovf.i")); conversions(sourceType: "double", destType: "nint", ExplicitNumeric, expectedImplicitIL: null, expectedExplicitIL: conv("conv.i"), expectedCheckedIL: conv("conv.ovf.i")); conversions(sourceType: "decimal", destType: "nint", ExplicitNumeric, expectedImplicitIL: null, @@ -7702,7 +7701,16 @@ .maxstack 1 IL_0002: call ""nint nint?.Value.get"" IL_0007: ret }"); - conversions(sourceType: "nuint?", destType: "nint", ExplicitNullableNumeric, expectedImplicitIL: null, expectedExplicitIL: convFromNullableT("conv.i", "nuint"), expectedCheckedIL: convFromNullableT("conv.ovf.i.un", "nuint")); + conversions(sourceType: "nuint?", destType: "nint", ExplicitNullableNumeric, expectedImplicitIL: null, expectedExplicitIL: +@" +{ + // Code size 8 (0x8) + .maxstack 1 + IL_0000: ldarga.s V_0 + IL_0002: call ""nuint nuint?.Value.get"" + IL_0007: ret +}", + expectedCheckedIL: convFromNullableT("conv.ovf.i.un", "nuint")); conversions(sourceType: "float?", destType: "nint", ExplicitNullableNumeric, expectedImplicitIL: null, expectedExplicitIL: convFromNullableT("conv.i", "float"), expectedCheckedIL: convFromNullableT("conv.ovf.i", "float")); conversions(sourceType: "double?", destType: "nint", ExplicitNullableNumeric, expectedImplicitIL: null, expectedExplicitIL: convFromNullableT("conv.i", "double"), expectedCheckedIL: convFromNullableT("conv.ovf.i", "double")); conversions(sourceType: "decimal?", destType: "nint", ExplicitNullableNumeric, expectedImplicitIL: null, @@ -7800,7 +7808,16 @@ .maxstack 1 IL_0001: newobj ""nint?..ctor(nint)"" IL_0006: ret }"); - conversions(sourceType: "nuint", destType: "nint?", ExplicitNullableNumeric, expectedImplicitIL: null, expectedExplicitIL: convToNullableT("conv.i", "nint"), expectedCheckedIL: convToNullableT("conv.ovf.i.un", "nint")); + conversions(sourceType: "nuint", destType: "nint?", ExplicitNullableNumeric, expectedImplicitIL: null, expectedExplicitIL: +@" +{ + // Code size 7 (0x7) + .maxstack 1 + IL_0000: ldarg.0 + IL_0001: newobj ""nint?..ctor(nint)"" + IL_0006: ret +}", + expectedCheckedIL: convToNullableT("conv.ovf.i.un", "nint")); conversions(sourceType: "float", destType: "nint?", ExplicitNullableNumeric, expectedImplicitIL: null, expectedExplicitIL: convToNullableT("conv.i", "nint"), expectedCheckedIL: convToNullableT("conv.ovf.i", "nint")); conversions(sourceType: "double", destType: "nint?", ExplicitNullableNumeric, expectedImplicitIL: null, expectedExplicitIL: convToNullableT("conv.i", "nint"), expectedCheckedIL: convToNullableT("conv.ovf.i", "nint")); conversions(sourceType: "decimal", destType: "nint?", ExplicitNullableNumeric, expectedImplicitIL: null, @@ -7850,7 +7867,28 @@ .maxstack 1 conversions(sourceType: "long?", destType: "nint?", ExplicitNullableNumeric, expectedImplicitIL: null, expectedExplicitIL: convFromToNullableT("conv.i", "long", "nint"), expectedCheckedIL: convFromToNullableT("conv.ovf.i", "long", "nint")); conversions(sourceType: "ulong?", destType: "nint?", ExplicitNullableNumeric, expectedImplicitIL: null, expectedExplicitIL: convFromToNullableT("conv.i", "ulong", "nint"), expectedCheckedIL: convFromToNullableT("conv.ovf.i.un", "ulong", "nint")); conversions(sourceType: "nint?", destType: "nint?", Identity, expectedImplicitIL: convNone, expectedExplicitIL: convNone); - conversions(sourceType: "nuint?", destType: "nint?", ExplicitNullableNumeric, expectedImplicitIL: null, expectedExplicitIL: convFromToNullableT("conv.i", "nuint", "nint"), expectedCheckedIL: convFromToNullableT("conv.ovf.i.un", "nuint", "nint")); + conversions(sourceType: "nuint?", destType: "nint?", ExplicitNullableNumeric, expectedImplicitIL: null, expectedExplicitIL: +@" +{ + // Code size 34 (0x22) + .maxstack 1 + .locals init (nuint? V_0, + nint? V_1) + IL_0000: ldarg.0 + IL_0001: stloc.0 + IL_0002: ldloca.s V_0 + IL_0004: call ""bool nuint?.HasValue.get"" + IL_0009: brtrue.s IL_0015 + IL_000b: ldloca.s V_1 + IL_000d: initobj ""nint?"" + IL_0013: ldloc.1 + IL_0014: ret + IL_0015: ldloca.s V_0 + IL_0017: call ""nuint nuint?.GetValueOrDefault()"" + IL_001c: newobj ""nint?..ctor(nint)"" + IL_0021: ret +}", + expectedCheckedIL: convFromToNullableT("conv.ovf.i.un", "nuint", "nint")); conversions(sourceType: "float?", destType: "nint?", ExplicitNullableNumeric, expectedImplicitIL: null, expectedExplicitIL: convFromToNullableT("conv.i", "float", "nint"), expectedCheckedIL: convFromToNullableT("conv.ovf.i", "float", "nint")); conversions(sourceType: "double?", destType: "nint?", ExplicitNullableNumeric, expectedImplicitIL: null, expectedExplicitIL: convFromToNullableT("conv.i", "double", "nint"), expectedCheckedIL: convFromToNullableT("conv.ovf.i", "double", "nint")); conversions(sourceType: "decimal?", destType: "nint?", ExplicitNullableNumeric, null, @@ -8126,7 +8164,7 @@ .maxstack 1 conversions(sourceType: "uint", destType: "nuint", ImplicitNumeric, expectedImplicitIL: conv("conv.u"), expectedExplicitIL: conv("conv.u")); conversions(sourceType: "long", destType: "nuint", ExplicitNumeric, expectedImplicitIL: null, expectedExplicitIL: conv("conv.u"), expectedCheckedIL: conv("conv.ovf.u")); conversions(sourceType: "ulong", destType: "nuint", ExplicitNumeric, expectedImplicitIL: null, expectedExplicitIL: conv("conv.u"), expectedCheckedIL: conv("conv.ovf.u.un")); - conversions(sourceType: "nint", destType: "nuint", ExplicitNumeric, expectedImplicitIL: null, expectedExplicitIL: conv("conv.u"), expectedCheckedIL: conv("conv.ovf.u")); + conversions(sourceType: "nint", destType: "nuint", ExplicitNumeric, expectedImplicitIL: null, expectedExplicitIL: convNone, expectedCheckedIL: conv("conv.ovf.u")); conversions(sourceType: "nuint", destType: "nuint", Identity, expectedImplicitIL: convNone, expectedExplicitIL: convNone); conversions(sourceType: "float", destType: "nuint", ExplicitNumeric, expectedImplicitIL: null, expectedExplicitIL: conv("conv.u"), expectedCheckedIL: conv("conv.ovf.u")); conversions(sourceType: "double", destType: "nuint", ExplicitNumeric, expectedImplicitIL: null, expectedExplicitIL: conv("conv.u"), expectedCheckedIL: conv("conv.ovf.u")); @@ -8160,7 +8198,16 @@ .maxstack 1 conversions(sourceType: "uint?", destType: "nuint", ExplicitNullableImplicitNumeric, expectedImplicitIL: null, expectedExplicitIL: convFromNullableT("conv.u", "uint")); conversions(sourceType: "long?", destType: "nuint", ExplicitNullableNumeric, expectedImplicitIL: null, expectedExplicitIL: convFromNullableT("conv.u", "long"), expectedCheckedIL: convFromNullableT("conv.ovf.u", "long")); conversions(sourceType: "ulong?", destType: "nuint", ExplicitNullableNumeric, expectedImplicitIL: null, expectedExplicitIL: convFromNullableT("conv.u", "ulong"), expectedCheckedIL: convFromNullableT("conv.ovf.u.un", "ulong")); - conversions(sourceType: "nint?", destType: "nuint", ExplicitNullableNumeric, expectedImplicitIL: null, expectedExplicitIL: convFromNullableT("conv.u", "nint"), expectedCheckedIL: convFromNullableT("conv.ovf.u", "nint")); + conversions(sourceType: "nint?", destType: "nuint", ExplicitNullableNumeric, expectedImplicitIL: null, expectedExplicitIL: +@" +{ + // Code size 8 (0x8) + .maxstack 1 + IL_0000: ldarga.s V_0 + IL_0002: call ""nint nint?.Value.get"" + IL_0007: ret +}", + expectedCheckedIL: convFromNullableT("conv.ovf.u", "nint")); conversions(sourceType: "nuint?", destType: "nuint", ExplicitNullableIdentity, expectedImplicitIL: null, @"{ // Code size 8 (0x8) @@ -8235,7 +8282,17 @@ .maxstack 1 conversions(sourceType: "uint", destType: "nuint?", ImplicitNullableNumeric, expectedImplicitIL: convToNullableT("conv.u", "nuint"), expectedExplicitIL: convToNullableT("conv.u", "nuint")); conversions(sourceType: "long", destType: "nuint?", ExplicitNullableNumeric, expectedImplicitIL: null, expectedExplicitIL: convToNullableT("conv.u", "nuint"), expectedCheckedIL: convToNullableT("conv.ovf.u", "nuint")); conversions(sourceType: "ulong", destType: "nuint?", ExplicitNullableNumeric, expectedImplicitIL: null, expectedExplicitIL: convToNullableT("conv.u", "nuint"), expectedCheckedIL: convToNullableT("conv.ovf.u.un", "nuint")); - conversions(sourceType: "nint", destType: "nuint?", ExplicitNullableNumeric, expectedImplicitIL: null, expectedExplicitIL: convToNullableT("conv.u", "nuint"), expectedCheckedIL: convToNullableT("conv.ovf.u", "nuint")); + conversions(sourceType: "nint", destType: "nuint?", ExplicitNullableNumeric, expectedImplicitIL: null, expectedExplicitIL: +@" +{ + // Code size 7 (0x7) + .maxstack 1 + IL_0000: ldarg.0 + IL_0001: newobj ""nuint?..ctor(nuint)"" + IL_0006: ret +} +", + expectedCheckedIL: convToNullableT("conv.ovf.u", "nuint")); conversions(sourceType: "nuint", destType: "nuint?", ImplicitNullableIdentity, @"{ // Code size 7 (0x7) @@ -8299,7 +8356,29 @@ .maxstack 1 conversions(sourceType: "uint?", destType: "nuint?", ImplicitNullableNumeric, expectedImplicitIL: convFromToNullableT("conv.u", "uint", "nuint"), expectedExplicitIL: convFromToNullableT("conv.u", "uint", "nuint")); conversions(sourceType: "long?", destType: "nuint?", ExplicitNullableNumeric, expectedImplicitIL: null, expectedExplicitIL: convFromToNullableT("conv.u", "long", "nuint"), expectedCheckedIL: convFromToNullableT("conv.ovf.u", "long", "nuint")); conversions(sourceType: "ulong?", destType: "nuint?", ExplicitNullableNumeric, expectedImplicitIL: null, expectedExplicitIL: convFromToNullableT("conv.u", "ulong", "nuint"), expectedCheckedIL: convFromToNullableT("conv.ovf.u.un", "ulong", "nuint")); - conversions(sourceType: "nint?", destType: "nuint?", ExplicitNullableNumeric, expectedImplicitIL: null, expectedExplicitIL: convFromToNullableT("conv.u", "nint", "nuint"), expectedCheckedIL: convFromToNullableT("conv.ovf.u", "nint", "nuint")); + conversions(sourceType: "nint?", destType: "nuint?", ExplicitNullableNumeric, expectedImplicitIL: null, expectedExplicitIL: +@" +{ + // Code size 34 (0x22) + .maxstack 1 + .locals init (nint? V_0, + nuint? V_1) + IL_0000: ldarg.0 + IL_0001: stloc.0 + IL_0002: ldloca.s V_0 + IL_0004: call ""bool nint?.HasValue.get"" + IL_0009: brtrue.s IL_0015 + IL_000b: ldloca.s V_1 + IL_000d: initobj ""nuint?"" + IL_0013: ldloc.1 + IL_0014: ret + IL_0015: ldloca.s V_0 + IL_0017: call ""nint nint?.GetValueOrDefault()"" + IL_001c: newobj ""nuint?..ctor(nuint)"" + IL_0021: ret +} +", + expectedCheckedIL: convFromToNullableT("conv.ovf.u", "nint", "nuint")); conversions(sourceType: "nuint?", destType: "nuint?", Identity, expectedImplicitIL: convNone, expectedExplicitIL: convNone); conversions(sourceType: "float?", destType: "nuint?", ExplicitNullableNumeric, expectedImplicitIL: null, expectedExplicitIL: convFromToNullableT("conv.u", "float", "nuint"), expectedCheckedIL: convFromToNullableT("conv.ovf.u", "float", "nuint")); conversions(sourceType: "double?", destType: "nuint?", ExplicitNullableNumeric, expectedImplicitIL: null, expectedExplicitIL: convFromToNullableT("conv.u", "double", "nuint"), expectedCheckedIL: convFromToNullableT("conv.ovf.u", "double", "nuint")); @@ -13433,11 +13512,11 @@ public void Int64Conversions() { convert(fromType: "nint", toType: "ulong", "int.MinValue", "18446744071562067968", "conv.i8", "System.OverflowException", "conv.ovf.u8"); convert(fromType: "nint", toType: "ulong", "int.MaxValue", "2147483647", "conv.i8", "2147483647", "conv.ovf.u8"); - convert(fromType: "nint", toType: "nuint", "int.MinValue", IntPtr.Size == 4 ? "2147483648" : "18446744071562067968", "conv.u", "System.OverflowException", "conv.ovf.u"); - convert(fromType: "nint", toType: "nuint", "int.MaxValue", "2147483647", "conv.u", "2147483647", "conv.ovf.u"); + convert(fromType: "nint", toType: "nuint", "int.MinValue", IntPtr.Size == 4 ? "2147483648" : "18446744071562067968", null, "System.OverflowException", "conv.ovf.u"); + convert(fromType: "nint", toType: "nuint", "int.MaxValue", "2147483647", null, "2147483647", "conv.ovf.u"); convert(fromType: "nuint", toType: "long", "uint.MaxValue", "4294967295", "conv.u8", "4294967295", "conv.ovf.i8.un"); - convert(fromType: "nuint", toType: "nint", "uint.MaxValue", IntPtr.Size == 4 ? "-1" : "4294967295", "conv.i", IntPtr.Size == 4 ? "System.OverflowException" : "4294967295", "conv.ovf.i.un"); + convert(fromType: "nuint", toType: "nint", "uint.MaxValue", IntPtr.Size == 4 ? "-1" : "4294967295", null, IntPtr.Size == 4 ? "System.OverflowException" : "4294967295", "conv.ovf.i.un"); string nintMinValue = IntPtr.Size == 4 ? int.MinValue.ToString() : long.MinValue.ToString(); string nintMaxValue = IntPtr.Size == 4 ? int.MaxValue.ToString() : long.MaxValue.ToString(); @@ -13445,11 +13524,11 @@ public void Int64Conversions() convert(fromType: "nint", toType: "ulong", nintMinValue, IntPtr.Size == 4 ? "18446744071562067968" : "9223372036854775808", "conv.i8", "System.OverflowException", "conv.ovf.u8"); convert(fromType: "nint", toType: "ulong", nintMaxValue, IntPtr.Size == 4 ? "2147483647" : "9223372036854775807", "conv.i8", IntPtr.Size == 4 ? "2147483647" : "9223372036854775807", "conv.ovf.u8"); - convert(fromType: "nint", toType: "nuint", nintMinValue, IntPtr.Size == 4 ? "2147483648" : "9223372036854775808", "conv.u", "System.OverflowException", "conv.ovf.u"); - convert(fromType: "nint", toType: "nuint", nintMaxValue, IntPtr.Size == 4 ? "2147483647" : "9223372036854775807", "conv.u", IntPtr.Size == 4 ? "2147483647" : "9223372036854775807", "conv.ovf.u"); + convert(fromType: "nint", toType: "nuint", nintMinValue, IntPtr.Size == 4 ? "2147483648" : "9223372036854775808", null, "System.OverflowException", "conv.ovf.u"); + convert(fromType: "nint", toType: "nuint", nintMaxValue, IntPtr.Size == 4 ? "2147483647" : "9223372036854775807", null, IntPtr.Size == 4 ? "2147483647" : "9223372036854775807", "conv.ovf.u"); convert(fromType: "nuint", toType: "long", nuintMaxValue, IntPtr.Size == 4 ? "4294967295" : "-1", "conv.u8", IntPtr.Size == 4 ? "4294967295" : "System.OverflowException", "conv.ovf.i8.un"); - convert(fromType: "nuint", toType: "nint", nuintMaxValue, "-1", "conv.i", "System.OverflowException", "conv.ovf.i.un"); + convert(fromType: "nuint", toType: "nint", nuintMaxValue, "-1", null, "System.OverflowException", "conv.ovf.i.un"); void convert(string fromType, string toType, string fromValue, string toValueUnchecked, string toConvUnchecked, string toValueChecked, string toConvChecked) { @@ -13480,8 +13559,15 @@ static void Main() var verifier = CompileAndVerify(source, parseOptions: TestOptions.Regular9, expectedOutput: $@"{toValueUnchecked} {toValueChecked}"); - verifier.VerifyIL("Program.Convert", - $@"{{ + verifier.VerifyIL("Program.Convert", toConvUnchecked is null ? +@" +{ + // Code size 2 (0x2) + .maxstack 1 + IL_0000: ldarg.0 + IL_0001: ret +}" : +$@"{{ // Code size 3 (0x3) .maxstack 1 IL_0000: ldarg.0 @@ -14494,6 +14580,13 @@ public void SignedToUnsignedConversions_Explicit() }"; var comp = CreateCompilation(source); var verifier = CompileAndVerify(source); + string expectedExplicitILNop = +@"{ + // Code size 2 (0x2) + .maxstack 1 + IL_0000: ldarg.0 + IL_0001: ret +}"; string expectedExplicitILA = @"{ // Code size 3 (0x3) @@ -14522,7 +14615,7 @@ .maxstack 1 verifier.VerifyIL("NativeInts.Explicit2", expectedExplicitILA); verifier.VerifyIL("NativeInts.Explicit3", expectedExplicitILA); verifier.VerifyIL("NativeInts.Explicit4", expectedExplicitILB); - verifier.VerifyIL("NativeInts.Explicit5", expectedExplicitILB); + verifier.VerifyIL("NativeInts.Explicit5", expectedExplicitILNop); verifier.VerifyIL("NativeInts.Checked1", expectedCheckedIL); verifier.VerifyIL("NativeInts.Checked2", expectedCheckedIL); verifier.VerifyIL("NativeInts.Checked3", expectedCheckedIL); @@ -15534,5 +15627,31 @@ class C Diagnostic(ErrorCode.ERR_BadBinaryOps, $"x {op} count").WithArguments(op, type, "int").WithLocation(5, 16) ); } + + [Theory] + [CombinatorialData] + [WorkItem(60944, "https://github.com/dotnet/roslyn/issues/60944")] + public void NopConversions([CombinatorialValues("nint", "nuint")] string inputType, [CombinatorialValues("nint", "nuint")] string outputType) + { + var source = +@"class Program +{ + static " + outputType + @" F1(" + inputType + @" x) + { + return unchecked((" + outputType + @")x); + } +}"; + var comp = CreateCompilation(source); + var verifier = CompileAndVerify(comp).VerifyDiagnostics(); + verifier.VerifyIL("Program.F1", +@" +{ + // Code size 2 (0x2) + .maxstack 1 + IL_0000: ldarg.0 + IL_0001: ret +} +"); + } } } diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/NullableReferenceTypesTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/NullableReferenceTypesTests.cs index 575a9c90bdbe7..2e6600ca261dc 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/NullableReferenceTypesTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/NullableReferenceTypesTests.cs @@ -1205,10 +1205,50 @@ class C ); } + [Theory] + [InlineData(LanguageVersion.CSharp10)] + [InlineData(LanguageVersion.CSharp11)] + public void SuppressNullableWarning_RefReturn(LanguageVersion langVersion) + { + var source = +@"#nullable enable +ref struct R +{ + public R(ref T t) { } +} +class C +{ + static ref R M(bool b) + { + string s = string.Empty; + R r = new R(ref s); + if (b) + return ref r; // 1 + else + return ref r!; // 2 + } +}"; + var comp = CreateCompilation(source, parseOptions: TestOptions.Regular.WithLanguageVersion(langVersion)); + comp.VerifyDiagnostics( + // (13,24): error CS8168: Cannot return local 'r' by reference because it is not a ref local + // return ref r; // 1 + Diagnostic(ErrorCode.ERR_RefReturnLocal, "r").WithArguments("r").WithLocation(13, 24), + // (13,24): warning CS8619: Nullability of reference types in value of type 'R' doesn't match target type 'R'. + // return ref r; // 1 + Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "r").WithArguments("R", "R").WithLocation(13, 24), + // (15,24): error CS8168: Cannot return local 'r' by reference because it is not a ref local + // return ref r!; // 2 + Diagnostic(ErrorCode.ERR_RefReturnLocal, "r").WithArguments("r").WithLocation(15, 24), + // (15,24): warning CS8619: Nullability of reference types in value of type 'R' doesn't match target type 'R'. + // return ref r!; // 2 + Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "r").WithArguments("R", "R").WithLocation(15, 24)); + } + [Fact, WorkItem(31297, "https://github.com/dotnet/roslyn/issues/31297")] public void SuppressNullableWarning_RefSpanReturn() { - var comp = CreateCompilationWithMscorlibAndSpan(@" + var source = +@"#nullable enable using System; class C { @@ -1228,8 +1268,9 @@ ref Span M2(ref Span x, bool b) else return ref x!; } -}", options: WithNullable(TestOptions.ReleaseDll, NullableContextOptions.Enable)); +}"; + var comp = CreateCompilationWithMscorlibAndSpan(source, parseOptions: TestOptions.Regular10, options: TestOptions.ReleaseDll); comp.VerifyDiagnostics( // (10,24): error CS8157: Cannot return 'y' by reference because it was initialized to a value that cannot be returned by reference // return ref y; // 1 @@ -1241,6 +1282,28 @@ ref Span M2(ref Span x, bool b) // return ref x; // 3 Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "x").WithArguments("System.Span", "System.Span").WithLocation(17, 24) ); + + comp = CreateCompilationWithMscorlibAndSpan(source, options: TestOptions.ReleaseDll); + comp.VerifyDiagnostics( + // (10,24): error CS8157: Cannot return 'y' by reference because it was initialized to a value that cannot be returned by reference + // return ref y; // 1 + Diagnostic(ErrorCode.ERR_RefReturnNonreturnableLocal, "y").WithArguments("y").WithLocation(10, 24), + // (12,24): error CS8157: Cannot return 'y' by reference because it was initialized to a value that cannot be returned by reference + // return ref y!; // 2 + Diagnostic(ErrorCode.ERR_RefReturnNonreturnableLocal, "y").WithArguments("y").WithLocation(12, 24), + // (17,24): error CS8166: Cannot return a parameter by reference 'x' because it is not a ref parameter + // return ref x; // 3 + Diagnostic(ErrorCode.ERR_RefReturnParameter, "x").WithArguments("x").WithLocation(17, 24), + // (17,24): warning CS8619: Nullability of reference types in value of type 'System.Span' doesn't match target type 'System.Span'. + // return ref x; // 3 + Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "x").WithArguments("System.Span", "System.Span").WithLocation(17, 24), + // (19,24): error CS8166: Cannot return a parameter by reference 'x' because it is not a ref parameter + // return ref x!; + Diagnostic(ErrorCode.ERR_RefReturnParameter, "x").WithArguments("x").WithLocation(19, 24), + // (19,24): warning CS8619: Nullability of reference types in value of type 'System.Span' doesn't match target type 'System.Span'. + // return ref x!; + Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "x").WithArguments("System.Span", "System.Span").WithLocation(19, 24) + ); } [Fact, WorkItem(31297, "https://github.com/dotnet/roslyn/issues/31297")] diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/OperatorTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/OperatorTests.cs index 367338c2b9dd1..3b5b83b8ef484 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/OperatorTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/OperatorTests.cs @@ -7636,10 +7636,6 @@ ExpressionSyntax node4 symbol1.ContainingType.EnumUnderlyingTypeOrSelf().SpecialType.IsIntegralType() || symbol1.ContainingType.SpecialType == SpecialType.System_Char); break; - - default: - expectChecked = type.IsDynamic(); - break; } Assert.Equal(expectChecked, symbol1.IsCheckedBuiltin); @@ -8396,7 +8392,7 @@ ExpressionSyntax node8 Assert.Equal(MethodKind.BuiltinOperator, symbol1.MethodKind); Assert.True(symbol1.IsImplicitlyDeclared); - bool isChecked; + bool isChecked = false; switch (op) { @@ -8406,10 +8402,6 @@ ExpressionSyntax node8 case BinaryOperatorKind.Division: isChecked = isDynamic || symbol1.ContainingSymbol.Kind == SymbolKind.PointerType || symbol1.ContainingType.EnumUnderlyingTypeOrSelf().SpecialType.IsIntegralType(); break; - - default: - isChecked = isDynamic; - break; } string expectedSymbol = String.Format("{4} {0}.{2}({1} left, {3} right)", @@ -8650,6 +8642,56 @@ void Test(dynamic x) compilation = compilation.WithOptions(TestOptions.ReleaseDll.WithOverflowChecks(true)); semanticModel = compilation.GetSemanticModel(tree); + var symbols2 = (from node2 in nodes select (IMethodSymbol)semanticModel.GetSymbolInfo(node2).Symbol).ToArray(); + foreach (var symbol2 in symbols2) + { + Assert.False(symbol2.IsCheckedBuiltin); + Assert.True(((ITypeSymbol)symbol2.ContainingSymbol).IsDynamic()); + Assert.Null(symbol2.ContainingType); + } + + for (int i = 0; i < symbols1.Length; i++) + { + Assert.Equal(symbols1[i], symbols2[i]); + } + } + + [Fact] + public void DynamicBinaryIntrinsicSymbols2() + { + var source = +@" +class Module1 +{ + void Test(dynamic x) + { + var z1 = x + 0; + var z2 = 0 + x; + } +}"; + + var compilation = CreateCompilation(source, options: TestOptions.ReleaseDll.WithOverflowChecks(false)); + + var tree = compilation.SyntaxTrees.Single(); + var semanticModel = compilation.GetSemanticModel(tree); + + var nodes = (from node in tree.GetRoot().DescendantNodes() + select node as BinaryExpressionSyntax). + Where(node => node is not null).ToArray(); + + Assert.Equal(2, nodes.Length); + + var symbols1 = (from node1 in nodes select (IMethodSymbol)semanticModel.GetSymbolInfo(node1).Symbol).ToArray(); + foreach (var symbol1 in symbols1) + { + Assert.False(symbol1.IsCheckedBuiltin); + Assert.True(((ITypeSymbol)symbol1.ContainingSymbol).IsDynamic()); + Assert.Null(symbol1.ContainingType); + } + + compilation = compilation.WithOptions(TestOptions.ReleaseDll.WithOverflowChecks(true)); + semanticModel = compilation.GetSemanticModel(tree); + var symbols2 = (from node2 in nodes select (IMethodSymbol)semanticModel.GetSymbolInfo(node2).Symbol).ToArray(); foreach (var symbol2 in symbols2) { diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/RawInterpolationTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/RawInterpolationTests.cs index 9c09a472a332f..74a391f68c4c0 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/RawInterpolationTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/RawInterpolationTests.cs @@ -1266,9 +1266,9 @@ string M() CreateCompilation(text, parseOptions: CSharpParseOptions.Default.WithLanguageVersion(LanguageVersion.CSharp5)).VerifyDiagnostics( - // (6,24): error CS8652: The feature 'raw string literals' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // (6,24): error CS8026: Feature 'raw string literals' is not available in C# 5. Please use language version 11.0 or greater. // string other = """world"""; - Diagnostic(ErrorCode.ERR_FeatureInPreview, @"""""""world""""""").WithArguments("raw string literals").WithLocation(6, 24), + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion5, @"""""""world""""""").WithArguments("raw string literals", "11.0").WithLocation(6, 24), // (7,16): error CS8026: Feature 'interpolated strings' is not available in C# 5. Please use language version 6 or greater. // return $"""hello + {other}"""; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion5, @"$""""""hello + {other}""""""").WithArguments("interpolated strings", "6").WithLocation(7, 16)); diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/RawInterpolationTests_Handler.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/RawInterpolationTests_Handler.cs index bc25f8214cde2..53a53abed40ea 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/RawInterpolationTests_Handler.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/RawInterpolationTests_Handler.cs @@ -589,9 +589,9 @@ public void UseOfSpanInInterpolationHole_CSharp9() var comp = CreateCompilation(new[] { source, GetInterpolatedStringHandlerDefinition(includeSpanOverloads: true, useDefaultParameters: false, useBoolReturns: false) }, parseOptions: TestOptions.Regular9, targetFramework: TargetFramework.NetCoreApp); comp.VerifyDiagnostics( - // (4,19): error CS8652: The feature 'raw string literals' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // (4,19): error CS8773: Feature 'raw string literals' is not available in C# 9.0. Please use language version 11.0 or greater. // Console.WriteLine($"""{span}"""); - Diagnostic(ErrorCode.ERR_FeatureInPreview, @"$""""""{span}""""""").WithArguments("raw string literals").WithLocation(4, 19), + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion9, @"$""""""{span}""""""").WithArguments("raw string literals", "11.0").WithLocation(4, 19), // (4,24): error CS8773: Feature 'interpolated string handlers' is not available in C# 9.0. Please use language version 10.0 or greater. // Console.WriteLine($"""{span}"""); Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion9, "span").WithArguments("interpolated string handlers", "10.0").WithLocation(4, 24)); @@ -2120,18 +2120,18 @@ public void TargetTypedInterpolationHoles_Errors(string expression) if (expression.Contains('+')) { comp.VerifyDiagnostics( - // (1,26): error CS8652: The feature 'raw string literals' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // (1,26): error CS8773: Feature 'raw string literals' is not available in C# 9.0. Please use language version 11.0 or greater. // System.Console.WriteLine($"""{(null, default)}""" + $"""{new()}"""); - Diagnostic(ErrorCode.ERR_FeatureInPreview, @"$""""""{(null, default)}""""""").WithArguments("raw string literals").WithLocation(1, 26), + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion9, @"$""""""{(null, default)}""""""").WithArguments("raw string literals", "11.0").WithLocation(1, 26), // (1,31): error CS1503: Argument 1: cannot convert from '(, default)' to 'object' // System.Console.WriteLine($"""{(null, default)}""" + $"""{new()}"""); Diagnostic(ErrorCode.ERR_BadArgType, "(null, default)").WithArguments("1", "(, default)", "object").WithLocation(1, 31), // (1,31): error CS8773: Feature 'interpolated string handlers' is not available in C# 9.0. Please use language version 10.0 or greater. // System.Console.WriteLine($"""{(null, default)}""" + $"""{new()}"""); Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion9, "(null, default)").WithArguments("interpolated string handlers", "10.0").WithLocation(1, 31), - // (1,53): error CS8652: The feature 'raw string literals' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // (1,53): error CS8773: Feature 'raw string literals' is not available in C# 9.0. Please use language version 11.0 or greater. // System.Console.WriteLine($"""{(null, default)}""" + $"""{new()}"""); - Diagnostic(ErrorCode.ERR_FeatureInPreview, @"$""""""{new()}""""""").WithArguments("raw string literals").WithLocation(1, 53), + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion9, @"$""""""{new()}""""""").WithArguments("raw string literals", "11.0").WithLocation(1, 53), // (1,58): error CS1729: 'string' does not contain a constructor that takes 0 arguments // System.Console.WriteLine($"""{(null, default)}""" + $"""{new()}"""); Diagnostic(ErrorCode.ERR_BadCtorArgCount, "new()").WithArguments("string", "0").WithLocation(1, 58)); @@ -2139,9 +2139,9 @@ public void TargetTypedInterpolationHoles_Errors(string expression) else { comp.VerifyDiagnostics( - // (1,26): error CS8652: The feature 'raw string literals' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // (1,26): error CS8773: Feature 'raw string literals' is not available in C# 9.0. Please use language version 11.0 or greater. // System.Console.WriteLine($"""{(null, default)}{new()}"""); - Diagnostic(ErrorCode.ERR_FeatureInPreview, @"$""""""{(null, default)}{new()}""""""").WithArguments("raw string literals").WithLocation(1, 26), + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion9, @"$""""""{(null, default)}{new()}""""""").WithArguments("raw string literals", "11.0").WithLocation(1, 26), // (1,31): error CS1503: Argument 1: cannot convert from '(, default)' to 'object' // System.Console.WriteLine($"""{(null, default)}{new()}"""); Diagnostic(ErrorCode.ERR_BadArgType, "(null, default)").WithArguments("1", "(, default)", "object").WithLocation(1, 31), @@ -3774,27 +3774,27 @@ public ref partial struct DefaultInterpolatedStringHandler if (expression.Contains('+')) { comp.VerifyDiagnostics( - // (3,11): error CS8652: The feature 'raw string literals' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // (3,11): error CS8773: Feature 'raw string literals' is not available in C# 9.0. Please use language version 11.0 or greater. // C.M(() => $"""{new S { Field = """Field""" }}""" + $""" - Diagnostic(ErrorCode.ERR_FeatureInPreview, @"$""""""{new S { Field = """"""Field"""""" }}""""""").WithArguments("raw string literals").WithLocation(3, 11), - // (3,32): error CS8652: The feature 'raw string literals' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion9, @"$""""""{new S { Field = """"""Field"""""" }}""""""").WithArguments("raw string literals", "11.0").WithLocation(3, 11), + // (3,32): error CS8773: Feature 'raw string literals' is not available in C# 9.0. Please use language version 11.0 or greater. // C.M(() => $"""{new S { Field = """Field""" }}""" + $""" - Diagnostic(ErrorCode.ERR_FeatureInPreview, @"""""""Field""""""").WithArguments("raw string literals").WithLocation(3, 32), - // (3,52): error CS8652: The feature 'raw string literals' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion9, @"""""""Field""""""").WithArguments("raw string literals", "11.0").WithLocation(3, 32), + // (3,52): error CS8773: Feature 'raw string literals' is not available in C# 9.0. Please use language version 11.0 or greater. // C.M(() => $"""{new S { Field = """Field""" }}""" + $""" - Diagnostic(ErrorCode.ERR_FeatureInPreview, @"$"""""" + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion9, @"$"""""" -""""""").WithArguments("raw string literals").WithLocation(3, 52)); +""""""").WithArguments("raw string literals", "11.0").WithLocation(3, 52)); } else { comp.VerifyDiagnostics( - // (3,11): error CS8652: The feature 'raw string literals' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // (3,11): error CS8773: Feature 'raw string literals' is not available in C# 9.0. Please use language version 11.0 or greater. // C.M(() => $"""{new S { Field = """Field""" }}"""); - Diagnostic(ErrorCode.ERR_FeatureInPreview, @"$""""""{new S { Field = """"""Field"""""" }}""""""").WithArguments("raw string literals").WithLocation(3, 11), - // (3,32): error CS8652: The feature 'raw string literals' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion9, @"$""""""{new S { Field = """"""Field"""""" }}""""""").WithArguments("raw string literals", "11.0").WithLocation(3, 11), + // (3,32): error CS8773: Feature 'raw string literals' is not available in C# 9.0. Please use language version 11.0 or greater. // C.M(() => $"""{new S { Field = """Field""" }}"""); - Diagnostic(ErrorCode.ERR_FeatureInPreview, @"""""""Field""""""").WithArguments("raw string literals").WithLocation(3, 32)); + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion9, @"""""""Field""""""").WithArguments("raw string literals", "11.0").WithLocation(3, 32)); } comp = CreateCompilation(source, parseOptions: TestOptions.RegularPreview, targetFramework: TargetFramework.NetCoreApp); @@ -4077,19 +4077,19 @@ static class C if (expression.Contains('+')) { comp.VerifyEmitDiagnostics( - // (5,17): error CS8652: The feature 'raw string literals' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // (5,17): error CS8773: Feature 'raw string literals' is not available in C# 9.0. Please use language version 11.0 or greater. // param = $"""{1}""" + $"""{2}"""; - Diagnostic(ErrorCode.ERR_FeatureInPreview, @"$""""""{1}""""""").WithArguments("raw string literals").WithLocation(5, 17), - // (5,30): error CS8652: The feature 'raw string literals' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion9, @"$""""""{1}""""""").WithArguments("raw string literals", "11.0").WithLocation(5, 17), + // (5,30): error CS8773: Feature 'raw string literals' is not available in C# 9.0. Please use language version 11.0 or greater. // param = $"""{1}""" + $"""{2}"""; - Diagnostic(ErrorCode.ERR_FeatureInPreview, @"$""""""{2}""""""").WithArguments("raw string literals").WithLocation(5, 30)); + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion9, @"$""""""{2}""""""").WithArguments("raw string literals", "11.0").WithLocation(5, 30)); } else { comp.VerifyEmitDiagnostics( - // (5,17): error CS8652: The feature 'raw string literals' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // (5,17): error CS8773: Feature 'raw string literals' is not available in C# 9.0. Please use language version 11.0 or greater. // param = $"""{1}"""; - Diagnostic(ErrorCode.ERR_FeatureInPreview, @"$""""""{1}""""""").WithArguments("raw string literals").WithLocation(5, 17)); + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion9, @"$""""""{1}""""""").WithArguments("raw string literals", "11.0").WithLocation(5, 17)); } comp = CreateCompilation(source, parseOptions: TestOptions.RegularPreview); @@ -11096,16 +11096,10 @@ public ref struct S1 var comp = CreateCompilation(new[] { code, InterpolatedStringHandlerAttribute, InterpolatedStringHandlerArgumentAttribute }, targetFramework: TargetFramework.NetCoreApp); comp.VerifyDiagnostics( // (17,9): error CS8350: This combination of arguments to 'CustomHandler.M2(ref S1, ref CustomHandler)' is disallowed because it may expose variables referenced by parameter 'handler' outside of their declaration scope - // M2(ref s1, $"{s}"); - Diagnostic(ErrorCode.ERR_CallArgMixing, @"M2(ref s1, " + expression + @")").WithArguments("CustomHandler.M2(ref S1, ref CustomHandler)", "handler").WithLocation(17, 9), - // (17,16): error CS8156: An expression cannot be used in this context because it may not be passed or returned by reference // M2(ref s1, $"""{s}""" + $""" - Diagnostic(ErrorCode.ERR_RefReturnLvalueExpected, "s1").WithLocation(17, 16), - // (17,20): error CS8347: Cannot use a result of 'CustomHandler.CustomHandler(int, int, ref S1)' in this context because it may expose variables referenced by parameter 's1' outside of their declaration scope + Diagnostic(ErrorCode.ERR_CallArgMixing, @"M2(ref s1, " + expression + @")").WithArguments("CustomHandler.M2(ref S1, ref CustomHandler)", "handler").WithLocation(17, 9), + // (17,25): error CS8352: Cannot use variable 's' in this context because it may expose referenced variables outside of their declaration scope // M2(ref s1, $"""{s}""" + $""" - Diagnostic(ErrorCode.ERR_EscapeCall, expression).WithArguments("CustomHandler.CustomHandler(int, int, ref S1)", "s1").WithLocation(17, 20), - // (17,23): error CS8352: Cannot use variable 's' in this context because it may expose referenced variables outside of their declaration scope - // M2(ref s1, $"{s}"); Diagnostic(ErrorCode.ERR_EscapeVariable, "s").WithArguments("s").WithLocation(17, 25)); } @@ -11246,9 +11240,12 @@ public static ref CustomHandler M2(ref Span s, [InterpolatedStringHandlerA var comp = CreateCompilation(new[] { code, InterpolatedStringHandlerAttribute, InterpolatedStringHandlerArgumentAttribute }, targetFramework: TargetFramework.NetCoreApp); comp.VerifyDiagnostics( - // (16,16): error CS8352: Cannot use variable 'c' in this context because it may expose referenced variables outside of their declaration scope + // (18,16): error CS8352: Cannot use variable 'c' in this context because it may expose referenced variables outside of their declaration scope // return c; - Diagnostic(ErrorCode.ERR_EscapeVariable, "c").WithArguments("c").WithLocation(18, 16)); + Diagnostic(ErrorCode.ERR_EscapeVariable, "c").WithArguments("c").WithLocation(18, 16), + // (23,20): error CS8166: Cannot return a parameter by reference 'handler' because it is not a ref parameter + // return ref handler; + Diagnostic(ErrorCode.ERR_RefReturnParameter, "handler").WithArguments("handler").WithLocation(23, 20)); } [Fact] @@ -11285,16 +11282,10 @@ public ref struct S1 var comp = CreateCompilation(new[] { code, InterpolatedStringHandlerAttribute, InterpolatedStringHandlerArgumentAttribute }, targetFramework: TargetFramework.NetCoreApp); comp.VerifyDiagnostics( // (15,9): error CS8350: This combination of arguments to 'CustomHandler.M2(ref S1, CustomHandler)' is disallowed because it may expose variables referenced by parameter 'handler' outside of their declaration scope - // M2(ref s1, $"{s2}"); - Diagnostic(ErrorCode.ERR_CallArgMixing, @"M2(ref s1, $""""""{s2}"""""")").WithArguments("CustomHandler.M2(ref S1, CustomHandler)", "handler").WithLocation(15, 9), - // (15,16): error CS8156: An expression cannot be used in this context because it may not be passed or returned by reference // M2(ref s1, $"""{s2}"""); - Diagnostic(ErrorCode.ERR_RefReturnLvalueExpected, "s1").WithLocation(15, 16), - // (15,20): error CS8347: Cannot use a result of 'CustomHandler.CustomHandler(int, int, ref S1)' in this context because it may expose variables referenced by parameter 's1' outside of their declaration scope + Diagnostic(ErrorCode.ERR_CallArgMixing, @"M2(ref s1, $""""""{s2}"""""")").WithArguments("CustomHandler.M2(ref S1, CustomHandler)", "handler").WithLocation(15, 9), + // (15,25): error CS8352: Cannot use variable 's2' in this context because it may expose referenced variables outside of their declaration scope // M2(ref s1, $"""{s2}"""); - Diagnostic(ErrorCode.ERR_EscapeCall, @"$""""""{s2}""""""").WithArguments("CustomHandler.CustomHandler(int, int, ref S1)", "s1").WithLocation(15, 20), - // (15,23): error CS8352: Cannot use variable 's2' in this context because it may expose referenced variables outside of their declaration scope - // M2(ref s1, $"{s2}"); Diagnostic(ErrorCode.ERR_EscapeVariable, "s2").WithArguments("s2").WithLocation(15, 25)); } @@ -11324,13 +11315,7 @@ static void M(ref S s, [InterpolatedStringHandlerArgument(""s"")] CustomHandler }"; var comp = CreateCompilation(new[] { code, InterpolatedStringHandlerAttribute, InterpolatedStringHandlerArgumentAttribute }, targetFramework: TargetFramework.NetCoreApp); - comp.VerifyDiagnostics( - // (17,15): error CS8156: An expression cannot be used in this context because it may not be passed or returned by reference - // M(ref s, $"""{1}"""); - Diagnostic(ErrorCode.ERR_RefReturnLvalueExpected, "s").WithLocation(17, 15), - // (17,18): error CS8347: Cannot use a result of 'CustomHandler.CustomHandler(int, int, ref S)' in this context because it may expose variables referenced by parameter 's' outside of their declaration scope - // M(ref s, $"""{1}"""); - Diagnostic(ErrorCode.ERR_EscapeCall, @"$""""""{1}""""""").WithArguments("CustomHandler.CustomHandler(int, int, ref S)", "s").WithLocation(17, 18)); + comp.VerifyDiagnostics(); } [Theory, WorkItem(54703, "https://github.com/dotnet/roslyn/issues/54703")] diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/RecordStructTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/RecordStructTests.cs index 3e2e401936dab..3a0819e077485 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/RecordStructTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/RecordStructTests.cs @@ -1947,15 +1947,15 @@ public static void Main() }"; var comp = CreateCompilation(new[] { src, IsExternalInitTypeDefinition }, parseOptions: TestOptions.Regular10); comp.VerifyEmitDiagnostics( - // (3,15): error CS0843: Auto-implemented property 'C.X' must be fully assigned before control is returned to the caller. Consider updating to language version 'preview' to auto-default the property. + // (3,15): error CS0843: Auto-implemented property 'C.X' must be fully assigned before control is returned to the caller. Consider updating to language version '11.0' to auto-default the property. // record struct C(int X, int Y) - Diagnostic(ErrorCode.ERR_UnassignedThisAutoPropertyUnsupportedVersion, "C").WithArguments("C.X", "preview").WithLocation(3, 15), + Diagnostic(ErrorCode.ERR_UnassignedThisAutoPropertyUnsupportedVersion, "C").WithArguments("C.X", "11.0").WithLocation(3, 15), // (3,21): warning CS8907: Parameter 'X' is unread. Did you forget to use it to initialize the property with that name? // record struct C(int X, int Y) Diagnostic(ErrorCode.WRN_UnreadRecordParameter, "X").WithArguments("X").WithLocation(3, 21) ); - var verifier = CompileAndVerify(src, parseOptions: TestOptions.RegularNext); + var verifier = CompileAndVerify(src, parseOptions: TestOptions.Regular11); verifier.VerifyDiagnostics( // (3,21): warning CS8907: Parameter 'X' is unread. Did you forget to use it to initialize the property with that name? // record struct C(int X, int Y) @@ -2211,18 +2211,18 @@ record struct C1(object O1, object O2, object O3) // 1, 2 "; var comp = CreateCompilation(new[] { source, IsExternalInitTypeDefinition }, parseOptions: TestOptions.Regular10); comp.VerifyDiagnostics( - // (2,15): error CS0843: Auto-implemented property 'C1.O1' must be fully assigned before control is returned to the caller. Consider updating to language version 'preview' to auto-default the property. - // record struct C1(object O1, object O2, object O3) // 1, 2 - Diagnostic(ErrorCode.ERR_UnassignedThisAutoPropertyUnsupportedVersion, "C1").WithArguments("C1.O1", "preview").WithLocation(2, 15), - // (2,25): warning CS8907: Parameter 'O1' is unread. Did you forget to use it to initialize the property with that name? - // record struct C1(object O1, object O2, object O3) // 1, 2 - Diagnostic(ErrorCode.WRN_UnreadRecordParameter, "O1").WithArguments("O1").WithLocation(2, 25), - // (2,47): warning CS8907: Parameter 'O3' is unread. Did you forget to use it to initialize the property with that name? - // record struct C1(object O1, object O2, object O3) // 1, 2 - Diagnostic(ErrorCode.WRN_UnreadRecordParameter, "O3").WithArguments("O3").WithLocation(2, 47) - ); - - var verifier = CompileAndVerify(new[] { source, IsExternalInitTypeDefinition }, parseOptions: TestOptions.RegularNext, verify: Verification.Skipped); + // (2,15): error CS0843: Auto-implemented property 'C1.O1' must be fully assigned before control is returned to the caller. Consider updating to language version '11.0' to auto-default the property. + // record struct C1(object O1, object O2, object O3) // 1, 2 + Diagnostic(ErrorCode.ERR_UnassignedThisAutoPropertyUnsupportedVersion, "C1").WithArguments("C1.O1", "11.0").WithLocation(2, 15), + // (2,25): warning CS8907: Parameter 'O1' is unread. Did you forget to use it to initialize the property with that name? + // record struct C1(object O1, object O2, object O3) // 1, 2 + Diagnostic(ErrorCode.WRN_UnreadRecordParameter, "O1").WithArguments("O1").WithLocation(2, 25), + // (2,47): warning CS8907: Parameter 'O3' is unread. Did you forget to use it to initialize the property with that name? + // record struct C1(object O1, object O2, object O3) // 1, 2 + Diagnostic(ErrorCode.WRN_UnreadRecordParameter, "O3").WithArguments("O3").WithLocation(2, 47) + ); + + var verifier = CompileAndVerify(new[] { source, IsExternalInitTypeDefinition }, parseOptions: TestOptions.Regular11, verify: Verification.Skipped); verifier.VerifyDiagnostics( // (2,25): warning CS8907: Parameter 'O1' is unread. Did you forget to use it to initialize the property with that name? // record struct C1(object O1, object O2, object O3) // 1, 2 @@ -2893,15 +2893,15 @@ public static void Main() "; var comp = CreateCompilation(new[] { src, IsExternalInitTypeDefinition }, parseOptions: TestOptions.Regular10); comp.VerifyDiagnostics( - // (2,15): error CS0843: Auto-implemented property 'R.P' must be fully assigned before control is returned to the caller. Consider updating to language version 'preview' to auto-default the property. + // (2,15): error CS0843: Auto-implemented property 'R.P' must be fully assigned before control is returned to the caller. Consider updating to language version '11.0' to auto-default the property. // record struct R(int P = 42) - Diagnostic(ErrorCode.ERR_UnassignedThisAutoPropertyUnsupportedVersion, "R").WithArguments("R.P", "preview").WithLocation(2, 15), + Diagnostic(ErrorCode.ERR_UnassignedThisAutoPropertyUnsupportedVersion, "R").WithArguments("R.P", "11.0").WithLocation(2, 15), // (2,21): warning CS8907: Parameter 'P' is unread. Did you forget to use it to initialize the property with that name? // record struct R(int P = 42) Diagnostic(ErrorCode.WRN_UnreadRecordParameter, "P").WithArguments("P").WithLocation(2, 21) ); - var verifier = CompileAndVerify(new[] { src, IsExternalInitTypeDefinition }, parseOptions: TestOptions.RegularNext, verify: Verification.Skipped); + var verifier = CompileAndVerify(new[] { src, IsExternalInitTypeDefinition }, parseOptions: TestOptions.Regular11, verify: Verification.Skipped); verifier.VerifyDiagnostics( // (2,21): warning CS8907: Parameter 'P' is unread. Did you forget to use it to initialize the property with that name? // record struct R(int P = 42) @@ -3933,7 +3933,7 @@ public void Deconstruct_UserDefined_Accessibility_07(string accessibility) $@" record struct A(int X) {{ - { accessibility } void Deconstruct(out int a) + {accessibility} void Deconstruct(out int a) => throw null; }} "; @@ -4001,15 +4001,15 @@ record struct Pos2(int X) "; var comp = CreateCompilation(source, parseOptions: TestOptions.Regular10); comp.VerifyEmitDiagnostics( - // (2,15): error CS0171: Field 'Pos.x' must be fully assigned before control is returned to the caller. Consider updating to language version 'preview' to auto-default the field. + // (2,15): error CS0171: Field 'Pos.x' must be fully assigned before control is returned to the caller. Consider updating to language version '11.0' to auto-default the field. // record struct Pos(int X) - Diagnostic(ErrorCode.ERR_UnassignedThisUnsupportedVersion, "Pos").WithArguments("Pos.x", "preview").WithLocation(2, 15), + Diagnostic(ErrorCode.ERR_UnassignedThisUnsupportedVersion, "Pos").WithArguments("Pos.x", "11.0").WithLocation(2, 15), // (5,16): error CS8050: Only auto-implemented properties can have initializers. // public int X { get { return x; } set { x = value; } } = X; Diagnostic(ErrorCode.ERR_InitializerOnNonAutoProperty, "X").WithLocation(5, 16) ); - comp = CreateCompilation(source, parseOptions: TestOptions.RegularNext); + comp = CreateCompilation(source, parseOptions: TestOptions.Regular11); comp.VerifyEmitDiagnostics( // (5,16): error CS8050: Only auto-implemented properties can have initializers. // public int X { get { return x; } set { x = value; } } = X; @@ -4241,7 +4241,7 @@ public void RecordEquals_10(string accessibility) $@" record struct A {{ - { accessibility } bool Equals(A x) + {accessibility} bool Equals(A x) => throw null; bool System.IEquatable.Equals(A x) => throw null; @@ -4271,7 +4271,7 @@ public void RecordEquals_11(string accessibility) $@" record struct A {{ - { accessibility } bool Equals(A x) + {accessibility} bool Equals(A x) => throw null; bool System.IEquatable.Equals(A x) => throw null; @@ -7527,12 +7527,12 @@ record struct C var comp = CreateCompilation(src, parseOptions: TestOptions.Regular10); comp.VerifyDiagnostics( - // (8,13): error CS0188: The 'this' object cannot be used before all of its fields have been assigned. Consider updating to language version 'preview' to auto-default the unassigned fields. + // (8,13): error CS0188: The 'this' object cannot be used before all of its fields have been assigned. Consider updating to language version '11.0' to auto-default the unassigned fields. // _ = this with { X = 42 }; // 1 - Diagnostic(ErrorCode.ERR_UseDefViolationThisUnsupportedVersion, "this").WithArguments("preview").WithLocation(8, 13) + Diagnostic(ErrorCode.ERR_UseDefViolationThisUnsupportedVersion, "this").WithArguments("11.0").WithLocation(8, 13) ); - var verifier = CompileAndVerify(src, parseOptions: TestOptions.RegularNext); + var verifier = CompileAndVerify(src, parseOptions: TestOptions.Regular11); verifier.VerifyDiagnostics(); verifier.VerifyIL("C..ctor(string)", @" { @@ -7942,12 +7942,14 @@ public ref struct S2 ); } - [Fact] - public void WithExprOnStruct_OnRefStruct_ReceiverMayWrap() + [Theory] + [InlineData(LanguageVersion.CSharp10)] + [InlineData(LanguageVersion.CSharp11)] + public void WithExprOnStruct_OnRefStruct_ReceiverMayWrap(LanguageVersion languageVersion) { // Similar to test LocalWithNoInitializerEscape but wrapping method is used as receiver for `with` expression - var text = @" -using System; + var text = @"using System; +using System.Diagnostics.CodeAnalysis; class Program { static void Main() @@ -7957,7 +7959,7 @@ static void Main() sp = MayWrap(ref local) with { }; // 1, 2 } - static S1 MayWrap(ref Span arg) + static S1 MayWrap([UnscopedRef] ref Span arg) { return default; } @@ -7968,7 +7970,8 @@ ref struct S1 } } "; - CreateCompilationWithMscorlibAndSpan(text, parseOptions: TestOptions.Regular10).VerifyDiagnostics( + var comp = CreateCompilationWithMscorlibAndSpan(new[] { text, UnscopedRefAttributeDefinition }, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion)); + comp.VerifyDiagnostics( // (9,26): error CS8352: Cannot use variable 'local' in this context because it may expose referenced variables outside of their declaration scope // sp = MayWrap(ref local) with { }; // 1, 2 Diagnostic(ErrorCode.ERR_EscapeVariable, "local").WithArguments("local").WithLocation(9, 26), @@ -7976,15 +7979,6 @@ ref struct S1 // sp = MayWrap(ref local) with { }; // 1, 2 Diagnostic(ErrorCode.ERR_EscapeCall, "MayWrap(ref local)").WithArguments("Program.MayWrap(ref System.Span)", "arg").WithLocation(9, 14) ); - - CreateCompilationWithMscorlibAndSpan(text, parseOptions: TestOptions.RegularPreview).VerifyDiagnostics( - // (9,26): error CS8168: Cannot return local 'local' by reference because it is not a ref local - // sp = MayWrap(ref local) with { }; // 1, 2 - Diagnostic(ErrorCode.ERR_RefReturnLocal, "local").WithArguments("local").WithLocation(9, 26), - // (9,14): error CS8347: Cannot use a result of 'Program.MayWrap(ref Span)' in this context because it may expose variables referenced by parameter 'arg' outside of their declaration scope - // sp = MayWrap(ref local) with { }; // 1, 2 - Diagnostic(ErrorCode.ERR_EscapeCall, "MayWrap(ref local)").WithArguments("Program.MayWrap(ref System.Span)", "arg").WithLocation(9, 14) - ); } [Fact] @@ -11238,9 +11232,9 @@ public void ExplicitConstructors_10() }"; var comp = CreateCompilation(source, parseOptions: TestOptions.Regular10); comp.VerifyDiagnostics( - // (1,15): error CS0171: Field 'S.F' must be fully assigned before control is returned to the caller. Consider updating to language version 'preview' to auto-default the field. + // (1,15): error CS0171: Field 'S.F' must be fully assigned before control is returned to the caller. Consider updating to language version '11.0' to auto-default the field. // record struct S(object F) - Diagnostic(ErrorCode.ERR_UnassignedThisUnsupportedVersion, "S").WithArguments("S.F", "preview").WithLocation(1, 15), + Diagnostic(ErrorCode.ERR_UnassignedThisUnsupportedVersion, "S").WithArguments("S.F", "11.0").WithLocation(1, 15), // (1,24): warning CS8907: Parameter 'F' is unread. Did you forget to use it to initialize the property with that name? // record struct S(object F) Diagnostic(ErrorCode.WRN_UnreadRecordParameter, "F").WithArguments("F").WithLocation(1, 24), @@ -11248,7 +11242,7 @@ public void ExplicitConstructors_10() // public S(int i) : this() { F = i; } Diagnostic(ErrorCode.ERR_RecordStructConstructorCallsDefaultConstructor, "this").WithLocation(4, 23)); - comp = CreateCompilation(source, parseOptions: TestOptions.RegularNext); + comp = CreateCompilation(source, parseOptions: TestOptions.Regular11); comp.VerifyDiagnostics( // (1,24): warning CS8907: Parameter 'F' is unread. Did you forget to use it to initialize the property with that name? // record struct S(object F) diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/RecordTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/RecordTests.cs index 56aa2d491abbd..a4a057e66f280 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/RecordTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/RecordTests.cs @@ -9707,15 +9707,12 @@ public static void Main() // (9,9): error CS8147: Properties which return by reference cannot have set accessors // set { } Diagnostic(ErrorCode.ERR_RefPropertyCannotHaveSetAccessor, "set").WithLocation(9, 9), - // (15,32): error CS1525: Invalid expression term 'ref' + // (15,28): error CS8373: The left-hand side of a ref assignment must be a ref variable. // var c = new C(0) { X = ref a[0] }; - Diagnostic(ErrorCode.ERR_InvalidExprTerm, "ref a[0]").WithArguments("ref").WithLocation(15, 32), - // (15,32): error CS1073: Unexpected token 'ref' - // var c = new C(0) { X = ref a[0] }; - Diagnostic(ErrorCode.ERR_UnexpectedToken, "ref").WithArguments("ref").WithLocation(15, 32), - // (17,26): error CS1073: Unexpected token 'ref' + Diagnostic(ErrorCode.ERR_RefLocalOrParamExpected, "X").WithLocation(15, 28), + // (17,22): error CS8373: The left-hand side of a ref assignment must be a ref variable. // c = c with { X = ref a[0] }; - Diagnostic(ErrorCode.ERR_UnexpectedToken, "ref").WithArguments("ref").WithLocation(17, 26) + Diagnostic(ErrorCode.ERR_RefLocalOrParamExpected, "X").WithLocation(17, 22) ); } @@ -14009,7 +14006,7 @@ public void CopyCtor_Accessibility_01(string accessibility) $@" record A(int X) {{ - { accessibility } A(A a) + {accessibility} A(A a) => throw null; }} "; @@ -14030,7 +14027,7 @@ public void CopyCtor_Accessibility_02(string accessibility) $@" record A(int X) {{ - { accessibility } A(A a) + {accessibility} A(A a) => System.Console.Write(""RAN""); public static void Main() @@ -14056,7 +14053,7 @@ public void CopyCtor_Accessibility_03(string accessibility) $@" sealed record A(int X) {{ - { accessibility } A(A a) + {accessibility} A(A a) => System.Console.Write(""RAN""); public static void Main() @@ -14089,7 +14086,7 @@ public void CopyCtor_Accessibility_04(string accessibility) $@" sealed record A(int X) {{ - { accessibility } A(A a) + {accessibility} A(A a) => System.Console.Write(""RAN""); public static void Main() @@ -15554,7 +15551,7 @@ public void Deconstruct_UserDefined_Accessibility_07(string accessibility) $@" record A(int X) {{ - { accessibility } void Deconstruct(out int a) + {accessibility} void Deconstruct(out int a) => throw null; }} "; @@ -18443,7 +18440,7 @@ public void RecordEquals_10(string accessibility) $@" record A {{ - { accessibility } virtual bool Equals(A x) + {accessibility} virtual bool Equals(A x) => throw null; bool System.IEquatable.Equals(A x) => throw null; @@ -18469,7 +18466,7 @@ public void RecordEquals_11(string accessibility) $@" record A {{ - { accessibility } virtual bool Equals(A x) + {accessibility} virtual bool Equals(A x) => throw null; bool System.IEquatable.Equals(A x) => throw null; @@ -19004,7 +19001,7 @@ public void EqualityContract_05(string accessibility) $@" record A {{ - { accessibility } virtual System.Type EqualityContract + {accessibility} virtual System.Type EqualityContract => throw null; }} "; @@ -19025,7 +19022,7 @@ public void EqualityContract_06(string accessibility) $@" record A {{ - { accessibility } virtual System.Type EqualityContract + {accessibility} virtual System.Type EqualityContract => throw null; bool System.IEquatable.Equals(A x) => throw null; diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/RefEscapingTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/RefEscapingTests.cs index c4e52654972b2..544b98f972170 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/RefEscapingTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/RefEscapingTests.cs @@ -163,9 +163,10 @@ void M() Diagnostic(ErrorCode.ERR_LockNeedsReference, "s").WithArguments("System.Span").WithLocation(9, 15)); } - [Fact] - public void RefStructEscapeInIterator() - + [Theory] + [InlineData(LanguageVersion.CSharp10)] + [InlineData(LanguageVersion.CSharp11)] + public void RefStructEscapeInIterator(LanguageVersion languageVersion) { var comp = CreateCompilationWithMscorlibAndSpan(@" using System; @@ -177,18 +178,20 @@ IEnumerable Gen() Span s = stackalloc int[10]; yield return s; } -}"); +}", parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion)); comp.VerifyDiagnostics( // (9,22): error CS8352: Cannot use variable 's' in this context because it may expose referenced variables outside of their declaration scope // yield return s; Diagnostic(ErrorCode.ERR_EscapeVariable, "s").WithArguments("s").WithLocation(9, 22)); } - [Fact()] - public void RefLikeReturnEscape() + [Theory] + [InlineData(LanguageVersion.CSharp10)] + [InlineData(LanguageVersion.CSharp11)] + public void RefLikeReturnEscape(LanguageVersion languageVersion) { - var text = @" - using System; + var text = @"using System; + class Program { @@ -217,7 +220,8 @@ ref struct S1 } } "; - CreateCompilationWithMscorlibAndSpan(text, parseOptions: TestOptions.Regular10).VerifyDiagnostics( + var comp = CreateCompilationWithMscorlibAndSpan(text, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion)); + comp.VerifyDiagnostics( // (23,42): error CS8526: Cannot use variable 'local' in this context because it may expose referenced variables outside of their declaration scope // return ref Test1(MayWrap(ref local)); Diagnostic(ErrorCode.ERR_EscapeVariable, "local").WithArguments("local").WithLocation(23, 42), @@ -228,24 +232,12 @@ ref struct S1 // return ref Test1(MayWrap(ref local)); Diagnostic(ErrorCode.ERR_EscapeCall, "Test1(MayWrap(ref local))").WithArguments("Program.Test1(Program.S1)", "arg").WithLocation(23, 24) ); - - // C#11 reports ERR_RefReturnLocal rather than ERR_EscapeVariable for 'local' because CheckInvocationEscape() - // checks for ref-safe-to-escape of 'local' since it is passed as a 'ref' parameter to a method returning a ref struct. - CreateCompilationWithMscorlibAndSpan(text).VerifyDiagnostics( - // (23,42): error CS8168: Cannot return local 'local' by reference because it is not a ref local - // return ref Test1(MayWrap(ref local)); - Diagnostic(ErrorCode.ERR_RefReturnLocal, "local").WithArguments("local").WithLocation(23, 42), - // (23,30): error CS8347: Cannot use a result of 'Program.MayWrap(ref Span)' in this context because it may expose variables referenced by parameter 'arg' outside of their declaration scope - // return ref Test1(MayWrap(ref local)); - Diagnostic(ErrorCode.ERR_EscapeCall, "MayWrap(ref local)").WithArguments("Program.MayWrap(ref System.Span)", "arg").WithLocation(23, 30), - // (23,24): error CS8347: Cannot use a result of 'Program.Test1(Program.S1)' in this context because it may expose variables referenced by parameter 'arg' outside of their declaration scope - // return ref Test1(MayWrap(ref local)); - Diagnostic(ErrorCode.ERR_EscapeCall, "Test1(MayWrap(ref local))").WithArguments("Program.Test1(Program.S1)", "arg").WithLocation(23, 24) - ); } - [Fact()] - public void RefLikeReturnEscape1() + [Theory] + [InlineData(LanguageVersion.CSharp10)] + [InlineData(LanguageVersion.CSharp11)] + public void RefLikeReturnEscape1(LanguageVersion languageVersion) { var text = @" using System; @@ -278,7 +270,7 @@ ref struct S1 } } "; - CreateCompilationWithMscorlibAndSpan(text).VerifyDiagnostics( + CreateCompilationWithMscorlibAndSpan(text, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion)).VerifyDiagnostics( // (24,30): error CS8526: Cannot use variable 'sp' in this context because it may expose referenced variables outside of their declaration scope // return ref Test1(sp); Diagnostic(ErrorCode.ERR_EscapeVariable, "sp").WithArguments("sp").WithLocation(24, 30), @@ -288,7 +280,7 @@ ref struct S1 ); } - [Fact()] + [Fact] public void RefLikeReturnEscapeWithRefLikes() { var text = @" @@ -327,7 +319,9 @@ ref struct S1 } } "; - CreateCompilationWithMscorlibAndSpan(text).VerifyDiagnostics( + + var comp = CreateCompilationWithMscorlibAndSpan(text, parseOptions: TestOptions.Regular10); + comp.VerifyDiagnostics( // (23,34): error CS8168: Cannot return local 'sp' by reference because it is not a ref local // return ref Test1(ref sp); // error1 Diagnostic(ErrorCode.ERR_RefReturnLocal, "sp").WithArguments("sp").WithLocation(23, 34), @@ -341,10 +335,23 @@ ref struct S1 // return ref Test1(ref sp); // error2 Diagnostic(ErrorCode.ERR_EscapeCall, "Test1(ref sp)").WithArguments("Program.Test1(ref Program.S1)", "arg").WithLocation(29, 24) ); + + // No error reported for "// error2" in C#11 because no refs are captured in Test4(). + comp = CreateCompilationWithMscorlibAndSpan(text); + comp.VerifyDiagnostics( + // (23,34): error CS8352: Cannot use variable 'sp' in this context because it may expose referenced variables outside of their declaration scope + // return ref Test1(ref sp); // error1 + Diagnostic(ErrorCode.ERR_EscapeVariable, "sp").WithArguments("sp").WithLocation(23, 34), + // (23,24): error CS8347: Cannot use a result of 'Program.Test1(ref Program.S1)' in this context because it may expose variables referenced by parameter 'arg' outside of their declaration scope + // return ref Test1(ref sp); // error1 + Diagnostic(ErrorCode.ERR_EscapeCall, "Test1(ref sp)").WithArguments("Program.Test1(ref Program.S1)", "arg").WithLocation(23, 24) + ); } - [Fact()] - public void RefLikeReturnEscapeWithRefLikes1() + [Theory] + [InlineData(LanguageVersion.CSharp10)] + [InlineData(LanguageVersion.CSharp11)] + public void RefLikeReturnEscapeWithRefLikes1(LanguageVersion languageVersion) { var text = @" using System; @@ -392,7 +399,8 @@ ref struct S1 } } "; - CreateCompilationWithMscorlibAndSpan(text, parseOptions: TestOptions.Regular10).VerifyDiagnostics( + var comp = CreateCompilationWithMscorlibAndSpan(text, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion)); + comp.VerifyDiagnostics( // (33,19): error CS8526: Cannot use variable 'spNr' in this context because it may expose referenced variables outside of their declaration scope // spR = spNr; Diagnostic(ErrorCode.ERR_EscapeVariable, "spNr").WithArguments("spNr").WithLocation(33, 19), @@ -400,18 +408,15 @@ ref struct S1 // spR = ternary; Diagnostic(ErrorCode.ERR_EscapeVariable, "ternary").WithArguments("ternary").WithLocation(39, 19) ); - - // The initializer for `var spR = MayWrap(Test1(ref sp));` has escape scope of - // the current method in C#11, rather than the calling method in C#10, so `spR` - // is not treated as returnable and there are no subsequent errors as a result. - CreateCompilationWithMscorlibAndSpan(text).VerifyDiagnostics(); } - [Fact()] - public void RefLikeReturnEscapeInParam() + [Theory] + [InlineData(LanguageVersion.CSharp10)] + [InlineData(LanguageVersion.CSharp11)] + public void RefLikeReturnEscapeInParam(LanguageVersion languageVersion) { - var text = @" - using System; + var text = @"using System; + class Program { static void Main() @@ -448,7 +453,8 @@ ref struct S1 } } "; - CreateCompilationWithMscorlibAndSpan(text).VerifyDiagnostics( + var comp = CreateCompilationWithMscorlibAndSpan(text, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion)); + comp.VerifyDiagnostics( // (31,30): error CS8352: Cannot use variable 'sp' in this context because it may expose referenced variables outside of their declaration scope // return ref Test1(sp); Diagnostic(ErrorCode.ERR_EscapeVariable, "sp").WithArguments("sp").WithLocation(31, 30), @@ -508,8 +514,10 @@ ref struct S1 Diagnostic(ErrorCode.ERR_EscapeCall, "MayNotWrap()").WithArguments("Program.MayNotWrap(in int)", "arg").WithLocation(21, 30)); } - [Fact()] - public void RefLikeScopeEscape() + [Theory] + [InlineData(LanguageVersion.CSharp10)] + [InlineData(LanguageVersion.CSharp11)] + public void RefLikeScopeEscape(LanguageVersion languageVersion) { var text = @" using System; @@ -542,7 +550,7 @@ ref struct S1 } } "; - CreateCompilationWithMscorlibAndSpan(text).VerifyDiagnostics( + CreateCompilationWithMscorlibAndSpan(text, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion)).VerifyDiagnostics( // (18,29): error CS8526: Cannot use variable 'inner' in this context because it may expose referenced variables outside of their declaration scope // x = MayWrap(inner); Diagnostic(ErrorCode.ERR_EscapeVariable, "inner").WithArguments("inner").WithLocation(18, 29), @@ -552,8 +560,10 @@ ref struct S1 ); } - [Fact()] - public void RefLikeScopeEscapeVararg() + [Theory] + [InlineData(LanguageVersion.CSharp10)] + [InlineData(LanguageVersion.CSharp11)] + public void RefLikeScopeEscapeVararg(LanguageVersion languageVersion) { var text = @" using System; @@ -586,7 +596,7 @@ ref struct S1 } } "; - CreateCompilationWithMscorlibAndSpan(text).VerifyDiagnostics( + CreateCompilationWithMscorlibAndSpan(text, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion)).VerifyDiagnostics( // (18,35): error CS8352: Cannot use variable 'inner' in this context because it may expose referenced variables outside of their declaration scope // x = MayWrap(__arglist(inner)); Diagnostic(ErrorCode.ERR_EscapeVariable, "inner").WithArguments("inner").WithLocation(18, 35), @@ -596,8 +606,10 @@ ref struct S1 ); } - [Fact()] - public void RefScopeEscapeVararg() + [Theory] + [InlineData(LanguageVersion.CSharp10)] + [InlineData(LanguageVersion.CSharp11)] + public void RefScopeEscapeVararg(LanguageVersion languageVersion) { var text = @" using System; @@ -630,7 +642,7 @@ static ref int ReturnsRefSpan() Span local = stackalloc int[1]; // error here; - return ref ReturnsRef1(__arglist(ref local)); + return ref ReturnsRefSpan1(__arglist(ref local)); } static ref int ReturnsRefSpan1(__arglist) @@ -642,21 +654,23 @@ static ref int ReturnsRefSpan1(__arglist) } } "; - CreateCompilationWithMscorlibAndSpan(text).VerifyDiagnostics( - // (24,20): error CS8156: An expression cannot be used in this context because it may not be returned by reference + CreateCompilationWithMscorlibAndSpan(text, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion)).VerifyDiagnostics( + // (24,20): error CS8156: An expression cannot be used in this context because it may not be passed or returned by reference // return ref __refvalue(ai.GetNextArg(), int); Diagnostic(ErrorCode.ERR_RefReturnLvalueExpected, "__refvalue(ai.GetNextArg(), int)").WithLocation(24, 20), - // (32,46): error CS8352: Cannot use variable 'local' in this context because it may expose referenced variables outside of their declaration scope - // return ref ReturnsRef1(__arglist(ref local)); - Diagnostic(ErrorCode.ERR_EscapeVariable, "local").WithArguments("local").WithLocation(32, 46), - // (32,20): error CS8347: Cannot use a result of 'Program.ReturnsRef1(__arglist)' in this context because it may expose variables referenced by parameter '__arglist' outside of their declaration scope - // return ref ReturnsRef1(__arglist(ref local)); - Diagnostic(ErrorCode.ERR_EscapeCall, "ReturnsRef1(__arglist(ref local))").WithArguments("Program.ReturnsRef1(__arglist)", "__arglist").WithLocation(32, 20) + // (32,50): error CS8352: Cannot use variable 'local' in this context because it may expose referenced variables outside of their declaration scope + // return ref ReturnsRefSpan1(__arglist(ref local)); + Diagnostic(ErrorCode.ERR_EscapeVariable, "local").WithArguments("local").WithLocation(32, 50), + // (32,20): error CS8347: Cannot use a result of 'Program.ReturnsRefSpan1(__arglist)' in this context because it may expose variables referenced by parameter '__arglist' outside of their declaration scope + // return ref ReturnsRefSpan1(__arglist(ref local)); + Diagnostic(ErrorCode.ERR_EscapeCall, "ReturnsRefSpan1(__arglist(ref local))").WithArguments("Program.ReturnsRefSpan1(__arglist)", "__arglist").WithLocation(32, 20) ); } - [Fact()] - public void ThrowExpression() + [Theory] + [InlineData(LanguageVersion.CSharp10)] + [InlineData(LanguageVersion.CSharp11)] + public void ThrowExpression(LanguageVersion languageVersion) { var text = @" using System; @@ -681,12 +695,13 @@ static void Main() } "; - CreateCompilationWithMscorlibAndSpan(text).VerifyDiagnostics(); + CreateCompilationWithMscorlibAndSpan(text, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion)).VerifyDiagnostics(); } - - [Fact()] - public void UserDefinedLogical() + [Theory] + [InlineData(LanguageVersion.CSharp10)] + [InlineData(LanguageVersion.CSharp11)] + public void UserDefinedLogical(LanguageVersion languageVersion) { var text = @" using System; @@ -728,7 +743,7 @@ ref struct S1 } "; - CreateCompilationWithMscorlibAndSpan(text).VerifyDiagnostics( + CreateCompilationWithMscorlibAndSpan(text, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion)).VerifyDiagnostics( // (22,18): error CS8352: Cannot use variable 'local' in this context because it may expose referenced variables outside of their declaration scope // global = local && global; Diagnostic(ErrorCode.ERR_EscapeVariable, "local").WithArguments("local").WithLocation(22, 18), @@ -998,8 +1013,10 @@ static ref Span ReturnsSpan(out Span x) ); } - [Fact()] - public void RefLikeScopeEscapeReturnable() + [Theory] + [InlineData(LanguageVersion.CSharp10)] + [InlineData(LanguageVersion.CSharp11)] + public void RefLikeScopeEscapeReturnable(LanguageVersion languageVersion) { var text = @" using System; @@ -1033,7 +1050,8 @@ ref struct S1 } } "; - CreateCompilationWithMscorlibAndSpan(text, parseOptions: TestOptions.Regular10).VerifyDiagnostics( + var comp = CreateCompilationWithMscorlibAndSpan(text, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion)); + comp.VerifyDiagnostics( // (19,33): error CS8526: Cannot use variable 'inner' in this context because it may expose referenced variables outside of their declaration scope // x = MayWrap(ref inner); Diagnostic(ErrorCode.ERR_EscapeVariable, "inner").WithArguments("inner").WithLocation(19, 33), @@ -1041,27 +1059,12 @@ ref struct S1 // x = MayWrap(ref inner); Diagnostic(ErrorCode.ERR_EscapeCall, "MayWrap(ref inner)").WithArguments("Program.MayWrap(ref System.Span)", "arg").WithLocation(19, 21) ); - - // Breaking change in C#11 for x = MayWrap(ref outer); because a method invocation that - // returns a ref struct is safe-to-escape from ... the ref-safe-to-escape of all ref arguments. - CreateCompilationWithMscorlibAndSpan(text).VerifyDiagnostics( - // (16,33): error CS8168: Cannot return local 'outer' by reference because it is not a ref local - // x = MayWrap(ref outer); - Diagnostic(ErrorCode.ERR_RefReturnLocal, "outer").WithArguments("outer").WithLocation(16, 33), - // (16,21): error CS8347: Cannot use a result of 'Program.MayWrap(ref Span)' in this context because it may expose variables referenced by parameter 'arg' outside of their declaration scope - // x = MayWrap(ref outer); - Diagnostic(ErrorCode.ERR_EscapeCall, "MayWrap(ref outer)").WithArguments("Program.MayWrap(ref System.Span)", "arg").WithLocation(16, 21), - // (19,33): error CS8168: Cannot return local 'inner' by reference because it is not a ref local - // x = MayWrap(ref inner); - Diagnostic(ErrorCode.ERR_RefReturnLocal, "inner").WithArguments("inner").WithLocation(19, 33), - // (19,21): error CS8347: Cannot use a result of 'Program.MayWrap(ref Span)' in this context because it may expose variables referenced by parameter 'arg' outside of their declaration scope - // x = MayWrap(ref inner); - Diagnostic(ErrorCode.ERR_EscapeCall, "MayWrap(ref inner)").WithArguments("Program.MayWrap(ref System.Span)", "arg").WithLocation(19, 21) - ); } - [Fact()] - public void RefLikeScopeEscapeThis() + [Theory] + [InlineData(LanguageVersion.CSharp10)] + [InlineData(LanguageVersion.CSharp11)] + public void RefLikeScopeEscapeThis(LanguageVersion languageVersion) { var text = @" using System; @@ -1100,7 +1103,8 @@ ref struct S1 } } "; - CreateCompilationWithMscorlibAndSpan(text).VerifyDiagnostics( + var comp = CreateCompilationWithMscorlibAndSpan(text, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion)); + comp.VerifyDiagnostics( // (21,33): error CS8526: Cannot use variable 'inner' in this context because it may expose referenced variables outside of their declaration scope // x = MayWrap(ref inner).Slice(1); Diagnostic(ErrorCode.ERR_EscapeVariable, "inner").WithArguments("inner").WithLocation(21, 33), @@ -1110,8 +1114,10 @@ ref struct S1 ); } - [Fact()] - public void RefLikeScopeEscapeThisRef() + [Theory] + [InlineData(LanguageVersion.CSharp10)] + [InlineData(LanguageVersion.CSharp11)] + public void RefLikeScopeEscapeThisRef(LanguageVersion languageVersion) { var text = @" using System; @@ -1155,13 +1161,14 @@ ref struct S1 public ref S1 this[S1 i] => throw null; - public ref S1 ReturnsRefArg(ref S1 arg) => ref arg; + public ref S1 ReturnsRefArg([System.Diagnostics.CodeAnalysis.UnscopedRef] ref S1 arg) => throw null; public S1 Slice(int x) => this; } } "; - CreateCompilationWithMscorlibAndSpan(text).VerifyDiagnostics( + var comp = CreateCompilationWithMscorlibAndSpan(new[] { text, UnscopedRefAttributeDefinition }, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion)); + comp.VerifyDiagnostics( // (20,32): error CS8352: Cannot use variable 'inner' in this context because it may expose referenced variables outside of their declaration scope // x[0] = MayWrap(ref inner).Slice(1)[0]; Diagnostic(ErrorCode.ERR_EscapeVariable, "inner").WithArguments("inner").WithLocation(20, 32), @@ -1183,8 +1190,10 @@ ref struct S1 ); } - [Fact()] - public void RefLikeScopeEscapeField() + [Theory] + [InlineData(LanguageVersion.CSharp10)] + [InlineData(LanguageVersion.CSharp11)] + public void RefLikeScopeEscapeField(LanguageVersion languageVersion) { var text = @" using System; @@ -1224,7 +1233,7 @@ ref struct S0 } } "; - CreateCompilationWithMscorlibAndSpan(text).VerifyDiagnostics( + CreateCompilationWithMscorlibAndSpan(text, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion)).VerifyDiagnostics( // (18,31): error CS8526: Cannot use variable 'inner' in this context because it may expose referenced variables outside of their declaration scope // x.field = MayWrap(inner).Slice(1).field; Diagnostic(ErrorCode.ERR_EscapeVariable, "inner").WithArguments("inner").WithLocation(18, 31), @@ -1234,8 +1243,10 @@ ref struct S0 ); } - [Fact()] - public void RefLikeEscapeParamsAndTopLevel() + [Theory] + [InlineData(LanguageVersion.CSharp10)] + [InlineData(LanguageVersion.CSharp11)] + public void RefLikeEscapeParamsAndTopLevel(LanguageVersion languageVersion) { var text = @" class Program @@ -1268,13 +1279,15 @@ ref struct S1 } } "; - CreateCompilationWithMscorlibAndSpan(text).VerifyDiagnostics( + CreateCompilationWithMscorlibAndSpan(text, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion)).VerifyDiagnostics( // no diagnostics expected ); } - [Fact()] - public void RefLikeEscapeMixingCallSameArgValue() + [Theory] + [InlineData(LanguageVersion.CSharp10)] + [InlineData(LanguageVersion.CSharp11)] + public void RefLikeEscapeMixingCallSameArgValue(LanguageVersion languageVersion) { var text = @" using System; @@ -1315,11 +1328,13 @@ public ref struct S1 } } "; - CreateCompilationWithMscorlibAndSpan(text).VerifyDiagnostics(); + CreateCompilationWithMscorlibAndSpan(text, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion)).VerifyDiagnostics(); } - [Fact()] - public void RefLikeEscapeMixingCall() + [Theory] + [InlineData(LanguageVersion.CSharp10)] + [InlineData(LanguageVersion.CSharp11)] + public void RefLikeEscapeMixingCall(LanguageVersion languageVersion) { var text = @" using System; @@ -1366,7 +1381,9 @@ ref struct S1 } } "; - CreateCompilationWithMscorlibAndSpan(text).VerifyDiagnostics( + + var comp = CreateCompilationWithMscorlibAndSpan(text, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion)); + comp.VerifyDiagnostics( // (20,39): error CS8526: Cannot use variable 'rInner' in this context because it may expose referenced variables outside of their declaration scope // MayAssign(ref rOuter, ref rInner); Diagnostic(ErrorCode.ERR_EscapeVariable, "rInner").WithArguments("rInner").WithLocation(20, 39), @@ -1382,7 +1399,7 @@ ref struct S1 ); } - [Fact()] + [Fact] public void RefLikeEscapeMixingCallVararg() { var text = @" @@ -1440,6 +1457,7 @@ ref struct S1 } } "; + CreateCompilationWithMscorlibAndSpan(text, parseOptions: TestOptions.Regular10).VerifyDiagnostics( // (20,46): error CS8352: Cannot use variable 'rInner' in this context because it may expose referenced variables outside of their declaration scope // MayAssign2(__arglist(ref rOuter, ref rInner)); @@ -1455,10 +1473,15 @@ ref struct S1 Diagnostic(ErrorCode.ERR_CallArgMixing, "MayAssign1(__arglist(ref inner, ref rOuter))").WithArguments("Program.MayAssign1(__arglist)", "__arglist").WithLocation(23, 9) ); - // Breaking change in C#11 for arg2 = MayWrap(ref arg1); because a method invocation that - // returns a ref struct is safe-to-escape from ... the ref-safe-to-escape of all ref arguments, - // and arg2 is initialized with __refvalue which has ref-safe-to-escape of the current method. + // Breaking change in C#11: A ref to ref struct argument is considered + // an unscoped reference when passed to an __arglist. CreateCompilationWithMscorlibAndSpan(text).VerifyDiagnostics( + // (17,34): error CS8168: Cannot return local 'rOuter' by reference because it is not a ref local + // MayAssign2(__arglist(ref rOuter, ref rOuter)); + Diagnostic(ErrorCode.ERR_RefReturnLocal, "rOuter").WithArguments("rOuter").WithLocation(17, 34), + // (17,9): error CS8350: This combination of arguments to 'Program.MayAssign2(__arglist)' is disallowed because it may expose variables referenced by parameter '__arglist' outside of their declaration scope + // MayAssign2(__arglist(ref rOuter, ref rOuter)); + Diagnostic(ErrorCode.ERR_CallArgMixing, "MayAssign2(__arglist(ref rOuter, ref rOuter))").WithArguments("Program.MayAssign2(__arglist)", "__arglist").WithLocation(17, 9), // (20,46): error CS8352: Cannot use variable 'rInner' in this context because it may expose referenced variables outside of their declaration scope // MayAssign2(__arglist(ref rOuter, ref rInner)); Diagnostic(ErrorCode.ERR_EscapeVariable, "rInner").WithArguments("rInner").WithLocation(20, 46), @@ -1470,18 +1493,14 @@ ref struct S1 Diagnostic(ErrorCode.ERR_EscapeVariable, "inner").WithArguments("inner").WithLocation(23, 34), // (23,9): error CS8350: This combination of arguments to 'Program.MayAssign1(__arglist)' is disallowed because it may expose variables referenced by parameter '__arglist' outside of their declaration scope // MayAssign1(__arglist(ref inner, ref rOuter)); - Diagnostic(ErrorCode.ERR_CallArgMixing, "MayAssign1(__arglist(ref inner, ref rOuter))").WithArguments("Program.MayAssign1(__arglist)", "__arglist").WithLocation(23, 9), - // (33,28): error CS8157: Cannot return 'arg1' by reference because it was initialized to a value that cannot be returned by reference - // arg2 = MayWrap(ref arg1); - Diagnostic(ErrorCode.ERR_RefReturnNonreturnableLocal, "arg1").WithArguments("arg1").WithLocation(33, 28), - // (33,16): error CS8347: Cannot use a result of 'Program.MayWrap(ref Span)' in this context because it may expose variables referenced by parameter 'arg' outside of their declaration scope - // arg2 = MayWrap(ref arg1); - Diagnostic(ErrorCode.ERR_EscapeCall, "MayWrap(ref arg1)").WithArguments("Program.MayWrap(ref System.Span)", "arg").WithLocation(33, 16) + Diagnostic(ErrorCode.ERR_CallArgMixing, "MayAssign1(__arglist(ref inner, ref rOuter))").WithArguments("Program.MayAssign1(__arglist)", "__arglist").WithLocation(23, 9) ); } - [Fact()] - public void RefLikeEscapeMixingIndex() + [Theory] + [InlineData(LanguageVersion.CSharp10)] + [InlineData(LanguageVersion.CSharp11)] + public void RefLikeEscapeMixingIndex(LanguageVersion languageVersion) { var text = @" class Program @@ -1537,13 +1556,15 @@ ref struct S1 } } "; - CreateCompilationWithMscorlibAndSpan(text).VerifyDiagnostics( + CreateCompilationWithMscorlibAndSpan(text, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion)).VerifyDiagnostics( // no diagnostics ); } - [Fact()] - public void RefLikeEscapeMixingIndexOnRefLike() + [Theory] + [InlineData(LanguageVersion.CSharp10)] + [InlineData(LanguageVersion.CSharp11)] + public void RefLikeEscapeMixingIndexOnRefLike(LanguageVersion languageVersion) { var text = @" using System; @@ -1609,24 +1630,27 @@ public int this[in S1 arg1] } } "; - CreateCompilationWithMscorlibAndSpan(text).VerifyDiagnostics( - // (24,29): error CS8526: Cannot use variable 'rInner' in this context because it may expose referenced variables outside of their declaration scope + var comp = CreateCompilationWithMscorlibAndSpan(text, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion)); + comp.VerifyDiagnostics( + // (24,29): error CS8352: Cannot use variable 'rInner' in this context because it may expose referenced variables outside of their declaration scope // int dummy3 = rOuter[rInner]; Diagnostic(ErrorCode.ERR_EscapeVariable, "rInner").WithArguments("rInner").WithLocation(24, 29), - // (24,22): error CS8524: This combination of arguments to 'Program.S1.this[in Program.S1]' is disallowed because it may expose variables referenced by parameter 'arg1' outside of their declaration scope + // (24,22): error CS8350: This combination of arguments to 'Program.S1.this[in Program.S1]' is disallowed because it may expose variables referenced by parameter 'arg1' outside of their declaration scope // int dummy3 = rOuter[rInner]; Diagnostic(ErrorCode.ERR_CallArgMixing, "rOuter[rInner]").WithArguments("Program.S1.this[in Program.S1]", "arg1").WithLocation(24, 22), - // (27,29): error CS8526: Cannot use variable 'inner' in this context because it may expose referenced variables outside of their declaration scope + // (27,29): error CS8352: Cannot use variable 'inner' in this context because it may expose referenced variables outside of their declaration scope // int dummy4 = rOuter[inner]; Diagnostic(ErrorCode.ERR_EscapeVariable, "inner").WithArguments("inner").WithLocation(27, 29), - // (27,22): error CS8524: This combination of arguments to 'Program.S1.this[in Span]' is disallowed because it may expose variables referenced by parameter 'arg1' outside of their declaration scope + // (27,22): error CS8350: This combination of arguments to 'Program.S1.this[in Span]' is disallowed because it may expose variables referenced by parameter 'arg1' outside of their declaration scope // int dummy4 = rOuter[inner]; Diagnostic(ErrorCode.ERR_CallArgMixing, "rOuter[inner]").WithArguments("Program.S1.this[in System.Span]", "arg1").WithLocation(27, 22) ); } - [Fact()] - public void RefLikeEscapeMixingCtor() + [Theory] + [InlineData(LanguageVersion.CSharp10)] + [InlineData(LanguageVersion.CSharp11)] + public void RefLikeEscapeMixingCtor(LanguageVersion languageVersion) { var text = @" using System; @@ -1679,24 +1703,27 @@ ref struct S1 } } "; - CreateCompilationWithMscorlibAndSpan(text).VerifyDiagnostics( - // (26,43): error CS8526: Cannot use variable 'rInner' in this context because it may expose referenced variables outside of their declaration scope + var comp = CreateCompilationWithMscorlibAndSpan(text, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion)); + comp.VerifyDiagnostics( + // (26,43): error CS8352: Cannot use variable 'rInner' in this context because it may expose referenced variables outside of their declaration scope // MayAssignDel1(ref rOuter, ref rInner); Diagnostic(ErrorCode.ERR_EscapeVariable, "rInner").WithArguments("rInner").WithLocation(26, 43), - // (26,13): error CS8524: This combination of arguments to 'Program.D1.Invoke(ref Program.S1, ref Program.S1)' is disallowed because it may expose variables referenced by parameter 'arg2' outside of their declaration scope + // (26,13): error CS8350: This combination of arguments to 'Program.D1.Invoke(ref Program.S1, ref Program.S1)' is disallowed because it may expose variables referenced by parameter 'arg2' outside of their declaration scope // MayAssignDel1(ref rOuter, ref rInner); Diagnostic(ErrorCode.ERR_CallArgMixing, "MayAssignDel1(ref rOuter, ref rInner)").WithArguments("Program.D1.Invoke(ref Program.S1, ref Program.S1)", "arg2").WithLocation(26, 13), - // (29,31): error CS8526: Cannot use variable 'inner' in this context because it may expose referenced variables outside of their declaration scope + // (29,31): error CS8352: Cannot use variable 'inner' in this context because it may expose referenced variables outside of their declaration scope // MayAssignDel2(ref inner, ref rOuter); Diagnostic(ErrorCode.ERR_EscapeVariable, "inner").WithArguments("inner").WithLocation(29, 31), - // (29,13): error CS8524: This combination of arguments to 'Program.D2.Invoke(ref Span, ref Program.S1)' is disallowed because it may expose variables referenced by parameter 'arg1' outside of their declaration scope + // (29,13): error CS8350: This combination of arguments to 'Program.D2.Invoke(ref Span, ref Program.S1)' is disallowed because it may expose variables referenced by parameter 'arg1' outside of their declaration scope // MayAssignDel2(ref inner, ref rOuter); Diagnostic(ErrorCode.ERR_CallArgMixing, "MayAssignDel2(ref inner, ref rOuter)").WithArguments("Program.D2.Invoke(ref System.Span, ref Program.S1)", "arg1").WithLocation(29, 13) ); } - [Fact()] - public void RefLikeObjInitializers() + [Theory] + [InlineData(LanguageVersion.CSharp10)] + [InlineData(LanguageVersion.CSharp11)] + public void RefLikeObjInitializers(LanguageVersion languageVersion) { var text = @" using System; @@ -1749,7 +1776,7 @@ public ref struct S2 } } "; - CreateCompilationWithMscorlibAndSpan(text).VerifyDiagnostics( + CreateCompilationWithMscorlibAndSpan(text, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion)).VerifyDiagnostics( // (16,47): error CS8352: Cannot use variable 'inner' in this context because it may expose referenced variables outside of their declaration scope // return new S2() { Field1 = outer, Field2 = inner }; Diagnostic(ErrorCode.ERR_EscapeVariable, "Field2 = inner").WithArguments("inner").WithLocation(16, 47), @@ -1759,8 +1786,10 @@ public ref struct S2 ); } - [Fact()] - public void RefLikeObjInitializers1() + [Theory] + [InlineData(LanguageVersion.CSharp10)] + [InlineData(LanguageVersion.CSharp11)] + public void RefLikeObjInitializers1(LanguageVersion languageVersion) { var text = @" using System; @@ -1816,7 +1845,7 @@ public ref struct S2 } } "; - CreateCompilationWithMscorlibAndSpan(text).VerifyDiagnostics( + CreateCompilationWithMscorlibAndSpan(text, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion)).VerifyDiagnostics( // (18,20): error CS8352: Cannot use variable 'x1' in this context because it may expose referenced variables outside of their declaration scope // return x1; Diagnostic(ErrorCode.ERR_EscapeVariable, "x1").WithArguments("x1").WithLocation(18, 20), @@ -1826,8 +1855,10 @@ public ref struct S2 ); } - [Fact()] - public void RefLikeObjInitializersIndexer() + [Theory] + [InlineData(LanguageVersion.CSharp10)] + [InlineData(LanguageVersion.CSharp11)] + public void RefLikeObjInitializersIndexer(LanguageVersion languageVersion) { var text = @" using System; @@ -1889,7 +1920,7 @@ public S1 this[S1 i] } } "; - CreateCompilationWithMscorlibAndSpan(text).VerifyDiagnostics( + CreateCompilationWithMscorlibAndSpan(text, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion)).VerifyDiagnostics( // (16,28): error CS8352: Cannot use variable 'inner' in this context because it may expose referenced variables outside of their declaration scope // return new S2() { [inner] = outer, Field2 = outer }; Diagnostic(ErrorCode.ERR_EscapeVariable, "inner").WithArguments("inner").WithLocation(16, 28), @@ -1899,8 +1930,10 @@ public S1 this[S1 i] ); } - [Fact()] - public void RefLikeObjInitializersIndexer1() + [Theory] + [InlineData(LanguageVersion.CSharp10)] + [InlineData(LanguageVersion.CSharp11)] + public void RefLikeObjInitializersIndexer1(LanguageVersion languageVersion) { var text = @" using System; @@ -1971,7 +2004,7 @@ public S1 this[S1 i] } } "; - CreateCompilationWithMscorlibAndSpan(text).VerifyDiagnostics( + CreateCompilationWithMscorlibAndSpan(text, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion)).VerifyDiagnostics( // (18,16): error CS8352: Cannot use variable 'x1' in this context because it may expose referenced variables outside of their declaration scope // return x1; Diagnostic(ErrorCode.ERR_EscapeVariable, "x1").WithArguments("x1").WithLocation(18, 16), @@ -1981,8 +2014,10 @@ public S1 this[S1 i] ); } - [Fact()] - public void RefLikeObjInitializersNested() + [Theory] + [InlineData(LanguageVersion.CSharp10)] + [InlineData(LanguageVersion.CSharp11)] + public void RefLikeObjInitializersNested(LanguageVersion languageVersion) { var text = @" using System; @@ -2059,7 +2094,7 @@ public ref struct S1 } } "; - CreateCompilationWithMscorlibAndSpan(text).VerifyDiagnostics( + CreateCompilationWithMscorlibAndSpan(text, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion)).VerifyDiagnostics( // (15,38): error CS8352: Cannot use variable 'inner' in this context because it may expose referenced variables outside of their declaration scope // return new S2() { Field2 = {[inner] = outer} }; Diagnostic(ErrorCode.ERR_EscapeVariable, "inner").WithArguments("inner").WithLocation(15, 38), @@ -2075,8 +2110,10 @@ public ref struct S1 ); } - [Fact()] - public void RefLikeColInitializer() + [Theory] + [InlineData(LanguageVersion.CSharp10)] + [InlineData(LanguageVersion.CSharp11)] + public void RefLikeColInitializer(LanguageVersion languageVersion) { var text = @" using System; @@ -2096,11 +2133,13 @@ static void Main() } } "; - CreateCompilationWithMscorlibAndSpan(text).VerifyDiagnostics(); + CreateCompilationWithMscorlibAndSpan(text, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion)).VerifyDiagnostics(); } - [Fact()] - public void RefLikeEscapeMixingDelegate() + [Theory] + [InlineData(LanguageVersion.CSharp10)] + [InlineData(LanguageVersion.CSharp11)] + public void RefLikeEscapeMixingDelegate(LanguageVersion languageVersion) { var text = @" using System; @@ -2147,7 +2186,8 @@ ref struct S1 } } "; - CreateCompilationWithMscorlibAndSpan(text).VerifyDiagnostics( + var comp = CreateCompilationWithMscorlibAndSpan(text, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion)); + comp.VerifyDiagnostics( // (20,54): error CS8526: Cannot use variable 'rInner' in this context because it may expose referenced variables outside of their declaration scope // var dummy2 = new Program(ref rOuter, ref rInner); Diagnostic(ErrorCode.ERR_EscapeVariable, "rInner").WithArguments("rInner").WithLocation(20, 54), @@ -2163,8 +2203,10 @@ ref struct S1 ); } - [Fact()] - public void RefLikeEscapeMixingCallOptionalIn() + [Theory] + [InlineData(LanguageVersion.CSharp10)] + [InlineData(LanguageVersion.CSharp11)] + public void RefLikeEscapeMixingCallOptionalIn(LanguageVersion languageVersion) { var text = @" using System; @@ -2203,11 +2245,13 @@ ref struct S1 } } "; - CreateCompilationWithMscorlibAndSpan(text).VerifyDiagnostics(); + CreateCompilationWithMscorlibAndSpan(text, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion)).VerifyDiagnostics(); } - [Fact()] - public void MismatchedRefTernaryEscape() + [Theory] + [InlineData(LanguageVersion.CSharp10)] + [InlineData(LanguageVersion.CSharp11)] + public void MismatchedRefTernaryEscape(LanguageVersion languageVersion) { var text = @" class Program @@ -2237,7 +2281,7 @@ ref int Test1() } } "; - CreateCompilationWithMscorlibAndSpan(text).VerifyDiagnostics( + CreateCompilationWithMscorlibAndSpan(text, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion)).VerifyDiagnostics( // (17,47): error CS8168: Cannot return local 'local' by reference because it is not a ref local // return ref true ? ref field : ref local; Diagnostic(ErrorCode.ERR_RefReturnLocal, "local").WithArguments("local").WithLocation(17, 47), @@ -2250,8 +2294,10 @@ ref int Test1() ); } - [Fact()] - public void MismatchedRefTernaryEscapeBlock() + [Theory] + [InlineData(LanguageVersion.CSharp10)] + [InlineData(LanguageVersion.CSharp11)] + public void MismatchedRefTernaryEscapeBlock(LanguageVersion languageVersion) { var text = @" using System; @@ -2312,7 +2358,8 @@ ref struct S1 } } "; - CreateCompilationWithMscorlibAndSpan(text).VerifyDiagnostics( + var comp = CreateCompilationWithMscorlibAndSpan(text, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion)); + comp.VerifyDiagnostics( // (27,44): error CS8526: Cannot use variable 'sInner' in this context because it may expose referenced variables outside of their declaration scope // ternarySame2 = true ? sOuter : sInner; Diagnostic(ErrorCode.ERR_EscapeVariable, "sInner").WithArguments("sInner").WithLocation(27, 44), @@ -2340,8 +2387,10 @@ ref struct S1 ); } - [Fact()] - public void StackallocEscape() + [Theory] + [InlineData(LanguageVersion.CSharp10)] + [InlineData(LanguageVersion.CSharp11)] + public void StackallocEscape(LanguageVersion languageVersion) { var text = @" using System; @@ -2378,7 +2427,7 @@ Span Test6() } } "; - CreateCompilationWithMscorlibAndSpan(text).VerifyDiagnostics( + 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 // return true? local : default(Span); Diagnostic(ErrorCode.ERR_EscapeVariable, "local").WithArguments("local").WithLocation(19, 26), @@ -2392,11 +2441,13 @@ Span Test6() } [WorkItem(21831, "https://github.com/dotnet/roslyn/issues/21831")] - [Fact()] - public void LocalWithNoInitializerEscape() + [Theory] + [InlineData(LanguageVersion.CSharp10)] + [InlineData(LanguageVersion.CSharp11)] + public void LocalWithNoInitializerEscape(LanguageVersion languageVersion) { - var text = @" - using System; + var text = @"using System; + class Program { static void Main() @@ -2430,7 +2481,8 @@ ref struct S1 } } "; - CreateCompilationWithMscorlibAndSpan(text, parseOptions: TestOptions.Regular10).VerifyDiagnostics( + var comp = CreateCompilationWithMscorlibAndSpan(text, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion)); + comp.VerifyDiagnostics( // (16,30): error CS8526: Cannot use variable 'local' in this context because it may expose referenced variables outside of their declaration scope // sp = MayWrap(ref local); Diagnostic(ErrorCode.ERR_EscapeVariable, "local").WithArguments("local").WithLocation(16, 30), @@ -2441,25 +2493,13 @@ ref struct S1 // return sp1; Diagnostic(ErrorCode.ERR_EscapeVariable, "sp1").WithArguments("sp1").WithLocation(22, 20) ); - - // C#11 reports ERR_RefReturnLocal rather than ERR_EscapeVariable for 'local' because CheckInvocationEscape() - // checks for ref-safe-to-escape of 'local' since it is passed as a 'ref' parameter to a method returning a ref struct. - CreateCompilationWithMscorlibAndSpan(text).VerifyDiagnostics( - // (16,30): error CS8168: Cannot return local 'local' by reference because it is not a ref local - // sp = MayWrap(ref local); - Diagnostic(ErrorCode.ERR_RefReturnLocal, "local").WithArguments("local").WithLocation(16, 30), - // (16,18): error CS8521: Cannot use a result of 'Program.MayWrap(ref Span)' in this context because it may expose variables referenced by parameter 'arg' outside of their declaration scope - // sp = MayWrap(ref local); - Diagnostic(ErrorCode.ERR_EscapeCall, "MayWrap(ref local)").WithArguments("Program.MayWrap(ref System.Span)", "arg").WithLocation(16, 18), - // (22,20): error CS8526: Cannot use variable 'sp1' in this context because it may expose referenced variables outside of their declaration scope - // return sp1; - Diagnostic(ErrorCode.ERR_EscapeVariable, "sp1").WithArguments("sp1").WithLocation(22, 20) - ); } [WorkItem(21858, "https://github.com/dotnet/roslyn/issues/21858")] - [Fact()] - public void FieldOfRefLikeEscape() + [Theory] + [InlineData(LanguageVersion.CSharp10)] + [InlineData(LanguageVersion.CSharp11)] + public void FieldOfRefLikeEscape(LanguageVersion languageVersion) { var text = @" class Program @@ -2499,7 +2539,7 @@ ref struct S2{} } "; - CreateCompilationWithMscorlibAndSpan(text).VerifyDiagnostics( + CreateCompilationWithMscorlibAndSpan(text, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion)).VerifyDiagnostics( // (31,28): error CS8170: Struct members cannot return 'this' or other instance members by reference // return ref x; Diagnostic(ErrorCode.ERR_RefReturnStructThis, "x").WithLocation(31, 28) @@ -2507,8 +2547,10 @@ ref struct S2{} } [WorkItem(21880, "https://github.com/dotnet/roslyn/issues/21880")] - [Fact()] - public void MemberOfReadonlyRefLikeEscape() + [Theory] + [InlineData(LanguageVersion.CSharp10)] + [InlineData(LanguageVersion.CSharp11)] + public void MemberOfReadonlyRefLikeEscape(LanguageVersion languageVersion) { var text = @" using System; @@ -2541,7 +2583,7 @@ public void TryGet(out Span result) } } "; - CreateCompilationWithMscorlibAndSpan(text).VerifyDiagnostics( + CreateCompilationWithMscorlibAndSpan(text, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion)).VerifyDiagnostics( // (12,33): error CS8526: Cannot use variable 'value1' in this context because it may expose referenced variables outside of their declaration scope // new SW().TryGet(out value1); Diagnostic(ErrorCode.ERR_EscapeVariable, "value1").WithArguments("value1").WithLocation(12, 33), @@ -2552,8 +2594,10 @@ public void TryGet(out Span result) } [WorkItem(21911, "https://github.com/dotnet/roslyn/issues/21911")] - [Fact()] - public void MemberOfReadonlyRefLikeEscapeSpans() + [Theory] + [InlineData(LanguageVersion.CSharp10)] + [InlineData(LanguageVersion.CSharp11)] + public void MemberOfReadonlyRefLikeEscapeSpans(LanguageVersion languageVersion) { var text = @" using System; @@ -2585,7 +2629,7 @@ public void CopyTo(Span other) } } "; - CreateCompilationWithMscorlibAndSpan(text).VerifyDiagnostics( + CreateCompilationWithMscorlibAndSpan(text, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion)).VerifyDiagnostics( // (17,43): error CS8352: Cannot use variable 'stackAllocated' in this context because it may expose referenced variables outside of their declaration scope // new NotReadOnly().CopyTo(stackAllocated); Diagnostic(ErrorCode.ERR_EscapeVariable, "stackAllocated").WithArguments("stackAllocated").WithLocation(17, 43), @@ -2595,8 +2639,11 @@ public void CopyTo(Span other) ); } - [Fact, WorkItem(35146, "https://github.com/dotnet/roslyn/issues/35146")] - public void ReadOnlyRefStruct_Method_RefLikeStructParameter() + [WorkItem(35146, "https://github.com/dotnet/roslyn/issues/35146")] + [Theory] + [InlineData(LanguageVersion.CSharp10)] + [InlineData(LanguageVersion.CSharp11)] + public void ReadOnlyRefStruct_Method_RefLikeStructParameter(LanguageVersion languageVersion) { var csharp = @" using System; @@ -2612,12 +2659,15 @@ public unsafe static void N(S b) } } "; - var comp = CreateCompilationWithMscorlibAndSpan(csharp, TestOptions.UnsafeDebugDll); + var comp = CreateCompilationWithMscorlibAndSpan(csharp, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion), options: TestOptions.UnsafeDebugDll); comp.VerifyDiagnostics(); } - [Fact, WorkItem(35146, "https://github.com/dotnet/roslyn/issues/35146")] - public void ReadOnlyMethod_RefLikeStructParameter() + [WorkItem(35146, "https://github.com/dotnet/roslyn/issues/35146")] + [Theory] + [InlineData(LanguageVersion.CSharp10)] + [InlineData(LanguageVersion.CSharp11)] + public void ReadOnlyMethod_RefLikeStructParameter(LanguageVersion languageVersion) { var csharp = @" using System; @@ -2633,12 +2683,15 @@ public unsafe static void N(S b) } } "; - var comp = CreateCompilationWithMscorlibAndSpan(csharp, TestOptions.UnsafeDebugDll); + var comp = CreateCompilationWithMscorlibAndSpan(csharp, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion), options: TestOptions.UnsafeDebugDll); comp.VerifyDiagnostics(); } - [Fact, WorkItem(35146, "https://github.com/dotnet/roslyn/issues/35146")] - public void ReadOnlyRefStruct_RefLikeProperty() + [WorkItem(35146, "https://github.com/dotnet/roslyn/issues/35146")] + [Theory] + [InlineData(LanguageVersion.CSharp10)] + [InlineData(LanguageVersion.CSharp11)] + public void ReadOnlyRefStruct_RefLikeProperty(LanguageVersion languageVersion) { var csharp = @" using System; @@ -2654,15 +2707,18 @@ public unsafe static void N(S b) } } "; - var comp = CreateCompilationWithMscorlibAndSpan(csharp, TestOptions.UnsafeDebugDll); + var comp = CreateCompilationWithMscorlibAndSpan(csharp, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion), options: TestOptions.UnsafeDebugDll); comp.VerifyDiagnostics( // (11,15): error CS8352: Cannot use variable 'x' in this context because it may expose referenced variables outside of their declaration scope // b.P = x; Diagnostic(ErrorCode.ERR_EscapeVariable, "x").WithArguments("x").WithLocation(11, 15)); } - [Fact, WorkItem(35146, "https://github.com/dotnet/roslyn/issues/35146")] - public void ReadOnlyRefLikeProperty_01() + [WorkItem(35146, "https://github.com/dotnet/roslyn/issues/35146")] + [Theory] + [InlineData(LanguageVersion.CSharp10)] + [InlineData(LanguageVersion.CSharp11)] + public void ReadOnlyRefLikeProperty_01(LanguageVersion languageVersion) { var csharp = @" using System; @@ -2678,15 +2734,18 @@ public unsafe static void N(S b) } } "; - var comp = CreateCompilationWithMscorlibAndSpan(csharp, TestOptions.UnsafeDebugDll); + var comp = CreateCompilationWithMscorlibAndSpan(csharp, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion), options: TestOptions.UnsafeDebugDll); comp.VerifyDiagnostics( // (11,15): error CS8352: Cannot use variable 'x' in this context because it may expose referenced variables outside of their declaration scope // b.P = x; Diagnostic(ErrorCode.ERR_EscapeVariable, "x").WithArguments("x").WithLocation(11, 15)); } - [Fact, WorkItem(35146, "https://github.com/dotnet/roslyn/issues/35146")] - public void ReadOnlyRefLikeProperty_02() + [WorkItem(35146, "https://github.com/dotnet/roslyn/issues/35146")] + [Theory] + [InlineData(LanguageVersion.CSharp10)] + [InlineData(LanguageVersion.CSharp11)] + public void ReadOnlyRefLikeProperty_02(LanguageVersion languageVersion) { var csharp = @" using System; @@ -2702,15 +2761,18 @@ public unsafe static void N(S b) } } "; - var comp = CreateCompilationWithMscorlibAndSpan(csharp, TestOptions.UnsafeDebugDll); + var comp = CreateCompilationWithMscorlibAndSpan(csharp, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion), options: TestOptions.UnsafeDebugDll); comp.VerifyDiagnostics( // (11,15): error CS8352: Cannot use variable 'x' in this context because it may expose referenced variables outside of their declaration scope // b.P = x; Diagnostic(ErrorCode.ERR_EscapeVariable, "x").WithArguments("x").WithLocation(11, 15)); } - [Fact, WorkItem(35146, "https://github.com/dotnet/roslyn/issues/35146")] - public void ReadOnlyIndexer_RefLikeStructParameter_01() + [WorkItem(35146, "https://github.com/dotnet/roslyn/issues/35146")] + [Theory] + [InlineData(LanguageVersion.CSharp10)] + [InlineData(LanguageVersion.CSharp11)] + public void ReadOnlyIndexer_RefLikeStructParameter_01(LanguageVersion languageVersion) { var csharp = @" using System; @@ -2728,7 +2790,7 @@ public unsafe static Span N(S b) } } "; - var comp = CreateCompilationWithMscorlibAndSpan(csharp, TestOptions.UnsafeDebugDll); + var comp = CreateCompilationWithMscorlibAndSpan(csharp, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion), options: TestOptions.UnsafeDebugDll); comp.VerifyDiagnostics( // (13,16): error CS8347: Cannot use a result of 'S.this[Span]' in this context because it may expose variables referenced by parameter 'span' outside of their declaration scope // return b[x]; @@ -2738,8 +2800,11 @@ public unsafe static Span N(S b) Diagnostic(ErrorCode.ERR_EscapeVariable, "x").WithArguments("x").WithLocation(13, 18)); } - [Fact, WorkItem(35146, "https://github.com/dotnet/roslyn/issues/35146")] - public void ReadOnlyIndexer_RefLikeStructParameter_02() + [WorkItem(35146, "https://github.com/dotnet/roslyn/issues/35146")] + [Theory] + [InlineData(LanguageVersion.CSharp10)] + [InlineData(LanguageVersion.CSharp11)] + public void ReadOnlyIndexer_RefLikeStructParameter_02(LanguageVersion languageVersion) { var csharp = @" using System; @@ -2755,7 +2820,7 @@ public unsafe static void N(S b) } } "; - var comp = CreateCompilationWithMscorlibAndSpan(csharp, TestOptions.UnsafeDebugDll); + var comp = CreateCompilationWithMscorlibAndSpan(csharp, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion), options: TestOptions.UnsafeDebugDll); comp.VerifyDiagnostics( // (10,13): error CS8350: This combination of arguments to 'S.this[Span]' is disallowed because it may expose variables referenced by parameter 'span' outside of their declaration scope // _ = b[x]; @@ -2772,8 +2837,10 @@ public unsafe static void N(S b) } [WorkItem(22197, "https://github.com/dotnet/roslyn/issues/22197")] - [Fact()] - public void RefTernaryMustMatchValEscapes() + [Theory] + [InlineData(LanguageVersion.CSharp10)] + [InlineData(LanguageVersion.CSharp11)] + public void RefTernaryMustMatchValEscapes(LanguageVersion languageVersion) { var text = @" using System; @@ -2801,7 +2868,7 @@ public static void Main() } } "; - CreateCompilationWithMscorlibAndSpan(text).VerifyDiagnostics( + CreateCompilationWithMscorlibAndSpan(text, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion)).VerifyDiagnostics( // (13,56): error CS8526: Cannot use variable 'local' in this context because it may expose referenced variables outside of their declaration scope // ref var r1 = ref (flag1 ? ref global : ref local); Diagnostic(ErrorCode.ERR_EscapeVariable, "local").WithArguments("local").WithLocation(13, 56), @@ -2818,8 +2885,10 @@ public static void Main() } [WorkItem(22197, "https://github.com/dotnet/roslyn/issues/22197")] - [Fact()] - public void RefTernaryMustMatchValEscapes1() + [Theory] + [InlineData(LanguageVersion.CSharp10)] + [InlineData(LanguageVersion.CSharp11)] + public void RefTernaryMustMatchValEscapes1(LanguageVersion languageVersion) { var text = @" using System; @@ -2838,7 +2907,7 @@ public void M(ref Span global) } } "; - var comp = CreateCompilationWithMscorlibAndSpan(text); + var comp = CreateCompilationWithMscorlibAndSpan(text, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion)); comp.VerifyDiagnostics(); var compiled = CompileAndVerify(comp, verify: Verification.Passes); @@ -2854,8 +2923,10 @@ .maxstack 1 "); } - [Fact] - public void DeconstructionAssignmentToGlobal() + [Theory] + [InlineData(LanguageVersion.CSharp10)] + [InlineData(LanguageVersion.CSharp11)] + public void DeconstructionAssignmentToGlobal(LanguageVersion languageVersion) { var text = @" using System; @@ -2885,7 +2956,7 @@ public static void Deconstruct(this Span self, out Span x, out Span self, out Span x, out Span self, out Span x, out Span y) => throw null; } "; - CreateCompilationWithMscorlibAndSpan(text).VerifyDiagnostics( + CreateCompilationWithMscorlibAndSpan(text, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion)).VerifyDiagnostics( // (9,22): error CS8352: Cannot use variable 'local' in this context because it may expose referenced variables outside of their declaration scope // (M(), M()) = local; // error Diagnostic(ErrorCode.ERR_EscapeVariable, "local").WithArguments("local").WithLocation(9, 22) ); } - [Fact] - public void DeconstructionAssignmentWithRefExtension() + [Theory] + [InlineData(LanguageVersion.CSharp10)] + [InlineData(LanguageVersion.CSharp11)] + public void DeconstructionAssignmentWithRefExtension(LanguageVersion languageVersion) { var text = @" using System; @@ -2945,7 +3020,7 @@ public static class Extensions public static void Deconstruct(ref this Span self, out Span x, out Span y) => throw null; } "; - CreateCompilationWithMscorlibAndSpan(text).VerifyDiagnostics( + CreateCompilationWithMscorlibAndSpan(text, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion)).VerifyDiagnostics( // (8,9): error CS1510: A ref or out value must be an assignable variable // (global, global) = global; Diagnostic(ErrorCode.ERR_RefLvalueExpected, "(global, global) = global").WithLocation(8, 9), @@ -2958,8 +3033,10 @@ public static class Extensions ); } - [Fact] - public void DeconstructionAssignmentWithRefReadonlyExtension() + [Theory] + [InlineData(LanguageVersion.CSharp10)] + [InlineData(LanguageVersion.CSharp11)] + public void DeconstructionAssignmentWithRefReadonlyExtension(LanguageVersion languageVersion) { var text = @" using System; @@ -2979,7 +3056,7 @@ public static class Extensions public static void Deconstruct(in this Span self, out Span x, out Span y) => throw null; } "; - CreateCompilationWithMscorlibAndSpan(text).VerifyDiagnostics( + CreateCompilationWithMscorlibAndSpan(text, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion)).VerifyDiagnostics( // (10,28): error CS8352: Cannot use variable 'local' in this context because it may expose referenced variables outside of their declaration scope // (global, global) = local; // error Diagnostic(ErrorCode.ERR_EscapeVariable, "local").WithArguments("local").WithLocation(10, 28) @@ -3302,8 +3379,10 @@ public ValueTuple(T1 item1, T2 item2) ); } - [Fact] - public void DeconstructionAssignmentToOuter() + [Theory] + [InlineData(LanguageVersion.CSharp10)] + [InlineData(LanguageVersion.CSharp11)] + public void DeconstructionAssignmentToOuter(LanguageVersion languageVersion) { var text = @" using System; @@ -3330,11 +3409,13 @@ public static class Extensions } "; - CreateCompilationWithMscorlibAndSpan(text).VerifyDiagnostics(); + CreateCompilationWithMscorlibAndSpan(text, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion)).VerifyDiagnostics(); } - [Fact] - public void DeconstructionDeclaration() + [Theory] + [InlineData(LanguageVersion.CSharp10)] + [InlineData(LanguageVersion.CSharp11)] + public void DeconstructionDeclaration(LanguageVersion languageVersion) { var text = @" using System; @@ -3359,7 +3440,7 @@ public static class Extensions public static void Deconstruct(this Span self, out Span x, out Span y) => throw null; } "; - CreateCompilationWithMscorlibAndSpan(text).VerifyDiagnostics( + CreateCompilationWithMscorlibAndSpan(text, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion)).VerifyDiagnostics( // (10,18): error CS8352: Cannot use variable 'local1' in this context because it may expose referenced variables outside of their declaration scope // global = local1; // error 1 Diagnostic(ErrorCode.ERR_EscapeVariable, "local1").WithArguments("local1").WithLocation(10, 18), @@ -3369,8 +3450,10 @@ public static class Extensions ); } - [Fact] - public void RefLikeForeach() + [Theory] + [InlineData(LanguageVersion.CSharp10)] + [InlineData(LanguageVersion.CSharp11)] + public void RefLikeForeach(LanguageVersion languageVersion) { var text = @" using System; @@ -3396,15 +3479,17 @@ public ref struct S public static implicit operator S(Span s) => throw null; } "; - CreateCompilationWithMscorlibAndSpan(text).VerifyDiagnostics( + CreateCompilationWithMscorlibAndSpan(text, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion)).VerifyDiagnostics( // (11,22): error CS8352: Cannot use variable 'local' in this context because it may expose referenced variables outside of their declaration scope // global = local; // error Diagnostic(ErrorCode.ERR_EscapeVariable, "local").WithArguments("local").WithLocation(11, 22) ); } - [Fact] - public void RefLikeDeconstructionForeach() + [Theory] + [InlineData(LanguageVersion.CSharp10)] + [InlineData(LanguageVersion.CSharp11)] + public void RefLikeDeconstructionForeach(LanguageVersion languageVersion) { var text = @" using System; @@ -3432,7 +3517,7 @@ public ref struct S public void Deconstruct(out S s1, out S s2) => throw null; } "; - CreateCompilationWithMscorlibAndSpan(text).VerifyDiagnostics( + CreateCompilationWithMscorlibAndSpan(text, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion)).VerifyDiagnostics( // (11,22): error CS8352: Cannot use variable 'local1' in this context because it may expose referenced variables outside of their declaration scope // global = local1; // error 1 Diagnostic(ErrorCode.ERR_EscapeVariable, "local1").WithArguments("local1").WithLocation(11, 22), @@ -3442,9 +3527,11 @@ public ref struct S ); } - [Fact] [WorkItem(22361, "https://github.com/dotnet/roslyn/issues/22361")] - public void RefLikeOutVarFromLocal() + [Theory] + [InlineData(LanguageVersion.CSharp10)] + [InlineData(LanguageVersion.CSharp11)] + public void RefLikeOutVarFromLocal(LanguageVersion languageVersion) { var text = @" using System; @@ -3469,15 +3556,17 @@ public ref struct S "; // Tracking issue: https://github.com/dotnet/roslyn/issues/22361 - CreateCompilationWithMscorlibAndSpan(text).VerifyDiagnostics( + CreateCompilationWithMscorlibAndSpan(text, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion)).VerifyDiagnostics( // (9,9): error CS8352: Cannot use variable 'local1' in this context because it may expose referenced variables outside of their declaration scope // local1.M(out S local2); Diagnostic(ErrorCode.ERR_EscapeVariable, "local1").WithArguments("local1").WithLocation(9, 9) ); } - [Fact] - public void RefLikeOutVarFromGlobal() + [Theory] + [InlineData(LanguageVersion.CSharp10)] + [InlineData(LanguageVersion.CSharp11)] + public void RefLikeOutVarFromGlobal(LanguageVersion languageVersion) { var text = @" using System; @@ -3498,12 +3587,14 @@ public ref struct S public void M(out S s) => throw null; } "; - CreateCompilationWithMscorlibAndSpan(text).VerifyDiagnostics(); + CreateCompilationWithMscorlibAndSpan(text, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion)).VerifyDiagnostics(); } [WorkItem(22456, "https://github.com/dotnet/roslyn/issues/22456")] - [Fact] - public void InMatchesIn() + [Theory] + [InlineData(LanguageVersion.CSharp10)] + [InlineData(LanguageVersion.CSharp11)] + public void InMatchesIn(LanguageVersion languageVersion) { var text = @" public class C @@ -3539,12 +3630,14 @@ static ref readonly int Test4() } "; - CreateCompilationWithMscorlibAndSpan(text).VerifyDiagnostics(); + CreateCompilationWithMscorlibAndSpan(text, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion)).VerifyDiagnostics(); } - [Fact] [WorkItem(24776, "https://github.com/dotnet/roslyn/issues/24776")] - public void PointerElementAccess_RefStructPointer() + [Theory] + [InlineData(LanguageVersion.CSharp10)] + [InlineData(LanguageVersion.CSharp11)] + public void PointerElementAccess_RefStructPointer(LanguageVersion languageVersion) { CreateCompilation(@" public ref struct TestStruct @@ -3563,15 +3656,17 @@ public static unsafe void Test(TestStruct[] ar) } } } -}", options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics( +}", parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion), options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics( // (8,36): error CS0611: Array elements cannot be of type 'TestStruct' // public static unsafe void Test(TestStruct[] ar) Diagnostic(ErrorCode.ERR_ArrayElementCantBeRefAny, "TestStruct").WithArguments("TestStruct").WithLocation(8, 36)); } - [Fact] [WorkItem(24776, "https://github.com/dotnet/roslyn/issues/24776")] - public void PointerIndirectionOperator_RefStructPointer() + [Theory] + [InlineData(LanguageVersion.CSharp10)] + [InlineData(LanguageVersion.CSharp11)] + public void PointerIndirectionOperator_RefStructPointer(LanguageVersion languageVersion) { CreateCompilation(@" public ref struct TestStruct @@ -3587,15 +3682,17 @@ public static unsafe void Test(TestStruct[] ar) var x = *p; } } -}", options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics( +}", parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion), options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics( // (8,36): error CS0611: Array elements cannot be of type 'TestStruct' // public static unsafe void Test(TestStruct[] ar) Diagnostic(ErrorCode.ERR_ArrayElementCantBeRefAny, "TestStruct").WithArguments("TestStruct").WithLocation(8, 36)); } - [Fact] [WorkItem(25398, "https://github.com/dotnet/roslyn/issues/25398")] - public void AwaitRefStruct() + [Theory] + [InlineData(LanguageVersion.CSharp10)] + [InlineData(LanguageVersion.CSharp11)] + public void AwaitRefStruct(LanguageVersion languageVersion) { CreateCompilation(@" using System.Threading.Tasks; @@ -3617,7 +3714,7 @@ async Task M(Task t) void M(S t, ref S t1) { } -}", options: TestOptions.ReleaseDll).VerifyDiagnostics( +}", parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion), options: TestOptions.ReleaseDll).VerifyDiagnostics( // (8,26): error CS0306: The type 'S' may not be used as a type argument // async Task M(Task t) Diagnostic(ErrorCode.ERR_BadTypeArgument, "t").WithArguments("S").WithLocation(8, 26), @@ -3633,9 +3730,11 @@ void M(S t, ref S t1) ); } - [Fact] [WorkItem(25398, "https://github.com/dotnet/roslyn/issues/25398")] - public void CoalesceRefStruct() + [Theory] + [InlineData(LanguageVersion.CSharp10)] + [InlineData(LanguageVersion.CSharp11)] + public void CoalesceRefStruct(LanguageVersion languageVersion) { CreateCompilation(@" ref struct S { } @@ -3648,7 +3747,7 @@ void M() var a = (S?)null ?? default; } -}", options: TestOptions.ReleaseDll).VerifyDiagnostics( +}", parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion), options: TestOptions.ReleaseDll).VerifyDiagnostics( // (8,14): error CS0306: The type 'S' may not be used as a type argument // _ = (S?)null ?? default; Diagnostic(ErrorCode.ERR_BadTypeArgument, "S?").WithArguments("S").WithLocation(8, 14), @@ -3658,9 +3757,11 @@ void M() ); } - [Fact] [WorkItem(25398, "https://github.com/dotnet/roslyn/issues/25398")] - public void ArrayAccessRefStruct() + [Theory] + [InlineData(LanguageVersion.CSharp10)] + [InlineData(LanguageVersion.CSharp11)] + public void ArrayAccessRefStruct(LanguageVersion languageVersion) { CreateCompilation(@" ref struct S { } @@ -3673,7 +3774,7 @@ void M() var a = ((S[])null)[0]; } -}", options: TestOptions.ReleaseDll).VerifyDiagnostics( +}", parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion), options: TestOptions.ReleaseDll).VerifyDiagnostics( // (8,15): error CS0611: Array elements cannot be of type 'S' // _ = ((S[])null)[0]; Diagnostic(ErrorCode.ERR_ArrayElementCantBeRefAny, "S").WithArguments("S").WithLocation(8, 15), @@ -3683,9 +3784,11 @@ void M() ); } - [Fact] [WorkItem(25398, "https://github.com/dotnet/roslyn/issues/25398")] - public void ConditionalRefStruct() + [Theory] + [InlineData(LanguageVersion.CSharp10)] + [InlineData(LanguageVersion.CSharp11)] + public void ConditionalRefStruct(LanguageVersion languageVersion) { CreateCompilation(@" ref struct S { } @@ -3700,7 +3803,7 @@ void M() } S Test() => default; -}", options: TestOptions.ReleaseDll).VerifyDiagnostics( +}", parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion), options: TestOptions.ReleaseDll).VerifyDiagnostics( // (8,23): error CS8977: 'S' cannot be made nullable. // _ = ((C)null)?.Test(); Diagnostic(ErrorCode.ERR_CannotBeMadeNullable, ".Test()").WithArguments("S").WithLocation(8, 23), @@ -3710,9 +3813,11 @@ void M() ); } - [Fact] [WorkItem(25485, "https://github.com/dotnet/roslyn/issues/25485")] - public void ArrayAccess_CrashesEscapeRules() + [Theory] + [InlineData(LanguageVersion.CSharp10)] + [InlineData(LanguageVersion.CSharp11)] + public void ArrayAccess_CrashesEscapeRules(LanguageVersion languageVersion) { CreateCompilationWithMscorlibAndSpan(@" using System; @@ -3726,14 +3831,17 @@ public void Foo(Span[] first, Thing[] second) public struct Thing { } -").VerifyDiagnostics( +", parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion)).VerifyDiagnostics( // (5,21): error CS0611: Array elements cannot be of type 'Span' // public void Foo(Span[] first, Thing[] second) Diagnostic(ErrorCode.ERR_ArrayElementCantBeRefAny, "Span").WithArguments("System.Span").WithLocation(5, 21)); } - [Fact, WorkItem(26457, "https://github.com/dotnet/roslyn/issues/26457")] - public void RefThisAssignment_Class() + [WorkItem(26457, "https://github.com/dotnet/roslyn/issues/26457")] + [Theory] + [InlineData(LanguageVersion.CSharp10)] + [InlineData(LanguageVersion.CSharp11)] + public void RefThisAssignment_Class(LanguageVersion languageVersion) { CreateCompilation(@" class Test @@ -3744,7 +3852,7 @@ public void M(ref Test obj) obj = ref this; this = ref obj; } -}").VerifyDiagnostics( +}", parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion)).VerifyDiagnostics( // (6,9): error CS8373: The left-hand side of a ref assignment must be a ref variable. // this = ref this; Diagnostic(ErrorCode.ERR_RefLocalOrParamExpected, "this").WithLocation(6, 9), @@ -3759,8 +3867,11 @@ public void M(ref Test obj) Diagnostic(ErrorCode.ERR_RefLocalOrParamExpected, "this").WithLocation(8, 9)); } - [Fact, WorkItem(26457, "https://github.com/dotnet/roslyn/issues/26457")] - public void RefThisAssignment_Struct() + [WorkItem(26457, "https://github.com/dotnet/roslyn/issues/26457")] + [Theory] + [InlineData(LanguageVersion.CSharp10)] + [InlineData(LanguageVersion.CSharp11)] + public void RefThisAssignment_Struct(LanguageVersion languageVersion) { CreateCompilation(@" struct Test @@ -3771,7 +3882,7 @@ public void M(ref Test obj) obj = ref this; this = ref obj; } -}").VerifyDiagnostics( +}", parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion)).VerifyDiagnostics( // (6,9): error CS8373: The left-hand side of a ref assignment must be a ref variable. // this = ref this; Diagnostic(ErrorCode.ERR_RefLocalOrParamExpected, "this").WithLocation(6, 9), @@ -3783,8 +3894,11 @@ public void M(ref Test obj) Diagnostic(ErrorCode.ERR_RefLocalOrParamExpected, "this").WithLocation(8, 9)); } - [Fact, WorkItem(26457, "https://github.com/dotnet/roslyn/issues/26457")] - public void RefThisAssignment_ReadOnlyStruct() + [WorkItem(26457, "https://github.com/dotnet/roslyn/issues/26457")] + [Theory] + [InlineData(LanguageVersion.CSharp10)] + [InlineData(LanguageVersion.CSharp11)] + public void RefThisAssignment_ReadOnlyStruct(LanguageVersion languageVersion) { CreateCompilation(@" readonly struct Test @@ -3795,7 +3909,7 @@ public void M(ref Test obj) obj = ref this; this = ref obj; } -}").VerifyDiagnostics( +}", parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion)).VerifyDiagnostics( // (6,9): error CS8373: The left-hand side of a ref assignment must be a ref variable. // this = ref this; Diagnostic(ErrorCode.ERR_RefLocalOrParamExpected, "this").WithLocation(6, 9), @@ -3807,10 +3921,11 @@ public void M(ref Test obj) Diagnostic(ErrorCode.ERR_RefLocalOrParamExpected, "this").WithLocation(8, 9)); } - [Fact, WorkItem(26457, "https://github.com/dotnet/roslyn/issues/26457")] + [WorkItem(26457, "https://github.com/dotnet/roslyn/issues/26457")] + [Fact] public void RefThisAssignment_RefStruct() { - CreateCompilation(@" + var source = @" ref struct Test { public void M(ref Test obj) @@ -3819,7 +3934,9 @@ public void M(ref Test obj) obj = ref this; this = ref obj; } -}").VerifyDiagnostics( +}"; + + CreateCompilation(source, parseOptions: TestOptions.Regular10).VerifyDiagnostics( // (6,9): error CS8373: The left-hand side of a ref assignment must be a ref variable. // this = ref this; Diagnostic(ErrorCode.ERR_RefLocalOrParamExpected, "this").WithLocation(6, 9), @@ -3829,10 +3946,21 @@ public void M(ref Test obj) // (8,9): error CS8373: The left-hand side of a ref assignment must be a ref variable. // this = ref obj; Diagnostic(ErrorCode.ERR_RefLocalOrParamExpected, "this").WithLocation(8, 9)); + + CreateCompilation(source).VerifyDiagnostics( + // (6,9): error CS8373: The left-hand side of a ref assignment must be a ref variable. + // this = ref this; + Diagnostic(ErrorCode.ERR_RefLocalOrParamExpected, "this").WithLocation(6, 9), + // (8,9): error CS8373: The left-hand side of a ref assignment must be a ref variable. + // this = ref obj; + Diagnostic(ErrorCode.ERR_RefLocalOrParamExpected, "this").WithLocation(8, 9)); } - [Fact, WorkItem(26457, "https://github.com/dotnet/roslyn/issues/26457")] - public void RefThisAssignment_ReadOnlyRefStruct() + [WorkItem(26457, "https://github.com/dotnet/roslyn/issues/26457")] + [Theory] + [InlineData(LanguageVersion.CSharp10)] + [InlineData(LanguageVersion.CSharp11)] + public void RefThisAssignment_ReadOnlyRefStruct(LanguageVersion languageVersion) { CreateCompilation(@" readonly ref struct Test @@ -3843,7 +3971,7 @@ public void M(ref Test obj) obj = ref this; this = ref obj; } -}").VerifyDiagnostics( +}", parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion)).VerifyDiagnostics( // (6,9): error CS8373: The left-hand side of a ref assignment must be a ref variable. // this = ref this; Diagnostic(ErrorCode.ERR_RefLocalOrParamExpected, "this").WithLocation(6, 9), @@ -3855,9 +3983,11 @@ public void M(ref Test obj) Diagnostic(ErrorCode.ERR_RefLocalOrParamExpected, "this").WithLocation(8, 9)); } - [Fact] [WorkItem(29927, "https://github.com/dotnet/roslyn/issues/29927")] - public void CoalesceSpanReturn() + [Theory] + [InlineData(LanguageVersion.CSharp10)] + [InlineData(LanguageVersion.CSharp11)] + public void CoalesceSpanReturn(LanguageVersion languageVersion) { CreateCompilationWithMscorlibAndSpan(@" using System; @@ -3867,12 +3997,14 @@ Span M() { return null ?? new Span(); } -}", options: TestOptions.ReleaseDll).VerifyDiagnostics(); +}", parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion), options: TestOptions.ReleaseDll).VerifyDiagnostics(); } - [Fact] [WorkItem(29927, "https://github.com/dotnet/roslyn/issues/29927")] - public void CoalesceAssignSpanReturn() + [Theory] + [InlineData(LanguageVersion.CSharp10)] + [InlineData(LanguageVersion.CSharp11)] + public void CoalesceAssignSpanReturn(LanguageVersion languageVersion) { CreateCompilationWithMscorlibAndSpan(@" using System; @@ -3883,12 +4015,14 @@ Span M() var x = null ?? new Span(); return x; } -}", options: TestOptions.ReleaseDll).VerifyDiagnostics(); +}", parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion), options: TestOptions.ReleaseDll).VerifyDiagnostics(); } - [Fact] [WorkItem(29927, "https://github.com/dotnet/roslyn/issues/29927")] - public void CoalesceRefSpanReturn() + [Theory] + [InlineData(LanguageVersion.CSharp10)] + [InlineData(LanguageVersion.CSharp11)] + public void CoalesceRefSpanReturn(LanguageVersion languageVersion) { CreateCompilationWithMscorlibAndSpan(@" using System; @@ -3899,15 +4033,56 @@ Span M() Span x = stackalloc byte[10]; return null ?? x; } -}", options: TestOptions.ReleaseDll).VerifyDiagnostics( +}", parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion), options: TestOptions.ReleaseDll).VerifyDiagnostics( // (8,24): error CS8352: Cannot use variable 'x' in this context because it may expose referenced variables outside of their declaration scope // return null ?? x; Diagnostic(ErrorCode.ERR_EscapeVariable, "x").WithArguments("x").WithLocation(8, 24) ); } - [Fact(Skip = "https://github.com/dotnet/roslyn/issues/40583")] - public void ConvertedSpanReturn() + [WorkItem(62973, "https://github.com/dotnet/roslyn/issues/62973")] + [Fact] + public void RegressionTest62973() + { + var compilation = CreateCompilation( +""" +#nullable enable +using System.Collections.Generic; + +System.Console.WriteLine(""); + +public class ArrayPool { } +public readonly ref struct PooledArrayHandle +{ + public void Dispose() { } +} + +public static class Test +{ + public static PooledArrayHandle RentArray(this int length, out T[] array, ArrayPool? pool = null) { + throw null!; + } + + 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; + } + } +} +"""); + compilation.VerifyEmitDiagnostics( + // (20,19): error CS4013: Instance of type 'PooledArrayHandle' cannot be used inside a nested function, query expression, iterator block or async method + // using var handle = RentArray(200, out var array); + Diagnostic(ErrorCode.ERR_SpecialByRefInLambda, "handle = RentArray(200, out var array)").WithArguments("PooledArrayHandle").WithLocation(20, 19)); + } + + [Theory(Skip = "https://github.com/dotnet/roslyn/issues/40583")] + [InlineData(LanguageVersion.CSharp10)] + [InlineData(LanguageVersion.CSharp11)] + public void ConvertedSpanReturn(LanguageVersion languageVersion) { CreateCompilationWithMscorlibAndSpan(@" using System; @@ -3920,7 +4095,64 @@ class D { public static implicit operator D(Span span) => new D(); } -", options: TestOptions.ReleaseDll).VerifyDiagnostics(); +", parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion), options: TestOptions.ReleaseDll).VerifyDiagnostics(); + } + + [WorkItem(63384, "https://github.com/dotnet/roslyn/issues/63384")] + [Theory] + [InlineData("nuint")] + [InlineData("nint")] + public void NativeIntegerThis(string type) + { + var compilation = CreateCompilation( + $$""" + ref struct S + { + static int M({{type}} ptr) => ptr.GetHashCode(); + } + """); + + compilation.VerifyDiagnostics(); + } + + [Fact] + [WorkItem(63446, "https://github.com/dotnet/roslyn/issues/63446")] + public void RefDiscardAssignment() + { + var source = @" +class Program +{ + static int dummy; + + static ref int F() + { + return ref dummy; + } + + static void Main() + { + Test(); + System.Console.WriteLine(""Done""); + } + + static void Test() + { + _ = ref F(); + } +} +"; + + CompileAndVerify(source, expectedOutput: "Done").VerifyDiagnostics(). + VerifyIL("Program.Test", +@" +{ + // Code size 7 (0x7) + .maxstack 1 + IL_0000: call ""ref int Program.F()"" + IL_0005: pop + IL_0006: ret +} +"); } } } diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/RefFieldTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/RefFieldTests.cs index 92a4577d232a9..8c27fede8f1f5 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/RefFieldTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/RefFieldTests.cs @@ -4,6 +4,7 @@ #nullable disable +using System.Collections.Generic; using System.Linq; using Microsoft.CodeAnalysis.CSharp.Symbols; using Microsoft.CodeAnalysis.CSharp.Symbols.Metadata.PE; @@ -30,6 +31,14 @@ private static bool IsNet70OrGreater() private static string IncludeExpectedOutput(string expectedOutput) => IsNet70OrGreater() ? expectedOutput : null; + private static IEnumerable CopyWithoutSharingCachedSymbols(IEnumerable references) + { + foreach (var reference in references) + { + yield return ((AssemblyMetadata)((MetadataImageReference)reference).GetMetadata()).CopyWithoutSharingCachedSymbols().GetReference(); + } + } + [CombinatorialData] [Theory] public void LanguageVersionDiagnostics(bool useCompilationReference) @@ -90,16 +99,21 @@ void M5(S s5) M2(ref s5.F1); } }"; - var comp = CreateCompilation(sourceA, parseOptions: TestOptions.Regular10); + var mscorlibRefWithRefFields = GetMscorlibRefWithoutSharingCachedSymbols(); + + // Note: we use skipExtraValidation so that nobody pulls + // on the compilation or its references before we set the RuntimeSupportsByRefFields flag. + var comp = CreateEmptyCompilation(sourceA, references: new[] { mscorlibRefWithRefFields }, parseOptions: TestOptions.Regular10, skipExtraValidation: true); + comp.Assembly.RuntimeSupportsByRefFields = true; comp.VerifyEmitDiagnostics( - // (3,12): error CS8652: The feature 'ref fields' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // (3,12): error CS8936: Feature 'ref fields' is not available in C# 10.0. Please use language version 11.0 or greater. // public ref T F1; - Diagnostic(ErrorCode.ERR_FeatureInPreview, "ref T").WithArguments("ref fields").WithLocation(3, 12), - // (4,12): error CS8652: The feature 'ref fields' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "ref T").WithArguments("ref fields", "11.0").WithLocation(3, 12), + // (4,12): error CS8936: Feature 'ref fields' is not available in C# 10.0. Please use language version 11.0 or greater. // public ref readonly T F2; - Diagnostic(ErrorCode.ERR_FeatureInPreview, "ref readonly T").WithArguments("ref fields").WithLocation(4, 12)); + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "ref readonly T").WithArguments("ref fields", "11.0").WithLocation(4, 12)); - comp = CreateCompilation(sourceA); + comp = CreateEmptyCompilation(sourceA, references: new[] { mscorlibRefWithRefFields }); comp.VerifyEmitDiagnostics(); var refA = AsReference(comp, useCompilationReference); @@ -128,28 +142,28 @@ static void M3(S s) } }"; - comp = CreateCompilation(sourceB, references: new[] { refA }, parseOptions: TestOptions.Regular10); + comp = CreateEmptyCompilation(sourceB, references: new[] { refA, mscorlibRefWithRefFields }, parseOptions: TestOptions.Regular10); comp.VerifyEmitDiagnostics( - // (8,25): error CS8652: The feature 'ref fields' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // (8,25): error CS8936: Feature 'ref fields' is not available in C# 10.0. Please use language version 11.0 or greater. // s1 = new S { F1 = t }; - Diagnostic(ErrorCode.ERR_FeatureInPreview, "F1").WithArguments("ref fields").WithLocation(8, 25), - // (14,25): error CS8652: The feature 'ref fields' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "F1").WithArguments("ref fields", "11.0").WithLocation(8, 25), + // (14,25): error CS8936: Feature 'ref fields' is not available in C# 10.0. Please use language version 11.0 or greater. // s2 = new S { F1 = t }; - Diagnostic(ErrorCode.ERR_FeatureInPreview, "F1").WithArguments("ref fields").WithLocation(14, 25), - // (19,12): error CS8652: The feature 'ref fields' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "F1").WithArguments("ref fields", "11.0").WithLocation(14, 25), + // (19,12): error CS8936: Feature 'ref fields' is not available in C# 10.0. Please use language version 11.0 or greater. // M1(s.F1); - Diagnostic(ErrorCode.ERR_FeatureInPreview, "s.F1").WithArguments("ref fields").WithLocation(19, 12), - // (20,12): error CS8652: The feature 'ref fields' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "s.F1").WithArguments("ref fields", "11.0").WithLocation(19, 12), + // (20,12): error CS8936: Feature 'ref fields' is not available in C# 10.0. Please use language version 11.0 or greater. // M1(s.F2); - Diagnostic(ErrorCode.ERR_FeatureInPreview, "s.F2").WithArguments("ref fields").WithLocation(20, 12), - // (21,16): error CS8652: The feature 'ref fields' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "s.F2").WithArguments("ref fields", "11.0").WithLocation(20, 12), + // (21,16): error CS8936: Feature 'ref fields' is not available in C# 10.0. Please use language version 11.0 or greater. // M2(ref s.F1); - Diagnostic(ErrorCode.ERR_FeatureInPreview, "s.F1").WithArguments("ref fields").WithLocation(21, 16)); + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "s.F1").WithArguments("ref fields", "11.0").WithLocation(21, 16)); VerifyFieldSymbol(comp.GetMember("S.F1"), "ref T S.F1", RefKind.Ref, new string[0]); VerifyFieldSymbol(comp.GetMember("S.F2"), "ref readonly T S.F2", RefKind.RefReadOnly, new string[0]); - comp = CreateCompilation(sourceB, references: new[] { refA }, parseOptions: TestOptions.RegularNext); + comp = CreateEmptyCompilation(sourceB, references: new[] { refA, mscorlibRefWithRefFields }, parseOptions: TestOptions.Regular11); comp.VerifyEmitDiagnostics(); VerifyFieldSymbol(comp.GetMember("S.F1"), "ref T S.F1", RefKind.Ref, new string[0]); @@ -166,15 +180,22 @@ public void RefField(bool useCompilationReference) public ref T F; public S(ref T t) { F = ref t; } }"; - var comp = CreateCompilation(sourceA, parseOptions: TestOptions.Regular10); + // Avoid sharing mscorlib symbols with other tests since we are about to change + // RuntimeSupportsByRefFields property for it. + var mscorlibRefWithRefFields = GetMscorlibRefWithoutSharingCachedSymbols(); + + // Note: we use skipExtraValidation so that nobody pulls + // on the compilation or its references before we set the RuntimeSupportsByRefFields flag. + var comp = CreateEmptyCompilation(sourceA, references: new[] { mscorlibRefWithRefFields }, parseOptions: TestOptions.Regular10, skipExtraValidation: true); + comp.Assembly.RuntimeSupportsByRefFields = true; comp.VerifyEmitDiagnostics( - // (3,12): error CS8652: The feature 'ref fields' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // (3,12): error CS8936: Feature 'ref fields' is not available in C# 10.0. Please use language version 11.0 or greater. // public ref T F; - Diagnostic(ErrorCode.ERR_FeatureInPreview, "ref T").WithArguments("ref fields").WithLocation(3, 12)); + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "ref T").WithArguments("ref fields", "11.0").WithLocation(3, 12)); VerifyFieldSymbol(comp.GetMember("S.F"), "ref T S.F", RefKind.Ref, new string[0]); - comp = CreateCompilation(sourceA); + comp = CreateEmptyCompilation(sourceA, references: new[] { mscorlibRefWithRefFields }); comp.VerifyEmitDiagnostics(); var refA = AsReference(comp, useCompilationReference); VerifyFieldSymbol(comp.GetMember("S.F"), "ref T S.F", RefKind.Ref, new string[0]); @@ -196,21 +217,22 @@ static void Main() } }"; - comp = CreateCompilation(sourceB, references: new[] { refA }, parseOptions: TestOptions.Regular10); + comp = CreateEmptyCompilation(sourceB, references: new[] { refA, mscorlibRefWithRefFields }, parseOptions: TestOptions.Regular10); comp.VerifyEmitDiagnostics( - // (8,9): error CS8652: The feature 'ref fields' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // (8,9): error CS8936: Feature 'ref fields' is not available in C# 10.0. Please use language version 11.0 or greater. // s.F = 2; - Diagnostic(ErrorCode.ERR_FeatureInPreview, "s.F").WithArguments("ref fields").WithLocation(8, 9), - // (9,27): error CS8652: The feature 'ref fields' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "s.F").WithArguments("ref fields", "11.0").WithLocation(8, 9), + // (9,27): error CS8936: Feature 'ref fields' is not available in C# 10.0. Please use language version 11.0 or greater. // Console.WriteLine(s.F); - Diagnostic(ErrorCode.ERR_FeatureInPreview, "s.F").WithArguments("ref fields").WithLocation(9, 27), - // (12,27): error CS8652: The feature 'ref fields' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "s.F").WithArguments("ref fields", "11.0").WithLocation(9, 27), + // (12,27): error CS8936: Feature 'ref fields' is not available in C# 10.0. Please use language version 11.0 or greater. // Console.WriteLine(s.F); - Diagnostic(ErrorCode.ERR_FeatureInPreview, "s.F").WithArguments("ref fields").WithLocation(12, 27)); + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "s.F").WithArguments("ref fields", "11.0").WithLocation(12, 27)); VerifyFieldSymbol(comp.GetMember("S.F"), "ref T S.F", RefKind.Ref, new string[0]); - var verifier = CompileAndVerify(sourceB, references: new[] { refA }, parseOptions: TestOptions.RegularNext, verify: Verification.Skipped, expectedOutput: IncludeExpectedOutput( + comp = CreateEmptyCompilation(sourceB, references: new[] { refA, mscorlibRefWithRefFields }, parseOptions: TestOptions.Regular11, options: TestOptions.ReleaseExe); + var verifier = CompileAndVerify(comp, verify: Verification.Skipped, expectedOutput: IncludeExpectedOutput( @"2 2 3 @@ -233,15 +255,22 @@ public S(in T t) F = ref t; } }"; - var comp = CreateCompilation(sourceA, parseOptions: TestOptions.Regular10); + // Avoid sharing mscorlib symbols with other tests since we are about to change + // RuntimeSupportsByRefFields property for it. + var mscorlibRefWithRefFields = GetMscorlibRefWithoutSharingCachedSymbols(); + + // Note: we use skipExtraValidation so that nobody pulls + // on the compilation or its references before we set the RuntimeSupportsByRefFields flag. + var comp = CreateEmptyCompilation(sourceA, references: new[] { mscorlibRefWithRefFields }, parseOptions: TestOptions.Regular10, skipExtraValidation: true); + comp.Assembly.RuntimeSupportsByRefFields = true; comp.VerifyEmitDiagnostics( - // (3,12): error CS8652: The feature 'ref fields' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // (3,12): error CS8936: Feature 'ref fields' is not available in C# 10.0. Please use language version 11.0 or greater. // public ref readonly T F; - Diagnostic(ErrorCode.ERR_FeatureInPreview, "ref readonly T").WithArguments("ref fields").WithLocation(3, 12)); + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "ref readonly T").WithArguments("ref fields", "11.0").WithLocation(3, 12)); VerifyFieldSymbol(comp.GetMember("S.F"), "ref readonly T S.F", RefKind.RefReadOnly, new string[0]); - comp = CreateCompilation(sourceA); + comp = CreateEmptyCompilation(sourceA, references: new[] { mscorlibRefWithRefFields }); comp.VerifyEmitDiagnostics(); var refA = AsReference(comp, useCompilationReference); VerifyFieldSymbol(comp.GetMember("S.F"), "ref readonly T S.F", RefKind.RefReadOnly, new string[0]); @@ -268,21 +297,22 @@ static void Main() } }"; - comp = CreateCompilation(sourceB, references: new[] { refA }, parseOptions: TestOptions.Regular10); + comp = CreateEmptyCompilation(sourceB, references: new[] { refA, mscorlibRefWithRefFields }, parseOptions: TestOptions.Regular10); comp.VerifyEmitDiagnostics( - // (13,9): error CS8652: The feature 'ref fields' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // (13,9): error CS8936: Feature 'ref fields' is not available in C# 10.0. Please use language version 11.0 or greater. // s.F.G = 2; - Diagnostic(ErrorCode.ERR_FeatureInPreview, "s.F").WithArguments("ref fields").WithLocation(13, 9), - // (14,27): error CS8652: The feature 'ref fields' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "s.F").WithArguments("ref fields", "11.0").WithLocation(13, 9), + // (14,27): error CS8936: Feature 'ref fields' is not available in C# 10.0. Please use language version 11.0 or greater. // Console.WriteLine(s.F.G); - Diagnostic(ErrorCode.ERR_FeatureInPreview, "s.F").WithArguments("ref fields").WithLocation(14, 27), - // (17,27): error CS8652: The feature 'ref fields' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "s.F").WithArguments("ref fields", "11.0").WithLocation(14, 27), + // (17,27): error CS8936: Feature 'ref fields' is not available in C# 10.0. Please use language version 11.0 or greater. // Console.WriteLine(s.F.G); - Diagnostic(ErrorCode.ERR_FeatureInPreview, "s.F").WithArguments("ref fields").WithLocation(17, 27)); + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "s.F").WithArguments("ref fields", "11.0").WithLocation(17, 27)); VerifyFieldSymbol(comp.GetMember("S.F"), "ref readonly T S.F", RefKind.RefReadOnly, new string[0]); - var verifier = CompileAndVerify(sourceB, references: new[] { refA }, parseOptions: TestOptions.RegularNext, verify: Verification.Skipped, expectedOutput: IncludeExpectedOutput( + comp = CreateEmptyCompilation(sourceB, references: new[] { refA, mscorlibRefWithRefFields }, parseOptions: TestOptions.Regular11, options: TestOptions.ReleaseExe); + var verifier = CompileAndVerify(comp, verify: Verification.Skipped, expectedOutput: IncludeExpectedOutput( @"2 2 3 @@ -418,7 +448,7 @@ public void FixedField_01() public fixed ref int F1[3]; public fixed ref readonly int F2[3]; }"; - var comp = CreateCompilation(source, options: TestOptions.UnsafeReleaseDll); + var comp = CreateCompilation(source, options: TestOptions.UnsafeReleaseDll, runtimeFeature: RuntimeFlag.ByRefFields); comp.VerifyEmitDiagnostics( // (3,26): error CS9049: A fixed field must not be a ref field. // public fixed ref int F1[3]; @@ -456,7 +486,7 @@ unsafe static void Main() Console.WriteLine(s.F[1]); } }"; - var comp = CreateCompilation(sourceB, references: new[] { refA }, options: TestOptions.UnsafeReleaseExe); + var comp = CreateCompilation(sourceB, references: new[] { refA }, options: TestOptions.UnsafeReleaseExe, runtimeFeature: RuntimeFlag.ByRefFields); comp.VerifyEmitDiagnostics( // (7,29): error CS0570: 'S.F' is not supported by the language // Console.WriteLine(s.F[1]); @@ -486,7 +516,7 @@ static void Main() Console.WriteLine(r.F2); } }"; - var comp = CreateCompilation(sourceB, references: new[] { refA }); + var comp = CreateCompilation(sourceB, references: new[] { refA }, runtimeFeature: RuntimeFlag.ByRefFields); comp.VerifyEmitDiagnostics( // (7,29): error CS0570: 'R.F1' is not supported by the language // Console.WriteLine(r.F1); @@ -510,7 +540,7 @@ ref struct R volatile ref int _v1; volatile ref readonly int _v2; }"; - var comp = CreateCompilation(source); + var comp = CreateCompilation(source, runtimeFeature: RuntimeFlag.ByRefFields); comp.VerifyEmitDiagnostics( // (4,20): error CS0106: The modifier 'static' is not valid for this item // static ref int _s1; @@ -538,6 +568,200 @@ ref struct R Diagnostic(ErrorCode.ERR_BadMemberFlag, "_v2").WithArguments("volatile").WithLocation(9, 31)); } + [Fact, WorkItem(63018, "https://github.com/dotnet/roslyn/issues/63018")] + public void InitRefField_AutoDefault() + { + var source = """ +using System; + +var x = 42; +scoped var r = new R(); +r.field = ref x; + +ref struct R +{ + public ref int field; + + public R() + { + Console.WriteLine("explicit ctor"); + } +} +"""; + var comp = CreateCompilation(source, options: TestOptions.ReleaseExe, runtimeFeature: RuntimeFlag.ByRefFields); + comp.VerifyDiagnostics(); + var verifier = CompileAndVerify(comp, verify: Verification.Skipped, expectedOutput: IncludeExpectedOutput("explicit ctor")); + verifier.VerifyIL("R..ctor()", @" +{ + // Code size 19 (0x13) + .maxstack 2 + IL_0000: ldarg.0 + IL_0001: ldc.i4.0 + IL_0002: conv.u + IL_0003: stfld ""ref int R.field"" + IL_0008: ldstr ""explicit ctor"" + IL_000d: call ""void System.Console.WriteLine(string)"" + IL_0012: ret +}"); + } + + // Test skipped because we don't allow faking runtime feature flags when using specific TargetFramework + [Fact(Skip = "https://github.com/dotnet/roslyn/issues/61463"), WorkItem(63018, "https://github.com/dotnet/roslyn/issues/63018")] + public void InitRefField_UnsafeNullRef() + { + var source = """ +using System; + +var x = 42; +scoped var r = new R(); +r.field = ref x; + +ref struct R +{ + public ref int field; + + public R() + { + field = ref System.Runtime.CompilerServices.Unsafe.NullRef(); + Console.WriteLine("explicit ctor"); + } +} +"""; + var comp = CreateCompilation(source, targetFramework: TargetFramework.Net60, options: TestOptions.ReleaseExe); + comp.VerifyDiagnostics(); + var verifier = CompileAndVerify(comp, verify: Verification.Skipped, expectedOutput: IncludeExpectedOutput("explicit ctor")); + verifier.VerifyIL("R..ctor()", @" +{ + // Code size 22 (0x16) + .maxstack 2 + IL_0000: ldarg.0 + IL_0001: call ""ref int System.Runtime.CompilerServices.Unsafe.NullRef()"" + IL_0006: stfld ""ref int R.field"" + IL_000b: ldstr ""explicit ctor"" + IL_0010: call ""void System.Console.WriteLine(string)"" + IL_0015: ret +}"); + } + + [Fact, WorkItem(63018, "https://github.com/dotnet/roslyn/issues/63018")] + public void InitRefField_AutoDefault_RefReadonly() + { + var source = """ +using System; + +var x = 42; +scoped var r = new R(); +r.field = ref x; + +ref struct R +{ + public ref readonly int field; + + public R() + { + Console.WriteLine("explicit ctor"); + } +} +"""; + var comp = CreateCompilation(source, options: TestOptions.ReleaseExe, runtimeFeature: RuntimeFlag.ByRefFields); + comp.VerifyDiagnostics(); + + var verifier = CompileAndVerify(comp, verify: Verification.Skipped, expectedOutput: IncludeExpectedOutput("explicit ctor")); + verifier.VerifyIL("R..ctor()", @" +{ + // Code size 19 (0x13) + .maxstack 2 + IL_0000: ldarg.0 + IL_0001: ldc.i4.0 + IL_0002: conv.u + IL_0003: stfld ""ref readonly int R.field"" + IL_0008: ldstr ""explicit ctor"" + IL_000d: call ""void System.Console.WriteLine(string)"" + IL_0012: ret +}"); + } + + [Fact, WorkItem(63018, "https://github.com/dotnet/roslyn/issues/63018")] + public void InitRefField_AutoDefault_ReadonlyRef() + { + var source = """ +using System; + +var r = new R(); + +ref struct R +{ + public readonly ref int field; + + public R() + { + Console.WriteLine("explicit ctor"); + } +} +"""; + var comp = CreateCompilation(source, options: TestOptions.ReleaseExe, runtimeFeature: RuntimeFlag.ByRefFields); + comp.VerifyDiagnostics( + // (7,29): warning CS0649: Field 'R.field' is never assigned to, and will always have its default value 0 + // public readonly ref int field; + Diagnostic(ErrorCode.WRN_UnassignedInternalField, "field").WithArguments("R.field", "0").WithLocation(7, 29) + ); + + var verifier = CompileAndVerify(comp, verify: Verification.Skipped, expectedOutput: IncludeExpectedOutput("explicit ctor")); + verifier.VerifyIL("R..ctor()", @" +{ + // Code size 19 (0x13) + .maxstack 2 + IL_0000: ldarg.0 + IL_0001: ldc.i4.0 + IL_0002: conv.u + IL_0003: stfld ""ref int R.field"" + IL_0008: ldstr ""explicit ctor"" + IL_000d: call ""void System.Console.WriteLine(string)"" + IL_0012: ret +}"); + } + + [Fact, WorkItem(63018, "https://github.com/dotnet/roslyn/issues/63018")] + public void InitRefField_AutoDefault_WithOtherFieldInitializer() + { + var source = """ +using System; + +var x = 42; +scoped var r = new R(); +r.field = ref x; + +ref struct R +{ + public ref int field; + public int otherField = 42; + + public R() + { + Console.WriteLine("explicit ctor"); + } +} +"""; + var comp = CreateCompilation(source, parseOptions: TestOptions.Regular11, options: TestOptions.ReleaseExe, runtimeFeature: RuntimeFlag.ByRefFields); + comp.VerifyDiagnostics(); + var verifier = CompileAndVerify(comp, verify: Verification.Skipped, expectedOutput: IncludeExpectedOutput("explicit ctor")); + verifier.VerifyIL("R..ctor()", @" + { + // Code size 27 (0x1b) + .maxstack 2 + IL_0000: ldarg.0 + IL_0001: ldc.i4.0 + IL_0002: conv.u + IL_0003: stfld ""ref int R.field"" + IL_0008: ldarg.0 + IL_0009: ldc.i4.s 42 + IL_000b: stfld ""int R.otherField"" + IL_0010: ldstr ""explicit ctor"" + IL_0015: call ""void System.Console.WriteLine(string)"" + IL_001a: ret +}"); + } + /// /// Unexpected modreq(). /// @@ -562,7 +786,7 @@ static void Main() Console.WriteLine(a.F); } }"; - var comp = CreateCompilation(sourceB, new[] { refA }); + var comp = CreateCompilation(sourceB, new[] { refA }, runtimeFeature: RuntimeFlag.ByRefFields); comp.VerifyEmitDiagnostics( // (7,29): error CS0570: 'A.F' is not supported by the language // Console.WriteLine(a.F); @@ -594,7 +818,7 @@ static void Main() Console.WriteLine(a.F); } }"; - var comp = CreateCompilation(sourceB, new[] { refA }); + var comp = CreateCompilation(sourceB, new[] { refA }, runtimeFeature: RuntimeFlag.ByRefFields); comp.VerifyEmitDiagnostics( // (7,29): error CS0570: 'A.F' is not supported by the language // Console.WriteLine(a.F); @@ -634,7 +858,7 @@ static void Main() Console.WriteLine(b.F); } }"; - var comp = CreateCompilation(sourceC, new[] { refB }); + var comp = CreateCompilation(sourceC, new[] { refB }, runtimeFeature: RuntimeFlag.ByRefFields); comp.VerifyEmitDiagnostics( // (7,29): error CS0012: The type 'A' is defined in an assembly that is not referenced. You must add a reference to assembly 'A, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null'. // Console.WriteLine(b.F); @@ -664,7 +888,8 @@ .field public int8& F3 static object F2() => new R().F2; static int F3() => new R().F3; }"; - var verifier = CompileAndVerify(sourceB, new[] { refA }, verify: Verification.Skipped); + var compB = CreateCompilation(sourceB, references: new[] { refA }, runtimeFeature: RuntimeFlag.ByRefFields); + var verifier = CompileAndVerify(compB, verify: Verification.Skipped); // MemberRefMetadataDecoder.FindFieldBySignature() is used to find fields when realIL: true. verifier.VerifyIL("B.F1", realIL: true, expectedIL: @"{ @@ -716,6 +941,37 @@ .locals init (R V_0) AssertEx.Equal(expectedReferences, fieldReferences.ToTestDisplayStrings()); } + [WorkItem(62596, "https://github.com/dotnet/roslyn/issues/62596")] + [Theory] + [InlineData("class")] + [InlineData("struct")] + [InlineData("record")] + [InlineData("record struct")] + public void NonRefStructContainer(string type) + { + var source = +$@"#pragma warning disable 169 +{type} R +{{ + ref int F; +}}"; + + var comp = CreateCompilation(source, parseOptions: TestOptions.Regular10, runtimeFeature: RuntimeFlag.ByRefFields); + comp.VerifyEmitDiagnostics( + // (4,5): error CS8936: Feature 'ref fields' is not available in C# 10.0. Please use language version 11.0 or greater. + // ref int F; + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "ref int").WithArguments("ref fields", "11.0").WithLocation(4, 5), + // (4,13): error CS9059: A ref field can only be declared in a ref struct. + // ref int F; + Diagnostic(ErrorCode.ERR_RefFieldInNonRefStruct, "F").WithLocation(4, 13)); + + comp = CreateCompilation(source, runtimeFeature: RuntimeFlag.ByRefFields); + comp.VerifyEmitDiagnostics( + // (4,13): error CS9059: A ref field can only be declared in a ref struct. + // ref int F; + Diagnostic(ErrorCode.ERR_RefFieldInNonRefStruct, "F").WithLocation(4, 13)); + } + /// /// Determination of enum underlying type should ignore ref fields /// and fields with required custom modifiers. @@ -804,28 +1060,29 @@ static ref T F(R r) comp = CreateEmptyCompilation(source, references: new[] { refA }, parseOptions: TestOptions.Regular10); comp.VerifyDiagnostics( - // (3,12): error CS8652: The feature 'ref fields' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // (3,12): error CS8936: Feature 'ref fields' is not available in C# 10.0. Please use language version 11.0 or greater. // public ref T F; - Diagnostic(ErrorCode.ERR_FeatureInPreview, "ref T").WithArguments("ref fields").WithLocation(3, 12), + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "ref T").WithArguments("ref fields", "11.0").WithLocation(3, 12), + // (3,18): error CS9061: Target runtime doesn't support ref fields. + // public ref T F; + Diagnostic(ErrorCode.ERR_RuntimeDoesNotSupportRefFields, "F").WithLocation(3, 18), // (10,20): error CS8167: Cannot return by reference a member of parameter 'r' because it is not a ref or out parameter // return ref r.F; Diagnostic(ErrorCode.ERR_RefReturnParameter2, "r").WithArguments("r").WithLocation(10, 20)); Assert.False(comp.Assembly.RuntimeSupportsByRefFields); comp = CreateEmptyCompilation(source, references: new[] { refAB }, parseOptions: TestOptions.Regular10); - // https://github.com/dotnet/roslyn/issues/62131: Enable updated escape rules if - // System.Runtime.CompilerServices.RuntimeFeature.ByRefFields exists. comp.VerifyDiagnostics( - // (3,12): error CS8652: The feature 'ref fields' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // (3,12): error CS8936: Feature 'ref fields' is not available in C# 10.0. Please use language version 11.0 or greater. // public ref T F; - Diagnostic(ErrorCode.ERR_FeatureInPreview, "ref T").WithArguments("ref fields").WithLocation(3, 12), - // (10,20): error CS8167: Cannot return by reference a member of parameter 'r' because it is not a ref or out parameter - // return ref r.F; - Diagnostic(ErrorCode.ERR_RefReturnParameter2, "r").WithArguments("r").WithLocation(10, 20)); + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "ref T").WithArguments("ref fields", "11.0").WithLocation(3, 12)); Assert.True(comp.Assembly.RuntimeSupportsByRefFields); comp = CreateEmptyCompilation(source, references: new[] { refA }); - comp.VerifyDiagnostics(); + comp.VerifyDiagnostics( + // (3,18): error CS9061: Target runtime doesn't support ref fields. + // public ref T F; + Diagnostic(ErrorCode.ERR_RuntimeDoesNotSupportRefFields, "F").WithLocation(3, 18)); Assert.False(comp.Assembly.RuntimeSupportsByRefFields); comp = CreateEmptyCompilation(source, references: new[] { refAB }); @@ -841,6 +1098,7 @@ public void RefFieldTypeRefStruct_01() { var source = @"#pragma warning disable 169 +using System.Diagnostics.CodeAnalysis; ref struct R1 { } @@ -850,17 +1108,17 @@ ref struct R2 } class Program { - static void F(ref R1 r1) + static void F([UnscopedRef] ref R1 r1) { var r2 = new R2(); r2.F = ref r1; } }"; - var comp = CreateCompilation(source); + var comp = CreateCompilation(new[] { source, UnscopedRefAttributeDefinition }, runtimeFeature: RuntimeFlag.ByRefFields); comp.VerifyEmitDiagnostics( - // (7,12): error CS9050: A ref field cannot refer to a ref struct. + // (8,12): error CS9050: A ref field cannot refer to a ref struct. // public ref R1 F; - Diagnostic(ErrorCode.ERR_RefFieldCannotReferToRefStruct, "ref R1").WithLocation(7, 12)); + Diagnostic(ErrorCode.ERR_RefFieldCannotReferToRefStruct, "ref R1").WithLocation(8, 12)); } /// @@ -891,7 +1149,7 @@ static void F(ref R1 r1) r2.F = ref r1; } }"; - var comp = CreateCompilation(sourceB, references: new[] { refA }); + var comp = CreateCompilation(sourceB, references: new[] { refA }, runtimeFeature: RuntimeFlag.ByRefFields); comp.VerifyEmitDiagnostics( // (6,12): error CS0570: 'R2.F' is not supported by the language // r2.F = ref r1; @@ -917,39 +1175,24 @@ static ref T F2(T t) return ref r2.F; } }"; - - var expectedLegacyDiagnostics = new DiagnosticDescription[] - { - // (3,5): error CS8652: The feature 'ref fields' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + var comp = CreateCompilation(source, parseOptions: TestOptions.Regular10, runtimeFeature: RuntimeFlag.ByRefFields); + comp.VerifyDiagnostics( + // (3,5): error CS8936: Feature 'ref fields' is not available in C# 10.0. Please use language version 11.0 or greater. // ref T F; - Diagnostic(ErrorCode.ERR_FeatureInPreview, "ref T").WithArguments("ref fields").WithLocation(3, 5), - // (5,23): error CS8170: Struct members cannot return 'this' or other instance members by reference - // ref T F0() => ref this.F; - Diagnostic(ErrorCode.ERR_RefReturnStructThis, "this.F").WithLocation(5, 23), - // (8,20): error CS8167: Cannot return by reference a member of parameter 'r1' because it is not a ref or out parameter - // return ref r1.F; - Diagnostic(ErrorCode.ERR_RefReturnParameter2, "r1").WithArguments("r1").WithLocation(8, 20), - // (13,20): error CS8169: Cannot return a member of local 'r2' by reference because it is not a ref local + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "ref T").WithArguments("ref fields", "11.0").WithLocation(3, 5), + // (13,20): error CS8352: Cannot use variable 'r2' in this context because it may expose referenced variables outside of their declaration scope // return ref r2.F; - Diagnostic(ErrorCode.ERR_RefReturnLocal2, "r2").WithArguments("r2").WithLocation(13, 20) - }; + Diagnostic(ErrorCode.ERR_EscapeVariable, "r2.F").WithArguments("r2").WithLocation(13, 20)); - var expectedUpdatedDiagnostics = new DiagnosticDescription[] - { + comp = CreateCompilation(source, runtimeFeature: RuntimeFlag.ByRefFields); + comp.VerifyEmitDiagnostics( // (13,20): error CS8352: Cannot use variable 'r2' in this context because it may expose referenced variables outside of their declaration scope // return ref r2.F; - Diagnostic(ErrorCode.ERR_EscapeVariable, "r2.F").WithArguments("r2").WithLocation(13, 20), - }; - - var comp = CreateCompilation(source, parseOptions: TestOptions.Regular10); - comp.VerifyDiagnostics(comp.Assembly.RuntimeSupportsByRefFields ? expectedUpdatedDiagnostics : expectedLegacyDiagnostics); - - comp = CreateCompilation(source); - comp.VerifyEmitDiagnostics(expectedUpdatedDiagnostics); + Diagnostic(ErrorCode.ERR_EscapeVariable, "r2.F").WithArguments("r2").WithLocation(13, 20)); } [Fact] - public void RefFields_RefReassignment() + public void RefFields_RefReassignment_01() { var source = @"ref struct R @@ -973,26 +1216,211 @@ static R F2(R r2) return r2; } }"; - - var expectedLegacyDiagnostics = new DiagnosticDescription[] - { - // (3,5): error CS8652: The feature 'ref fields' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + var comp = CreateCompilation(source, parseOptions: TestOptions.Regular10, runtimeFeature: RuntimeFlag.ByRefFields); + comp.VerifyDiagnostics( + // (3,5): error CS8936: Feature 'ref fields' is not available in C# 10.0. Please use language version 11.0 or greater. // ref T F; - Diagnostic(ErrorCode.ERR_FeatureInPreview, "ref T").WithArguments("ref fields").WithLocation(3, 5), - }; + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "ref T").WithArguments("ref fields", "11.0").WithLocation(3, 5), + // (18,9): error CS8374: Cannot ref-assign 't' to 'F' because 't' has a narrower escape scope than 'F'. + // r2.F = ref t; + Diagnostic(ErrorCode.ERR_RefAssignNarrower, "r2.F = ref t").WithArguments("F", "t").WithLocation(18, 9) + ); - var expectedUpdatedDiagnostics = new DiagnosticDescription[] - { + comp = CreateCompilation(source, runtimeFeature: RuntimeFlag.ByRefFields); + comp.VerifyEmitDiagnostics( // (18,9): error CS8374: Cannot ref-assign 't' to 'F' because 't' has a narrower escape scope than 'F'. // r2.F = ref t; Diagnostic(ErrorCode.ERR_RefAssignNarrower, "r2.F = ref t").WithArguments("F", "t").WithLocation(18, 9) - }; + ); + } - var comp = CreateCompilation(source, parseOptions: TestOptions.Regular10); - comp.VerifyDiagnostics(comp.Assembly.RuntimeSupportsByRefFields ? expectedUpdatedDiagnostics : expectedLegacyDiagnostics); + [Fact] + [WorkItem(63434, "https://github.com/dotnet/roslyn/issues/63434")] + public void RefFields_RefReassignment_02() + { + var source = +@" +using System; - comp = CreateCompilation(source); - comp.VerifyEmitDiagnostics(expectedUpdatedDiagnostics); +class Program +{ + static void Main() + { + int i = 42; + var r = new R() { Field = ref i }; + Console.WriteLine(r.Field); + i = 43; + Console.WriteLine(r.Field); + } +} + +ref struct R +{ + public ref int Field; +} +"; + var comp = CreateCompilation(source, options: TestOptions.ReleaseExe, runtimeFeature: RuntimeFlag.ByRefFields); + CompileAndVerify(comp, verify: Verification.Skipped, expectedOutput: IncludeExpectedOutput( +@"42 +43")).VerifyDiagnostics(). + VerifyIL("Program.Main", +@" +{ + // Code size 48 (0x30) + .maxstack 2 + .locals init (int V_0, //i + R V_1) + IL_0000: ldc.i4.s 42 + IL_0002: stloc.0 + IL_0003: ldloca.s V_1 + IL_0005: initobj ""R"" + IL_000b: ldloca.s V_1 + IL_000d: ldloca.s V_0 + IL_000f: stfld ""ref int R.Field"" + IL_0014: ldloc.1 + IL_0015: dup + IL_0016: ldfld ""ref int R.Field"" + IL_001b: ldind.i4 + IL_001c: call ""void System.Console.WriteLine(int)"" + IL_0021: ldc.i4.s 43 + IL_0023: stloc.0 + IL_0024: ldfld ""ref int R.Field"" + IL_0029: ldind.i4 + IL_002a: call ""void System.Console.WriteLine(int)"" + IL_002f: ret +} +"); + } + + [Fact] + public void RefFields_RefReassignment_03() + { + var source = +@" +using System; + +class Program +{ + static void Main() + { + int i = 42; + var r = new R(); + r.Field = ref i; + Console.WriteLine(r.Field); + } +} + +ref struct R +{ + public ref int Field; +} +"; + var comp = CreateCompilation(source, options: TestOptions.ReleaseExe, runtimeFeature: RuntimeFlag.ByRefFields); + comp.VerifyDiagnostics( + // (10,9): error CS8374: Cannot ref-assign 'i' to 'Field' because 'i' has a narrower escape scope than 'Field'. + // r.Field = ref i; + Diagnostic(ErrorCode.ERR_RefAssignNarrower, "r.Field = ref i").WithArguments("Field", "i").WithLocation(10, 9) + ); + } + + [Fact] + [WorkItem(63434, "https://github.com/dotnet/roslyn/issues/63434")] + public void RefFields_RefReassignment_04() + { + var source = +@" +using System; + +class Program +{ + static void Main() + { + int i = 42; + Test(ref i); + } + + static void Test(ref int i) + { + var r = new R() { Field = ref i }; + Console.WriteLine(r.Field); + } +} + +ref struct R +{ + public ref int Field; +} +"; + var comp = CreateCompilation(source, options: TestOptions.ReleaseExe, runtimeFeature: RuntimeFlag.ByRefFields); + CompileAndVerify(comp, verify: Verification.Skipped, expectedOutput: IncludeExpectedOutput("42")).VerifyDiagnostics(). + VerifyIL("Program.Test", +@" +{ + // Code size 29 (0x1d) + .maxstack 2 + .locals init (R V_0) + IL_0000: ldloca.s V_0 + IL_0002: initobj ""R"" + IL_0008: ldloca.s V_0 + IL_000a: ldarg.0 + IL_000b: stfld ""ref int R.Field"" + IL_0010: ldloc.0 + IL_0011: ldfld ""ref int R.Field"" + IL_0016: ldind.i4 + IL_0017: call ""void System.Console.WriteLine(int)"" + IL_001c: ret +} +"); + } + + [Fact] + public void RefFields_RefReassignment_05() + { + var source = +@" +using System; + +class Program +{ + static void Main() + { + int i = 42; + Test(ref i); + } + + static void Test(ref int i) + { + var r = new R(); + r.Field = ref i; + Console.WriteLine(r.Field); + } +} + +ref struct R +{ + public ref int Field; +} +"; + var comp = CreateCompilation(source, options: TestOptions.ReleaseExe, runtimeFeature: RuntimeFlag.ByRefFields); + CompileAndVerify(comp, verify: Verification.Skipped, expectedOutput: IncludeExpectedOutput("42")).VerifyDiagnostics(). + VerifyIL("Program.Test", +@" +{ + // Code size 29 (0x1d) + .maxstack 2 + .locals init (R V_0) //r + IL_0000: ldloca.s V_0 + IL_0002: initobj ""R"" + IL_0008: ldloca.s V_0 + IL_000a: ldarg.0 + IL_000b: stfld ""ref int R.Field"" + IL_0010: ldloc.0 + IL_0011: ldfld ""ref int R.Field"" + IL_0016: ldind.i4 + IL_0017: call ""void System.Console.WriteLine(int)"" + IL_001c: ret +} +"); } [Fact] @@ -1036,13 +1464,13 @@ class Program { static ref C F1(ref C c) => ref c; static ref S F2(ref S s) => ref s; - static ref R F3(ref R r) => ref r; + static ref R F3(ref R r) => ref r; // 1 static ref readonly C F4(in C c) => ref c; static ref readonly S F5(in S s) => ref s; - static ref readonly R F6(in R r) => ref r; - static ref C F7(out C c) { c = default; return ref c; } // 1 - static ref S F8(out S s) { s = default; return ref s; } // 2 - static ref R F9(out R r) { r = default; return ref r; } // 3 + static ref readonly R F6(in R r) => ref r; // 2 + static ref C F7(out C c) { c = default; return ref c; } // 3 + static ref S F8(out S s) { s = default; return ref s; } // 4 + static ref R F9(out R r) { r = default; return ref r; } // 5 }"; var expectedLegacyDiagnostics = new DiagnosticDescription[] @@ -1051,14 +1479,20 @@ class Program var expectedUpdatedDiagnostics = new DiagnosticDescription[] { + // (8,37): error CS8166: Cannot return a parameter by reference 'r' because it is not a ref parameter + // static ref R F3(ref R r) => ref r; // 1 + Diagnostic(ErrorCode.ERR_RefReturnParameter, "r").WithArguments("r").WithLocation(8, 37), + // (11,45): error CS8166: Cannot return a parameter by reference 'r' because it is not a ref parameter + // static ref readonly R F6(in R r) => ref r; // 2 + Diagnostic(ErrorCode.ERR_RefReturnParameter, "r").WithArguments("r").WithLocation(11, 45), // (12,56): error CS8166: Cannot return a parameter by reference 'c' because it is not a ref parameter - // static ref C F7(out C c) { c = default; return ref c; } // 1 + // static ref C F7(out C c) { c = default; return ref c; } // 3 Diagnostic(ErrorCode.ERR_RefReturnParameter, "c").WithArguments("c").WithLocation(12, 56), // (13,56): error CS8166: Cannot return a parameter by reference 's' because it is not a ref parameter - // static ref S F8(out S s) { s = default; return ref s; } // 2 + // static ref S F8(out S s) { s = default; return ref s; } // 4 Diagnostic(ErrorCode.ERR_RefReturnParameter, "s").WithArguments("s").WithLocation(13, 56), // (14,56): error CS8166: Cannot return a parameter by reference 'r' because it is not a ref parameter - // static ref R F9(out R r) { r = default; return ref r; } // 3 + // static ref R F9(out R r) { r = default; return ref r; } // 5 Diagnostic(ErrorCode.ERR_RefReturnParameter, "r").WithArguments("r").WithLocation(14, 56) }; @@ -2182,88 +2616,45 @@ static R G9() public void MethodInvocation_Scoped_Lvalue() { var source = -@"class Program +@" +using System.Diagnostics.CodeAnalysis; +class Program { - static ref T F0(ref R x, ref R y) => throw null; - static ref T F1(ref R x, ref scoped R y) => throw null; - static ref T F2(ref R x, scoped ref R y) => throw null; - static ref T F3(ref scoped R x, ref scoped R y) => throw null; - static ref T F4(ref scoped R x, scoped ref R y) => throw null; - static ref T F5(scoped ref R x, scoped ref R y) => throw null; - - static ref T F00(ref R x) { R y = default; return ref F0(ref x, ref y); } // 1 - static ref T F01(ref R x) { R y = default; return ref F1(ref x, ref y); } - static ref T F02(ref R x) { R y = default; return ref F2(ref x, ref y); } - static ref T F03(ref R x) { R y = default; return ref F3(ref x, ref y); } - static ref T F04(ref R x) { R y = default; return ref F4(ref x, ref y); } - static ref T F05(ref R x) { R y = default; return ref F5(ref x, ref y); } - - static ref T F10(ref scoped R x) { R y = default; return ref F0(ref x, ref y); } // 2 - static ref T F11(ref scoped R x) { R y = default; return ref F1(ref x, ref y); } // 3 - static ref T F12(ref scoped R x) { R y = default; return ref F2(ref x, ref y); } // 4 - static ref T F13(ref scoped R x) { R y = default; return ref F3(ref x, ref y); } - static ref T F14(ref scoped R x) { R y = default; return ref F4(ref x, ref y); } - static ref T F15(ref scoped R x) { R y = default; return ref F5(ref x, ref y); } // 5 - - static ref T F20(scoped ref R x) { R y = default; return ref F0(ref x, ref y); } // 6 - static ref T F21(scoped ref R x) { R y = default; return ref F1(ref x, ref y); } // 7 - static ref T F22(scoped ref R x) { R y = default; return ref F2(ref x, ref y); } // 8 - static ref T F23(scoped ref R x) { R y = default; return ref F3(ref x, ref y); } - static ref T F24(scoped ref R x) { R y = default; return ref F4(ref x, ref y); } - static ref T F25(scoped ref R x) { R y = default; return ref F5(ref x, ref y); } + static ref T F0([UnscopedRef] ref R x, [UnscopedRef] ref R y) => throw null; + static ref T F2([UnscopedRef] ref R x, ref R y) => throw null; + static ref T F5(ref R x, ref R y) => throw null; + + static ref T F00([UnscopedRef] ref R x) { R y = default; return ref F0(ref x, ref y); } // 1 + static ref T F02([UnscopedRef] ref R x) { R y = default; return ref F2(ref x, ref y); } + static ref T F05([UnscopedRef] ref R x) { R y = default; return ref F5(ref x, ref y); } + + static ref T F20(ref R x) { R y = default; return ref F0(ref x, ref y); } // 2 + static ref T F22(ref R x) { R y = default; return ref F2(ref x, ref y); } // 3 + static ref T F25(ref R x) { R y = default; return ref F5(ref x, ref y); } } ref struct R { } "; - var comp = CreateCompilation(source); + var comp = CreateCompilation(new[] { source, UnscopedRefAttributeDefinition }); comp.VerifyEmitDiagnostics( - // (10,68): error CS8347: Cannot use a result of 'Program.F0(ref R, ref R)' in this context because it may expose variables referenced by parameter 'y' outside of their declaration scope - // static ref T F00(ref R x) { R y = default; return ref F0(ref x, ref y); } // 1 - Diagnostic(ErrorCode.ERR_EscapeCall, "F0(ref x, ref y)").WithArguments("Program.F0(ref R, ref R)", "y").WithLocation(10, 68), - // (10,82): error CS8168: Cannot return local 'y' by reference because it is not a ref local - // static ref T F00(ref R x) { R y = default; return ref F0(ref x, ref y); } // 1 - Diagnostic(ErrorCode.ERR_RefReturnLocal, "y").WithArguments("y").WithLocation(10, 82), - // (17,75): error CS8350: This combination of arguments to 'Program.F0(ref R, ref R)' is disallowed because it may expose variables referenced by parameter 'x' outside of their declaration scope - // static ref T F10(ref scoped R x) { R y = default; return ref F0(ref x, ref y); } // 2 - Diagnostic(ErrorCode.ERR_CallArgMixing, "F0(ref x, ref y)").WithArguments("Program.F0(ref R, ref R)", "x").WithLocation(17, 75), - // (17,82): error CS8352: Cannot use variable 'ref R' in this context because it may expose referenced variables outside of their declaration scope - // static ref T F10(ref scoped R x) { R y = default; return ref F0(ref x, ref y); } // 2 - Diagnostic(ErrorCode.ERR_EscapeVariable, "x").WithArguments("ref R").WithLocation(17, 82), - // (18,75): error CS8347: Cannot use a result of 'Program.F1(ref R, ref R)' in this context because it may expose variables referenced by parameter 'x' outside of their declaration scope - // static ref T F11(ref scoped R x) { R y = default; return ref F1(ref x, ref y); } // 3 - Diagnostic(ErrorCode.ERR_EscapeCall, "F1(ref x, ref y)").WithArguments("Program.F1(ref R, ref R)", "x").WithLocation(18, 75), - // (18,82): error CS8166: Cannot return a parameter by reference 'x' because it is not a ref parameter - // static ref T F11(ref scoped R x) { R y = default; return ref F1(ref x, ref y); } // 3 - Diagnostic(ErrorCode.ERR_RefReturnParameter, "x").WithArguments("x").WithLocation(18, 82), - // (19,75): error CS8350: This combination of arguments to 'Program.F2(ref R, ref R)' is disallowed because it may expose variables referenced by parameter 'x' outside of their declaration scope - // static ref T F12(ref scoped R x) { R y = default; return ref F2(ref x, ref y); } // 4 - Diagnostic(ErrorCode.ERR_CallArgMixing, "F2(ref x, ref y)").WithArguments("Program.F2(ref R, ref R)", "x").WithLocation(19, 75), - // (19,82): error CS8352: Cannot use variable 'ref R' in this context because it may expose referenced variables outside of their declaration scope - // static ref T F12(ref scoped R x) { R y = default; return ref F2(ref x, ref y); } // 4 - Diagnostic(ErrorCode.ERR_EscapeVariable, "x").WithArguments("ref R").WithLocation(19, 82), - // (22,75): error CS8350: This combination of arguments to 'Program.F5(ref R, ref R)' is disallowed because it may expose variables referenced by parameter 'x' outside of their declaration scope - // static ref T F15(ref scoped R x) { R y = default; return ref F5(ref x, ref y); } // 5 - Diagnostic(ErrorCode.ERR_CallArgMixing, "F5(ref x, ref y)").WithArguments("Program.F5(ref R, ref R)", "x").WithLocation(22, 75), - // (22,82): error CS8352: Cannot use variable 'ref R' in this context because it may expose referenced variables outside of their declaration scope - // static ref T F15(ref scoped R x) { R y = default; return ref F5(ref x, ref y); } // 5 - Diagnostic(ErrorCode.ERR_EscapeVariable, "x").WithArguments("ref R").WithLocation(22, 82), - // (24,75): error CS8347: Cannot use a result of 'Program.F0(ref R, ref R)' in this context because it may expose variables referenced by parameter 'x' outside of their declaration scope - // static ref T F20(scoped ref R x) { R y = default; return ref F0(ref x, ref y); } // 6 - Diagnostic(ErrorCode.ERR_EscapeCall, "F0(ref x, ref y)").WithArguments("Program.F0(ref R, ref R)", "x").WithLocation(24, 75), - // (24,82): error CS8166: Cannot return a parameter by reference 'x' because it is not a ref parameter - // static ref T F20(scoped ref R x) { R y = default; return ref F0(ref x, ref y); } // 6 - Diagnostic(ErrorCode.ERR_RefReturnParameter, "x").WithArguments("x").WithLocation(24, 82), - // (25,75): error CS8347: Cannot use a result of 'Program.F1(ref R, ref R)' in this context because it may expose variables referenced by parameter 'x' outside of their declaration scope - // static ref T F21(scoped ref R x) { R y = default; return ref F1(ref x, ref y); } // 7 - Diagnostic(ErrorCode.ERR_EscapeCall, "F1(ref x, ref y)").WithArguments("Program.F1(ref R, ref R)", "x").WithLocation(25, 75), - // (25,82): error CS8166: Cannot return a parameter by reference 'x' because it is not a ref parameter - // static ref T F21(scoped ref R x) { R y = default; return ref F1(ref x, ref y); } // 7 - Diagnostic(ErrorCode.ERR_RefReturnParameter, "x").WithArguments("x").WithLocation(25, 82), - // (26,75): error CS8347: Cannot use a result of 'Program.F2(ref R, ref R)' in this context because it may expose variables referenced by parameter 'x' outside of their declaration scope - // static ref T F22(scoped ref R x) { R y = default; return ref F2(ref x, ref y); } // 8 - Diagnostic(ErrorCode.ERR_EscapeCall, "F2(ref x, ref y)").WithArguments("Program.F2(ref R, ref R)", "x").WithLocation(26, 75), - // (26,82): error CS8166: Cannot return a parameter by reference 'x' because it is not a ref parameter - // static ref T F22(scoped ref R x) { R y = default; return ref F2(ref x, ref y); } // 8 - Diagnostic(ErrorCode.ERR_RefReturnParameter, "x").WithArguments("x").WithLocation(26, 82)); + // (9,82): error CS8350: This combination of arguments to 'Program.F0(ref R, ref R)' is disallowed because it may expose variables referenced by parameter 'y' outside of their declaration scope + // static ref T F00([UnscopedRef] ref R x) { R y = default; return ref F0(ref x, ref y); } // 1 + Diagnostic(ErrorCode.ERR_CallArgMixing, "F0(ref x, ref y)").WithArguments("Program.F0(ref R, ref R)", "y").WithLocation(9, 82), + // (9,96): error CS8168: Cannot return local 'y' by reference because it is not a ref local + // static ref T F00([UnscopedRef] ref R x) { R y = default; return ref F0(ref x, ref y); } // 1 + Diagnostic(ErrorCode.ERR_RefReturnLocal, "y").WithArguments("y").WithLocation(9, 96), + // (13,68): error CS8350: This combination of arguments to 'Program.F0(ref R, ref R)' is disallowed because it may expose variables referenced by parameter 'x' outside of their declaration scope + // static ref T F20(ref R x) { R y = default; return ref F0(ref x, ref y); } // 2 + Diagnostic(ErrorCode.ERR_CallArgMixing, "F0(ref x, ref y)").WithArguments("Program.F0(ref R, ref R)", "x").WithLocation(13, 68), + // (13,75): error CS8166: Cannot return a parameter by reference 'x' because it is not a ref parameter + // static ref T F20(ref R x) { R y = default; return ref F0(ref x, ref y); } // 2 + Diagnostic(ErrorCode.ERR_RefReturnParameter, "x").WithArguments("x").WithLocation(13, 75), + // (14,68): error CS8350: This combination of arguments to 'Program.F2(ref R, ref R)' is disallowed because it may expose variables referenced by parameter 'x' outside of their declaration scope + // static ref T F22(ref R x) { R y = default; return ref F2(ref x, ref y); } // 3 + Diagnostic(ErrorCode.ERR_CallArgMixing, "F2(ref x, ref y)").WithArguments("Program.F2(ref R, ref R)", "x").WithLocation(14, 68), + // (14,75): error CS8166: Cannot return a parameter by reference 'x' because it is not a ref parameter + // static ref T F22(ref R x) { R y = default; return ref F2(ref x, ref y); } // 3 + Diagnostic(ErrorCode.ERR_RefReturnParameter, "x").WithArguments("x").WithLocation(14, 75) + ); } [Fact] @@ -2311,93 +2702,75 @@ class Program } [Fact] - public void MethodArgumentsMustMatch_01() + public void MethodInvocation_Params() + { + var source = +@"ref struct R +{ + public R(ref int i) { } +} +class Program +{ + static R M1(R input, params object[] array) + { + return input; + } + static R M2() + { + int i = 42; + var r = new R(ref i); + return M1(r); + } + static R M3() + { + int i = 42; + var r = new R(ref i); + return M1(r, 0, 1, 2); + } +}"; + var comp = CreateCompilation(source); + comp.VerifyEmitDiagnostics( + // (15,16): error CS8347: Cannot use a result of 'Program.M1(R, params object[])' in this context because it may expose variables referenced by parameter 'input' outside of their declaration scope + // return M1(r); + Diagnostic(ErrorCode.ERR_EscapeCall, "M1(r)").WithArguments("Program.M1(R, params object[])", "input").WithLocation(15, 16), + // (15,19): error CS8352: Cannot use variable 'r' in this context because it may expose referenced variables outside of their declaration scope + // return M1(r); + Diagnostic(ErrorCode.ERR_EscapeVariable, "r").WithArguments("r").WithLocation(15, 19), + // (21,16): error CS8347: Cannot use a result of 'Program.M1(R, params object[])' in this context because it may expose variables referenced by parameter 'input' outside of their declaration scope + // return M1(r, 0, 1, 2); + Diagnostic(ErrorCode.ERR_EscapeCall, "M1(r, 0, 1, 2)").WithArguments("Program.M1(R, params object[])", "input").WithLocation(21, 16), + // (21,19): error CS8352: Cannot use variable 'r' in this context because it may expose referenced variables outside of their declaration scope + // return M1(r, 0, 1, 2); + Diagnostic(ErrorCode.ERR_EscapeVariable, "r").WithArguments("r").WithLocation(21, 19)); + } + + [Fact] + public void MethodArgumentsMustMatch_01() { var source = @"ref struct R { public void F0(ref R r) => throw null; - public void F1(ref scoped R r) => throw null; public void F2(scoped ref R r) => throw null; } class Program { static void F00(ref R x, ref R y) { x.F0(ref y); } - static void F01(ref R x, ref R y) { x.F1(ref y); } static void F02(ref R x, ref R y) { x.F2(ref y); } - static void F10(ref R x, ref scoped R y) { x.F0(ref y); } // 1 - static void F11(ref R x, ref scoped R y) { x.F1(ref y); } - static void F12(ref R x, ref scoped R y) { x.F2(ref y); } // 2 - static void F20(ref R x, scoped ref R y) { x.F0(ref y); } - static void F21(ref R x, scoped ref R y) { x.F1(ref y); } static void F22(ref R x, scoped ref R y) { x.F2(ref y); } - static void F30(ref scoped R x, ref R y) { x.F0(ref y); } // 3 - static void F31(ref scoped R x, ref R y) { x.F1(ref y); } - static void F32(ref scoped R x, ref R y) { x.F2(ref y); } // 4 - - static void F40(ref scoped R x, ref scoped R y) { x.F0(ref y); } - static void F41(ref scoped R x, ref scoped R y) { x.F1(ref y); } - static void F42(ref scoped R x, ref scoped R y) { x.F2(ref y); } - - static void F50(ref scoped R x, scoped ref R y) { x.F0(ref y); } // 5 - static void F51(ref scoped R x, scoped ref R y) { x.F1(ref y); } - static void F52(ref scoped R x, scoped ref R y) { x.F2(ref y); } // 6 - static void F60(scoped ref R x, ref R y) { x.F0(ref y); } - static void F61(scoped ref R x, ref R y) { x.F1(ref y); } static void F62(scoped ref R x, ref R y) { x.F2(ref y); } - static void F70(scoped ref R x, ref scoped R y) { x.F0(ref y); } // 7 - static void F71(scoped ref R x, ref scoped R y) { x.F1(ref y); } - static void F72(scoped ref R x, ref scoped R y) { x.F2(ref y); } // 8 - static void F80(scoped ref R x, scoped ref R y) { x.F0(ref y); } - static void F81(scoped ref R x, scoped ref R y) { x.F1(ref y); } static void F82(scoped ref R x, scoped ref R y) { x.F2(ref y); } }"; var comp = CreateCompilation(source); // Should we also report ErrorCode.ERR_CallArgMixing for 3, 4, 5, 6? See the call to // CheckValEscape() for the receiver at the end of CheckInvocationArgMixing(). - comp.VerifyEmitDiagnostics( - // (13,48): error CS8350: This combination of arguments to 'R.F0(ref R)' is disallowed because it may expose variables referenced by parameter 'r' outside of their declaration scope - // static void F10(ref R x, ref scoped R y) { x.F0(ref y); } // 1 - Diagnostic(ErrorCode.ERR_CallArgMixing, "x.F0(ref y)").WithArguments("R.F0(ref R)", "r").WithLocation(13, 48), - // (13,57): error CS8352: Cannot use variable 'ref R' in this context because it may expose referenced variables outside of their declaration scope - // static void F10(ref R x, ref scoped R y) { x.F0(ref y); } // 1 - Diagnostic(ErrorCode.ERR_EscapeVariable, "y").WithArguments("ref R").WithLocation(13, 57), - // (15,48): error CS8350: This combination of arguments to 'R.F2(ref R)' is disallowed because it may expose variables referenced by parameter 'r' outside of their declaration scope - // static void F12(ref R x, ref scoped R y) { x.F2(ref y); } // 2 - Diagnostic(ErrorCode.ERR_CallArgMixing, "x.F2(ref y)").WithArguments("R.F2(ref R)", "r").WithLocation(15, 48), - // (15,57): error CS8352: Cannot use variable 'ref R' in this context because it may expose referenced variables outside of their declaration scope - // static void F12(ref R x, ref scoped R y) { x.F2(ref y); } // 2 - Diagnostic(ErrorCode.ERR_EscapeVariable, "y").WithArguments("ref R").WithLocation(15, 57), - // (21,48): error CS8352: Cannot use variable 'ref R' in this context because it may expose referenced variables outside of their declaration scope - // static void F30(ref scoped R x, ref R y) { x.F0(ref y); } // 3 - Diagnostic(ErrorCode.ERR_EscapeVariable, "x").WithArguments("ref R").WithLocation(21, 48), - // (23,48): error CS8352: Cannot use variable 'ref R' in this context because it may expose referenced variables outside of their declaration scope - // static void F32(ref scoped R x, ref R y) { x.F2(ref y); } // 4 - Diagnostic(ErrorCode.ERR_EscapeVariable, "x").WithArguments("ref R").WithLocation(23, 48), - // (29,55): error CS8352: Cannot use variable 'ref R' in this context because it may expose referenced variables outside of their declaration scope - // static void F50(ref scoped R x, scoped ref R y) { x.F0(ref y); } // 5 - Diagnostic(ErrorCode.ERR_EscapeVariable, "x").WithArguments("ref R").WithLocation(29, 55), - // (31,55): error CS8352: Cannot use variable 'ref R' in this context because it may expose referenced variables outside of their declaration scope - // static void F52(ref scoped R x, scoped ref R y) { x.F2(ref y); } // 6 - Diagnostic(ErrorCode.ERR_EscapeVariable, "x").WithArguments("ref R").WithLocation(31, 55), - // (37,55): error CS8350: This combination of arguments to 'R.F0(ref R)' is disallowed because it may expose variables referenced by parameter 'r' outside of their declaration scope - // static void F70(scoped ref R x, ref scoped R y) { x.F0(ref y); } // 7 - Diagnostic(ErrorCode.ERR_CallArgMixing, "x.F0(ref y)").WithArguments("R.F0(ref R)", "r").WithLocation(37, 55), - // (37,64): error CS8352: Cannot use variable 'ref R' in this context because it may expose referenced variables outside of their declaration scope - // static void F70(scoped ref R x, ref scoped R y) { x.F0(ref y); } // 7 - Diagnostic(ErrorCode.ERR_EscapeVariable, "y").WithArguments("ref R").WithLocation(37, 64), - // (39,55): error CS8350: This combination of arguments to 'R.F2(ref R)' is disallowed because it may expose variables referenced by parameter 'r' outside of their declaration scope - // static void F72(scoped ref R x, ref scoped R y) { x.F2(ref y); } // 8 - Diagnostic(ErrorCode.ERR_CallArgMixing, "x.F2(ref y)").WithArguments("R.F2(ref R)", "r").WithLocation(39, 55), - // (39,64): error CS8352: Cannot use variable 'ref R' in this context because it may expose referenced variables outside of their declaration scope - // static void F72(scoped ref R x, ref scoped R y) { x.F2(ref y); } // 8 - Diagnostic(ErrorCode.ERR_EscapeVariable, "y").WithArguments("ref R").WithLocation(39, 64)); + comp.VerifyEmitDiagnostics(); } [Fact] @@ -2410,92 +2783,23 @@ public void MethodArgumentsMustMatch_02() class Program { static void F0(ref R a, ref R b) => throw null; - static void F1(ref R a, ref scoped R b) => throw null; static void F2(ref R a, scoped ref R b) => throw null; - static void F3(ref scoped R a, ref scoped R b) => throw null; - static void F4(ref scoped R a, scoped ref R b) => throw null; static void F5(scoped ref R a, scoped ref R b) => throw null; static void F00(ref R x, ref R y) { F0(ref x, ref y); } - static void F01(ref R x, ref R y) { F1(ref x, ref y); } static void F02(ref R x, ref R y) { F2(ref x, ref y); } - static void F03(ref R x, ref R y) { F3(ref x, ref y); } - static void F04(ref R x, ref R y) { F4(ref x, ref y); } static void F05(ref R x, ref R y) { F5(ref x, ref y); } - static void F10(ref R x, ref scoped R y) { F0(ref x, ref y); } // 1 - static void F11(ref R x, ref scoped R y) { F1(ref x, ref y); } - static void F12(ref R x, ref scoped R y) { F2(ref x, ref y); } // 2 - static void F13(ref R x, ref scoped R y) { F3(ref x, ref y); } - static void F14(ref R x, ref scoped R y) { F4(ref x, ref y); } - static void F15(ref R x, ref scoped R y) { F5(ref x, ref y); } // 3 - static void F20(ref R x, scoped ref R y) { F0(ref x, ref y); } - static void F21(ref R x, scoped ref R y) { F1(ref x, ref y); } static void F22(ref R x, scoped ref R y) { F2(ref x, ref y); } - static void F23(ref R x, scoped ref R y) { F3(ref x, ref y); } - static void F24(ref R x, scoped ref R y) { F4(ref x, ref y); } static void F25(ref R x, scoped ref R y) { F5(ref x, ref y); } - static void F30(ref scoped R x, ref scoped R y) { F0(ref x, ref y); } - static void F31(ref scoped R x, ref scoped R y) { F1(ref x, ref y); } - static void F32(ref scoped R x, ref scoped R y) { F2(ref x, ref y); } - static void F33(ref scoped R x, ref scoped R y) { F3(ref x, ref y); } - static void F34(ref scoped R x, ref scoped R y) { F4(ref x, ref y); } - static void F35(ref scoped R x, ref scoped R y) { F5(ref x, ref y); } - - static void F40(ref scoped R x, scoped ref R y) { F0(ref x, ref y); } // 4 - static void F41(ref scoped R x, scoped ref R y) { F1(ref x, ref y); } - static void F42(ref scoped R x, scoped ref R y) { F2(ref x, ref y); } // 5 - static void F43(ref scoped R x, scoped ref R y) { F3(ref x, ref y); } - static void F44(ref scoped R x, scoped ref R y) { F4(ref x, ref y); } - static void F45(ref scoped R x, scoped ref R y) { F5(ref x, ref y); } // 6 - static void F50(scoped ref R x, scoped ref R y) { F0(ref x, ref y); } - static void F51(scoped ref R x, scoped ref R y) { F1(ref x, ref y); } static void F52(scoped ref R x, scoped ref R y) { F2(ref x, ref y); } - static void F53(scoped ref R x, scoped ref R y) { F3(ref x, ref y); } - static void F54(scoped ref R x, scoped ref R y) { F4(ref x, ref y); } static void F55(scoped ref R x, scoped ref R y) { F5(ref x, ref y); } }"; var comp = CreateCompilation(source); - comp.VerifyEmitDiagnostics( - // (20,48): error CS8350: This combination of arguments to 'Program.F0(ref R, ref R)' is disallowed because it may expose variables referenced by parameter 'b' outside of their declaration scope - // static void F10(ref R x, ref scoped R y) { F0(ref x, ref y); } // 1 - Diagnostic(ErrorCode.ERR_CallArgMixing, "F0(ref x, ref y)").WithArguments("Program.F0(ref R, ref R)", "b").WithLocation(20, 48), - // (20,62): error CS8352: Cannot use variable 'ref R' in this context because it may expose referenced variables outside of their declaration scope - // static void F10(ref R x, ref scoped R y) { F0(ref x, ref y); } // 1 - Diagnostic(ErrorCode.ERR_EscapeVariable, "y").WithArguments("ref R").WithLocation(20, 62), - // (22,48): error CS8350: This combination of arguments to 'Program.F2(ref R, ref R)' is disallowed because it may expose variables referenced by parameter 'b' outside of their declaration scope - // static void F12(ref R x, ref scoped R y) { F2(ref x, ref y); } // 2 - Diagnostic(ErrorCode.ERR_CallArgMixing, "F2(ref x, ref y)").WithArguments("Program.F2(ref R, ref R)", "b").WithLocation(22, 48), - // (22,62): error CS8352: Cannot use variable 'ref R' in this context because it may expose referenced variables outside of their declaration scope - // static void F12(ref R x, ref scoped R y) { F2(ref x, ref y); } // 2 - Diagnostic(ErrorCode.ERR_EscapeVariable, "y").WithArguments("ref R").WithLocation(22, 62), - // (25,48): error CS8350: This combination of arguments to 'Program.F5(ref R, ref R)' is disallowed because it may expose variables referenced by parameter 'b' outside of their declaration scope - // static void F15(ref R x, ref scoped R y) { F5(ref x, ref y); } // 3 - Diagnostic(ErrorCode.ERR_CallArgMixing, "F5(ref x, ref y)").WithArguments("Program.F5(ref R, ref R)", "b").WithLocation(25, 48), - // (25,62): error CS8352: Cannot use variable 'ref R' in this context because it may expose referenced variables outside of their declaration scope - // static void F15(ref R x, ref scoped R y) { F5(ref x, ref y); } // 3 - Diagnostic(ErrorCode.ERR_EscapeVariable, "y").WithArguments("ref R").WithLocation(25, 62), - // (41,55): error CS8350: This combination of arguments to 'Program.F0(ref R, ref R)' is disallowed because it may expose variables referenced by parameter 'a' outside of their declaration scope - // static void F40(ref scoped R x, scoped ref R y) { F0(ref x, ref y); } // 4 - Diagnostic(ErrorCode.ERR_CallArgMixing, "F0(ref x, ref y)").WithArguments("Program.F0(ref R, ref R)", "a").WithLocation(41, 55), - // (41,62): error CS8352: Cannot use variable 'ref R' in this context because it may expose referenced variables outside of their declaration scope - // static void F40(ref scoped R x, scoped ref R y) { F0(ref x, ref y); } // 4 - Diagnostic(ErrorCode.ERR_EscapeVariable, "x").WithArguments("ref R").WithLocation(41, 62), - // (43,55): error CS8350: This combination of arguments to 'Program.F2(ref R, ref R)' is disallowed because it may expose variables referenced by parameter 'a' outside of their declaration scope - // static void F42(ref scoped R x, scoped ref R y) { F2(ref x, ref y); } // 5 - Diagnostic(ErrorCode.ERR_CallArgMixing, "F2(ref x, ref y)").WithArguments("Program.F2(ref R, ref R)", "a").WithLocation(43, 55), - // (43,62): error CS8352: Cannot use variable 'ref R' in this context because it may expose referenced variables outside of their declaration scope - // static void F42(ref scoped R x, scoped ref R y) { F2(ref x, ref y); } // 5 - Diagnostic(ErrorCode.ERR_EscapeVariable, "x").WithArguments("ref R").WithLocation(43, 62), - // (46,55): error CS8350: This combination of arguments to 'Program.F5(ref R, ref R)' is disallowed because it may expose variables referenced by parameter 'a' outside of their declaration scope - // static void F45(ref scoped R x, scoped ref R y) { F5(ref x, ref y); } // 6 - Diagnostic(ErrorCode.ERR_CallArgMixing, "F5(ref x, ref y)").WithArguments("Program.F5(ref R, ref R)", "a").WithLocation(46, 55), - // (46,62): error CS8352: Cannot use variable 'ref R' in this context because it may expose referenced variables outside of their declaration scope - // static void F45(ref scoped R x, scoped ref R y) { F5(ref x, ref y); } // 6 - Diagnostic(ErrorCode.ERR_EscapeVariable, "x").WithArguments("ref R").WithLocation(46, 62)); + comp.VerifyEmitDiagnostics(); } [Fact] @@ -2509,10 +2813,7 @@ public R(ref T t) { } class Program { static void F0(ref R a, ref R b) => throw null; - static void F1(ref R a, ref scoped R b) => throw null; static void F2(ref R a, scoped ref R b) => throw null; - static void F3(ref scoped R a, ref scoped R b) => throw null; - static void F4(ref scoped R a, scoped ref R b) => throw null; static void F5(scoped ref R a, scoped ref R b) => throw null; static void F(ref R x) @@ -2521,72 +2822,60 @@ static void F(ref R x) R y = new R(ref t); F0(ref x, ref x); - F1(ref x, ref x); F2(ref x, ref x); - F3(ref x, ref x); - F4(ref x, ref x); F5(ref x, ref x); F0(ref x, ref y); // 1 - F1(ref x, ref y); F2(ref x, ref y); // 2 - F3(ref x, ref y); - F4(ref x, ref y); F5(ref x, ref y); // 3 F0(ref y, ref x); // 4 - F1(ref y, ref x); F2(ref y, ref x); // 5 - F3(ref y, ref x); - F4(ref y, ref x); F5(ref y, ref x); // 6 F0(ref y, ref y); - F1(ref y, ref y); F2(ref y, ref y); - F3(ref y, ref y); - F4(ref y, ref y); F5(ref y, ref y); } }"; var comp = CreateCompilation(source); comp.VerifyEmitDiagnostics( - // (26,9): error CS8350: This combination of arguments to 'Program.F0(ref R, ref R)' is disallowed because it may expose variables referenced by parameter 'b' outside of their declaration scope + // (20,9): error CS8350: This combination of arguments to 'Program.F0(ref R, ref R)' is disallowed because it may expose variables referenced by parameter 'b' outside of their declaration scope // F0(ref x, ref y); // 1 - Diagnostic(ErrorCode.ERR_CallArgMixing, "F0(ref x, ref y)").WithArguments("Program.F0(ref R, ref R)", "b").WithLocation(26, 9), - // (26,23): error CS8352: Cannot use variable 'y' in this context because it may expose referenced variables outside of their declaration scope + Diagnostic(ErrorCode.ERR_CallArgMixing, "F0(ref x, ref y)").WithArguments("Program.F0(ref R, ref R)", "b").WithLocation(20, 9), + // (20,23): error CS8352: Cannot use variable 'y' in this context because it may expose referenced variables outside of their declaration scope // F0(ref x, ref y); // 1 - Diagnostic(ErrorCode.ERR_EscapeVariable, "y").WithArguments("y").WithLocation(26, 23), - // (28,9): error CS8350: This combination of arguments to 'Program.F2(ref R, ref R)' is disallowed because it may expose variables referenced by parameter 'b' outside of their declaration scope + Diagnostic(ErrorCode.ERR_EscapeVariable, "y").WithArguments("y").WithLocation(20, 23), + // (21,9): error CS8350: This combination of arguments to 'Program.F2(ref R, ref R)' is disallowed because it may expose variables referenced by parameter 'b' outside of their declaration scope // F2(ref x, ref y); // 2 - Diagnostic(ErrorCode.ERR_CallArgMixing, "F2(ref x, ref y)").WithArguments("Program.F2(ref R, ref R)", "b").WithLocation(28, 9), - // (28,23): error CS8352: Cannot use variable 'y' in this context because it may expose referenced variables outside of their declaration scope + Diagnostic(ErrorCode.ERR_CallArgMixing, "F2(ref x, ref y)").WithArguments("Program.F2(ref R, ref R)", "b").WithLocation(21, 9), + // (21,23): error CS8352: Cannot use variable 'y' in this context because it may expose referenced variables outside of their declaration scope // F2(ref x, ref y); // 2 - Diagnostic(ErrorCode.ERR_EscapeVariable, "y").WithArguments("y").WithLocation(28, 23), - // (31,9): error CS8350: This combination of arguments to 'Program.F5(ref R, ref R)' is disallowed because it may expose variables referenced by parameter 'b' outside of their declaration scope + Diagnostic(ErrorCode.ERR_EscapeVariable, "y").WithArguments("y").WithLocation(21, 23), + // (22,9): error CS8350: This combination of arguments to 'Program.F5(ref R, ref R)' is disallowed because it may expose variables referenced by parameter 'b' outside of their declaration scope // F5(ref x, ref y); // 3 - Diagnostic(ErrorCode.ERR_CallArgMixing, "F5(ref x, ref y)").WithArguments("Program.F5(ref R, ref R)", "b").WithLocation(31, 9), - // (31,23): error CS8352: Cannot use variable 'y' in this context because it may expose referenced variables outside of their declaration scope + Diagnostic(ErrorCode.ERR_CallArgMixing, "F5(ref x, ref y)").WithArguments("Program.F5(ref R, ref R)", "b").WithLocation(22, 9), + // (22,23): error CS8352: Cannot use variable 'y' in this context because it may expose referenced variables outside of their declaration scope // F5(ref x, ref y); // 3 - Diagnostic(ErrorCode.ERR_EscapeVariable, "y").WithArguments("y").WithLocation(31, 23), - // (33,9): error CS8350: This combination of arguments to 'Program.F0(ref R, ref R)' is disallowed because it may expose variables referenced by parameter 'a' outside of their declaration scope + Diagnostic(ErrorCode.ERR_EscapeVariable, "y").WithArguments("y").WithLocation(22, 23), + // (24,9): error CS8350: This combination of arguments to 'Program.F0(ref R, ref R)' is disallowed because it may expose variables referenced by parameter 'a' outside of their declaration scope // F0(ref y, ref x); // 4 - Diagnostic(ErrorCode.ERR_CallArgMixing, "F0(ref y, ref x)").WithArguments("Program.F0(ref R, ref R)", "a").WithLocation(33, 9), - // (33,16): error CS8352: Cannot use variable 'y' in this context because it may expose referenced variables outside of their declaration scope + Diagnostic(ErrorCode.ERR_CallArgMixing, "F0(ref y, ref x)").WithArguments("Program.F0(ref R, ref R)", "a").WithLocation(24, 9), + // (24,16): error CS8352: Cannot use variable 'y' in this context because it may expose referenced variables outside of their declaration scope // F0(ref y, ref x); // 4 - Diagnostic(ErrorCode.ERR_EscapeVariable, "y").WithArguments("y").WithLocation(33, 16), - // (35,9): error CS8350: This combination of arguments to 'Program.F2(ref R, ref R)' is disallowed because it may expose variables referenced by parameter 'a' outside of their declaration scope + Diagnostic(ErrorCode.ERR_EscapeVariable, "y").WithArguments("y").WithLocation(24, 16), + // (25,9): error CS8350: This combination of arguments to 'Program.F2(ref R, ref R)' is disallowed because it may expose variables referenced by parameter 'a' outside of their declaration scope // F2(ref y, ref x); // 5 - Diagnostic(ErrorCode.ERR_CallArgMixing, "F2(ref y, ref x)").WithArguments("Program.F2(ref R, ref R)", "a").WithLocation(35, 9), - // (35,16): error CS8352: Cannot use variable 'y' in this context because it may expose referenced variables outside of their declaration scope + Diagnostic(ErrorCode.ERR_CallArgMixing, "F2(ref y, ref x)").WithArguments("Program.F2(ref R, ref R)", "a").WithLocation(25, 9), + // (25,16): error CS8352: Cannot use variable 'y' in this context because it may expose referenced variables outside of their declaration scope // F2(ref y, ref x); // 5 - Diagnostic(ErrorCode.ERR_EscapeVariable, "y").WithArguments("y").WithLocation(35, 16), - // (38,9): error CS8350: This combination of arguments to 'Program.F5(ref R, ref R)' is disallowed because it may expose variables referenced by parameter 'a' outside of their declaration scope + Diagnostic(ErrorCode.ERR_EscapeVariable, "y").WithArguments("y").WithLocation(25, 16), + // (26,9): error CS8350: This combination of arguments to 'Program.F5(ref R, ref R)' is disallowed because it may expose variables referenced by parameter 'a' outside of their declaration scope // F5(ref y, ref x); // 6 - Diagnostic(ErrorCode.ERR_CallArgMixing, "F5(ref y, ref x)").WithArguments("Program.F5(ref R, ref R)", "a").WithLocation(38, 9), - // (38,16): error CS8352: Cannot use variable 'y' in this context because it may expose referenced variables outside of their declaration scope + Diagnostic(ErrorCode.ERR_CallArgMixing, "F5(ref y, ref x)").WithArguments("Program.F5(ref R, ref R)", "a").WithLocation(26, 9), + // (26,16): error CS8352: Cannot use variable 'y' in this context because it may expose referenced variables outside of their declaration scope // F5(ref y, ref x); // 6 - Diagnostic(ErrorCode.ERR_EscapeVariable, "y").WithArguments("y").WithLocation(38, 16)); + Diagnostic(ErrorCode.ERR_EscapeVariable, "y").WithArguments("y").WithLocation(26, 16)); } [Fact] @@ -2597,33 +2886,15 @@ public void MethodArgumentsMustMatch_04() class Program { static void F0(ref R x, in R y) => throw null; - static void F1(ref R x, in scoped R y) => throw null; static void F2(ref R x, scoped in R y) => throw null; static void F00(ref R x, in R y) { F0(ref x, in y); } - static void F01(ref R x, in R y) { F1(ref x, in y); } static void F02(ref R x, in R y) { F2(ref x, in y); } - static void F10(ref R x, in scoped R y) { F0(ref x, in y); } // 1 - static void F11(ref R x, in scoped R y) { F1(ref x, in y); } - static void F12(ref R x, in scoped R y) { F2(ref x, in y); } // 2 static void F20(ref R x, scoped in R y) { F0(ref x, in y); } - static void F21(ref R x, scoped in R y) { F1(ref x, in y); } static void F22(ref R x, scoped in R y) { F2(ref x, in y); } }"; var comp = CreateCompilation(source); - comp.VerifyEmitDiagnostics( - // (11,47): error CS8350: This combination of arguments to 'Program.F0(ref R, in R)' is disallowed because it may expose variables referenced by parameter 'y' outside of their declaration scope - // static void F10(ref R x, in scoped R y) { F0(ref x, in y); } // 1 - Diagnostic(ErrorCode.ERR_CallArgMixing, "F0(ref x, in y)").WithArguments("Program.F0(ref R, in R)", "y").WithLocation(11, 47), - // (11,60): error CS8352: Cannot use variable 'in R' in this context because it may expose referenced variables outside of their declaration scope - // static void F10(ref R x, in scoped R y) { F0(ref x, in y); } // 1 - Diagnostic(ErrorCode.ERR_EscapeVariable, "y").WithArguments("in R").WithLocation(11, 60), - // (13,47): error CS8350: This combination of arguments to 'Program.F2(ref R, in R)' is disallowed because it may expose variables referenced by parameter 'y' outside of their declaration scope - // static void F12(ref R x, in scoped R y) { F2(ref x, in y); } // 2 - Diagnostic(ErrorCode.ERR_CallArgMixing, "F2(ref x, in y)").WithArguments("Program.F2(ref R, in R)", "y").WithLocation(13, 47), - // (13,60): error CS8352: Cannot use variable 'in R' in this context because it may expose referenced variables outside of their declaration scope - // static void F12(ref R x, in scoped R y) { F2(ref x, in y); } // 2 - Diagnostic(ErrorCode.ERR_EscapeVariable, "y").WithArguments("in R").WithLocation(13, 60)); + comp.VerifyEmitDiagnostics(); } [Fact] @@ -2634,35 +2905,15 @@ public void MethodArgumentsMustMatch_05() class Program { static void F0(ref R x, out R y) => throw null; - static void F1(ref R x, out scoped R y) => throw null; static void F2(ref R x, scoped out R y) => throw null; static void F00(ref R x, out R y) { F0(ref x, out y); } - static void F01(ref R x, out R y) { F1(ref x, out y); } static void F02(ref R x, out R y) { F2(ref x, out y); } - static void F10(ref R x, out scoped R y) { F0(ref x, out y); } // 1 - static void F11(ref R x, out scoped R y) { F1(ref x, out y); } - static void F12(ref R x, out scoped R y) { F2(ref x, out y); } // 2 static void F20(ref R x, scoped out R y) { F0(ref x, out y); } - static void F21(ref R x, scoped out R y) { F1(ref x, out y); } static void F22(ref R x, scoped out R y) { F2(ref x, out y); } }"; var comp = CreateCompilation(source); - // https://github.com/dotnet/roslyn/issues/62094: References within out parameter - // should not be considered escaping. - comp.VerifyEmitDiagnostics( - // (11,48): error CS8350: This combination of arguments to 'Program.F0(ref R, out R)' is disallowed because it may expose variables referenced by parameter 'y' outside of their declaration scope - // static void F10(ref R x, out scoped R y) { F0(ref x, out y); } // 1 - Diagnostic(ErrorCode.ERR_CallArgMixing, "F0(ref x, out y)").WithArguments("Program.F0(ref R, out R)", "y").WithLocation(11, 48), - // (11,62): error CS8352: Cannot use variable 'out R' in this context because it may expose referenced variables outside of their declaration scope - // static void F10(ref R x, out scoped R y) { F0(ref x, out y); } // 1 - Diagnostic(ErrorCode.ERR_EscapeVariable, "y").WithArguments("out R").WithLocation(11, 62), - // (13,48): error CS8350: This combination of arguments to 'Program.F2(ref R, out R)' is disallowed because it may expose variables referenced by parameter 'y' outside of their declaration scope - // static void F12(ref R x, out scoped R y) { F2(ref x, out y); } // 2 - Diagnostic(ErrorCode.ERR_CallArgMixing, "F2(ref x, out y)").WithArguments("Program.F2(ref R, out R)", "y").WithLocation(13, 48), - // (13,62): error CS8352: Cannot use variable 'out R' in this context because it may expose referenced variables outside of their declaration scope - // static void F12(ref R x, out scoped R y) { F2(ref x, out y); } // 2 - Diagnostic(ErrorCode.ERR_EscapeVariable, "y").WithArguments("out R").WithLocation(13, 62)); + comp.VerifyEmitDiagnostics(); } [Fact] @@ -2675,1045 +2926,1212 @@ class Program static void F0(__arglist) { } static void F1(ref R a, __arglist) { } - static void F00(ref R x, ref R y) { F0(__arglist(ref x, ref y)); } - static void F01(ref R x, ref R y) { F1(ref x, __arglist(ref y)); } - static void F10(ref R x, ref scoped R y) { F0(__arglist(ref x, ref y)); } // 1 - static void F11(ref R x, ref scoped R y) { F1(ref x, __arglist(ref y)); } // 2 - static void F20(ref R x, scoped ref R y) { F0(__arglist(ref x, ref y)); } - static void F21(ref R x, scoped ref R y) { F1(ref x, __arglist(ref y)); } - static void F30(ref scoped R x, ref scoped R y) { F0(__arglist(ref x, ref y)); } - static void F31(ref scoped R x, ref scoped R y) { F1(ref x, __arglist(ref y)); } - static void F40(ref scoped R x, scoped ref R y) { F0(__arglist(ref x, ref y)); } // 3 - static void F41(ref scoped R x, scoped ref R y) { F1(ref x, __arglist(ref y)); } // 4 - static void F50(scoped ref R x, scoped ref R y) { F0(__arglist(ref x, ref y)); } - static void F51(scoped ref R x, scoped ref R y) { F1(ref x, __arglist(ref y)); } + static void F00(ref R x, ref R y) { F0(__arglist(ref x, ref y)); } // 1 + static void F01(ref R x, ref R y) { F1(ref x, __arglist(ref y)); } // 2 + static void F20(ref R x, scoped ref R y) { F0(__arglist(ref x, ref y)); } // 3 + static void F21(ref R x, scoped ref R y) { F1(ref x, __arglist(ref y)); } // 4 + static void F50(scoped ref R x, scoped ref R y) { F0(__arglist(ref x, ref y)); } // 5 + static void F51(scoped ref R x, scoped ref R y) { F1(ref x, __arglist(ref y)); } // 6 }"; var comp = CreateCompilation(source); comp.VerifyEmitDiagnostics( + // (7,41): error CS8350: This combination of arguments to 'Program.F0(__arglist)' is disallowed because it may expose variables referenced by parameter '__arglist' outside of their declaration scope + // static void F00(ref R x, ref R y) { F0(__arglist(ref x, ref y)); } // 1 + Diagnostic(ErrorCode.ERR_CallArgMixing, "F0(__arglist(ref x, ref y))").WithArguments("Program.F0(__arglist)", "__arglist").WithLocation(7, 41), + // (7,58): error CS8166: Cannot return a parameter by reference 'x' because it is not a ref parameter + // static void F00(ref R x, ref R y) { F0(__arglist(ref x, ref y)); } // 1 + Diagnostic(ErrorCode.ERR_RefReturnParameter, "x").WithArguments("x").WithLocation(7, 58), + // (8,41): error CS8350: This combination of arguments to 'Program.F1(ref R, __arglist)' is disallowed because it may expose variables referenced by parameter '__arglist' outside of their declaration scope + // static void F01(ref R x, ref R y) { F1(ref x, __arglist(ref y)); } // 2 + Diagnostic(ErrorCode.ERR_CallArgMixing, "F1(ref x, __arglist(ref y))").WithArguments("Program.F1(ref R, __arglist)", "__arglist").WithLocation(8, 41), + // (8,65): error CS8166: Cannot return a parameter by reference 'y' because it is not a ref parameter + // static void F01(ref R x, ref R y) { F1(ref x, __arglist(ref y)); } // 2 + Diagnostic(ErrorCode.ERR_RefReturnParameter, "y").WithArguments("y").WithLocation(8, 65), // (9,48): error CS8350: This combination of arguments to 'Program.F0(__arglist)' is disallowed because it may expose variables referenced by parameter '__arglist' outside of their declaration scope - // static void F10(ref R x, ref scoped R y) { F0(__arglist(ref x, ref y)); } // 1 + // static void F20(ref R x, scoped ref R y) { F0(__arglist(ref x, ref y)); } // 3 Diagnostic(ErrorCode.ERR_CallArgMixing, "F0(__arglist(ref x, ref y))").WithArguments("Program.F0(__arglist)", "__arglist").WithLocation(9, 48), - // (9,72): error CS8352: Cannot use variable 'ref R' in this context because it may expose referenced variables outside of their declaration scope - // static void F10(ref R x, ref scoped R y) { F0(__arglist(ref x, ref y)); } // 1 - Diagnostic(ErrorCode.ERR_EscapeVariable, "y").WithArguments("ref R").WithLocation(9, 72), + // (9,65): error CS8166: Cannot return a parameter by reference 'x' because it is not a ref parameter + // static void F20(ref R x, scoped ref R y) { F0(__arglist(ref x, ref y)); } // 3 + Diagnostic(ErrorCode.ERR_RefReturnParameter, "x").WithArguments("x").WithLocation(9, 65), // (10,48): error CS8350: This combination of arguments to 'Program.F1(ref R, __arglist)' is disallowed because it may expose variables referenced by parameter '__arglist' outside of their declaration scope - // static void F11(ref R x, ref scoped R y) { F1(ref x, __arglist(ref y)); } // 2 + // static void F21(ref R x, scoped ref R y) { F1(ref x, __arglist(ref y)); } // 4 Diagnostic(ErrorCode.ERR_CallArgMixing, "F1(ref x, __arglist(ref y))").WithArguments("Program.F1(ref R, __arglist)", "__arglist").WithLocation(10, 48), - // (10,72): error CS8352: Cannot use variable 'ref R' in this context because it may expose referenced variables outside of their declaration scope - // static void F11(ref R x, ref scoped R y) { F1(ref x, __arglist(ref y)); } // 2 - Diagnostic(ErrorCode.ERR_EscapeVariable, "y").WithArguments("ref R").WithLocation(10, 72), - // (15,55): error CS8350: This combination of arguments to 'Program.F0(__arglist)' is disallowed because it may expose variables referenced by parameter '__arglist' outside of their declaration scope - // static void F40(ref scoped R x, scoped ref R y) { F0(__arglist(ref x, ref y)); } // 3 - Diagnostic(ErrorCode.ERR_CallArgMixing, "F0(__arglist(ref x, ref y))").WithArguments("Program.F0(__arglist)", "__arglist").WithLocation(15, 55), - // (15,72): error CS8352: Cannot use variable 'ref R' in this context because it may expose referenced variables outside of their declaration scope - // static void F40(ref scoped R x, scoped ref R y) { F0(__arglist(ref x, ref y)); } // 3 - Diagnostic(ErrorCode.ERR_EscapeVariable, "x").WithArguments("ref R").WithLocation(15, 72), - // (16,55): error CS8350: This combination of arguments to 'Program.F1(ref R, __arglist)' is disallowed because it may expose variables referenced by parameter 'a' outside of their declaration scope - // static void F41(ref scoped R x, scoped ref R y) { F1(ref x, __arglist(ref y)); } // 4 - Diagnostic(ErrorCode.ERR_CallArgMixing, "F1(ref x, __arglist(ref y))").WithArguments("Program.F1(ref R, __arglist)", "a").WithLocation(16, 55), - // (16,62): error CS8352: Cannot use variable 'ref R' in this context because it may expose referenced variables outside of their declaration scope - // static void F41(ref scoped R x, scoped ref R y) { F1(ref x, __arglist(ref y)); } // 4 - Diagnostic(ErrorCode.ERR_EscapeVariable, "x").WithArguments("ref R").WithLocation(16, 62)); + // (10,72): error CS8166: Cannot return a parameter by reference 'y' because it is not a ref parameter + // static void F21(ref R x, scoped ref R y) { F1(ref x, __arglist(ref y)); } // 4 + Diagnostic(ErrorCode.ERR_RefReturnParameter, "y").WithArguments("y").WithLocation(10, 72), + // (11,55): error CS8350: This combination of arguments to 'Program.F0(__arglist)' is disallowed because it may expose variables referenced by parameter '__arglist' outside of their declaration scope + // static void F50(scoped ref R x, scoped ref R y) { F0(__arglist(ref x, ref y)); } // 5 + Diagnostic(ErrorCode.ERR_CallArgMixing, "F0(__arglist(ref x, ref y))").WithArguments("Program.F0(__arglist)", "__arglist").WithLocation(11, 55), + // (11,72): error CS8166: Cannot return a parameter by reference 'x' because it is not a ref parameter + // static void F50(scoped ref R x, scoped ref R y) { F0(__arglist(ref x, ref y)); } // 5 + Diagnostic(ErrorCode.ERR_RefReturnParameter, "x").WithArguments("x").WithLocation(11, 72), + // (12,55): error CS8350: This combination of arguments to 'Program.F1(ref R, __arglist)' is disallowed because it may expose variables referenced by parameter '__arglist' outside of their declaration scope + // static void F51(scoped ref R x, scoped ref R y) { F1(ref x, __arglist(ref y)); } // 6 + Diagnostic(ErrorCode.ERR_CallArgMixing, "F1(ref x, __arglist(ref y))").WithArguments("Program.F1(ref R, __arglist)", "__arglist").WithLocation(12, 55), + // (12,79): error CS8166: Cannot return a parameter by reference 'y' because it is not a ref parameter + // static void F51(scoped ref R x, scoped ref R y) { F1(ref x, __arglist(ref y)); } // 6 + Diagnostic(ErrorCode.ERR_RefReturnParameter, "y").WithArguments("y").WithLocation(12, 79)); } [Fact] - public void NestedFieldAccessor() + public void MethodArgumentsMustMatch_07() + { + var source = +@"using System.Diagnostics.CodeAnalysis; +ref struct R { } +class Program +{ + static void F0(__arglist) { } + static void F1(ref R a, __arglist) { } + + static void F00(ref R x, ref R y) { F0(__arglist(ref x, ref y)); } // 1 + static void F01(ref R x, ref R y) { F1(ref x, __arglist(ref y)); } // 2 + static void F20(ref R x, [UnscopedRef] ref R y) { F0(__arglist(ref x, ref y)); } // 3 + static void F21(ref R x, [UnscopedRef] ref R y) { F1(ref x, __arglist(ref y)); } + static void F50([UnscopedRef] ref R x, [UnscopedRef] ref R y) { F0(__arglist(ref x, ref y)); } + static void F51([UnscopedRef] ref R x, [UnscopedRef] ref R y) { F1(ref x, __arglist(ref y)); } +}"; + var comp = CreateCompilation(new[] { source, UnscopedRefAttributeDefinition }); + comp.VerifyEmitDiagnostics( + // (8,41): error CS8350: This combination of arguments to 'Program.F0(__arglist)' is disallowed because it may expose variables referenced by parameter '__arglist' outside of their declaration scope + // static void F00(ref R x, ref R y) { F0(__arglist(ref x, ref y)); } // 1 + Diagnostic(ErrorCode.ERR_CallArgMixing, "F0(__arglist(ref x, ref y))").WithArguments("Program.F0(__arglist)", "__arglist").WithLocation(8, 41), + // (8,58): error CS8166: Cannot return a parameter by reference 'x' because it is not a ref parameter + // static void F00(ref R x, ref R y) { F0(__arglist(ref x, ref y)); } // 1 + Diagnostic(ErrorCode.ERR_RefReturnParameter, "x").WithArguments("x").WithLocation(8, 58), + // (9,41): error CS8350: This combination of arguments to 'Program.F1(ref R, __arglist)' is disallowed because it may expose variables referenced by parameter '__arglist' outside of their declaration scope + // static void F01(ref R x, ref R y) { F1(ref x, __arglist(ref y)); } // 2 + Diagnostic(ErrorCode.ERR_CallArgMixing, "F1(ref x, __arglist(ref y))").WithArguments("Program.F1(ref R, __arglist)", "__arglist").WithLocation(9, 41), + // (9,65): error CS8166: Cannot return a parameter by reference 'y' because it is not a ref parameter + // static void F01(ref R x, ref R y) { F1(ref x, __arglist(ref y)); } // 2 + Diagnostic(ErrorCode.ERR_RefReturnParameter, "y").WithArguments("y").WithLocation(9, 65), + // (10,55): error CS8350: This combination of arguments to 'Program.F0(__arglist)' is disallowed because it may expose variables referenced by parameter '__arglist' outside of their declaration scope + // static void F20(ref R x, [UnscopedRef] ref R y) { F0(__arglist(ref x, ref y)); } // 3 + Diagnostic(ErrorCode.ERR_CallArgMixing, "F0(__arglist(ref x, ref y))").WithArguments("Program.F0(__arglist)", "__arglist").WithLocation(10, 55), + // (10,72): error CS8166: Cannot return a parameter by reference 'x' because it is not a ref parameter + // static void F20(ref R x, [UnscopedRef] ref R y) { F0(__arglist(ref x, ref y)); } // 3 + Diagnostic(ErrorCode.ERR_RefReturnParameter, "x").WithArguments("x").WithLocation(10, 72)); + } + + /// + /// ref to ref struct in __arglist is unscoped ref. + /// + [Fact] + public void MethodArgumentsMustMatch_08() { var source = @"ref struct R { - private ref T _t; - public R(ref T t) { _t = t; } - public ref T F0() => ref _t; - ref T F1() => ref F0(); + public R(ref T t) { } } class Program { - static ref T F2(ref R r) => ref r.F0(); + static void F0(__arglist) { } + static void F1() + { + var x = new R(); + int i = 1; + var y = new R(ref i); + F0(__arglist(ref x)); // 1 + F0(__arglist(ref y)); + F0(__arglist(ref x, ref x)); // 2 + F0(__arglist(ref x, ref y)); // 3 + F0(__arglist(ref y, ref x)); // 4 + F0(__arglist(ref y, ref y)); + } }"; - var comp = CreateCompilation(source); + + var comp = CreateCompilation(source, parseOptions: TestOptions.Regular10); comp.VerifyEmitDiagnostics(); + + comp = CreateCompilation(source); + comp.VerifyEmitDiagnostics( + // (13,9): error CS8350: This combination of arguments to 'Program.F0(__arglist)' is disallowed because it may expose variables referenced by parameter '__arglist' outside of their declaration scope + // F0(__arglist(ref x)); // 1 + Diagnostic(ErrorCode.ERR_CallArgMixing, "F0(__arglist(ref x))").WithArguments("Program.F0(__arglist)", "__arglist").WithLocation(13, 9), + // (13,26): error CS8168: Cannot return local 'x' by reference because it is not a ref local + // F0(__arglist(ref x)); // 1 + Diagnostic(ErrorCode.ERR_RefReturnLocal, "x").WithArguments("x").WithLocation(13, 26), + // (15,9): error CS8350: This combination of arguments to 'Program.F0(__arglist)' is disallowed because it may expose variables referenced by parameter '__arglist' outside of their declaration scope + // F0(__arglist(ref x, ref x)); // 2 + Diagnostic(ErrorCode.ERR_CallArgMixing, "F0(__arglist(ref x, ref x))").WithArguments("Program.F0(__arglist)", "__arglist").WithLocation(15, 9), + // (15,26): error CS8168: Cannot return local 'x' by reference because it is not a ref local + // F0(__arglist(ref x, ref x)); // 2 + Diagnostic(ErrorCode.ERR_RefReturnLocal, "x").WithArguments("x").WithLocation(15, 26), + // (16,9): error CS8350: This combination of arguments to 'Program.F0(__arglist)' is disallowed because it may expose variables referenced by parameter '__arglist' outside of their declaration scope + // F0(__arglist(ref x, ref y)); // 3 + Diagnostic(ErrorCode.ERR_CallArgMixing, "F0(__arglist(ref x, ref y))").WithArguments("Program.F0(__arglist)", "__arglist").WithLocation(16, 9), + // (16,33): error CS8352: Cannot use variable 'y' in this context because it may expose referenced variables outside of their declaration scope + // F0(__arglist(ref x, ref y)); // 3 + Diagnostic(ErrorCode.ERR_EscapeVariable, "y").WithArguments("y").WithLocation(16, 33), + // (17,9): error CS8350: This combination of arguments to 'Program.F0(__arglist)' is disallowed because it may expose variables referenced by parameter '__arglist' outside of their declaration scope + // F0(__arglist(ref y, ref x)); // 4 + Diagnostic(ErrorCode.ERR_CallArgMixing, "F0(__arglist(ref y, ref x))").WithArguments("Program.F0(__arglist)", "__arglist").WithLocation(17, 9), + // (17,26): error CS8352: Cannot use variable 'y' in this context because it may expose referenced variables outside of their declaration scope + // F0(__arglist(ref y, ref x)); // 4 + Diagnostic(ErrorCode.ERR_EscapeVariable, "y").WithArguments("y").WithLocation(17, 26)); } + /// + /// ref to ref struct in __arglist is unscoped ref. + /// [Fact] - public void Constructors() + public void MethodArgumentsMustMatch_09() { var source = -@"ref struct S +@"ref struct R { - public ref T F; - public S(ref T t) + public R(ref T t) { } +} +class Program +{ + static void F0(ref R a, __arglist) { } + static void F1() { - F = ref t; + var x = new R(); + int i = 1; + var y = new R(ref i); + F0(ref x, __arglist(ref x)); // 1 + F0(ref x, __arglist(ref y)); // 2 + F0(ref y, __arglist(ref x)); // 3 + F0(ref y, __arglist(ref y)); } - S(object unused, T t0) +}"; + + var comp = CreateCompilation(source, parseOptions: TestOptions.Regular10); + comp.VerifyEmitDiagnostics(); + + comp = CreateCompilation(source); + comp.VerifyEmitDiagnostics( + // (13,9): error CS8350: This combination of arguments to 'Program.F0(ref R, __arglist)' is disallowed because it may expose variables referenced by parameter '__arglist' outside of their declaration scope + // F0(ref x, __arglist(ref x)); // 1 + Diagnostic(ErrorCode.ERR_CallArgMixing, "F0(ref x, __arglist(ref x))").WithArguments("Program.F0(ref R, __arglist)", "__arglist").WithLocation(13, 9), + // (13,33): error CS8168: Cannot return local 'x' by reference because it is not a ref local + // F0(ref x, __arglist(ref x)); // 1 + Diagnostic(ErrorCode.ERR_RefReturnLocal, "x").WithArguments("x").WithLocation(13, 33), + // (14,9): error CS8350: This combination of arguments to 'Program.F0(ref R, __arglist)' is disallowed because it may expose variables referenced by parameter '__arglist' outside of their declaration scope + // F0(ref x, __arglist(ref y)); // 2 + Diagnostic(ErrorCode.ERR_CallArgMixing, "F0(ref x, __arglist(ref y))").WithArguments("Program.F0(ref R, __arglist)", "__arglist").WithLocation(14, 9), + // (14,33): error CS8352: Cannot use variable 'y' in this context because it may expose referenced variables outside of their declaration scope + // F0(ref x, __arglist(ref y)); // 2 + Diagnostic(ErrorCode.ERR_EscapeVariable, "y").WithArguments("y").WithLocation(14, 33), + // (15,9): error CS8350: This combination of arguments to 'Program.F0(ref R, __arglist)' is disallowed because it may expose variables referenced by parameter 'a' outside of their declaration scope + // F0(ref y, __arglist(ref x)); // 3 + Diagnostic(ErrorCode.ERR_CallArgMixing, "F0(ref y, __arglist(ref x))").WithArguments("Program.F0(ref R, __arglist)", "a").WithLocation(15, 9), + // (15,16): error CS8352: Cannot use variable 'y' in this context because it may expose referenced variables outside of their declaration scope + // F0(ref y, __arglist(ref x)); // 3 + Diagnostic(ErrorCode.ERR_EscapeVariable, "y").WithArguments("y").WithLocation(15, 16)); + } + + [Fact] + public void MethodArgumentsMustMatch_10() + { + var source = +@"using System.Diagnostics.CodeAnalysis; +ref struct R +{ + public R(ref int i) { } +} +class Program +{ + static void F1() { - this = default; - this = new S(); - this = new S(ref t0); - this = new S { F = t0 }; + R r1 = default; + F2(ref r1); + F3(ref r1); // 1 } - void M1(T t1) + static void F2(ref R r2) { - this = default; - this = new S(); - this = new S(ref t1); - this = new S { F = t1 }; } - static void M2(T t2) + static void F3([UnscopedRef] ref R r3) { - S s2; - s2 = default; - s2 = new S(); - s2 = new S(ref t2); - s2 = new S { F = t2 }; } - static void M3(ref T t3) +}"; + var comp = CreateCompilation(new[] { source, UnscopedRefAttributeDefinition }); + comp.VerifyDiagnostics( + // (12,9): error CS8350: This combination of arguments to 'Program.F3(ref R)' is disallowed because it may expose variables referenced by parameter 'r3' outside of their declaration scope + // F3(ref r1); // 1 + Diagnostic(ErrorCode.ERR_CallArgMixing, "F3(ref r1)").WithArguments("Program.F3(ref R)", "r3").WithLocation(12, 9), + // (12,16): error CS8168: Cannot return local 'r1' by reference because it is not a ref local + // F3(ref r1); // 1 + Diagnostic(ErrorCode.ERR_RefReturnLocal, "r1").WithArguments("r1").WithLocation(12, 16)); + } + + [Fact] + public void MethodArgumentsMustMatch_11() + { + var source = +@"using System.Diagnostics.CodeAnalysis; +ref struct R +{ + public R(ref int i) { } +} +class Program +{ + static void F1() { - S s3; - s3 = new S(ref t3); - s3 = new S { F = t3 }; + R x1 = default; + R y1 = default; + F2(ref x1, ref y1); // 1 + F2(ref y1, ref x1); // 2 } - static void M4(T t4) + static void F2(ref R x2, [UnscopedRef] ref R y2) { - S s; - s = new S(); - s = new S(ref t4); - s = new S { F = t4 }; } }"; - var comp = CreateCompilation(source); - comp.VerifyEmitDiagnostics( - // (12,16): error CS8347: Cannot use a result of 'S.S(ref T)' in this context because it may expose variables referenced by parameter 't' outside of their declaration scope - // this = new S(ref t0); - Diagnostic(ErrorCode.ERR_EscapeCall, "new S(ref t0)").WithArguments("S.S(ref T)", "t").WithLocation(12, 16), - // (12,29): error CS8166: Cannot return a parameter by reference 't0' because it is not a ref parameter - // this = new S(ref t0); - Diagnostic(ErrorCode.ERR_RefReturnParameter, "t0").WithArguments("t0").WithLocation(12, 29), - // (19,16): error CS8347: Cannot use a result of 'S.S(ref T)' in this context because it may expose variables referenced by parameter 't' outside of their declaration scope - // this = new S(ref t1); - Diagnostic(ErrorCode.ERR_EscapeCall, "new S(ref t1)").WithArguments("S.S(ref T)", "t").WithLocation(19, 16), - // (19,29): error CS8166: Cannot return a parameter by reference 't1' because it is not a ref parameter - // this = new S(ref t1); - Diagnostic(ErrorCode.ERR_RefReturnParameter, "t1").WithArguments("t1").WithLocation(19, 29), - // (27,14): error CS8347: Cannot use a result of 'S.S(ref T)' in this context because it may expose variables referenced by parameter 't' outside of their declaration scope - // s2 = new S(ref t2); - Diagnostic(ErrorCode.ERR_EscapeCall, "new S(ref t2)").WithArguments("S.S(ref T)", "t").WithLocation(27, 14), - // (27,27): error CS8166: Cannot return a parameter by reference 't2' because it is not a ref parameter - // s2 = new S(ref t2); - Diagnostic(ErrorCode.ERR_RefReturnParameter, "t2").WithArguments("t2").WithLocation(27, 27), - // (40,13): error CS8347: Cannot use a result of 'S.S(ref T)' in this context because it may expose variables referenced by parameter 't' outside of their declaration scope - // s = new S(ref t4); - Diagnostic(ErrorCode.ERR_EscapeCall, "new S(ref t4)").WithArguments("S.S(ref T)", "t").WithLocation(40, 13), - // (40,26): error CS8166: Cannot return a parameter by reference 't4' because it is not a ref parameter - // s = new S(ref t4); - Diagnostic(ErrorCode.ERR_RefReturnParameter, "t4").WithArguments("t4").WithLocation(40, 26)); + var comp = CreateCompilation(new[] { source, UnscopedRefAttributeDefinition }); + comp.VerifyDiagnostics( + // (12,9): error CS8350: This combination of arguments to 'Program.F2(ref R, ref R)' is disallowed because it may expose variables referenced by parameter 'y2' outside of their declaration scope + // F2(ref x1, ref y1); // 1 + Diagnostic(ErrorCode.ERR_CallArgMixing, "F2(ref x1, ref y1)").WithArguments("Program.F2(ref R, ref R)", "y2").WithLocation(12, 9), + // (12,24): error CS8168: Cannot return local 'y1' by reference because it is not a ref local + // F2(ref x1, ref y1); // 1 + Diagnostic(ErrorCode.ERR_RefReturnLocal, "y1").WithArguments("y1").WithLocation(12, 24), + // (13,9): error CS8350: This combination of arguments to 'Program.F2(ref R, ref R)' is disallowed because it may expose variables referenced by parameter 'y2' outside of their declaration scope + // F2(ref y1, ref x1); // 2 + Diagnostic(ErrorCode.ERR_CallArgMixing, "F2(ref y1, ref x1)").WithArguments("Program.F2(ref R, ref R)", "y2").WithLocation(13, 9), + // (13,24): error CS8168: Cannot return local 'x1' by reference because it is not a ref local + // F2(ref y1, ref x1); // 2 + Diagnostic(ErrorCode.ERR_RefReturnLocal, "x1").WithArguments("x1").WithLocation(13, 24)); } [Fact] - public void DefiniteAssignment_01() + public void MethodArgumentsMustMatch_12() { var source = -@"ref struct S1 -{ - public ref T F; -} -ref struct S2 -{ - public ref T F; - public S2(ref T t) { } -} -ref struct S3 +@"ref struct R { - public ref T F; - public S3(ref T t) : this() { } + public R(ref int i) { } } -ref struct S4 +class Program { - public ref T F; - public S4(ref T t) + static void F1() { - this = default; + R x1 = default; + int i = 42; + R y1 = new R(ref i); // implicitly scoped + F2(ref x1, ref y1); // 1 + F2(ref y1, ref x1); // 2 } + static void F2(ref R x2, ref R y2) + { + } +}"; + var comp = CreateCompilation(new[] { source, UnscopedRefAttributeDefinition }); + comp.VerifyDiagnostics( + // (12,9): error CS8350: This combination of arguments to 'Program.F2(ref R, ref R)' is disallowed because it may expose variables referenced by parameter 'y2' outside of their declaration scope + // F2(ref x1, ref y1); // 1 + Diagnostic(ErrorCode.ERR_CallArgMixing, "F2(ref x1, ref y1)").WithArguments("Program.F2(ref R, ref R)", "y2").WithLocation(12, 9), + // (12,24): error CS8352: Cannot use variable 'y1' in this context because it may expose referenced variables outside of their declaration scope + // F2(ref x1, ref y1); // 1 + Diagnostic(ErrorCode.ERR_EscapeVariable, "y1").WithArguments("y1").WithLocation(12, 24), + // (13,9): error CS8350: This combination of arguments to 'Program.F2(ref R, ref R)' is disallowed because it may expose variables referenced by parameter 'x2' outside of their declaration scope + // F2(ref y1, ref x1); // 2 + Diagnostic(ErrorCode.ERR_CallArgMixing, "F2(ref y1, ref x1)").WithArguments("Program.F2(ref R, ref R)", "x2").WithLocation(13, 9), + // (13,16): error CS8352: Cannot use variable 'y1' in this context because it may expose referenced variables outside of their declaration scope + // F2(ref y1, ref x1); // 2 + Diagnostic(ErrorCode.ERR_EscapeVariable, "y1").WithArguments("y1").WithLocation(13, 16)); + } + + [Theory] + [InlineData(LanguageVersion.CSharp10)] + [InlineData(LanguageVersion.CSharp11)] + public void Arglist_RefToRefStruct(LanguageVersion languageVersion) + { + var source = +@"using System; +ref struct R +{ } class Program { - static void F(ref T t) + static ref R F(__arglist) { - new S1().F = ref t; - new S2().F = ref t; - new S3().F = ref t; - new S4().F = ref t; - new S1().F = t; - new S2().F = t; - new S3().F = t; - new S4().F = t; + var args = new ArgIterator(__arglist); + ref R r = ref __refvalue(args.GetNextArg(), R); + return ref r; } }"; - var comp = CreateCompilation(source); + var comp = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion)); comp.VerifyEmitDiagnostics( - // (27,9): error CS0131: The left-hand side of an assignment must be a variable, property or indexer - // new S1().F = ref t; - Diagnostic(ErrorCode.ERR_AssgLvalueExpected, "new S1().F").WithLocation(27, 9), - // (28,9): error CS0131: The left-hand side of an assignment must be a variable, property or indexer - // new S2().F = ref t; - Diagnostic(ErrorCode.ERR_AssgLvalueExpected, "new S2().F").WithLocation(28, 9), - // (29,9): error CS0131: The left-hand side of an assignment must be a variable, property or indexer - // new S3().F = ref t; - Diagnostic(ErrorCode.ERR_AssgLvalueExpected, "new S3().F").WithLocation(29, 9), - // (30,9): error CS0131: The left-hand side of an assignment must be a variable, property or indexer - // new S4().F = ref t; - Diagnostic(ErrorCode.ERR_AssgLvalueExpected, "new S4().F").WithLocation(30, 9)); + // (11,20): error CS8157: Cannot return 'r' by reference because it was initialized to a value that cannot be returned by reference + // return ref r; + Diagnostic(ErrorCode.ERR_RefReturnNonreturnableLocal, "r").WithArguments("r").WithLocation(11, 20)); } - [Fact] - public void DefiniteAssignment_02() + [Theory] + [InlineData(LanguageVersion.CSharp10)] + [InlineData(LanguageVersion.CSharp11)] + public void Arglist_RefReturnedAsRef(LanguageVersion languageVersion) { - // Should we report a warning when assigning a value rather than a ref in the - // constructor, because a NullReferenceException will be thrown at runtime? var source = -@"ref struct S +@"using System; +class Program { - public ref T F; - public S(ref T t) + static ref int F1(__arglist) { - F = t; + var args = new ArgIterator(__arglist); + return ref __refvalue(args.GetNextArg(), int); + } + static ref int F2() + { + int i = 2; + return ref F1(__arglist(ref i)); } }"; - var comp = CreateCompilation(source); - comp.VerifyEmitDiagnostics(); + var comp = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion)); + comp.VerifyEmitDiagnostics( + // (7,20): error CS8156: An expression cannot be used in this context because it may not be passed or returned by reference + // return ref __refvalue(args.GetNextArg(), int); + Diagnostic(ErrorCode.ERR_RefReturnLvalueExpected, "__refvalue(args.GetNextArg(), int)").WithLocation(7, 20)); } [Fact] - public void AssignLocal() + public void Arglist_RefReturnedAsRefStruct() { var source = -@"ref struct S +@"using System; +ref struct R { - public ref T F1; - public ref readonly T F2; - public readonly ref T F3; - public readonly ref readonly T F4; - public S() - { - T t = default; - F1 = ref t; - F2 = ref t; - F3 = ref t; - F4 = ref t; - } + public R(ref T t) { } } class Program { - static void M(ref S x) + static R F1(__arglist) { - T t = default; - x.F1 = ref t; - x.F2 = ref t; - x.F3 = ref t; - x.F4 = ref t; - S y = new S(); - y.F1 = ref t; - y.F2 = ref t; - y.F3 = ref t; - y.F4 = ref t; + var args = new ArgIterator(__arglist); + ref int i = ref __refvalue(args.GetNextArg(), int); + return new R(ref i); + } + static R F2() + { + int i = 2; + return F1(__arglist(ref i)); } }"; - var comp = CreateCompilation(new[] { source, IsExternalInitTypeDefinition }); + + var comp = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.Regular10); + comp.VerifyEmitDiagnostics(); + + comp = CreateCompilationWithMscorlib45(source); comp.VerifyEmitDiagnostics( - // (10,9): error CS8374: Cannot ref-assign 't' to 'F1' because 't' has a narrower escape scope than 'F1'. - // F1 = ref t; - Diagnostic(ErrorCode.ERR_RefAssignNarrower, "F1 = ref t").WithArguments("F1", "t").WithLocation(10, 9), - // (11,9): error CS8374: Cannot ref-assign 't' to 'F2' because 't' has a narrower escape scope than 'F2'. - // F2 = ref t; - Diagnostic(ErrorCode.ERR_RefAssignNarrower, "F2 = ref t").WithArguments("F2", "t").WithLocation(11, 9), - // (12,9): error CS8374: Cannot ref-assign 't' to 'F3' because 't' has a narrower escape scope than 'F3'. - // F3 = ref t; - Diagnostic(ErrorCode.ERR_RefAssignNarrower, "F3 = ref t").WithArguments("F3", "t").WithLocation(12, 9), - // (13,9): error CS8374: Cannot ref-assign 't' to 'F4' because 't' has a narrower escape scope than 'F4'. - // F4 = ref t; - Diagnostic(ErrorCode.ERR_RefAssignNarrower, "F4 = ref t").WithArguments("F4", "t").WithLocation(13, 9), - // (21,9): error CS8374: Cannot ref-assign 't' to 'F1' because 't' has a narrower escape scope than 'F1'. - // x.F1 = ref t; - Diagnostic(ErrorCode.ERR_RefAssignNarrower, "x.F1 = ref t").WithArguments("F1", "t").WithLocation(21, 9), - // (22,9): error CS8374: Cannot ref-assign 't' to 'F2' because 't' has a narrower escape scope than 'F2'. - // x.F2 = ref t; - Diagnostic(ErrorCode.ERR_RefAssignNarrower, "x.F2 = ref t").WithArguments("F2", "t").WithLocation(22, 9), - // (23,9): error CS0191: A readonly field cannot be assigned to (except in a constructor or init-only setter of the type in which the field is defined or a variable initializer) - // x.F3 = ref t; - Diagnostic(ErrorCode.ERR_AssgReadonly, "x.F3").WithLocation(23, 9), - // (24,9): error CS0191: A readonly field cannot be assigned to (except in a constructor or init-only setter of the type in which the field is defined or a variable initializer) - // x.F4 = ref t; - Diagnostic(ErrorCode.ERR_AssgReadonly, "x.F4").WithLocation(24, 9), - // (26,9): error CS8374: Cannot ref-assign 't' to 'F1' because 't' has a narrower escape scope than 'F1'. - // y.F1 = ref t; - Diagnostic(ErrorCode.ERR_RefAssignNarrower, "y.F1 = ref t").WithArguments("F1", "t").WithLocation(26, 9), - // (27,9): error CS8374: Cannot ref-assign 't' to 'F2' because 't' has a narrower escape scope than 'F2'. - // y.F2 = ref t; - Diagnostic(ErrorCode.ERR_RefAssignNarrower, "y.F2 = ref t").WithArguments("F2", "t").WithLocation(27, 9), - // (28,9): error CS0191: A readonly field cannot be assigned to (except in a constructor or init-only setter of the type in which the field is defined or a variable initializer) - // y.F3 = ref t; - Diagnostic(ErrorCode.ERR_AssgReadonly, "y.F3").WithLocation(28, 9), - // (29,9): error CS0191: A readonly field cannot be assigned to (except in a constructor or init-only setter of the type in which the field is defined or a variable initializer) - // y.F4 = ref t; - Diagnostic(ErrorCode.ERR_AssgReadonly, "y.F4").WithLocation(29, 9)); + // (12,16): error CS8347: Cannot use a result of 'R.R(ref int)' in this context because it may expose variables referenced by parameter 't' outside of their declaration scope + // return new R(ref i); + Diagnostic(ErrorCode.ERR_EscapeCall, "new R(ref i)").WithArguments("R.R(ref int)", "t").WithLocation(12, 16), + // (12,31): error CS8157: Cannot return 'i' by reference because it was initialized to a value that cannot be returned by reference + // return new R(ref i); + Diagnostic(ErrorCode.ERR_RefReturnNonreturnableLocal, "i").WithArguments("i").WithLocation(12, 31)); } [Fact] - public void AssignValueTo_InstanceMethod_RefField() + public void ImplicitIn_01() { var source = -@"ref struct S +@"ref struct R { - public ref T F; - public S(T tValue, ref T tRef, out T tOut, in T tIn) + public void F(in T t) { } +} +class Program +{ + static R F1() { - tOut = default; - F = tValue; - F = tRef; - F = tOut; - F = tIn; + var r1 = new R(); + int i = 1; + r1.F(in i); // 1 + return r1; } - object P + static R F2() { - init - { - F = GetValue(); - F = GetRef(); - F = GetRefReadonly(); - } + var r2 = new R(); + int i = 2; + r2.F(i); // 2 + return r2; + } + static R F3() + { + var r3 = new R(); + r3.F(3); // 3 + return r3; } - static T GetValue() => throw null; - static ref T GetRef() => throw null; - static ref readonly T GetRefReadonly() => throw null; }"; - var comp = CreateCompilation(new[] { source, IsExternalInitTypeDefinition }); + + var comp = CreateCompilation(source, parseOptions: TestOptions.Regular10); comp.VerifyEmitDiagnostics(); + + comp = CreateCompilation(source); + comp.VerifyEmitDiagnostics( + // (11,9): error CS8350: This combination of arguments to 'R.F(in int)' is disallowed because it may expose variables referenced by parameter 't' outside of their declaration scope + // r1.F(in i); // 1 + Diagnostic(ErrorCode.ERR_CallArgMixing, "r1.F(in i)").WithArguments("R.F(in int)", "t").WithLocation(11, 9), + // (11,17): error CS8168: Cannot return local 'i' by reference because it is not a ref local + // r1.F(in i); // 1 + Diagnostic(ErrorCode.ERR_RefReturnLocal, "i").WithArguments("i").WithLocation(11, 17), + // (18,9): error CS8350: This combination of arguments to 'R.F(in int)' is disallowed because it may expose variables referenced by parameter 't' outside of their declaration scope + // r2.F(i); // 2 + Diagnostic(ErrorCode.ERR_CallArgMixing, "r2.F(i)").WithArguments("R.F(in int)", "t").WithLocation(18, 9), + // (18,14): error CS8168: Cannot return local 'i' by reference because it is not a ref local + // r2.F(i); // 2 + Diagnostic(ErrorCode.ERR_RefReturnLocal, "i").WithArguments("i").WithLocation(18, 14), + // (24,9): error CS8350: This combination of arguments to 'R.F(in int)' is disallowed because it may expose variables referenced by parameter 't' outside of their declaration scope + // r3.F(3); // 3 + Diagnostic(ErrorCode.ERR_CallArgMixing, "r3.F(3)").WithArguments("R.F(in int)", "t").WithLocation(24, 9), + // (24,14): error CS8156: An expression cannot be used in this context because it may not be passed or returned by reference + // r3.F(3); // 3 + Diagnostic(ErrorCode.ERR_RefReturnLvalueExpected, "3").WithLocation(24, 14)); } - [Fact] - public void AssignValueTo_InstanceMethod_RefReadonlyField() + [Theory] + [InlineData(LanguageVersion.CSharp10)] + [InlineData(LanguageVersion.CSharp11)] + public void ImplicitIn_02(LanguageVersion languageVersion) { var source = -@"ref struct S +@"class Program { - public ref readonly T F; - public S(T tValue, ref T tRef, out T tOut, in T tIn) + static ref readonly T F(in T t) { - tOut = default; - F = tValue; // 1 - F = tRef; // 2 - F = tOut; // 3 - F = tIn; // 4 + return ref t; } - object P + static ref readonly int F1() { - init - { - F = GetValue(); // 5 - F = GetRef(); // 6 - F = GetRefReadonly(); // 7 - } + int i1 = 1; + return ref F(in i1); // 1 + } + static ref readonly int F2() + { + int i2 = 2; + return ref F(i2); // 2 + } + static ref readonly int F3() + { + return ref F(3); // 3 } - static T GetValue() => throw null; - static ref T GetRef() => throw null; - static ref readonly T GetRefReadonly() => throw null; }"; - var comp = CreateCompilation(new[] { source, IsExternalInitTypeDefinition }); - comp.VerifyEmitDiagnostics( - // (7,9): error CS8331: Cannot assign to field 'S.F' because it is a readonly variable - // F = tValue; // 1 - Diagnostic(ErrorCode.ERR_AssignReadonlyNotField, "F").WithArguments("field", "S.F").WithLocation(7, 9), - // (8,9): error CS8331: Cannot assign to field 'S.F' because it is a readonly variable - // F = tRef; // 2 - Diagnostic(ErrorCode.ERR_AssignReadonlyNotField, "F").WithArguments("field", "S.F").WithLocation(8, 9), - // (9,9): error CS8331: Cannot assign to field 'S.F' because it is a readonly variable - // F = tOut; // 3 - Diagnostic(ErrorCode.ERR_AssignReadonlyNotField, "F").WithArguments("field", "S.F").WithLocation(9, 9), - // (10,9): error CS8331: Cannot assign to field 'S.F' because it is a readonly variable - // F = tIn; // 4 - Diagnostic(ErrorCode.ERR_AssignReadonlyNotField, "F").WithArguments("field", "S.F").WithLocation(10, 9), - // (16,13): error CS8331: Cannot assign to field 'S.F' because it is a readonly variable - // F = GetValue(); // 5 - Diagnostic(ErrorCode.ERR_AssignReadonlyNotField, "F").WithArguments("field", "S.F").WithLocation(16, 13), - // (17,13): error CS8331: Cannot assign to field 'S.F' because it is a readonly variable - // F = GetRef(); // 6 - Diagnostic(ErrorCode.ERR_AssignReadonlyNotField, "F").WithArguments("field", "S.F").WithLocation(17, 13), - // (18,13): error CS8331: Cannot assign to field 'S.F' because it is a readonly variable - // F = GetRefReadonly(); // 7 - Diagnostic(ErrorCode.ERR_AssignReadonlyNotField, "F").WithArguments("field", "S.F").WithLocation(18, 13)); - } - [Fact] - public void AssignValueTo_InstanceMethod_ReadonlyRefField() + var comp = CreateCompilation(source, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion)); + comp.VerifyEmitDiagnostics( + // (10,20): error CS8347: Cannot use a result of 'Program.F(in int)' in this context because it may expose variables referenced by parameter 't' outside of their declaration scope + // return ref F(in i1); // 1 + Diagnostic(ErrorCode.ERR_EscapeCall, "F(in i1)").WithArguments("Program.F(in int)", "t").WithLocation(10, 20), + // (10,25): error CS8168: Cannot return local 'i1' by reference because it is not a ref local + // return ref F(in i1); // 1 + Diagnostic(ErrorCode.ERR_RefReturnLocal, "i1").WithArguments("i1").WithLocation(10, 25), + // (15,20): error CS8347: Cannot use a result of 'Program.F(in int)' in this context because it may expose variables referenced by parameter 't' outside of their declaration scope + // return ref F(i2); // 2 + Diagnostic(ErrorCode.ERR_EscapeCall, "F(i2)").WithArguments("Program.F(in int)", "t").WithLocation(15, 20), + // (15,22): error CS8168: Cannot return local 'i2' by reference because it is not a ref local + // return ref F(i2); // 2 + Diagnostic(ErrorCode.ERR_RefReturnLocal, "i2").WithArguments("i2").WithLocation(15, 22), + // (19,20): error CS8347: Cannot use a result of 'Program.F(in int)' in this context because it may expose variables referenced by parameter 't' outside of their declaration scope + // return ref F(3); // 3 + Diagnostic(ErrorCode.ERR_EscapeCall, "F(3)").WithArguments("Program.F(in int)", "t").WithLocation(19, 20), + // (19,22): error CS8156: An expression cannot be used in this context because it may not be passed or returned by reference + // return ref F(3); // 3 + Diagnostic(ErrorCode.ERR_RefReturnLvalueExpected, "3").WithLocation(19, 22)); + } + + [Fact] + public void ImplicitIn_03() { var source = -@"ref struct S +@"class Program { - public readonly ref T F; - public S(T tValue, ref T tRef, out T tOut, in T tIn) + static ref readonly T F(in T x, scoped in T y) { - tOut = default; - F = tValue; - F = tRef; - F = tOut; - F = tIn; + return ref x; } - object P + static ref readonly int F1() { - init - { - F = GetValue(); - F = GetRef(); - F = GetRefReadonly(); - } + int x1 = 1; + int y1 = 1; + return ref F(in x1, in y1); // 1 + } + static ref readonly int F2() + { + int x2 = 2; + int y2 = 2; + return ref F(x2, in y2); // 2 + } + static ref readonly int F3() + { + int y3 = 3; + return ref F(3, in y3); // 3 } - static T GetValue() => throw null; - static ref T GetRef() => throw null; - static ref readonly T GetRefReadonly() => throw null; }"; - var comp = CreateCompilation(new[] { source, IsExternalInitTypeDefinition }); - comp.VerifyEmitDiagnostics(); - } - [Fact] - public void AssignValueTo_InstanceMethod_ReadonlyRefReadonlyField() - { - var source = -@"ref struct S + var comp = CreateCompilation(source); + comp.VerifyEmitDiagnostics( + // (11,20): error CS8347: Cannot use a result of 'Program.F(in int, in int)' in this context because it may expose variables referenced by parameter 'x' outside of their declaration scope + // return ref F(in x1, in y1); // 1 + Diagnostic(ErrorCode.ERR_EscapeCall, "F(in x1, in y1)").WithArguments("Program.F(in int, in int)", "x").WithLocation(11, 20), + // (11,25): error CS8168: Cannot return local 'x1' by reference because it is not a ref local + // return ref F(in x1, in y1); // 1 + Diagnostic(ErrorCode.ERR_RefReturnLocal, "x1").WithArguments("x1").WithLocation(11, 25), + // (17,20): error CS8347: Cannot use a result of 'Program.F(in int, in int)' in this context because it may expose variables referenced by parameter 'x' outside of their declaration scope + // return ref F(x2, in y2); // 2 + Diagnostic(ErrorCode.ERR_EscapeCall, "F(x2, in y2)").WithArguments("Program.F(in int, in int)", "x").WithLocation(17, 20), + // (17,22): error CS8168: Cannot return local 'x2' by reference because it is not a ref local + // return ref F(x2, in y2); // 2 + Diagnostic(ErrorCode.ERR_RefReturnLocal, "x2").WithArguments("x2").WithLocation(17, 22), + // (22,20): error CS8347: Cannot use a result of 'Program.F(in int, in int)' in this context because it may expose variables referenced by parameter 'x' outside of their declaration scope + // return ref F(3, in y3); // 3 + Diagnostic(ErrorCode.ERR_EscapeCall, "F(3, in y3)").WithArguments("Program.F(in int, in int)", "x").WithLocation(22, 20), + // (22,22): error CS8156: An expression cannot be used in this context because it may not be passed or returned by reference + // return ref F(3, in y3); // 3 + Diagnostic(ErrorCode.ERR_RefReturnLvalueExpected, "3").WithLocation(22, 22)); + } + + [Fact] + public void RefToRefStruct_InstanceMethods() + { + var source = +@"using System.Diagnostics.CodeAnalysis; +ref struct R { - public readonly ref readonly T F; - public S(T tValue, ref T tRef, out T tOut, in T tIn) + public R(ref R other) { } + public void F1(ref R other) { } + [UnscopedRef] public void F2(ref R other) { } +} +class Program +{ + static R F0() { - tOut = default; - F = tValue; // 1 - F = tRef; // 2 - F = tOut; // 3 - F = tIn; // 4 + var x0 = new R(); + var y0 = new R(ref x0); + return x0; } - object P + static R F1() { - init - { - F = GetValue(); // 5 - F = GetRef(); // 6 - F = GetRefReadonly(); // 7 - } + var x1 = new R(); + var y1 = new R(); + y1.F1(ref x1); + return x1; + } + static R F2() + { + var x2 = new R(); + var y2 = new R(); + y2.F2(ref x2); // 1 + return x2; } - static T GetValue() => throw null; - static ref T GetRef() => throw null; - static ref readonly T GetRefReadonly() => throw null; }"; - var comp = CreateCompilation(new[] { source, IsExternalInitTypeDefinition }); + var comp = CreateCompilation(new[] { source, UnscopedRefAttributeDefinition }); comp.VerifyEmitDiagnostics( - // (7,9): error CS8331: Cannot assign to field 'S.F' because it is a readonly variable - // F = tValue; // 1 - Diagnostic(ErrorCode.ERR_AssignReadonlyNotField, "F").WithArguments("field", "S.F").WithLocation(7, 9), - // (8,9): error CS8331: Cannot assign to field 'S.F' because it is a readonly variable - // F = tRef; // 2 - Diagnostic(ErrorCode.ERR_AssignReadonlyNotField, "F").WithArguments("field", "S.F").WithLocation(8, 9), - // (9,9): error CS8331: Cannot assign to field 'S.F' because it is a readonly variable - // F = tOut; // 3 - Diagnostic(ErrorCode.ERR_AssignReadonlyNotField, "F").WithArguments("field", "S.F").WithLocation(9, 9), - // (10,9): error CS8331: Cannot assign to field 'S.F' because it is a readonly variable - // F = tIn; // 4 - Diagnostic(ErrorCode.ERR_AssignReadonlyNotField, "F").WithArguments("field", "S.F").WithLocation(10, 9), - // (16,13): error CS8331: Cannot assign to field 'S.F' because it is a readonly variable - // F = GetValue(); // 5 - Diagnostic(ErrorCode.ERR_AssignReadonlyNotField, "F").WithArguments("field", "S.F").WithLocation(16, 13), - // (17,13): error CS8331: Cannot assign to field 'S.F' because it is a readonly variable - // F = GetRef(); // 6 - Diagnostic(ErrorCode.ERR_AssignReadonlyNotField, "F").WithArguments("field", "S.F").WithLocation(17, 13), - // (18,13): error CS8331: Cannot assign to field 'S.F' because it is a readonly variable - // F = GetRefReadonly(); // 7 - Diagnostic(ErrorCode.ERR_AssignReadonlyNotField, "F").WithArguments("field", "S.F").WithLocation(18, 13)); + // (27,9): error CS8168: Cannot return local 'y2' by reference because it is not a ref local + // y2.F2(ref x2); // 1 + Diagnostic(ErrorCode.ERR_RefReturnLocal, "y2").WithArguments("y2").WithLocation(27, 9)); } [Fact] - public void AssignRefTo_InstanceMethod_RefField() + public void RefToRefStruct_ConstructorInitializer() { var source = -@"ref struct S +@"ref struct R { - public ref T F; - public S(T tValue, ref T tRef, out T tOut, in T tIn) - { - tOut = default; - F = ref tValue; // 1 - F = ref tRef; - F = ref tOut; // 2 - F = ref tIn; // 3 - } - T P + public R(ref R other) { } + public R(ref R other, int i) : + this(ref other) { - init - { - F = ref value; // 4 - F = ref GetRef(); - F = ref GetRefReadonly(); // 5 - } } - static ref T GetRef() => throw null; - static ref readonly T GetRefReadonly() => throw null; }"; - var comp = CreateCompilation(new[] { source, IsExternalInitTypeDefinition }); - comp.VerifyEmitDiagnostics( - // (7,9): error CS8374: Cannot ref-assign 'tValue' to 'F' because 'tValue' has a narrower escape scope than 'F'. - // F = ref tValue; // 1 - Diagnostic(ErrorCode.ERR_RefAssignNarrower, "F = ref tValue").WithArguments("F", "tValue").WithLocation(7, 9), - // (9,9): error CS8374: Cannot ref-assign 'tOut' to 'F' because 'tOut' has a narrower escape scope than 'F'. - // F = ref tOut; // 2 - Diagnostic(ErrorCode.ERR_RefAssignNarrower, "F = ref tOut").WithArguments("F", "tOut").WithLocation(9, 9), - // (10,17): error CS8331: Cannot assign to variable 'in T' because it is a readonly variable - // F = ref tIn; // 3 - Diagnostic(ErrorCode.ERR_AssignReadonlyNotField, "tIn").WithArguments("variable", "in T").WithLocation(10, 17), - // (16,13): error CS8374: Cannot ref-assign 'value' to 'F' because 'value' has a narrower escape scope than 'F'. - // F = ref value; // 4 - Diagnostic(ErrorCode.ERR_RefAssignNarrower, "F = ref value").WithArguments("F", "value").WithLocation(16, 13), - // (18,21): error CS8331: Cannot assign to method 'S.GetRefReadonly()' because it is a readonly variable - // F = ref GetRefReadonly(); // 5 - Diagnostic(ErrorCode.ERR_AssignReadonlyNotField, "GetRefReadonly()").WithArguments("method", "S.GetRefReadonly()").WithLocation(18, 21)); + var comp = CreateCompilation(source); + comp.VerifyEmitDiagnostics(); } [Fact] - public void AssignRefTo_InstanceMethod_RefReadonlyField() + public void NestedFieldAccessor() { var source = -@"ref struct S +@"ref struct R { - public ref readonly T F; - public S(T tValue, ref T tRef, out T tOut, in T tIn) + private ref T _t; + public R(ref T t) { _t = t; } + public ref T F0() => ref _t; + ref T F1() => ref F0(); +} +class Program +{ + static ref T F2(ref R r) => ref r.F0(); +}"; + var comp = CreateCompilation(source, runtimeFeature: RuntimeFlag.ByRefFields); + comp.VerifyEmitDiagnostics(); + } + + [Fact] + public void Constructors() + { + var source = +@"ref struct S +{ + public ref T F; + public S(ref T t) { - tOut = default; - F = ref tValue; // 1 - F = ref tRef; - F = ref tOut; // 2 - F = ref tIn; + F = ref t; } - T P + S(object unused, T t0) { - init - { - F = ref value; // 3 - F = ref GetRef(); - F = ref GetRefReadonly(); - } + this = default; + this = new S(); + this = new S(ref t0); + this = new S { F = t0 }; + } + void M1(T t1) + { + this = default; + this = new S(); + this = new S(ref t1); + this = new S { F = t1 }; + } + static void M2(T t2) + { + S s2; + s2 = default; + s2 = new S(); + s2 = new S(ref t2); + s2 = new S { F = t2 }; + } + static void M3(ref T t3) + { + S s3; + s3 = new S(ref t3); + s3 = new S { F = t3 }; + } + static void M4(T t4) + { + S s; + s = new S(); + s = new S(ref t4); + s = new S { F = t4 }; } - static ref T GetRef() => throw null; - static ref readonly T GetRefReadonly() => throw null; }"; - var comp = CreateCompilation(new[] { source, IsExternalInitTypeDefinition }); + var comp = CreateCompilation(source, runtimeFeature: RuntimeFlag.ByRefFields); comp.VerifyEmitDiagnostics( - // (7,9): error CS8374: Cannot ref-assign 'tValue' to 'F' because 'tValue' has a narrower escape scope than 'F'. - // F = ref tValue; // 1 - Diagnostic(ErrorCode.ERR_RefAssignNarrower, "F = ref tValue").WithArguments("F", "tValue").WithLocation(7, 9), - // (9,9): error CS8374: Cannot ref-assign 'tOut' to 'F' because 'tOut' has a narrower escape scope than 'F'. - // F = ref tOut; // 2 - Diagnostic(ErrorCode.ERR_RefAssignNarrower, "F = ref tOut").WithArguments("F", "tOut").WithLocation(9, 9), - // (16,13): error CS8374: Cannot ref-assign 'value' to 'F' because 'value' has a narrower escape scope than 'F'. - // F = ref value; // 3 - Diagnostic(ErrorCode.ERR_RefAssignNarrower, "F = ref value").WithArguments("F", "value").WithLocation(16, 13)); + // (12,16): error CS8347: Cannot use a result of 'S.S(ref T)' in this context because it may expose variables referenced by parameter 't' outside of their declaration scope + // this = new S(ref t0); + Diagnostic(ErrorCode.ERR_EscapeCall, "new S(ref t0)").WithArguments("S.S(ref T)", "t").WithLocation(12, 16), + // (12,29): error CS8166: Cannot return a parameter by reference 't0' because it is not a ref parameter + // this = new S(ref t0); + Diagnostic(ErrorCode.ERR_RefReturnParameter, "t0").WithArguments("t0").WithLocation(12, 29), + // (19,16): error CS8347: Cannot use a result of 'S.S(ref T)' in this context because it may expose variables referenced by parameter 't' outside of their declaration scope + // this = new S(ref t1); + Diagnostic(ErrorCode.ERR_EscapeCall, "new S(ref t1)").WithArguments("S.S(ref T)", "t").WithLocation(19, 16), + // (19,29): error CS8166: Cannot return a parameter by reference 't1' because it is not a ref parameter + // this = new S(ref t1); + Diagnostic(ErrorCode.ERR_RefReturnParameter, "t1").WithArguments("t1").WithLocation(19, 29), + // (27,14): error CS8347: Cannot use a result of 'S.S(ref T)' in this context because it may expose variables referenced by parameter 't' outside of their declaration scope + // s2 = new S(ref t2); + Diagnostic(ErrorCode.ERR_EscapeCall, "new S(ref t2)").WithArguments("S.S(ref T)", "t").WithLocation(27, 14), + // (27,27): error CS8166: Cannot return a parameter by reference 't2' because it is not a ref parameter + // s2 = new S(ref t2); + Diagnostic(ErrorCode.ERR_RefReturnParameter, "t2").WithArguments("t2").WithLocation(27, 27), + // (40,13): error CS8347: Cannot use a result of 'S.S(ref T)' in this context because it may expose variables referenced by parameter 't' outside of their declaration scope + // s = new S(ref t4); + Diagnostic(ErrorCode.ERR_EscapeCall, "new S(ref t4)").WithArguments("S.S(ref T)", "t").WithLocation(40, 13), + // (40,26): error CS8166: Cannot return a parameter by reference 't4' because it is not a ref parameter + // s = new S(ref t4); + Diagnostic(ErrorCode.ERR_RefReturnParameter, "t4").WithArguments("t4").WithLocation(40, 26)); } [Fact] - public void AssignRefTo_InstanceMethod_ReadonlyRefField() + public void DefiniteAssignment_01() { var source = -@"ref struct S +@"ref struct S1 { - public readonly ref T F; - public S(T tValue, ref T tRef, out T tOut, in T tIn) + public ref T F; +} +ref struct S2 +{ + public ref T F; + public S2(ref T t) { } +} +ref struct S3 +{ + public ref T F; + public S3(ref T t) : this() { } +} +ref struct S4 +{ + public ref T F; + public S4(ref T t) { - tOut = default; - F = ref tValue; // 1 - F = ref tRef; - F = ref tOut; // 2 - F = ref tIn; // 3 + this = default; } - T P +} +class Program +{ + static void F(ref T t) { - init - { - F = ref value; // 4 - F = ref GetRef(); - F = ref GetRefReadonly(); // 5 - } + new S1().F = ref t; + new S2().F = ref t; + new S3().F = ref t; + new S4().F = ref t; + new S1().F = t; + new S2().F = t; + new S3().F = t; + new S4().F = t; } - static ref T GetRef() => throw null; - static ref readonly T GetRefReadonly() => throw null; }"; - var comp = CreateCompilation(new[] { source, IsExternalInitTypeDefinition }); + var comp = CreateCompilation(source, runtimeFeature: RuntimeFlag.ByRefFields); comp.VerifyEmitDiagnostics( - // (7,9): error CS8374: Cannot ref-assign 'tValue' to 'F' because 'tValue' has a narrower escape scope than 'F'. - // F = ref tValue; // 1 - Diagnostic(ErrorCode.ERR_RefAssignNarrower, "F = ref tValue").WithArguments("F", "tValue").WithLocation(7, 9), - // (9,9): error CS8374: Cannot ref-assign 'tOut' to 'F' because 'tOut' has a narrower escape scope than 'F'. - // F = ref tOut; // 2 - Diagnostic(ErrorCode.ERR_RefAssignNarrower, "F = ref tOut").WithArguments("F", "tOut").WithLocation(9, 9), - // (10,17): error CS8331: Cannot assign to variable 'in T' because it is a readonly variable - // F = ref tIn; // 3 - Diagnostic(ErrorCode.ERR_AssignReadonlyNotField, "tIn").WithArguments("variable", "in T").WithLocation(10, 17), - // (16,13): error CS8374: Cannot ref-assign 'value' to 'F' because 'value' has a narrower escape scope than 'F'. - // F = ref value; // 4 - Diagnostic(ErrorCode.ERR_RefAssignNarrower, "F = ref value").WithArguments("F", "value").WithLocation(16, 13), - // (18,21): error CS8331: Cannot assign to method 'S.GetRefReadonly()' because it is a readonly variable - // F = ref GetRefReadonly(); // 5 - Diagnostic(ErrorCode.ERR_AssignReadonlyNotField, "GetRefReadonly()").WithArguments("method", "S.GetRefReadonly()").WithLocation(18, 21)); + // (27,9): error CS0131: The left-hand side of an assignment must be a variable, property or indexer + // new S1().F = ref t; + Diagnostic(ErrorCode.ERR_AssgLvalueExpected, "new S1().F").WithLocation(27, 9), + // (28,9): error CS0131: The left-hand side of an assignment must be a variable, property or indexer + // new S2().F = ref t; + Diagnostic(ErrorCode.ERR_AssgLvalueExpected, "new S2().F").WithLocation(28, 9), + // (29,9): error CS0131: The left-hand side of an assignment must be a variable, property or indexer + // new S3().F = ref t; + Diagnostic(ErrorCode.ERR_AssgLvalueExpected, "new S3().F").WithLocation(29, 9), + // (30,9): error CS0131: The left-hand side of an assignment must be a variable, property or indexer + // new S4().F = ref t; + Diagnostic(ErrorCode.ERR_AssgLvalueExpected, "new S4().F").WithLocation(30, 9)); } [Fact] - public void AssignRefTo_InstanceMethod_ReadonlyRefReadonlyField() + public void DefiniteAssignment_02() { + // Should we report a warning when assigning a value rather than a ref in the + // constructor, because a NullReferenceException will be thrown at runtime? var source = @"ref struct S { - public readonly ref readonly T F; - public S(T tValue, ref T tRef, out T tOut, in T tIn) - { - tOut = default; - F = ref tValue; // 1 - F = ref tRef; - F = ref tOut; // 2 - F = ref tIn; - } - T P + public ref T F; + public S(ref T t) { - init - { - F = ref value; // 3 - F = ref GetRef(); - F = ref GetRefReadonly(); - } + F = t; } - static ref T GetRef() => throw null; - static ref readonly T GetRefReadonly() => throw null; }"; - var comp = CreateCompilation(new[] { source, IsExternalInitTypeDefinition }); - comp.VerifyEmitDiagnostics( - // (7,9): error CS8374: Cannot ref-assign 'tValue' to 'F' because 'tValue' has a narrower escape scope than 'F'. - // F = ref tValue; // 1 - Diagnostic(ErrorCode.ERR_RefAssignNarrower, "F = ref tValue").WithArguments("F", "tValue").WithLocation(7, 9), - // (9,9): error CS8374: Cannot ref-assign 'tOut' to 'F' because 'tOut' has a narrower escape scope than 'F'. - // F = ref tOut; // 2 - Diagnostic(ErrorCode.ERR_RefAssignNarrower, "F = ref tOut").WithArguments("F", "tOut").WithLocation(9, 9), - // (16,13): error CS8374: Cannot ref-assign 'value' to 'F' because 'value' has a narrower escape scope than 'F'. - // F = ref value; // 3 - Diagnostic(ErrorCode.ERR_RefAssignNarrower, "F = ref value").WithArguments("F", "value").WithLocation(16, 13)); + var comp = CreateCompilation(source, runtimeFeature: RuntimeFlag.ByRefFields); + comp.VerifyEmitDiagnostics(); } [Fact] - public void AssignValueTo_RefField() + public void AssignLocal() { var source = -@"using System; - -ref struct S +@"ref struct S { - public ref T F; - public S(ref T t) { F = ref t; } + public ref T F1; + public ref readonly T F2; + public readonly ref T F3; + public readonly ref readonly T F4; + public S() + { + T t = default; + F1 = ref t; + F2 = ref t; + F3 = ref t; + F4 = ref t; + } } - class Program { - static void AssignValueToValue(S s, T tValue) { s.F = tValue; } - static void AssignRefToValue(S s, ref T tRef) { s.F = tRef; } - static void AssignOutToValue(S s, out T tOut) { tOut = default; s.F = tOut; } - static void AssignInToValue(S s, in T tIn) { s.F = tIn; } - - static void AssignValueToRef(ref S sRef, T tValue) { sRef.F = tValue; } - static void AssignRefToRef(ref S sRef, ref T tRef) { sRef.F = tRef; } - static void AssignOutToRef(ref S sRef, out T tOut) { tOut = default; sRef.F = tOut; } - static void AssignInToRef(ref S sRef, in T tIn) { sRef.F = tIn; } - - static void AssignValueToOut(out S sOut, S sInit, T tValue) { sOut = sInit; sOut.F = tValue; } - static void AssignRefToOut(out S sOut, S sInit, ref T tRef) { sOut = sInit; sOut.F = tRef; } - static void AssignOutToOut(out S sOut, S sInit, out T tOut) { sOut = sInit; tOut = default; sOut.F = tOut; } - static void AssignInToOut(out S sOut, S sInit, in T tIn) { sOut = sInit; sOut.F = tIn; } - - static void AssignValueToIn(in S sIn, T tValue) { sIn.F = tValue; } - static void AssignRefToIn(in S sIn, ref T tRef) { sIn.F = tRef; } - static void AssignOutToIn(in S sIn, out T tOut) { tOut = default; sIn.F = tOut; } - static void AssignInToIn(in S sIn, in T tIn) { sIn.F = tIn; } - - static void Main() + static void M(ref S x) { - int x, y; - scoped S s; + T t = default; + x.F1 = ref t; + x.F2 = ref t; + x.F3 = ref t; + x.F4 = ref t; + S y = new S(); + y.F1 = ref t; + y.F2 = ref t; + y.F3 = ref t; + y.F4 = ref t; + } +}"; + var comp = CreateCompilation(new[] { source, IsExternalInitTypeDefinition }, runtimeFeature: RuntimeFlag.ByRefFields); + comp.VerifyEmitDiagnostics( + // (10,9): error CS8374: Cannot ref-assign 't' to 'F1' because 't' has a narrower escape scope than 'F1'. + // F1 = ref t; + Diagnostic(ErrorCode.ERR_RefAssignNarrower, "F1 = ref t").WithArguments("F1", "t").WithLocation(10, 9), + // (11,9): error CS8374: Cannot ref-assign 't' to 'F2' because 't' has a narrower escape scope than 'F2'. + // F2 = ref t; + Diagnostic(ErrorCode.ERR_RefAssignNarrower, "F2 = ref t").WithArguments("F2", "t").WithLocation(11, 9), + // (12,9): error CS8374: Cannot ref-assign 't' to 'F3' because 't' has a narrower escape scope than 'F3'. + // F3 = ref t; + Diagnostic(ErrorCode.ERR_RefAssignNarrower, "F3 = ref t").WithArguments("F3", "t").WithLocation(12, 9), + // (13,9): error CS8374: Cannot ref-assign 't' to 'F4' because 't' has a narrower escape scope than 'F4'. + // F4 = ref t; + Diagnostic(ErrorCode.ERR_RefAssignNarrower, "F4 = ref t").WithArguments("F4", "t").WithLocation(13, 9), + // (21,9): error CS8374: Cannot ref-assign 't' to 'F1' because 't' has a narrower escape scope than 'F1'. + // x.F1 = ref t; + Diagnostic(ErrorCode.ERR_RefAssignNarrower, "x.F1 = ref t").WithArguments("F1", "t").WithLocation(21, 9), + // (22,9): error CS8374: Cannot ref-assign 't' to 'F2' because 't' has a narrower escape scope than 'F2'. + // x.F2 = ref t; + Diagnostic(ErrorCode.ERR_RefAssignNarrower, "x.F2 = ref t").WithArguments("F2", "t").WithLocation(22, 9), + // (23,9): error CS0191: A readonly field cannot be assigned to (except in a constructor or init-only setter of the type in which the field is defined or a variable initializer) + // x.F3 = ref t; + Diagnostic(ErrorCode.ERR_AssgReadonly, "x.F3").WithLocation(23, 9), + // (24,9): error CS0191: A readonly field cannot be assigned to (except in a constructor or init-only setter of the type in which the field is defined or a variable initializer) + // x.F4 = ref t; + Diagnostic(ErrorCode.ERR_AssgReadonly, "x.F4").WithLocation(24, 9), + // (26,9): error CS8374: Cannot ref-assign 't' to 'F1' because 't' has a narrower escape scope than 'F1'. + // y.F1 = ref t; + Diagnostic(ErrorCode.ERR_RefAssignNarrower, "y.F1 = ref t").WithArguments("F1", "t").WithLocation(26, 9), + // (27,9): error CS8374: Cannot ref-assign 't' to 'F2' because 't' has a narrower escape scope than 'F2'. + // y.F2 = ref t; + Diagnostic(ErrorCode.ERR_RefAssignNarrower, "y.F2 = ref t").WithArguments("F2", "t").WithLocation(27, 9), + // (28,9): error CS0191: A readonly field cannot be assigned to (except in a constructor or init-only setter of the type in which the field is defined or a variable initializer) + // y.F3 = ref t; + Diagnostic(ErrorCode.ERR_AssgReadonly, "y.F3").WithLocation(28, 9), + // (29,9): error CS0191: A readonly field cannot be assigned to (except in a constructor or init-only setter of the type in which the field is defined or a variable initializer) + // y.F4 = ref t; + Diagnostic(ErrorCode.ERR_AssgReadonly, "y.F4").WithLocation(29, 9)); + } - x = 1; y = 2; - s = new S(ref x); - AssignValueToValue(s, y); - Console.WriteLine(s.F); - x = 1; y = 2; - s = new S(ref x); - AssignRefToValue(s, ref y); - Console.WriteLine(s.F); - x = 1; y = 2; - s = new S(ref x); - AssignOutToValue(s, out y); - Console.WriteLine(s.F); - x = 1; y = 2; - s = new S(ref x); - AssignInToValue(s, y); - Console.WriteLine(s.F); + [Fact] + public void AssignValueTo_InstanceMethod_RefField() + { + var source = +@"ref struct S +{ + public ref T F; + public S(T tValue, ref T tRef, out T tOut, in T tIn) + { + tOut = default; + F = tValue; + F = tRef; + F = tOut; + F = tIn; + } + object P + { + init + { + F = GetValue(); + F = GetRef(); + F = GetRefReadonly(); + } + } + static T GetValue() => throw null; + static ref T GetRef() => throw null; + static ref readonly T GetRefReadonly() => throw null; +}"; + var comp = CreateCompilation(new[] { source, IsExternalInitTypeDefinition }, runtimeFeature: RuntimeFlag.ByRefFields); + comp.VerifyEmitDiagnostics(); + } - x = 3; y = 4; - s = new S(ref x); - AssignValueToRef(ref s, y); - Console.WriteLine(s.F); - x = 3; y = 4; - s = new S(ref x); - AssignRefToRef(ref s, ref y); - Console.WriteLine(s.F); - x = 3; y = 4; - s = new S(ref x); - AssignOutToRef(ref s, out y); - Console.WriteLine(s.F); - x = 3; y = 4; - s = new S(ref x); - AssignInToRef(ref s, y); - Console.WriteLine(s.F); + [Fact] + public void AssignValueTo_InstanceMethod_RefReadonlyField() + { + var source = +@"ref struct S +{ + public ref readonly T F; + public S(T tValue, ref T tRef, out T tOut, in T tIn) + { + tOut = default; + F = tValue; // 1 + F = tRef; // 2 + F = tOut; // 3 + F = tIn; // 4 + } + object P + { + init + { + F = GetValue(); // 5 + F = GetRef(); // 6 + F = GetRefReadonly(); // 7 + } + } + static T GetValue() => throw null; + static ref T GetRef() => throw null; + static ref readonly T GetRefReadonly() => throw null; +}"; + var comp = CreateCompilation(new[] { source, IsExternalInitTypeDefinition }, runtimeFeature: RuntimeFlag.ByRefFields); + comp.VerifyEmitDiagnostics( + // (7,9): error CS8331: Cannot assign to field 'S.F' because it is a readonly variable + // F = tValue; // 1 + Diagnostic(ErrorCode.ERR_AssignReadonlyNotField, "F").WithArguments("field", "S.F").WithLocation(7, 9), + // (8,9): error CS8331: Cannot assign to field 'S.F' because it is a readonly variable + // F = tRef; // 2 + Diagnostic(ErrorCode.ERR_AssignReadonlyNotField, "F").WithArguments("field", "S.F").WithLocation(8, 9), + // (9,9): error CS8331: Cannot assign to field 'S.F' because it is a readonly variable + // F = tOut; // 3 + Diagnostic(ErrorCode.ERR_AssignReadonlyNotField, "F").WithArguments("field", "S.F").WithLocation(9, 9), + // (10,9): error CS8331: Cannot assign to field 'S.F' because it is a readonly variable + // F = tIn; // 4 + Diagnostic(ErrorCode.ERR_AssignReadonlyNotField, "F").WithArguments("field", "S.F").WithLocation(10, 9), + // (16,13): error CS8331: Cannot assign to field 'S.F' because it is a readonly variable + // F = GetValue(); // 5 + Diagnostic(ErrorCode.ERR_AssignReadonlyNotField, "F").WithArguments("field", "S.F").WithLocation(16, 13), + // (17,13): error CS8331: Cannot assign to field 'S.F' because it is a readonly variable + // F = GetRef(); // 6 + Diagnostic(ErrorCode.ERR_AssignReadonlyNotField, "F").WithArguments("field", "S.F").WithLocation(17, 13), + // (18,13): error CS8331: Cannot assign to field 'S.F' because it is a readonly variable + // F = GetRefReadonly(); // 7 + Diagnostic(ErrorCode.ERR_AssignReadonlyNotField, "F").WithArguments("field", "S.F").WithLocation(18, 13)); + } - x = 5; y = 6; - s = new S(ref x); - AssignValueToOut(out s, new S(ref x), y); - Console.WriteLine(s.F); - x = 5; y = 6; - s = new S(ref x); - AssignRefToOut(out s, new S(ref x), ref y); - Console.WriteLine(s.F); - x = 5; y = 6; - s = new S(ref x); - AssignOutToOut(out s, new S(ref x), out y); - Console.WriteLine(s.F); - x = 5; y = 6; - s = new S(ref x); - AssignInToOut(out s, new S(ref x), y); - Console.WriteLine(s.F); + [Fact] + public void AssignValueTo_InstanceMethod_ReadonlyRefField() + { + var source = +@"ref struct S +{ + public readonly ref T F; + public S(T tValue, ref T tRef, out T tOut, in T tIn) + { + tOut = default; + F = tValue; + F = tRef; + F = tOut; + F = tIn; + } + object P + { + init + { + F = GetValue(); + F = GetRef(); + F = GetRefReadonly(); + } + } + static T GetValue() => throw null; + static ref T GetRef() => throw null; + static ref readonly T GetRefReadonly() => throw null; +}"; + var comp = CreateCompilation(new[] { source, IsExternalInitTypeDefinition }, runtimeFeature: RuntimeFlag.ByRefFields); + comp.VerifyEmitDiagnostics(); + } - x = 7; y = 8; - s = new S(ref x); - AssignValueToIn(s, y); - Console.WriteLine(s.F); - x = 7; y = 8; - s = new S(ref x); - AssignRefToIn(s, ref y); - Console.WriteLine(s.F); - x = 7; y = 8; - s = new S(ref x); - AssignOutToIn(s, out y); - Console.WriteLine(s.F); - x = 7; y = 8; - s = new S(ref x); - AssignInToIn(s, y); - Console.WriteLine(s.F); + [Fact] + public void AssignValueTo_InstanceMethod_ReadonlyRefReadonlyField() + { + var source = +@"ref struct S +{ + public readonly ref readonly T F; + public S(T tValue, ref T tRef, out T tOut, in T tIn) + { + tOut = default; + F = tValue; // 1 + F = tRef; // 2 + F = tOut; // 3 + F = tIn; // 4 + } + object P + { + init + { + F = GetValue(); // 5 + F = GetRef(); // 6 + F = GetRefReadonly(); // 7 + } } + static T GetValue() => throw null; + static ref T GetRef() => throw null; + static ref readonly T GetRefReadonly() => throw null; }"; - var verifier = CompileAndVerify(source, verify: Verification.Skipped, expectedOutput: IncludeExpectedOutput( -@"2 -2 -0 -2 -4 -4 -0 -4 -6 -6 -0 -6 -8 -8 -0 -8")); - verifier.VerifyILMultiple( - "Program.AssignValueToValue", -@"{ - // Code size 13 (0xd) - .maxstack 2 - IL_0000: ldarg.0 - IL_0001: ldfld ""ref T S.F"" - IL_0006: ldarg.1 - IL_0007: stobj ""T"" - IL_000c: ret -}", - "Program.AssignRefToValue", -@"{ - // Code size 18 (0x12) - .maxstack 2 - IL_0000: ldarg.0 - IL_0001: ldfld ""ref T S.F"" - IL_0006: ldarg.1 - IL_0007: ldobj ""T"" - IL_000c: stobj ""T"" - IL_0011: ret -}", - "Program.AssignOutToValue", -@"{ - // Code size 25 (0x19) - .maxstack 2 - IL_0000: ldarg.1 - IL_0001: initobj ""T"" - IL_0007: ldarg.0 - IL_0008: ldfld ""ref T S.F"" - IL_000d: ldarg.1 - IL_000e: ldobj ""T"" - IL_0013: stobj ""T"" - IL_0018: ret -}", - "Program.AssignInToValue", -@"{ - // Code size 18 (0x12) - .maxstack 2 - IL_0000: ldarg.0 - IL_0001: ldfld ""ref T S.F"" - IL_0006: ldarg.1 - IL_0007: ldobj ""T"" - IL_000c: stobj ""T"" - IL_0011: ret -}", - "Program.AssignValueToRef", -@"{ - // Code size 13 (0xd) - .maxstack 2 - IL_0000: ldarg.0 - IL_0001: ldfld ""ref T S.F"" - IL_0006: ldarg.1 - IL_0007: stobj ""T"" - IL_000c: ret -}", - "Program.AssignRefToRef", -@"{ - // Code size 18 (0x12) - .maxstack 2 - IL_0000: ldarg.0 - IL_0001: ldfld ""ref T S.F"" - IL_0006: ldarg.1 - IL_0007: ldobj ""T"" - IL_000c: stobj ""T"" - IL_0011: ret -}", - "Program.AssignOutToRef", -@"{ - // Code size 25 (0x19) - .maxstack 2 - IL_0000: ldarg.1 - IL_0001: initobj ""T"" - IL_0007: ldarg.0 - IL_0008: ldfld ""ref T S.F"" - IL_000d: ldarg.1 - IL_000e: ldobj ""T"" - IL_0013: stobj ""T"" - IL_0018: ret -}", - "Program.AssignInToRef", -@"{ - // Code size 18 (0x12) - .maxstack 2 - IL_0000: ldarg.0 - IL_0001: ldfld ""ref T S.F"" - IL_0006: ldarg.1 - IL_0007: ldobj ""T"" - IL_000c: stobj ""T"" - IL_0011: ret -}", - "Program.AssignValueToOut", -@"{ - // Code size 20 (0x14) - .maxstack 2 - IL_0000: ldarg.0 - IL_0001: ldarg.1 - IL_0002: stobj ""S"" - IL_0007: ldarg.0 - IL_0008: ldfld ""ref T S.F"" - IL_000d: ldarg.2 - IL_000e: stobj ""T"" - IL_0013: ret -}", - "Program.AssignRefToOut", -@"{ - // Code size 25 (0x19) - .maxstack 2 - IL_0000: ldarg.0 - IL_0001: ldarg.1 - IL_0002: stobj ""S"" - IL_0007: ldarg.0 - IL_0008: ldfld ""ref T S.F"" - IL_000d: ldarg.2 - IL_000e: ldobj ""T"" - IL_0013: stobj ""T"" - IL_0018: ret -}", - "Program.AssignOutToOut", -@"{ - // Code size 32 (0x20) - .maxstack 2 - IL_0000: ldarg.0 - IL_0001: ldarg.1 - IL_0002: stobj ""S"" - IL_0007: ldarg.2 - IL_0008: initobj ""T"" - IL_000e: ldarg.0 - IL_000f: ldfld ""ref T S.F"" - IL_0014: ldarg.2 - IL_0015: ldobj ""T"" - IL_001a: stobj ""T"" - IL_001f: ret -}", - "Program.AssignInToOut", -@"{ - // Code size 25 (0x19) - .maxstack 2 - IL_0000: ldarg.0 - IL_0001: ldarg.1 - IL_0002: stobj ""S"" - IL_0007: ldarg.0 - IL_0008: ldfld ""ref T S.F"" - IL_000d: ldarg.2 - IL_000e: ldobj ""T"" - IL_0013: stobj ""T"" - IL_0018: ret -}", - "Program.AssignValueToIn", -@"{ - // Code size 13 (0xd) - .maxstack 2 - IL_0000: ldarg.0 - IL_0001: ldfld ""ref T S.F"" - IL_0006: ldarg.1 - IL_0007: stobj ""T"" - IL_000c: ret -}", - "Program.AssignRefToIn", -@"{ - // Code size 18 (0x12) - .maxstack 2 - IL_0000: ldarg.0 - IL_0001: ldfld ""ref T S.F"" - IL_0006: ldarg.1 - IL_0007: ldobj ""T"" - IL_000c: stobj ""T"" - IL_0011: ret -}", - "Program.AssignOutToIn", -@"{ - // Code size 25 (0x19) - .maxstack 2 - IL_0000: ldarg.1 - IL_0001: initobj ""T"" - IL_0007: ldarg.0 - IL_0008: ldfld ""ref T S.F"" - IL_000d: ldarg.1 - IL_000e: ldobj ""T"" - IL_0013: stobj ""T"" - IL_0018: ret -}", - "Program.AssignInToIn", -@"{ - // Code size 18 (0x12) - .maxstack 2 - IL_0000: ldarg.0 - IL_0001: ldfld ""ref T S.F"" - IL_0006: ldarg.1 - IL_0007: ldobj ""T"" - IL_000c: stobj ""T"" - IL_0011: ret -}"); + var comp = CreateCompilation(new[] { source, IsExternalInitTypeDefinition }, runtimeFeature: RuntimeFlag.ByRefFields); + comp.VerifyEmitDiagnostics( + // (7,9): error CS8331: Cannot assign to field 'S.F' because it is a readonly variable + // F = tValue; // 1 + Diagnostic(ErrorCode.ERR_AssignReadonlyNotField, "F").WithArguments("field", "S.F").WithLocation(7, 9), + // (8,9): error CS8331: Cannot assign to field 'S.F' because it is a readonly variable + // F = tRef; // 2 + Diagnostic(ErrorCode.ERR_AssignReadonlyNotField, "F").WithArguments("field", "S.F").WithLocation(8, 9), + // (9,9): error CS8331: Cannot assign to field 'S.F' because it is a readonly variable + // F = tOut; // 3 + Diagnostic(ErrorCode.ERR_AssignReadonlyNotField, "F").WithArguments("field", "S.F").WithLocation(9, 9), + // (10,9): error CS8331: Cannot assign to field 'S.F' because it is a readonly variable + // F = tIn; // 4 + Diagnostic(ErrorCode.ERR_AssignReadonlyNotField, "F").WithArguments("field", "S.F").WithLocation(10, 9), + // (16,13): error CS8331: Cannot assign to field 'S.F' because it is a readonly variable + // F = GetValue(); // 5 + Diagnostic(ErrorCode.ERR_AssignReadonlyNotField, "F").WithArguments("field", "S.F").WithLocation(16, 13), + // (17,13): error CS8331: Cannot assign to field 'S.F' because it is a readonly variable + // F = GetRef(); // 6 + Diagnostic(ErrorCode.ERR_AssignReadonlyNotField, "F").WithArguments("field", "S.F").WithLocation(17, 13), + // (18,13): error CS8331: Cannot assign to field 'S.F' because it is a readonly variable + // F = GetRefReadonly(); // 7 + Diagnostic(ErrorCode.ERR_AssignReadonlyNotField, "F").WithArguments("field", "S.F").WithLocation(18, 13)); } [Fact] - public void AssignValueTo_RefReadonlyField() + public void AssignRefTo_InstanceMethod_RefField() { var source = @"ref struct S { - public ref readonly T F; - public S(ref T t) { F = ref t; } -} - -class Program -{ - static void AssignValueToValue(S s, T tValue) { s.F = tValue; } // 1 - static void AssignRefToValue(S s, ref T tRef) { s.F = tRef; } // 2 - static void AssignOutToValue(S s, out T tOut) { tOut = default; s.F = tOut; } // 3 - static void AssignInToValue(S s, in T tIn) { s.F = tIn; } // 4 - - static void AssignValueToRef(ref S sRef, T tValue) { sRef.F = tValue; } // 5 - static void AssignRefToRef(ref S sRef, ref T tRef) { sRef.F = tRef; } // 6 - static void AssignOutToRef(ref S sRef, out T tOut) { tOut = default; sRef.F = tOut; } // 7 - static void AssignInToRef(ref S sRef, in T tIn) { sRef.F = tIn; } // 8 - - static void AssignValueToOut(out S sOut, T tValue) { sOut = default; sOut.F = tValue; } // 9 - static void AssignRefToOut(out S sOut, ref T tRef) { sOut = default; sOut.F = tRef; } // 10 - static void AssignOutToOut(out S sOut, out T tOut) { sOut = default; tOut = default; sOut.F = tOut; } // 11 - static void AssignInToOut(out S sOut, in T tIn) { sOut = default; sOut.F = tIn; } // 12 - - static void AssignValueToIn(in S sIn, T tValue) { sIn.F = tValue; } // 13 - static void AssignRefToIn(in S sIn, ref T tRef) { sIn.F = tRef; } // 14 - static void AssignOutToIn(in S sIn, out T tOut) { tOut = default; sIn.F = tOut; } // 15 - static void AssignInToIn(in S sIn, in T tIn) { sIn.F = tIn; } // 16 + public ref T F; + public S(T tValue, ref T tRef, out T tOut, in T tIn) + { + tOut = default; + F = ref tValue; // 1 + F = ref tRef; + F = ref tOut; // 2 + F = ref tIn; // 3 + } + T P + { + init + { + F = ref value; // 4 + F = ref GetRef(); + F = ref GetRefReadonly(); // 5 + } + } + static ref T GetRef() => throw null; + static ref readonly T GetRefReadonly() => throw null; }"; - var comp = CreateCompilation(source); + var comp = CreateCompilation(new[] { source, IsExternalInitTypeDefinition }, runtimeFeature: RuntimeFlag.ByRefFields); comp.VerifyEmitDiagnostics( - // (9,59): error CS8331: Cannot assign to field 'S.F' because it is a readonly variable - // static void AssignValueToValue(S s, T tValue) { s.F = tValue; } // 1 - Diagnostic(ErrorCode.ERR_AssignReadonlyNotField, "s.F").WithArguments("field", "S.F").WithLocation(9, 59), - // (10,59): error CS8331: Cannot assign to field 'S.F' because it is a readonly variable - // static void AssignRefToValue(S s, ref T tRef) { s.F = tRef; } // 2 - Diagnostic(ErrorCode.ERR_AssignReadonlyNotField, "s.F").WithArguments("field", "S.F").WithLocation(10, 59), - // (11,75): error CS8331: Cannot assign to field 'S.F' because it is a readonly variable - // static void AssignOutToValue(S s, out T tOut) { tOut = default; s.F = tOut; } // 3 - Diagnostic(ErrorCode.ERR_AssignReadonlyNotField, "s.F").WithArguments("field", "S.F").WithLocation(11, 75), - // (12,59): error CS8331: Cannot assign to field 'S.F' because it is a readonly variable - // static void AssignInToValue(S s, in T tIn) { s.F = tIn; } // 4 - Diagnostic(ErrorCode.ERR_AssignReadonlyNotField, "s.F").WithArguments("field", "S.F").WithLocation(12, 59), - // (14,64): error CS8331: Cannot assign to field 'S.F' because it is a readonly variable - // static void AssignValueToRef(ref S sRef, T tValue) { sRef.F = tValue; } // 5 - Diagnostic(ErrorCode.ERR_AssignReadonlyNotField, "sRef.F").WithArguments("field", "S.F").WithLocation(14, 64), - // (15,64): error CS8331: Cannot assign to field 'S.F' because it is a readonly variable - // static void AssignRefToRef(ref S sRef, ref T tRef) { sRef.F = tRef; } // 6 - Diagnostic(ErrorCode.ERR_AssignReadonlyNotField, "sRef.F").WithArguments("field", "S.F").WithLocation(15, 64), - // (16,80): error CS8331: Cannot assign to field 'S.F' because it is a readonly variable - // static void AssignOutToRef(ref S sRef, out T tOut) { tOut = default; sRef.F = tOut; } // 7 - Diagnostic(ErrorCode.ERR_AssignReadonlyNotField, "sRef.F").WithArguments("field", "S.F").WithLocation(16, 80), - // (17,64): error CS8331: Cannot assign to field 'S.F' because it is a readonly variable - // static void AssignInToRef(ref S sRef, in T tIn) { sRef.F = tIn; } // 8 - Diagnostic(ErrorCode.ERR_AssignReadonlyNotField, "sRef.F").WithArguments("field", "S.F").WithLocation(17, 64), - // (19,80): error CS8331: Cannot assign to field 'S.F' because it is a readonly variable - // static void AssignValueToOut(out S sOut, T tValue) { sOut = default; sOut.F = tValue; } // 9 - Diagnostic(ErrorCode.ERR_AssignReadonlyNotField, "sOut.F").WithArguments("field", "S.F").WithLocation(19, 80), - // (20,80): error CS8331: Cannot assign to field 'S.F' because it is a readonly variable - // static void AssignRefToOut(out S sOut, ref T tRef) { sOut = default; sOut.F = tRef; } // 10 - Diagnostic(ErrorCode.ERR_AssignReadonlyNotField, "sOut.F").WithArguments("field", "S.F").WithLocation(20, 80), - // (21,96): error CS8331: Cannot assign to field 'S.F' because it is a readonly variable - // static void AssignOutToOut(out S sOut, out T tOut) { sOut = default; tOut = default; sOut.F = tOut; } // 11 - Diagnostic(ErrorCode.ERR_AssignReadonlyNotField, "sOut.F").WithArguments("field", "S.F").WithLocation(21, 96), - // (22,80): error CS8331: Cannot assign to field 'S.F' because it is a readonly variable - // static void AssignInToOut(out S sOut, in T tIn) { sOut = default; sOut.F = tIn; } // 12 - Diagnostic(ErrorCode.ERR_AssignReadonlyNotField, "sOut.F").WithArguments("field", "S.F").WithLocation(22, 80), - // (24,61): error CS8331: Cannot assign to field 'S.F' because it is a readonly variable - // static void AssignValueToIn(in S sIn, T tValue) { sIn.F = tValue; } // 13 - Diagnostic(ErrorCode.ERR_AssignReadonlyNotField, "sIn.F").WithArguments("field", "S.F").WithLocation(24, 61), - // (25,61): error CS8331: Cannot assign to field 'S.F' because it is a readonly variable - // static void AssignRefToIn(in S sIn, ref T tRef) { sIn.F = tRef; } // 14 - Diagnostic(ErrorCode.ERR_AssignReadonlyNotField, "sIn.F").WithArguments("field", "S.F").WithLocation(25, 61), - // (26,77): error CS8331: Cannot assign to field 'S.F' because it is a readonly variable - // static void AssignOutToIn(in S sIn, out T tOut) { tOut = default; sIn.F = tOut; } // 15 - Diagnostic(ErrorCode.ERR_AssignReadonlyNotField, "sIn.F").WithArguments("field", "S.F").WithLocation(26, 77), - // (27,61): error CS8331: Cannot assign to field 'S.F' because it is a readonly variable - // static void AssignInToIn(in S sIn, in T tIn) { sIn.F = tIn; } // 16 - Diagnostic(ErrorCode.ERR_AssignReadonlyNotField, "sIn.F").WithArguments("field", "S.F").WithLocation(27, 61)); + // (7,9): error CS8374: Cannot ref-assign 'tValue' to 'F' because 'tValue' has a narrower escape scope than 'F'. + // F = ref tValue; // 1 + Diagnostic(ErrorCode.ERR_RefAssignNarrower, "F = ref tValue").WithArguments("F", "tValue").WithLocation(7, 9), + // (9,9): error CS8374: Cannot ref-assign 'tOut' to 'F' because 'tOut' has a narrower escape scope than 'F'. + // F = ref tOut; // 2 + Diagnostic(ErrorCode.ERR_RefAssignNarrower, "F = ref tOut").WithArguments("F", "tOut").WithLocation(9, 9), + // (10,17): error CS8331: Cannot assign to variable 'in T' because it is a readonly variable + // F = ref tIn; // 3 + Diagnostic(ErrorCode.ERR_AssignReadonlyNotField, "tIn").WithArguments("variable", "in T").WithLocation(10, 17), + // (16,13): error CS8374: Cannot ref-assign 'value' to 'F' because 'value' has a narrower escape scope than 'F'. + // F = ref value; // 4 + Diagnostic(ErrorCode.ERR_RefAssignNarrower, "F = ref value").WithArguments("F", "value").WithLocation(16, 13), + // (18,21): error CS8331: Cannot assign to method 'S.GetRefReadonly()' because it is a readonly variable + // F = ref GetRefReadonly(); // 5 + Diagnostic(ErrorCode.ERR_AssignReadonlyNotField, "GetRefReadonly()").WithArguments("method", "S.GetRefReadonly()").WithLocation(18, 21)); } [Fact] - public void AssignValueTo_ReadonlyRefField() + public void AssignRefTo_InstanceMethod_RefReadonlyField() + { + var source = +@"ref struct S +{ + public ref readonly T F; + public S(T tValue, ref T tRef, out T tOut, in T tIn) + { + tOut = default; + F = ref tValue; // 1 + F = ref tRef; + F = ref tOut; // 2 + F = ref tIn; + } + T P + { + init + { + F = ref value; // 3 + F = ref GetRef(); + F = ref GetRefReadonly(); + } + } + static ref T GetRef() => throw null; + static ref readonly T GetRefReadonly() => throw null; +}"; + var comp = CreateCompilation(new[] { source, IsExternalInitTypeDefinition }, runtimeFeature: RuntimeFlag.ByRefFields); + comp.VerifyEmitDiagnostics( + // (7,9): error CS8374: Cannot ref-assign 'tValue' to 'F' because 'tValue' has a narrower escape scope than 'F'. + // F = ref tValue; // 1 + Diagnostic(ErrorCode.ERR_RefAssignNarrower, "F = ref tValue").WithArguments("F", "tValue").WithLocation(7, 9), + // (9,9): error CS8374: Cannot ref-assign 'tOut' to 'F' because 'tOut' has a narrower escape scope than 'F'. + // F = ref tOut; // 2 + Diagnostic(ErrorCode.ERR_RefAssignNarrower, "F = ref tOut").WithArguments("F", "tOut").WithLocation(9, 9), + // (16,13): error CS8374: Cannot ref-assign 'value' to 'F' because 'value' has a narrower escape scope than 'F'. + // F = ref value; // 3 + Diagnostic(ErrorCode.ERR_RefAssignNarrower, "F = ref value").WithArguments("F", "value").WithLocation(16, 13)); + } + + [Fact] + public void AssignRefTo_InstanceMethod_ReadonlyRefField() + { + var source = +@"ref struct S +{ + public readonly ref T F; + public S(T tValue, ref T tRef, out T tOut, in T tIn) + { + tOut = default; + F = ref tValue; // 1 + F = ref tRef; + F = ref tOut; // 2 + F = ref tIn; // 3 + } + T P + { + init + { + F = ref value; // 4 + F = ref GetRef(); + F = ref GetRefReadonly(); // 5 + } + } + static ref T GetRef() => throw null; + static ref readonly T GetRefReadonly() => throw null; +}"; + var comp = CreateCompilation(new[] { source, IsExternalInitTypeDefinition }, runtimeFeature: RuntimeFlag.ByRefFields); + comp.VerifyEmitDiagnostics( + // (7,9): error CS8374: Cannot ref-assign 'tValue' to 'F' because 'tValue' has a narrower escape scope than 'F'. + // F = ref tValue; // 1 + Diagnostic(ErrorCode.ERR_RefAssignNarrower, "F = ref tValue").WithArguments("F", "tValue").WithLocation(7, 9), + // (9,9): error CS8374: Cannot ref-assign 'tOut' to 'F' because 'tOut' has a narrower escape scope than 'F'. + // F = ref tOut; // 2 + Diagnostic(ErrorCode.ERR_RefAssignNarrower, "F = ref tOut").WithArguments("F", "tOut").WithLocation(9, 9), + // (10,17): error CS8331: Cannot assign to variable 'in T' because it is a readonly variable + // F = ref tIn; // 3 + Diagnostic(ErrorCode.ERR_AssignReadonlyNotField, "tIn").WithArguments("variable", "in T").WithLocation(10, 17), + // (16,13): error CS8374: Cannot ref-assign 'value' to 'F' because 'value' has a narrower escape scope than 'F'. + // F = ref value; // 4 + Diagnostic(ErrorCode.ERR_RefAssignNarrower, "F = ref value").WithArguments("F", "value").WithLocation(16, 13), + // (18,21): error CS8331: Cannot assign to method 'S.GetRefReadonly()' because it is a readonly variable + // F = ref GetRefReadonly(); // 5 + Diagnostic(ErrorCode.ERR_AssignReadonlyNotField, "GetRefReadonly()").WithArguments("method", "S.GetRefReadonly()").WithLocation(18, 21)); + } + + [Fact] + public void AssignRefTo_InstanceMethod_ReadonlyRefReadonlyField() + { + var source = +@"ref struct S +{ + public readonly ref readonly T F; + public S(T tValue, ref T tRef, out T tOut, in T tIn) + { + tOut = default; + F = ref tValue; // 1 + F = ref tRef; + F = ref tOut; // 2 + F = ref tIn; + } + T P + { + init + { + F = ref value; // 3 + F = ref GetRef(); + F = ref GetRefReadonly(); + } + } + static ref T GetRef() => throw null; + static ref readonly T GetRefReadonly() => throw null; +}"; + var comp = CreateCompilation(new[] { source, IsExternalInitTypeDefinition }, runtimeFeature: RuntimeFlag.ByRefFields); + comp.VerifyEmitDiagnostics( + // (7,9): error CS8374: Cannot ref-assign 'tValue' to 'F' because 'tValue' has a narrower escape scope than 'F'. + // F = ref tValue; // 1 + Diagnostic(ErrorCode.ERR_RefAssignNarrower, "F = ref tValue").WithArguments("F", "tValue").WithLocation(7, 9), + // (9,9): error CS8374: Cannot ref-assign 'tOut' to 'F' because 'tOut' has a narrower escape scope than 'F'. + // F = ref tOut; // 2 + Diagnostic(ErrorCode.ERR_RefAssignNarrower, "F = ref tOut").WithArguments("F", "tOut").WithLocation(9, 9), + // (16,13): error CS8374: Cannot ref-assign 'value' to 'F' because 'value' has a narrower escape scope than 'F'. + // F = ref value; // 3 + Diagnostic(ErrorCode.ERR_RefAssignNarrower, "F = ref value").WithArguments("F", "value").WithLocation(16, 13)); + } + + [Fact] + public void AssignValueTo_RefField() { var source = @"using System; ref struct S { - public readonly ref T F; + public ref T F; public S(ref T t) { F = ref t; } } @@ -3813,7 +4231,8 @@ static void Main() Console.WriteLine(s.F); } }"; - var verifier = CompileAndVerify(source, verify: Verification.Skipped, expectedOutput: IncludeExpectedOutput( + var comp = CreateCompilation(source, options: TestOptions.ReleaseExe, runtimeFeature: RuntimeFlag.ByRefFields); + var verifier = CompileAndVerify(comp, verify: Verification.Skipped, expectedOutput: IncludeExpectedOutput( @"2 2 0 @@ -4026,4451 +4445,7389 @@ .maxstack 2 } [Fact] - public void AssignValueTo_ReadonlyRefReadonlyField() + public void AssignValueTo_RefReadonlyField() + { + var source = +@"ref struct S +{ + public ref readonly T F; + public S(ref T t) { F = ref t; } +} + +class Program +{ + static void AssignValueToValue(S s, T tValue) { s.F = tValue; } // 1 + static void AssignRefToValue(S s, ref T tRef) { s.F = tRef; } // 2 + static void AssignOutToValue(S s, out T tOut) { tOut = default; s.F = tOut; } // 3 + static void AssignInToValue(S s, in T tIn) { s.F = tIn; } // 4 + + static void AssignValueToRef(ref S sRef, T tValue) { sRef.F = tValue; } // 5 + static void AssignRefToRef(ref S sRef, ref T tRef) { sRef.F = tRef; } // 6 + static void AssignOutToRef(ref S sRef, out T tOut) { tOut = default; sRef.F = tOut; } // 7 + static void AssignInToRef(ref S sRef, in T tIn) { sRef.F = tIn; } // 8 + + static void AssignValueToOut(out S sOut, T tValue) { sOut = default; sOut.F = tValue; } // 9 + static void AssignRefToOut(out S sOut, ref T tRef) { sOut = default; sOut.F = tRef; } // 10 + static void AssignOutToOut(out S sOut, out T tOut) { sOut = default; tOut = default; sOut.F = tOut; } // 11 + static void AssignInToOut(out S sOut, in T tIn) { sOut = default; sOut.F = tIn; } // 12 + + static void AssignValueToIn(in S sIn, T tValue) { sIn.F = tValue; } // 13 + static void AssignRefToIn(in S sIn, ref T tRef) { sIn.F = tRef; } // 14 + static void AssignOutToIn(in S sIn, out T tOut) { tOut = default; sIn.F = tOut; } // 15 + static void AssignInToIn(in S sIn, in T tIn) { sIn.F = tIn; } // 16 +}"; + var comp = CreateCompilation(source, runtimeFeature: RuntimeFlag.ByRefFields); + comp.VerifyEmitDiagnostics( + // (9,59): error CS8331: Cannot assign to field 'S.F' because it is a readonly variable + // static void AssignValueToValue(S s, T tValue) { s.F = tValue; } // 1 + Diagnostic(ErrorCode.ERR_AssignReadonlyNotField, "s.F").WithArguments("field", "S.F").WithLocation(9, 59), + // (10,59): error CS8331: Cannot assign to field 'S.F' because it is a readonly variable + // static void AssignRefToValue(S s, ref T tRef) { s.F = tRef; } // 2 + Diagnostic(ErrorCode.ERR_AssignReadonlyNotField, "s.F").WithArguments("field", "S.F").WithLocation(10, 59), + // (11,75): error CS8331: Cannot assign to field 'S.F' because it is a readonly variable + // static void AssignOutToValue(S s, out T tOut) { tOut = default; s.F = tOut; } // 3 + Diagnostic(ErrorCode.ERR_AssignReadonlyNotField, "s.F").WithArguments("field", "S.F").WithLocation(11, 75), + // (12,59): error CS8331: Cannot assign to field 'S.F' because it is a readonly variable + // static void AssignInToValue(S s, in T tIn) { s.F = tIn; } // 4 + Diagnostic(ErrorCode.ERR_AssignReadonlyNotField, "s.F").WithArguments("field", "S.F").WithLocation(12, 59), + // (14,64): error CS8331: Cannot assign to field 'S.F' because it is a readonly variable + // static void AssignValueToRef(ref S sRef, T tValue) { sRef.F = tValue; } // 5 + Diagnostic(ErrorCode.ERR_AssignReadonlyNotField, "sRef.F").WithArguments("field", "S.F").WithLocation(14, 64), + // (15,64): error CS8331: Cannot assign to field 'S.F' because it is a readonly variable + // static void AssignRefToRef(ref S sRef, ref T tRef) { sRef.F = tRef; } // 6 + Diagnostic(ErrorCode.ERR_AssignReadonlyNotField, "sRef.F").WithArguments("field", "S.F").WithLocation(15, 64), + // (16,80): error CS8331: Cannot assign to field 'S.F' because it is a readonly variable + // static void AssignOutToRef(ref S sRef, out T tOut) { tOut = default; sRef.F = tOut; } // 7 + Diagnostic(ErrorCode.ERR_AssignReadonlyNotField, "sRef.F").WithArguments("field", "S.F").WithLocation(16, 80), + // (17,64): error CS8331: Cannot assign to field 'S.F' because it is a readonly variable + // static void AssignInToRef(ref S sRef, in T tIn) { sRef.F = tIn; } // 8 + Diagnostic(ErrorCode.ERR_AssignReadonlyNotField, "sRef.F").WithArguments("field", "S.F").WithLocation(17, 64), + // (19,80): error CS8331: Cannot assign to field 'S.F' because it is a readonly variable + // static void AssignValueToOut(out S sOut, T tValue) { sOut = default; sOut.F = tValue; } // 9 + Diagnostic(ErrorCode.ERR_AssignReadonlyNotField, "sOut.F").WithArguments("field", "S.F").WithLocation(19, 80), + // (20,80): error CS8331: Cannot assign to field 'S.F' because it is a readonly variable + // static void AssignRefToOut(out S sOut, ref T tRef) { sOut = default; sOut.F = tRef; } // 10 + Diagnostic(ErrorCode.ERR_AssignReadonlyNotField, "sOut.F").WithArguments("field", "S.F").WithLocation(20, 80), + // (21,96): error CS8331: Cannot assign to field 'S.F' because it is a readonly variable + // static void AssignOutToOut(out S sOut, out T tOut) { sOut = default; tOut = default; sOut.F = tOut; } // 11 + Diagnostic(ErrorCode.ERR_AssignReadonlyNotField, "sOut.F").WithArguments("field", "S.F").WithLocation(21, 96), + // (22,80): error CS8331: Cannot assign to field 'S.F' because it is a readonly variable + // static void AssignInToOut(out S sOut, in T tIn) { sOut = default; sOut.F = tIn; } // 12 + Diagnostic(ErrorCode.ERR_AssignReadonlyNotField, "sOut.F").WithArguments("field", "S.F").WithLocation(22, 80), + // (24,61): error CS8331: Cannot assign to field 'S.F' because it is a readonly variable + // static void AssignValueToIn(in S sIn, T tValue) { sIn.F = tValue; } // 13 + Diagnostic(ErrorCode.ERR_AssignReadonlyNotField, "sIn.F").WithArguments("field", "S.F").WithLocation(24, 61), + // (25,61): error CS8331: Cannot assign to field 'S.F' because it is a readonly variable + // static void AssignRefToIn(in S sIn, ref T tRef) { sIn.F = tRef; } // 14 + Diagnostic(ErrorCode.ERR_AssignReadonlyNotField, "sIn.F").WithArguments("field", "S.F").WithLocation(25, 61), + // (26,77): error CS8331: Cannot assign to field 'S.F' because it is a readonly variable + // static void AssignOutToIn(in S sIn, out T tOut) { tOut = default; sIn.F = tOut; } // 15 + Diagnostic(ErrorCode.ERR_AssignReadonlyNotField, "sIn.F").WithArguments("field", "S.F").WithLocation(26, 77), + // (27,61): error CS8331: Cannot assign to field 'S.F' because it is a readonly variable + // static void AssignInToIn(in S sIn, in T tIn) { sIn.F = tIn; } // 16 + Diagnostic(ErrorCode.ERR_AssignReadonlyNotField, "sIn.F").WithArguments("field", "S.F").WithLocation(27, 61)); + } + + [Fact] + public void AssignValueTo_ReadonlyRefField() + { + var source = +@"using System; + +ref struct S +{ + public readonly ref T F; + public S(ref T t) { F = ref t; } +} + +class Program +{ + static void AssignValueToValue(S s, T tValue) { s.F = tValue; } + static void AssignRefToValue(S s, ref T tRef) { s.F = tRef; } + static void AssignOutToValue(S s, out T tOut) { tOut = default; s.F = tOut; } + static void AssignInToValue(S s, in T tIn) { s.F = tIn; } + + static void AssignValueToRef(ref S sRef, T tValue) { sRef.F = tValue; } + static void AssignRefToRef(ref S sRef, ref T tRef) { sRef.F = tRef; } + static void AssignOutToRef(ref S sRef, out T tOut) { tOut = default; sRef.F = tOut; } + static void AssignInToRef(ref S sRef, in T tIn) { sRef.F = tIn; } + + static void AssignValueToOut(out S sOut, S sInit, T tValue) { sOut = sInit; sOut.F = tValue; } + static void AssignRefToOut(out S sOut, S sInit, ref T tRef) { sOut = sInit; sOut.F = tRef; } + static void AssignOutToOut(out S sOut, S sInit, out T tOut) { sOut = sInit; tOut = default; sOut.F = tOut; } + static void AssignInToOut(out S sOut, S sInit, in T tIn) { sOut = sInit; sOut.F = tIn; } + + static void AssignValueToIn(in S sIn, T tValue) { sIn.F = tValue; } + static void AssignRefToIn(in S sIn, ref T tRef) { sIn.F = tRef; } + static void AssignOutToIn(in S sIn, out T tOut) { tOut = default; sIn.F = tOut; } + static void AssignInToIn(in S sIn, in T tIn) { sIn.F = tIn; } + + static void Main() + { + int x, y; + scoped S s; + + x = 1; y = 2; + s = new S(ref x); + AssignValueToValue(s, y); + Console.WriteLine(s.F); + x = 1; y = 2; + s = new S(ref x); + AssignRefToValue(s, ref y); + Console.WriteLine(s.F); + x = 1; y = 2; + s = new S(ref x); + AssignOutToValue(s, out y); + Console.WriteLine(s.F); + x = 1; y = 2; + s = new S(ref x); + AssignInToValue(s, y); + Console.WriteLine(s.F); + + x = 3; y = 4; + s = new S(ref x); + AssignValueToRef(ref s, y); + Console.WriteLine(s.F); + x = 3; y = 4; + s = new S(ref x); + AssignRefToRef(ref s, ref y); + Console.WriteLine(s.F); + x = 3; y = 4; + s = new S(ref x); + AssignOutToRef(ref s, out y); + Console.WriteLine(s.F); + x = 3; y = 4; + s = new S(ref x); + AssignInToRef(ref s, y); + Console.WriteLine(s.F); + + x = 5; y = 6; + s = new S(ref x); + AssignValueToOut(out s, new S(ref x), y); + Console.WriteLine(s.F); + x = 5; y = 6; + s = new S(ref x); + AssignRefToOut(out s, new S(ref x), ref y); + Console.WriteLine(s.F); + x = 5; y = 6; + s = new S(ref x); + AssignOutToOut(out s, new S(ref x), out y); + Console.WriteLine(s.F); + x = 5; y = 6; + s = new S(ref x); + AssignInToOut(out s, new S(ref x), y); + Console.WriteLine(s.F); + + x = 7; y = 8; + s = new S(ref x); + AssignValueToIn(s, y); + Console.WriteLine(s.F); + x = 7; y = 8; + s = new S(ref x); + AssignRefToIn(s, ref y); + Console.WriteLine(s.F); + x = 7; y = 8; + s = new S(ref x); + AssignOutToIn(s, out y); + Console.WriteLine(s.F); + x = 7; y = 8; + s = new S(ref x); + AssignInToIn(s, y); + Console.WriteLine(s.F); + } +}"; + var comp = CreateCompilation(source, options: TestOptions.ReleaseExe, runtimeFeature: RuntimeFlag.ByRefFields); + var verifier = CompileAndVerify(comp, verify: Verification.Skipped, expectedOutput: IncludeExpectedOutput( +@"2 +2 +0 +2 +4 +4 +0 +4 +6 +6 +0 +6 +8 +8 +0 +8")); + verifier.VerifyILMultiple( + "Program.AssignValueToValue", +@"{ + // Code size 13 (0xd) + .maxstack 2 + IL_0000: ldarg.0 + IL_0001: ldfld ""ref T S.F"" + IL_0006: ldarg.1 + IL_0007: stobj ""T"" + IL_000c: ret +}", + "Program.AssignRefToValue", +@"{ + // Code size 18 (0x12) + .maxstack 2 + IL_0000: ldarg.0 + IL_0001: ldfld ""ref T S.F"" + IL_0006: ldarg.1 + IL_0007: ldobj ""T"" + IL_000c: stobj ""T"" + IL_0011: ret +}", + "Program.AssignOutToValue", +@"{ + // Code size 25 (0x19) + .maxstack 2 + IL_0000: ldarg.1 + IL_0001: initobj ""T"" + IL_0007: ldarg.0 + IL_0008: ldfld ""ref T S.F"" + IL_000d: ldarg.1 + IL_000e: ldobj ""T"" + IL_0013: stobj ""T"" + IL_0018: ret +}", + "Program.AssignInToValue", +@"{ + // Code size 18 (0x12) + .maxstack 2 + IL_0000: ldarg.0 + IL_0001: ldfld ""ref T S.F"" + IL_0006: ldarg.1 + IL_0007: ldobj ""T"" + IL_000c: stobj ""T"" + IL_0011: ret +}", + "Program.AssignValueToRef", +@"{ + // Code size 13 (0xd) + .maxstack 2 + IL_0000: ldarg.0 + IL_0001: ldfld ""ref T S.F"" + IL_0006: ldarg.1 + IL_0007: stobj ""T"" + IL_000c: ret +}", + "Program.AssignRefToRef", +@"{ + // Code size 18 (0x12) + .maxstack 2 + IL_0000: ldarg.0 + IL_0001: ldfld ""ref T S.F"" + IL_0006: ldarg.1 + IL_0007: ldobj ""T"" + IL_000c: stobj ""T"" + IL_0011: ret +}", + "Program.AssignOutToRef", +@"{ + // Code size 25 (0x19) + .maxstack 2 + IL_0000: ldarg.1 + IL_0001: initobj ""T"" + IL_0007: ldarg.0 + IL_0008: ldfld ""ref T S.F"" + IL_000d: ldarg.1 + IL_000e: ldobj ""T"" + IL_0013: stobj ""T"" + IL_0018: ret +}", + "Program.AssignInToRef", +@"{ + // Code size 18 (0x12) + .maxstack 2 + IL_0000: ldarg.0 + IL_0001: ldfld ""ref T S.F"" + IL_0006: ldarg.1 + IL_0007: ldobj ""T"" + IL_000c: stobj ""T"" + IL_0011: ret +}", + "Program.AssignValueToOut", +@"{ + // Code size 20 (0x14) + .maxstack 2 + IL_0000: ldarg.0 + IL_0001: ldarg.1 + IL_0002: stobj ""S"" + IL_0007: ldarg.0 + IL_0008: ldfld ""ref T S.F"" + IL_000d: ldarg.2 + IL_000e: stobj ""T"" + IL_0013: ret +}", + "Program.AssignRefToOut", +@"{ + // Code size 25 (0x19) + .maxstack 2 + IL_0000: ldarg.0 + IL_0001: ldarg.1 + IL_0002: stobj ""S"" + IL_0007: ldarg.0 + IL_0008: ldfld ""ref T S.F"" + IL_000d: ldarg.2 + IL_000e: ldobj ""T"" + IL_0013: stobj ""T"" + IL_0018: ret +}", + "Program.AssignOutToOut", +@"{ + // Code size 32 (0x20) + .maxstack 2 + IL_0000: ldarg.0 + IL_0001: ldarg.1 + IL_0002: stobj ""S"" + IL_0007: ldarg.2 + IL_0008: initobj ""T"" + IL_000e: ldarg.0 + IL_000f: ldfld ""ref T S.F"" + IL_0014: ldarg.2 + IL_0015: ldobj ""T"" + IL_001a: stobj ""T"" + IL_001f: ret +}", + "Program.AssignInToOut", +@"{ + // Code size 25 (0x19) + .maxstack 2 + IL_0000: ldarg.0 + IL_0001: ldarg.1 + IL_0002: stobj ""S"" + IL_0007: ldarg.0 + IL_0008: ldfld ""ref T S.F"" + IL_000d: ldarg.2 + IL_000e: ldobj ""T"" + IL_0013: stobj ""T"" + IL_0018: ret +}", + "Program.AssignValueToIn", +@"{ + // Code size 13 (0xd) + .maxstack 2 + IL_0000: ldarg.0 + IL_0001: ldfld ""ref T S.F"" + IL_0006: ldarg.1 + IL_0007: stobj ""T"" + IL_000c: ret +}", + "Program.AssignRefToIn", +@"{ + // Code size 18 (0x12) + .maxstack 2 + IL_0000: ldarg.0 + IL_0001: ldfld ""ref T S.F"" + IL_0006: ldarg.1 + IL_0007: ldobj ""T"" + IL_000c: stobj ""T"" + IL_0011: ret +}", + "Program.AssignOutToIn", +@"{ + // Code size 25 (0x19) + .maxstack 2 + IL_0000: ldarg.1 + IL_0001: initobj ""T"" + IL_0007: ldarg.0 + IL_0008: ldfld ""ref T S.F"" + IL_000d: ldarg.1 + IL_000e: ldobj ""T"" + IL_0013: stobj ""T"" + IL_0018: ret +}", + "Program.AssignInToIn", +@"{ + // Code size 18 (0x12) + .maxstack 2 + IL_0000: ldarg.0 + IL_0001: ldfld ""ref T S.F"" + IL_0006: ldarg.1 + IL_0007: ldobj ""T"" + IL_000c: stobj ""T"" + IL_0011: ret +}"); + } + + [Fact] + public void AssignValueTo_ReadonlyRefReadonlyField() + { + var source = +@"ref struct S +{ + public readonly ref readonly T F; + public S(ref T t) { F = ref t; } +} + +class Program +{ + static void AssignValueToValue(S s, T tValue) { s.F = tValue; } // 1 + static void AssignRefToValue(S s, ref T tRef) { s.F = tRef; } // 2 + static void AssignOutToValue(S s, out T tOut) { tOut = default; s.F = tOut; } // 3 + static void AssignInToValue(S s, in T tIn) { s.F = tIn; } // 4 + + static void AssignValueToRef(ref S sRef, T tValue) { sRef.F = tValue; } // 5 + static void AssignRefToRef(ref S sRef, ref T tRef) { sRef.F = tRef; } // 6 + static void AssignOutToRef(ref S sRef, out T tOut) { tOut = default; sRef.F = tOut; } // 7 + static void AssignInToRef(ref S sRef, in T tIn) { sRef.F = tIn; } // 8 + + static void AssignValueToOut(out S sOut, T tValue) { sOut = default; sOut.F = tValue; } // 9 + static void AssignRefToOut(out S sOut, ref T tRef) { sOut = default; sOut.F = tRef; } // 10 + static void AssignOutToOut(out S sOut, out T tOut) { sOut = default; tOut = default; sOut.F = tOut; } // 11 + static void AssignInToOut(out S sOut, in T tIn) { sOut = default; sOut.F = tIn; } // 12 + + static void AssignValueToIn(in S sIn, T tValue) { sIn.F = tValue; } // 13 + static void AssignRefToIn(in S sIn, ref T tRef) { sIn.F = tRef; } // 14 + static void AssignOutToIn(in S sIn, out T tOut) { tOut = default; sIn.F = tOut; } // 15 + static void AssignInToIn(in S sIn, in T tIn) { sIn.F = tIn; } // 16 +}"; + var comp = CreateCompilation(source, runtimeFeature: RuntimeFlag.ByRefFields); + comp.VerifyEmitDiagnostics( + // (9,59): error CS8331: Cannot assign to field 'S.F' because it is a readonly variable + // static void AssignValueToValue(S s, T tValue) { s.F = tValue; } // 1 + Diagnostic(ErrorCode.ERR_AssignReadonlyNotField, "s.F").WithArguments("field", "S.F").WithLocation(9, 59), + // (10,59): error CS8331: Cannot assign to field 'S.F' because it is a readonly variable + // static void AssignRefToValue(S s, ref T tRef) { s.F = tRef; } // 2 + Diagnostic(ErrorCode.ERR_AssignReadonlyNotField, "s.F").WithArguments("field", "S.F").WithLocation(10, 59), + // (11,75): error CS8331: Cannot assign to field 'S.F' because it is a readonly variable + // static void AssignOutToValue(S s, out T tOut) { tOut = default; s.F = tOut; } // 3 + Diagnostic(ErrorCode.ERR_AssignReadonlyNotField, "s.F").WithArguments("field", "S.F").WithLocation(11, 75), + // (12,59): error CS8331: Cannot assign to field 'S.F' because it is a readonly variable + // static void AssignInToValue(S s, in T tIn) { s.F = tIn; } // 4 + Diagnostic(ErrorCode.ERR_AssignReadonlyNotField, "s.F").WithArguments("field", "S.F").WithLocation(12, 59), + // (14,64): error CS8331: Cannot assign to field 'S.F' because it is a readonly variable + // static void AssignValueToRef(ref S sRef, T tValue) { sRef.F = tValue; } // 5 + Diagnostic(ErrorCode.ERR_AssignReadonlyNotField, "sRef.F").WithArguments("field", "S.F").WithLocation(14, 64), + // (15,64): error CS8331: Cannot assign to field 'S.F' because it is a readonly variable + // static void AssignRefToRef(ref S sRef, ref T tRef) { sRef.F = tRef; } // 6 + Diagnostic(ErrorCode.ERR_AssignReadonlyNotField, "sRef.F").WithArguments("field", "S.F").WithLocation(15, 64), + // (16,80): error CS8331: Cannot assign to field 'S.F' because it is a readonly variable + // static void AssignOutToRef(ref S sRef, out T tOut) { tOut = default; sRef.F = tOut; } // 7 + Diagnostic(ErrorCode.ERR_AssignReadonlyNotField, "sRef.F").WithArguments("field", "S.F").WithLocation(16, 80), + // (17,64): error CS8331: Cannot assign to field 'S.F' because it is a readonly variable + // static void AssignInToRef(ref S sRef, in T tIn) { sRef.F = tIn; } // 8 + Diagnostic(ErrorCode.ERR_AssignReadonlyNotField, "sRef.F").WithArguments("field", "S.F").WithLocation(17, 64), + // (19,80): error CS8331: Cannot assign to field 'S.F' because it is a readonly variable + // static void AssignValueToOut(out S sOut, T tValue) { sOut = default; sOut.F = tValue; } // 9 + Diagnostic(ErrorCode.ERR_AssignReadonlyNotField, "sOut.F").WithArguments("field", "S.F").WithLocation(19, 80), + // (20,80): error CS8331: Cannot assign to field 'S.F' because it is a readonly variable + // static void AssignRefToOut(out S sOut, ref T tRef) { sOut = default; sOut.F = tRef; } // 10 + Diagnostic(ErrorCode.ERR_AssignReadonlyNotField, "sOut.F").WithArguments("field", "S.F").WithLocation(20, 80), + // (21,96): error CS8331: Cannot assign to field 'S.F' because it is a readonly variable + // static void AssignOutToOut(out S sOut, out T tOut) { sOut = default; tOut = default; sOut.F = tOut; } // 11 + Diagnostic(ErrorCode.ERR_AssignReadonlyNotField, "sOut.F").WithArguments("field", "S.F").WithLocation(21, 96), + // (22,80): error CS8331: Cannot assign to field 'S.F' because it is a readonly variable + // static void AssignInToOut(out S sOut, in T tIn) { sOut = default; sOut.F = tIn; } // 12 + Diagnostic(ErrorCode.ERR_AssignReadonlyNotField, "sOut.F").WithArguments("field", "S.F").WithLocation(22, 80), + // (24,61): error CS8331: Cannot assign to field 'S.F' because it is a readonly variable + // static void AssignValueToIn(in S sIn, T tValue) { sIn.F = tValue; } // 13 + Diagnostic(ErrorCode.ERR_AssignReadonlyNotField, "sIn.F").WithArguments("field", "S.F").WithLocation(24, 61), + // (25,61): error CS8331: Cannot assign to field 'S.F' because it is a readonly variable + // static void AssignRefToIn(in S sIn, ref T tRef) { sIn.F = tRef; } // 14 + Diagnostic(ErrorCode.ERR_AssignReadonlyNotField, "sIn.F").WithArguments("field", "S.F").WithLocation(25, 61), + // (26,77): error CS8331: Cannot assign to field 'S.F' because it is a readonly variable + // static void AssignOutToIn(in S sIn, out T tOut) { tOut = default; sIn.F = tOut; } // 15 + Diagnostic(ErrorCode.ERR_AssignReadonlyNotField, "sIn.F").WithArguments("field", "S.F").WithLocation(26, 77), + // (27,61): error CS8331: Cannot assign to field 'S.F' because it is a readonly variable + // static void AssignInToIn(in S sIn, in T tIn) { sIn.F = tIn; } // 16 + Diagnostic(ErrorCode.ERR_AssignReadonlyNotField, "sIn.F").WithArguments("field", "S.F").WithLocation(27, 61)); + } + + [Fact] + public void AssignRefTo_RefField() + { + var source = +@"ref struct S +{ + public ref T F; + public S(ref T t) { F = ref t; } +} + +class Program +{ + static void AssignValueToValue(S s, T tValue) { s.F = ref tValue; } // 1 + static void AssignRefToValue(S s, ref T tRef) { s.F = ref tRef; } + static void AssignOutToValue(S s, out T tOut) { tOut = default; s.F = ref tOut; } // 2 + static void AssignInToValue(S s, in T tIn) { s.F = ref tIn; } // 3 + + static void AssignValueToRef(ref S sRef, T tValue) { sRef.F = ref tValue; } // 4 + static void AssignRefToRef(ref S sRef, ref T tRef) { sRef.F = ref tRef; } + static void AssignOutToRef(ref S sRef, out T tOut) { tOut = default; sRef.F = ref tOut; } // 5 + static void AssignInToRef(ref S sRef, in T tIn) { sRef.F = ref tIn; } // 6 + + static void AssignValueToOut(out S sOut, T tValue) { sOut = default; sOut.F = ref tValue; } // 7 + static void AssignRefToOut(out S sOut, ref T tRef) { sOut = default; sOut.F = ref tRef; } + static void AssignOutToOut(out S sOut, out T tOut) { sOut = default; tOut = default; sOut.F = ref tOut; } // 8 + static void AssignInToOut(out S sOut, in T tIn) { sOut = default; sOut.F = ref tIn; } // 9 + + static void AssignValueToIn(in S sIn, T tValue) { sIn.F = ref tValue; } // 10 + static void AssignRefToIn(in S sIn, ref T tRef) { sIn.F = ref tRef; } // 11 + static void AssignOutToIn(in S sIn, out T tOut) { tOut = default; sIn.F = ref tOut; } // 12 + static void AssignInToIn(in S sIn, in T tIn) { sIn.F = ref tIn; } // 13 +}"; + var comp = CreateCompilation(source, runtimeFeature: RuntimeFlag.ByRefFields); + comp.VerifyEmitDiagnostics( + // (9,59): error CS8374: Cannot ref-assign 'tValue' to 'F' because 'tValue' has a narrower escape scope than 'F'. + // static void AssignValueToValue(S s, T tValue) { s.F = ref tValue; } // 1 + Diagnostic(ErrorCode.ERR_RefAssignNarrower, "s.F = ref tValue").WithArguments("F", "tValue").WithLocation(9, 59), + // (11,75): error CS8374: Cannot ref-assign 'tOut' to 'F' because 'tOut' has a narrower escape scope than 'F'. + // static void AssignOutToValue(S s, out T tOut) { tOut = default; s.F = ref tOut; } // 2 + Diagnostic(ErrorCode.ERR_RefAssignNarrower, "s.F = ref tOut").WithArguments("F", "tOut").WithLocation(11, 75), + // (12,69): error CS8331: Cannot assign to variable 'in T' because it is a readonly variable + // static void AssignInToValue(S s, in T tIn) { s.F = ref tIn; } // 3 + Diagnostic(ErrorCode.ERR_AssignReadonlyNotField, "tIn").WithArguments("variable", "in T").WithLocation(12, 69), + // (14,64): error CS8374: Cannot ref-assign 'tValue' to 'F' because 'tValue' has a narrower escape scope than 'F'. + // static void AssignValueToRef(ref S sRef, T tValue) { sRef.F = ref tValue; } // 4 + Diagnostic(ErrorCode.ERR_RefAssignNarrower, "sRef.F = ref tValue").WithArguments("F", "tValue").WithLocation(14, 64), + // (16,80): error CS8374: Cannot ref-assign 'tOut' to 'F' because 'tOut' has a narrower escape scope than 'F'. + // static void AssignOutToRef(ref S sRef, out T tOut) { tOut = default; sRef.F = ref tOut; } // 5 + Diagnostic(ErrorCode.ERR_RefAssignNarrower, "sRef.F = ref tOut").WithArguments("F", "tOut").WithLocation(16, 80), + // (17,77): error CS8331: Cannot assign to variable 'in T' because it is a readonly variable + // static void AssignInToRef(ref S sRef, in T tIn) { sRef.F = ref tIn; } // 6 + Diagnostic(ErrorCode.ERR_AssignReadonlyNotField, "tIn").WithArguments("variable", "in T").WithLocation(17, 77), + // (19,80): error CS8374: Cannot ref-assign 'tValue' to 'F' because 'tValue' has a narrower escape scope than 'F'. + // static void AssignValueToOut(out S sOut, T tValue) { sOut = default; sOut.F = ref tValue; } // 7 + Diagnostic(ErrorCode.ERR_RefAssignNarrower, "sOut.F = ref tValue").WithArguments("F", "tValue").WithLocation(19, 80), + // (21,96): error CS8374: Cannot ref-assign 'tOut' to 'F' because 'tOut' has a narrower escape scope than 'F'. + // static void AssignOutToOut(out S sOut, out T tOut) { sOut = default; tOut = default; sOut.F = ref tOut; } // 8 + Diagnostic(ErrorCode.ERR_RefAssignNarrower, "sOut.F = ref tOut").WithArguments("F", "tOut").WithLocation(21, 96), + // (22,93): error CS8331: Cannot assign to variable 'in T' because it is a readonly variable + // static void AssignInToOut(out S sOut, in T tIn) { sOut = default; sOut.F = ref tIn; } // 9 + Diagnostic(ErrorCode.ERR_AssignReadonlyNotField, "tIn").WithArguments("variable", "in T").WithLocation(22, 93), + // (24,61): error CS8332: Cannot assign to a member of variable 'in S' because it is a readonly variable + // static void AssignValueToIn(in S sIn, T tValue) { sIn.F = ref tValue; } // 10 + Diagnostic(ErrorCode.ERR_AssignReadonlyNotField2, "sIn.F").WithArguments("variable", "in S").WithLocation(24, 61), + // (25,61): error CS8332: Cannot assign to a member of variable 'in S' because it is a readonly variable + // static void AssignRefToIn(in S sIn, ref T tRef) { sIn.F = ref tRef; } // 11 + Diagnostic(ErrorCode.ERR_AssignReadonlyNotField2, "sIn.F").WithArguments("variable", "in S").WithLocation(25, 61), + // (26,77): error CS8332: Cannot assign to a member of variable 'in S' because it is a readonly variable + // static void AssignOutToIn(in S sIn, out T tOut) { tOut = default; sIn.F = ref tOut; } // 12 + Diagnostic(ErrorCode.ERR_AssignReadonlyNotField2, "sIn.F").WithArguments("variable", "in S").WithLocation(26, 77), + // (27,61): error CS8332: Cannot assign to a member of variable 'in S' because it is a readonly variable + // static void AssignInToIn(in S sIn, in T tIn) { sIn.F = ref tIn; } // 13 + Diagnostic(ErrorCode.ERR_AssignReadonlyNotField2, "sIn.F").WithArguments("variable", "in S").WithLocation(27, 61)); + + // Valid cases from above. + source = +@"using System; + +ref struct S +{ + public ref T F; + public S(ref T t) { F = ref t; } +} + +class Program +{ + static void AssignRefToValue(S s, ref T tRef) { s.F = ref tRef; } + + static void AssignRefToRef(ref S sRef, ref T tRef) { sRef.F = ref tRef; } + + static void AssignRefToOut(out S sOut, ref T tRef) { sOut = default; sOut.F = ref tRef; } + + static void Main() + { + int x, y; + scoped S s; + + x = 1; y = 2; + s = new S(ref x); + AssignRefToValue(s, ref y); + Console.WriteLine(s.F); + + x = 3; y = 4; + s = new S(ref x); + AssignRefToRef(ref s, ref y); + Console.WriteLine(s.F); + + x = 5; y = 6; + s = new S(ref x); + AssignRefToOut(out s, ref y); + Console.WriteLine(s.F); + } +}"; + comp = CreateCompilation(source, options: TestOptions.ReleaseExe, runtimeFeature: RuntimeFlag.ByRefFields); + var verifier = CompileAndVerify(comp, verify: Verification.Skipped, expectedOutput: IncludeExpectedOutput( +@"1 +4 +6")); + verifier.VerifyILMultiple( + "Program.AssignRefToValue", +@"{ + // Code size 9 (0x9) + .maxstack 2 + IL_0000: ldarga.s V_0 + IL_0002: ldarg.1 + IL_0003: stfld ""ref T S.F"" + IL_0008: ret +}", + "Program.AssignRefToRef", +@"{ + // Code size 8 (0x8) + .maxstack 2 + IL_0000: ldarg.0 + IL_0001: ldarg.1 + IL_0002: stfld ""ref T S.F"" + IL_0007: ret +}", + "Program.AssignRefToOut", +@"{ + // Code size 15 (0xf) + .maxstack 2 + IL_0000: ldarg.0 + IL_0001: initobj ""S"" + IL_0007: ldarg.0 + IL_0008: ldarg.1 + IL_0009: stfld ""ref T S.F"" + IL_000e: ret +}"); + } + + [Fact] + public void AssignRefTo_RefReadonlyField() + { + var source = +@"ref struct S +{ + public ref readonly T F; + public S(ref T t) { F = ref t; } +} + +class Program +{ + static void AssignValueToValue(S s, T tValue) { s.F = ref tValue; } // 1 + static void AssignRefToValue(S s, ref T tRef) { s.F = ref tRef; } + static void AssignOutToValue(S s, out T tOut) { tOut = default; s.F = ref tOut; } // 2 + static void AssignInToValue(S s, in T tIn) { s.F = ref tIn; } + + static void AssignValueToRef(ref S sRef, T tValue) { sRef.F = ref tValue; } // 3 + static void AssignRefToRef(ref S sRef, ref T tRef) { sRef.F = ref tRef; } + static void AssignOutToRef(ref S sRef, out T tOut) { tOut = default; sRef.F = ref tOut; } // 4 + static void AssignInToRef(ref S sRef, in T tIn) { sRef.F = ref tIn; } + + static void AssignValueToOut(out S sOut, T tValue) { sOut = default; sOut.F = ref tValue; } // 5 + static void AssignRefToOut(out S sOut, ref T tRef) { sOut = default; sOut.F = ref tRef; } + static void AssignOutToOut(out S sOut, out T tOut) { sOut = default; tOut = default; sOut.F = ref tOut; } // 6 + static void AssignInToOut(out S sOut, in T tIn) { sOut = default; sOut.F = ref tIn; } + + static void AssignValueToIn(in S sIn, T tValue) { sIn.F = ref tValue; } // 7 + static void AssignRefToIn(in S sIn, ref T tRef) { sIn.F = ref tRef; } // 8 + static void AssignOutToIn(in S sIn, out T tOut) { tOut = default; sIn.F = ref tOut; } // 9 + static void AssignInToIn(in S sIn, in T tIn) { sIn.F = ref tIn; } // 10 +}"; + var comp = CreateCompilation(source, runtimeFeature: RuntimeFlag.ByRefFields); + comp.VerifyEmitDiagnostics( + // (9,59): error CS8374: Cannot ref-assign 'tValue' to 'F' because 'tValue' has a narrower escape scope than 'F'. + // static void AssignValueToValue(S s, T tValue) { s.F = ref tValue; } // 1 + Diagnostic(ErrorCode.ERR_RefAssignNarrower, "s.F = ref tValue").WithArguments("F", "tValue").WithLocation(9, 59), + // (11,75): error CS8374: Cannot ref-assign 'tOut' to 'F' because 'tOut' has a narrower escape scope than 'F'. + // static void AssignOutToValue(S s, out T tOut) { tOut = default; s.F = ref tOut; } // 2 + Diagnostic(ErrorCode.ERR_RefAssignNarrower, "s.F = ref tOut").WithArguments("F", "tOut").WithLocation(11, 75), + // (14,64): error CS8374: Cannot ref-assign 'tValue' to 'F' because 'tValue' has a narrower escape scope than 'F'. + // static void AssignValueToRef(ref S sRef, T tValue) { sRef.F = ref tValue; } // 3 + Diagnostic(ErrorCode.ERR_RefAssignNarrower, "sRef.F = ref tValue").WithArguments("F", "tValue").WithLocation(14, 64), + // (16,80): error CS8374: Cannot ref-assign 'tOut' to 'F' because 'tOut' has a narrower escape scope than 'F'. + // static void AssignOutToRef(ref S sRef, out T tOut) { tOut = default; sRef.F = ref tOut; } // 4 + Diagnostic(ErrorCode.ERR_RefAssignNarrower, "sRef.F = ref tOut").WithArguments("F", "tOut").WithLocation(16, 80), + // (19,80): error CS8374: Cannot ref-assign 'tValue' to 'F' because 'tValue' has a narrower escape scope than 'F'. + // static void AssignValueToOut(out S sOut, T tValue) { sOut = default; sOut.F = ref tValue; } // 5 + Diagnostic(ErrorCode.ERR_RefAssignNarrower, "sOut.F = ref tValue").WithArguments("F", "tValue").WithLocation(19, 80), + // (21,96): error CS8374: Cannot ref-assign 'tOut' to 'F' because 'tOut' has a narrower escape scope than 'F'. + // static void AssignOutToOut(out S sOut, out T tOut) { sOut = default; tOut = default; sOut.F = ref tOut; } // 6 + Diagnostic(ErrorCode.ERR_RefAssignNarrower, "sOut.F = ref tOut").WithArguments("F", "tOut").WithLocation(21, 96), + // (24,61): error CS8332: Cannot assign to a member of variable 'in S' because it is a readonly variable + // static void AssignValueToIn(in S sIn, T tValue) { sIn.F = ref tValue; } // 7 + Diagnostic(ErrorCode.ERR_AssignReadonlyNotField2, "sIn.F").WithArguments("variable", "in S").WithLocation(24, 61), + // (25,61): error CS8332: Cannot assign to a member of variable 'in S' because it is a readonly variable + // static void AssignRefToIn(in S sIn, ref T tRef) { sIn.F = ref tRef; } // 8 + Diagnostic(ErrorCode.ERR_AssignReadonlyNotField2, "sIn.F").WithArguments("variable", "in S").WithLocation(25, 61), + // (26,77): error CS8332: Cannot assign to a member of variable 'in S' because it is a readonly variable + // static void AssignOutToIn(in S sIn, out T tOut) { tOut = default; sIn.F = ref tOut; } // 9 + Diagnostic(ErrorCode.ERR_AssignReadonlyNotField2, "sIn.F").WithArguments("variable", "in S").WithLocation(26, 77), + // (27,61): error CS8332: Cannot assign to a member of variable 'in S' because it is a readonly variable + // static void AssignInToIn(in S sIn, in T tIn) { sIn.F = ref tIn; } // 10 + Diagnostic(ErrorCode.ERR_AssignReadonlyNotField2, "sIn.F").WithArguments("variable", "in S").WithLocation(27, 61)); + + // Valid cases from above. + source = +@"using System; + +ref struct S +{ + public ref readonly T F; + public S(ref T t) { F = ref t; } +} + +class Program +{ + static void AssignRefToValue(S s, ref T tRef) { s.F = ref tRef; } + static void AssignInToValue(S s, in T tIn) { s.F = ref tIn; } + + static void AssignRefToRef(ref S sRef, ref T tRef) { sRef.F = ref tRef; } + static void AssignInToRef(ref S sRef, in T tIn) { sRef.F = ref tIn; } + + static void AssignRefToOut(out S sOut, ref T tRef) { sOut = default; sOut.F = ref tRef; } + static void AssignInToOut(out S sOut, in T tIn) { sOut = default; sOut.F = ref tIn; } + + static void Main() + { + int x, y; + scoped S s; + + x = 1; y = 2; + s = new S(ref x); + AssignRefToValue(s, ref y); + Console.WriteLine(s.F); + x = 1; y = 2; + s = new S(ref x); + AssignInToValue(s, y); + Console.WriteLine(s.F); + + x = 3; y = 4; + s = new S(ref x); + AssignRefToRef(ref s, ref y); + Console.WriteLine(s.F); + x = 3; y = 4; + s = new S(ref x); + AssignInToRef(ref s, y); + Console.WriteLine(s.F); + + x = 5; y = 6; + s = new S(ref x); + AssignRefToOut(out s, ref y); + Console.WriteLine(s.F); + x = 5; y = 6; + s = new S(ref x); + AssignInToOut(out s, y); + Console.WriteLine(s.F); + } +}"; + comp = CreateCompilation(source, options: TestOptions.ReleaseExe, runtimeFeature: RuntimeFlag.ByRefFields); + var verifier = CompileAndVerify(comp, verify: Verification.Skipped, expectedOutput: IncludeExpectedOutput( +@"1 +1 +4 +4 +6 +6")); + verifier.VerifyILMultiple( + "Program.AssignRefToValue", +@"{ + // Code size 9 (0x9) + .maxstack 2 + IL_0000: ldarga.s V_0 + IL_0002: ldarg.1 + IL_0003: stfld ""ref readonly T S.F"" + IL_0008: ret +}", + "Program.AssignInToValue", +@"{ + // Code size 9 (0x9) + .maxstack 2 + IL_0000: ldarga.s V_0 + IL_0002: ldarg.1 + IL_0003: stfld ""ref readonly T S.F"" + IL_0008: ret +}", + "Program.AssignRefToRef", +@"{ + // Code size 8 (0x8) + .maxstack 2 + IL_0000: ldarg.0 + IL_0001: ldarg.1 + IL_0002: stfld ""ref readonly T S.F"" + IL_0007: ret +}", + "Program.AssignInToRef", +@"{ + // Code size 8 (0x8) + .maxstack 2 + IL_0000: ldarg.0 + IL_0001: ldarg.1 + IL_0002: stfld ""ref readonly T S.F"" + IL_0007: ret +}", + "Program.AssignRefToOut", +@"{ + // Code size 15 (0xf) + .maxstack 2 + IL_0000: ldarg.0 + IL_0001: initobj ""S"" + IL_0007: ldarg.0 + IL_0008: ldarg.1 + IL_0009: stfld ""ref readonly T S.F"" + IL_000e: ret +}", + "Program.AssignInToOut", +@"{ + // Code size 15 (0xf) + .maxstack 2 + IL_0000: ldarg.0 + IL_0001: initobj ""S"" + IL_0007: ldarg.0 + IL_0008: ldarg.1 + IL_0009: stfld ""ref readonly T S.F"" + IL_000e: ret +}"); + } + + [Fact] + public void AssignRefTo_ReadonlyRefField() + { + var source = +@"ref struct S +{ + public readonly ref T F; + public S(ref T t) { F = ref t; } +} + +class Program +{ + static void AssignValueToValue(S s, T tValue) { s.F = ref tValue; } // 1 + static void AssignRefToValue(S s, ref T tRef) { s.F = ref tRef; } // 2 + static void AssignOutToValue(S s, out T tOut) { tOut = default; s.F = ref tOut; } // 3 + static void AssignInToValue(S s, in T tIn) { s.F = ref tIn; } // 4 + + static void AssignValueToRef(ref S sRef, T tValue) { sRef.F = ref tValue; } // 5 + static void AssignRefToRef(ref S sRef, ref T tRef) { sRef.F = ref tRef; } // 6 + static void AssignOutToRef(ref S sRef, out T tOut) { tOut = default; sRef.F = ref tOut; } // 7 + static void AssignInToRef(ref S sRef, in T tIn) { sRef.F = ref tIn; } // 8 + + static void AssignValueToOut(out S sOut, T tValue) { sOut = default; sOut.F = ref tValue; } // 9 + static void AssignRefToOut(out S sOut, ref T tRef) { sOut = default; sOut.F = ref tRef; } // 10 + static void AssignOutToOut(out S sOut, out T tOut) { sOut = default; tOut = default; sOut.F = ref tOut; } // 11 + static void AssignInToOut(out S sOut, in T tIn) { sOut = default; sOut.F = ref tIn; } // 12 + + static void AssignValueToIn(in S sIn, T tValue) { sIn.F = ref tValue; } // 13 + static void AssignRefToIn(in S sIn, ref T tRef) { sIn.F = ref tRef; } // 14 + static void AssignOutToIn(in S sIn, out T tOut) { tOut = default; sIn.F = ref tOut; } // 15 + static void AssignInToIn(in S sIn, in T tIn) { sIn.F = ref tIn; } // 16 +}"; + var comp = CreateCompilation(source, runtimeFeature: RuntimeFlag.ByRefFields); + comp.VerifyEmitDiagnostics( + // (9,59): error CS0191: A readonly field cannot be assigned to (except in a constructor or init-only setter of the type in which the field is defined or a variable initializer) + // static void AssignValueToValue(S s, T tValue) { s.F = ref tValue; } // 1 + Diagnostic(ErrorCode.ERR_AssgReadonly, "s.F").WithLocation(9, 59), + // (10,59): error CS0191: A readonly field cannot be assigned to (except in a constructor or init-only setter of the type in which the field is defined or a variable initializer) + // static void AssignRefToValue(S s, ref T tRef) { s.F = ref tRef; } // 2 + Diagnostic(ErrorCode.ERR_AssgReadonly, "s.F").WithLocation(10, 59), + // (11,75): error CS0191: A readonly field cannot be assigned to (except in a constructor or init-only setter of the type in which the field is defined or a variable initializer) + // static void AssignOutToValue(S s, out T tOut) { tOut = default; s.F = ref tOut; } // 3 + Diagnostic(ErrorCode.ERR_AssgReadonly, "s.F").WithLocation(11, 75), + // (12,59): error CS0191: A readonly field cannot be assigned to (except in a constructor or init-only setter of the type in which the field is defined or a variable initializer) + // static void AssignInToValue(S s, in T tIn) { s.F = ref tIn; } // 4 + Diagnostic(ErrorCode.ERR_AssgReadonly, "s.F").WithLocation(12, 59), + // (14,64): error CS0191: A readonly field cannot be assigned to (except in a constructor or init-only setter of the type in which the field is defined or a variable initializer) + // static void AssignValueToRef(ref S sRef, T tValue) { sRef.F = ref tValue; } // 5 + Diagnostic(ErrorCode.ERR_AssgReadonly, "sRef.F").WithLocation(14, 64), + // (15,64): error CS0191: A readonly field cannot be assigned to (except in a constructor or init-only setter of the type in which the field is defined or a variable initializer) + // static void AssignRefToRef(ref S sRef, ref T tRef) { sRef.F = ref tRef; } // 6 + Diagnostic(ErrorCode.ERR_AssgReadonly, "sRef.F").WithLocation(15, 64), + // (16,80): error CS0191: A readonly field cannot be assigned to (except in a constructor or init-only setter of the type in which the field is defined or a variable initializer) + // static void AssignOutToRef(ref S sRef, out T tOut) { tOut = default; sRef.F = ref tOut; } // 7 + Diagnostic(ErrorCode.ERR_AssgReadonly, "sRef.F").WithLocation(16, 80), + // (17,64): error CS0191: A readonly field cannot be assigned to (except in a constructor or init-only setter of the type in which the field is defined or a variable initializer) + // static void AssignInToRef(ref S sRef, in T tIn) { sRef.F = ref tIn; } // 8 + Diagnostic(ErrorCode.ERR_AssgReadonly, "sRef.F").WithLocation(17, 64), + // (19,80): error CS0191: A readonly field cannot be assigned to (except in a constructor or init-only setter of the type in which the field is defined or a variable initializer) + // static void AssignValueToOut(out S sOut, T tValue) { sOut = default; sOut.F = ref tValue; } // 9 + Diagnostic(ErrorCode.ERR_AssgReadonly, "sOut.F").WithLocation(19, 80), + // (20,80): error CS0191: A readonly field cannot be assigned to (except in a constructor or init-only setter of the type in which the field is defined or a variable initializer) + // static void AssignRefToOut(out S sOut, ref T tRef) { sOut = default; sOut.F = ref tRef; } // 10 + Diagnostic(ErrorCode.ERR_AssgReadonly, "sOut.F").WithLocation(20, 80), + // (21,96): error CS0191: A readonly field cannot be assigned to (except in a constructor or init-only setter of the type in which the field is defined or a variable initializer) + // static void AssignOutToOut(out S sOut, out T tOut) { sOut = default; tOut = default; sOut.F = ref tOut; } // 11 + Diagnostic(ErrorCode.ERR_AssgReadonly, "sOut.F").WithLocation(21, 96), + // (22,80): error CS0191: A readonly field cannot be assigned to (except in a constructor or init-only setter of the type in which the field is defined or a variable initializer) + // static void AssignInToOut(out S sOut, in T tIn) { sOut = default; sOut.F = ref tIn; } // 12 + Diagnostic(ErrorCode.ERR_AssgReadonly, "sOut.F").WithLocation(22, 80), + // (24,61): error CS0191: A readonly field cannot be assigned to (except in a constructor or init-only setter of the type in which the field is defined or a variable initializer) + // static void AssignValueToIn(in S sIn, T tValue) { sIn.F = ref tValue; } // 13 + Diagnostic(ErrorCode.ERR_AssgReadonly, "sIn.F").WithLocation(24, 61), + // (25,61): error CS0191: A readonly field cannot be assigned to (except in a constructor or init-only setter of the type in which the field is defined or a variable initializer) + // static void AssignRefToIn(in S sIn, ref T tRef) { sIn.F = ref tRef; } // 14 + Diagnostic(ErrorCode.ERR_AssgReadonly, "sIn.F").WithLocation(25, 61), + // (26,77): error CS0191: A readonly field cannot be assigned to (except in a constructor or init-only setter of the type in which the field is defined or a variable initializer) + // static void AssignOutToIn(in S sIn, out T tOut) { tOut = default; sIn.F = ref tOut; } // 15 + Diagnostic(ErrorCode.ERR_AssgReadonly, "sIn.F").WithLocation(26, 77), + // (27,61): error CS0191: A readonly field cannot be assigned to (except in a constructor or init-only setter of the type in which the field is defined or a variable initializer) + // static void AssignInToIn(in S sIn, in T tIn) { sIn.F = ref tIn; } // 16 + Diagnostic(ErrorCode.ERR_AssgReadonly, "sIn.F").WithLocation(27, 61)); + } + + [Fact] + public void AssignRefTo_ReadonlyRefReadonlyField() + { + var source = +@"ref struct S +{ + public readonly ref readonly T F; + public S(ref T t) { F = ref t; } +} + +class Program +{ + static void AssignValueToValue(S s, T tValue) { s.F = ref tValue; } // 1 + static void AssignRefToValue(S s, ref T tRef) { s.F = ref tRef; } // 2 + static void AssignOutToValue(S s, out T tOut) { tOut = default; s.F = ref tOut; } // 3 + static void AssignInToValue(S s, in T tIn) { s.F = ref tIn; } // 4 + + static void AssignValueToRef(ref S sRef, T tValue) { sRef.F = ref tValue; } // 5 + static void AssignRefToRef(ref S sRef, ref T tRef) { sRef.F = ref tRef; } // 6 + static void AssignOutToRef(ref S sRef, out T tOut) { tOut = default; sRef.F = ref tOut; } // 7 + static void AssignInToRef(ref S sRef, in T tIn) { sRef.F = ref tIn; } // 8 + + static void AssignValueToOut(out S sOut, T tValue) { sOut = default; sOut.F = ref tValue; } // 9 + static void AssignRefToOut(out S sOut, ref T tRef) { sOut = default; sOut.F = ref tRef; } // 10 + static void AssignOutToOut(out S sOut, out T tOut) { sOut = default; tOut = default; sOut.F = ref tOut; } // 11 + static void AssignInToOut(out S sOut, in T tIn) { sOut = default; sOut.F = ref tIn; } // 12 + + static void AssignValueToIn(in S sIn, T tValue) { sIn.F = ref tValue; } // 13 + static void AssignRefToIn(in S sIn, ref T tRef) { sIn.F = ref tRef; } // 14 + static void AssignOutToIn(in S sIn, out T tOut) { tOut = default; sIn.F = ref tOut; } // 15 + static void AssignInToIn(in S sIn, in T tIn) { sIn.F = ref tIn; } // 16 +}"; + var comp = CreateCompilation(source, runtimeFeature: RuntimeFlag.ByRefFields); + comp.VerifyEmitDiagnostics( + // (9,59): error CS0191: A readonly field cannot be assigned to (except in a constructor or init-only setter of the type in which the field is defined or a variable initializer) + // static void AssignValueToValue(S s, T tValue) { s.F = ref tValue; } // 1 + Diagnostic(ErrorCode.ERR_AssgReadonly, "s.F").WithLocation(9, 59), + // (10,59): error CS0191: A readonly field cannot be assigned to (except in a constructor or init-only setter of the type in which the field is defined or a variable initializer) + // static void AssignRefToValue(S s, ref T tRef) { s.F = ref tRef; } // 2 + Diagnostic(ErrorCode.ERR_AssgReadonly, "s.F").WithLocation(10, 59), + // (11,75): error CS0191: A readonly field cannot be assigned to (except in a constructor or init-only setter of the type in which the field is defined or a variable initializer) + // static void AssignOutToValue(S s, out T tOut) { tOut = default; s.F = ref tOut; } // 3 + Diagnostic(ErrorCode.ERR_AssgReadonly, "s.F").WithLocation(11, 75), + // (12,59): error CS0191: A readonly field cannot be assigned to (except in a constructor or init-only setter of the type in which the field is defined or a variable initializer) + // static void AssignInToValue(S s, in T tIn) { s.F = ref tIn; } // 4 + Diagnostic(ErrorCode.ERR_AssgReadonly, "s.F").WithLocation(12, 59), + // (14,64): error CS0191: A readonly field cannot be assigned to (except in a constructor or init-only setter of the type in which the field is defined or a variable initializer) + // static void AssignValueToRef(ref S sRef, T tValue) { sRef.F = ref tValue; } // 5 + Diagnostic(ErrorCode.ERR_AssgReadonly, "sRef.F").WithLocation(14, 64), + // (15,64): error CS0191: A readonly field cannot be assigned to (except in a constructor or init-only setter of the type in which the field is defined or a variable initializer) + // static void AssignRefToRef(ref S sRef, ref T tRef) { sRef.F = ref tRef; } // 6 + Diagnostic(ErrorCode.ERR_AssgReadonly, "sRef.F").WithLocation(15, 64), + // (16,80): error CS0191: A readonly field cannot be assigned to (except in a constructor or init-only setter of the type in which the field is defined or a variable initializer) + // static void AssignOutToRef(ref S sRef, out T tOut) { tOut = default; sRef.F = ref tOut; } // 7 + Diagnostic(ErrorCode.ERR_AssgReadonly, "sRef.F").WithLocation(16, 80), + // (17,64): error CS0191: A readonly field cannot be assigned to (except in a constructor or init-only setter of the type in which the field is defined or a variable initializer) + // static void AssignInToRef(ref S sRef, in T tIn) { sRef.F = ref tIn; } // 8 + Diagnostic(ErrorCode.ERR_AssgReadonly, "sRef.F").WithLocation(17, 64), + // (19,80): error CS0191: A readonly field cannot be assigned to (except in a constructor or init-only setter of the type in which the field is defined or a variable initializer) + // static void AssignValueToOut(out S sOut, T tValue) { sOut = default; sOut.F = ref tValue; } // 9 + Diagnostic(ErrorCode.ERR_AssgReadonly, "sOut.F").WithLocation(19, 80), + // (20,80): error CS0191: A readonly field cannot be assigned to (except in a constructor or init-only setter of the type in which the field is defined or a variable initializer) + // static void AssignRefToOut(out S sOut, ref T tRef) { sOut = default; sOut.F = ref tRef; } // 10 + Diagnostic(ErrorCode.ERR_AssgReadonly, "sOut.F").WithLocation(20, 80), + // (21,96): error CS0191: A readonly field cannot be assigned to (except in a constructor or init-only setter of the type in which the field is defined or a variable initializer) + // static void AssignOutToOut(out S sOut, out T tOut) { sOut = default; tOut = default; sOut.F = ref tOut; } // 11 + Diagnostic(ErrorCode.ERR_AssgReadonly, "sOut.F").WithLocation(21, 96), + // (22,80): error CS0191: A readonly field cannot be assigned to (except in a constructor or init-only setter of the type in which the field is defined or a variable initializer) + // static void AssignInToOut(out S sOut, in T tIn) { sOut = default; sOut.F = ref tIn; } // 12 + Diagnostic(ErrorCode.ERR_AssgReadonly, "sOut.F").WithLocation(22, 80), + // (24,61): error CS0191: A readonly field cannot be assigned to (except in a constructor or init-only setter of the type in which the field is defined or a variable initializer) + // static void AssignValueToIn(in S sIn, T tValue) { sIn.F = ref tValue; } // 13 + Diagnostic(ErrorCode.ERR_AssgReadonly, "sIn.F").WithLocation(24, 61), + // (25,61): error CS0191: A readonly field cannot be assigned to (except in a constructor or init-only setter of the type in which the field is defined or a variable initializer) + // static void AssignRefToIn(in S sIn, ref T tRef) { sIn.F = ref tRef; } // 14 + Diagnostic(ErrorCode.ERR_AssgReadonly, "sIn.F").WithLocation(25, 61), + // (26,77): error CS0191: A readonly field cannot be assigned to (except in a constructor or init-only setter of the type in which the field is defined or a variable initializer) + // static void AssignOutToIn(in S sIn, out T tOut) { tOut = default; sIn.F = ref tOut; } // 15 + Diagnostic(ErrorCode.ERR_AssgReadonly, "sIn.F").WithLocation(26, 77), + // (27,61): error CS0191: A readonly field cannot be assigned to (except in a constructor or init-only setter of the type in which the field is defined or a variable initializer) + // static void AssignInToIn(in S sIn, in T tIn) { sIn.F = ref tIn; } // 16 + Diagnostic(ErrorCode.ERR_AssgReadonly, "sIn.F").WithLocation(27, 61)); + } + + [Fact] + public void AssignOutParameterFrom_RefField() + { + var source = +@"#pragma warning disable 649 +ref struct S +{ + public ref T Ref; + public ref readonly T RefReadonly; + public readonly ref T ReadonlyRef; + public readonly ref readonly T ReadonlyRefReadonly; +} + +class Program +{ + static void FromValueRef(S s, out T t) { t = s.Ref; } + static void FromValueRefReadonly(S s, out T t) { t = s.RefReadonly; } + static void FromValueReadonlyRef(S s, out T t) { t = s.ReadonlyRef; } + static void FromValueReadonlyRefReadonly(S s, out T t) { t = s.ReadonlyRefReadonly; } + + static void FromRefRef(ref S s, out T t) { t = s.Ref; } + static void FromRefRefReadonly(ref S s, out T t) { t = s.RefReadonly; } + static void FromRefReadonlyRef(ref S s, out T t) { t = s.ReadonlyRef; } + static void FromRefReadonlyRefReadonly(ref S s, out T t) { t = s.ReadonlyRefReadonly; } + + static void FromOutRef(out S s, out T t) { s = default; t = s.Ref; } + static void FromOutRefReadonly(out S s, out T t) { s = default; t = s.RefReadonly; } + static void FromOutReadonlyRef(out S s, out T t) { s = default; t = s.ReadonlyRef; } + static void FromOutReadonlyRefReadonly(out S s, out T t) { s = default; t = s.ReadonlyRefReadonly; } + + static void FromInRef(in S s, out T t) { t = s.Ref; } + static void FromInRefReadonly(in S s, out T t) { t = s.RefReadonly; } + static void FromInReadonlyRef(in S s, out T t) { t = s.ReadonlyRef; } + static void FromInReadonlyRefReadonly(in S s, out T t) { t = s.ReadonlyRefReadonly; } +}"; + var comp = CreateCompilation(source, runtimeFeature: RuntimeFlag.ByRefFields); + comp.VerifyEmitDiagnostics(); + } + + [Fact] + public void AssignRefLocalFrom_RefField() + { + var source = +@"ref struct S +{ + public ref T Ref; + public ref readonly T RefReadonly; + public readonly ref T ReadonlyRef; + public readonly ref readonly T ReadonlyRefReadonly; +} + +class Program +{ + static void FromValueRef(S s) { ref T t = ref s.Ref; } + static void FromValueRefReadonly(S s) { ref T t = ref s.RefReadonly; } // 1 + static void FromValueReadonlyRef(S s) { ref T t = ref s.ReadonlyRef; } + static void FromValueReadonlyRefReadonly(S s) { ref T t = ref s.ReadonlyRefReadonly; } // 2 + + static void FromRefRef(ref S s) { ref T t = ref s.Ref; } + static void FromRefRefReadonly(ref S s) { ref T t = ref s.RefReadonly; } // 3 + static void FromRefReadonlyRef(ref S s) { ref T t = ref s.ReadonlyRef; } + static void FromRefReadonlyRefReadonly(ref S s) { ref T t = ref s.ReadonlyRefReadonly; } // 4 + + static void FromOutRef(out S s) { s = default; ref T t = ref s.Ref; } + static void FromOutRefReadonly(out S s) { s = default; ref T t = ref s.RefReadonly; } // 5 + static void FromOutReadonlyRef(out S s) { s = default; ref T t = ref s.ReadonlyRef; } + static void FromOutReadonlyRefReadonly(out S s) { s = default; ref T t = ref s.ReadonlyRefReadonly; } // 6 + + static void FromInRef(in S s) { ref T t = ref s.Ref; } + static void FromInRefReadonly(in S s) { ref T t = ref s.RefReadonly; } // 7 + static void FromInReadonlyRef(in S s) { ref T t = ref s.ReadonlyRef; } + static void FromInReadonlyRefReadonly(in S s) { ref T t = ref s.ReadonlyRefReadonly; } // 8 +}"; + var comp = CreateCompilation(source, runtimeFeature: RuntimeFlag.ByRefFields); + comp.VerifyEmitDiagnostics( + // (12,73): error CS8329: Cannot use field 'S.RefReadonly' as a ref or out value because it is a readonly variable + // static void FromValueRefReadonly(S s) { ref T t = ref s.RefReadonly; } // 1 + Diagnostic(ErrorCode.ERR_RefReadonlyNotField, "s.RefReadonly").WithArguments("field", "S.RefReadonly").WithLocation(12, 73), + // (14,73): error CS8329: Cannot use field 'S.ReadonlyRefReadonly' as a ref or out value because it is a readonly variable + // static void FromValueReadonlyRefReadonly(S s) { ref T t = ref s.ReadonlyRefReadonly; } // 2 + Diagnostic(ErrorCode.ERR_RefReadonlyNotField, "s.ReadonlyRefReadonly").WithArguments("field", "S.ReadonlyRefReadonly").WithLocation(14, 73), + // (17,75): error CS8329: Cannot use field 'S.RefReadonly' as a ref or out value because it is a readonly variable + // static void FromRefRefReadonly(ref S s) { ref T t = ref s.RefReadonly; } // 3 + Diagnostic(ErrorCode.ERR_RefReadonlyNotField, "s.RefReadonly").WithArguments("field", "S.RefReadonly").WithLocation(17, 75), + // (19,75): error CS8329: Cannot use field 'S.ReadonlyRefReadonly' as a ref or out value because it is a readonly variable + // static void FromRefReadonlyRefReadonly(ref S s) { ref T t = ref s.ReadonlyRefReadonly; } // 4 + Diagnostic(ErrorCode.ERR_RefReadonlyNotField, "s.ReadonlyRefReadonly").WithArguments("field", "S.ReadonlyRefReadonly").WithLocation(19, 75), + // (22,88): error CS8329: Cannot use field 'S.RefReadonly' as a ref or out value because it is a readonly variable + // static void FromOutRefReadonly(out S s) { s = default; ref T t = ref s.RefReadonly; } // 5 + Diagnostic(ErrorCode.ERR_RefReadonlyNotField, "s.RefReadonly").WithArguments("field", "S.RefReadonly").WithLocation(22, 88), + // (24,88): error CS8329: Cannot use field 'S.ReadonlyRefReadonly' as a ref or out value because it is a readonly variable + // static void FromOutReadonlyRefReadonly(out S s) { s = default; ref T t = ref s.ReadonlyRefReadonly; } // 6 + Diagnostic(ErrorCode.ERR_RefReadonlyNotField, "s.ReadonlyRefReadonly").WithArguments("field", "S.ReadonlyRefReadonly").WithLocation(24, 88), + // (27,73): error CS8329: Cannot use field 'S.RefReadonly' as a ref or out value because it is a readonly variable + // static void FromInRefReadonly(in S s) { ref T t = ref s.RefReadonly; } // 7 + Diagnostic(ErrorCode.ERR_RefReadonlyNotField, "s.RefReadonly").WithArguments("field", "S.RefReadonly").WithLocation(27, 73), + // (29,73): error CS8329: Cannot use field 'S.ReadonlyRefReadonly' as a ref or out value because it is a readonly variable + // static void FromInReadonlyRefReadonly(in S s) { ref T t = ref s.ReadonlyRefReadonly; } // 8 + Diagnostic(ErrorCode.ERR_RefReadonlyNotField, "s.ReadonlyRefReadonly").WithArguments("field", "S.ReadonlyRefReadonly").WithLocation(29, 73)); + } + + [Fact] + public void AssignRefReadonlyLocalFrom_RefField() + { + var source = +@"ref struct S +{ + public ref T Ref; + public ref readonly T RefReadonly; + public readonly ref T ReadonlyRef; + public readonly ref readonly T ReadonlyRefReadonly; +} + +class Program +{ + static void FromValueRef(S s) { ref readonly T t = ref s.Ref; } + static void FromValueRefReadonly(S s) { ref readonly T t = ref s.RefReadonly; } + static void FromValueReadonlyRef(S s) { ref readonly T t = ref s.ReadonlyRef; } + static void FromValueReadonlyRefReadonly(S s) { ref readonly T t = ref s.ReadonlyRefReadonly; } + + static void FromRefRef(ref S s) { ref readonly T t = ref s.Ref; } + static void FromRefRefReadonly(ref S s) { ref readonly T t = ref s.RefReadonly; } + static void FromRefReadonlyRef(ref S s) { ref readonly T t = ref s.ReadonlyRef; } + static void FromRefReadonlyRefReadonly(ref S s) { ref readonly T t = ref s.ReadonlyRefReadonly; } + + static void FromOutRef(out S s) { s = default; ref readonly T t = ref s.Ref; } + static void FromOutRefReadonly(out S s) { s = default; ref readonly T t = ref s.RefReadonly; } + static void FromOutReadonlyRef(out S s) { s = default; ref readonly T t = ref s.ReadonlyRef; } + static void FromOutReadonlyRefReadonly(out S s) { s = default; ref readonly T t = ref s.ReadonlyRefReadonly; } + + static void FromInRef(in S s) { ref readonly T t = ref s.Ref; } + static void FromInRefReadonly(in S s) { ref readonly T t = ref s.RefReadonly; } + static void FromInReadonlyRef(in S s) { ref readonly T t = ref s.ReadonlyRef; } + static void FromInReadonlyRefReadonly(in S s) { ref readonly T t = ref s.ReadonlyRefReadonly; } +}"; + var comp = CreateCompilation(source, runtimeFeature: RuntimeFlag.ByRefFields); + comp.VerifyEmitDiagnostics(); + } + + [Fact] + public void RefReturn() + { + var source = +@"class Program +{ + static ref T F1(T t) => ref t; // 1 + static ref T F2(ref T t) => ref t; + static ref T F3(out T t) { t = default; return ref t; } // 2 + static ref T F4(in T t) => ref t; // 3 + static ref readonly T F5(T t) => ref t; // 4 + static ref readonly T F6(ref T t) => ref t; + static ref readonly T F7(out T t) { t = default; return ref t; } // 5 + static ref readonly T F8(in T t) => ref t; +}"; + var comp = CreateCompilation(source); + comp.VerifyEmitDiagnostics( + // (3,36): error CS8166: Cannot return a parameter by reference 't' because it is not a ref parameter + // static ref T F1(T t) => ref t; // 1 + Diagnostic(ErrorCode.ERR_RefReturnParameter, "t").WithArguments("t").WithLocation(3, 36), + // (5,59): error CS8166: Cannot return a parameter by reference 't' because it is not a ref parameter + // static ref T F3(out T t) { t = default; return ref t; } // 2 + Diagnostic(ErrorCode.ERR_RefReturnParameter, "t").WithArguments("t").WithLocation(5, 59), + // (6,39): error CS8333: Cannot return variable 'in T' by writable reference because it is a readonly variable + // static ref T F4(in T t) => ref t; // 3 + Diagnostic(ErrorCode.ERR_RefReturnReadonlyNotField, "t").WithArguments("variable", "in T").WithLocation(6, 39), + // (7,45): error CS8166: Cannot return a parameter by reference 't' because it is not a ref parameter + // static ref readonly T F5(T t) => ref t; // 4 + Diagnostic(ErrorCode.ERR_RefReturnParameter, "t").WithArguments("t").WithLocation(7, 45), + // (9,68): error CS8166: Cannot return a parameter by reference 't' because it is not a ref parameter + // static ref readonly T F7(out T t) { t = default; return ref t; } // 5 + Diagnostic(ErrorCode.ERR_RefReturnParameter, "t").WithArguments("t").WithLocation(9, 68)); + } + + [Fact] + public void RefReturn_Ref() + { + var source = +@"ref struct S +{ + public ref T F; + public ref T F1() => ref F; + public ref readonly T F2() => ref F; +} +class Program +{ + static ref T F3(S s) => ref s.F; + static ref T F4(ref S s) => ref s.F; + static ref T F5(out S s) { s = default; return ref s.F; } + static ref T F6(in S s) => ref s.F; + static ref readonly T F7(S s) => ref s.F; + static ref readonly T F8(ref S s) => ref s.F; + static ref readonly T F9(out S s) { s = default; return ref s.F; } + static ref readonly T F10(in S s) => ref s.F; +}"; + var comp = CreateCompilation(source, runtimeFeature: RuntimeFlag.ByRefFields); + comp.VerifyEmitDiagnostics(); + } + + [Fact] + public void RefReturn_RefReadonly() + { + var source = +@"ref struct S +{ + public ref readonly T F; + public ref T F1() => ref F; + public ref readonly T F2() => ref F; +} +class Program +{ + static ref T F3(S s) => ref s.F; + static ref T F4(ref S s) => ref s.F; + static ref T F5(out S s) { s = default; return ref s.F; } + static ref T F6(in S s) => ref s.F; + static ref readonly T F7(S s) => ref s.F; + static ref readonly T F8(ref S s) => ref s.F; + static ref readonly T F9(out S s) { s = default; return ref s.F; } + static ref readonly T F10(in S s) => ref s.F; +}"; + var comp = CreateCompilation(source, runtimeFeature: RuntimeFlag.ByRefFields); + comp.VerifyEmitDiagnostics( + // (4,30): error CS8333: Cannot return field 'S.F' by writable reference because it is a readonly variable + // public ref T F1() => ref F; + Diagnostic(ErrorCode.ERR_RefReturnReadonlyNotField, "F").WithArguments("field", "S.F").WithLocation(4, 30), + // (9,39): error CS8333: Cannot return field 'S.F' by writable reference because it is a readonly variable + // static ref T F3(S s) => ref s.F; + Diagnostic(ErrorCode.ERR_RefReturnReadonlyNotField, "s.F").WithArguments("field", "S.F").WithLocation(9, 39), + // (10,43): error CS8333: Cannot return field 'S.F' by writable reference because it is a readonly variable + // static ref T F4(ref S s) => ref s.F; + Diagnostic(ErrorCode.ERR_RefReturnReadonlyNotField, "s.F").WithArguments("field", "S.F").WithLocation(10, 43), + // (11,62): error CS8333: Cannot return field 'S.F' by writable reference because it is a readonly variable + // static ref T F5(out S s) { s = default; return ref s.F; } + Diagnostic(ErrorCode.ERR_RefReturnReadonlyNotField, "s.F").WithArguments("field", "S.F").WithLocation(11, 62), + // (12,42): error CS8333: Cannot return field 'S.F' by writable reference because it is a readonly variable + // static ref T F6(in S s) => ref s.F; + Diagnostic(ErrorCode.ERR_RefReturnReadonlyNotField, "s.F").WithArguments("field", "S.F").WithLocation(12, 42)); + } + + [Fact] + public void RefReturn_ReadonlyRef() + { + var source = +@"ref struct S +{ + public readonly ref T F; + public ref T F1() => ref F; + public ref readonly T F2() => ref F; +} +class Program +{ + static ref T F3(S s) => ref s.F; + static ref T F4(ref S s) => ref s.F; + static ref T F5(out S s) { s = default; return ref s.F; } + static ref T F6(in S s) => ref s.F; + static ref readonly T F7(S s) => ref s.F; + static ref readonly T F8(ref S s) => ref s.F; + static ref readonly T F9(out S s) { s = default; return ref s.F; } + static ref readonly T F10(in S s) => ref s.F; +}"; + var comp = CreateCompilation(source, runtimeFeature: RuntimeFlag.ByRefFields); + comp.VerifyEmitDiagnostics(); + } + + [Fact] + public void RefReturn_ReadonlyRefReadonly() + { + var source = +@"ref struct S +{ + public readonly ref readonly T F; + public ref T F1() => ref F; + public ref readonly T F2() => ref F; +} +class Program +{ + static ref T F3(S s) => ref s.F; + static ref T F4(ref S s) => ref s.F; + static ref T F5(out S s) { s = default; return ref s.F; } + static ref T F6(in S s) => ref s.F; + static ref readonly T F7(S s) => ref s.F; + static ref readonly T F8(ref S s) => ref s.F; + static ref readonly T F9(out S s) { s = default; return ref s.F; } + static ref readonly T F10(in S s) => ref s.F; +}"; + var comp = CreateCompilation(source, runtimeFeature: RuntimeFlag.ByRefFields); + comp.VerifyEmitDiagnostics( + // (4,30): error CS8333: Cannot return field 'S.F' by writable reference because it is a readonly variable + // public ref T F1() => ref F; + Diagnostic(ErrorCode.ERR_RefReturnReadonlyNotField, "F").WithArguments("field", "S.F").WithLocation(4, 30), + // (9,39): error CS8333: Cannot return field 'S.F' by writable reference because it is a readonly variable + // static ref T F3(S s) => ref s.F; + Diagnostic(ErrorCode.ERR_RefReturnReadonlyNotField, "s.F").WithArguments("field", "S.F").WithLocation(9, 39), + // (10,43): error CS8333: Cannot return field 'S.F' by writable reference because it is a readonly variable + // static ref T F4(ref S s) => ref s.F; + Diagnostic(ErrorCode.ERR_RefReturnReadonlyNotField, "s.F").WithArguments("field", "S.F").WithLocation(10, 43), + // (11,62): error CS8333: Cannot return field 'S.F' by writable reference because it is a readonly variable + // static ref T F5(out S s) { s = default; return ref s.F; } + Diagnostic(ErrorCode.ERR_RefReturnReadonlyNotField, "s.F").WithArguments("field", "S.F").WithLocation(11, 62), + // (12,42): error CS8333: Cannot return field 'S.F' by writable reference because it is a readonly variable + // static ref T F6(in S s) => ref s.F; + Diagnostic(ErrorCode.ERR_RefReturnReadonlyNotField, "s.F").WithArguments("field", "S.F").WithLocation(12, 42)); + } + + [Fact] + public void RefParameter_InstanceMethod_Ref() + { + var source = +@"ref struct S +{ + public ref T F; + public S(ref T t) + { + F = ref t; + M1(F); + M2(ref F); + M3(out F); + M4(F); + M4(in F); + } + object P + { + init + { + M1(F); + M2(ref F); + M3(out F); + M4(F); + M4(in F); + } + } + void M() + { + M1(F); + M2(ref F); + M3(out F); + M4(F); + M4(in F); + } + static void M1(T t) { } + static void M2(ref T t) { } + static void M3(out T t) { t = default; } + static void M4(in T t) { } +}"; + var comp = CreateCompilation(new[] { source, IsExternalInitTypeDefinition }, runtimeFeature: RuntimeFlag.ByRefFields); + comp.VerifyEmitDiagnostics(); + } + + [Fact] + public void RefParameter_InstanceMethod_RefReadonly() + { + var source = +@"ref struct S +{ + public ref readonly T F; + public S(ref T t) + { + F = ref t; + M1(F); + M2(ref F); // 1 + M3(out F); // 2 + M4(F); + M4(in F); + } + object P + { + init + { + M1(F); + M2(ref F); // 3 + M3(out F); // 4 + M4(F); + M4(in F); + } + } + void M() + { + M1(F); + M2(ref F); // 5 + M3(out F); // 6 + M4(F); + M4(in F); + } + static void M1(T t) { } + static void M2(ref T t) { } + static void M3(out T t) { t = default; } + static void M4(in T t) { } +}"; + var comp = CreateCompilation(new[] { source, IsExternalInitTypeDefinition }, runtimeFeature: RuntimeFlag.ByRefFields); + comp.VerifyEmitDiagnostics( + // (8,16): error CS8329: Cannot use field 'S.F' as a ref or out value because it is a readonly variable + // M2(ref F); // 1 + Diagnostic(ErrorCode.ERR_RefReadonlyNotField, "F").WithArguments("field", "S.F").WithLocation(8, 16), + // (9,16): error CS8329: Cannot use field 'S.F' as a ref or out value because it is a readonly variable + // M3(out F); // 2 + Diagnostic(ErrorCode.ERR_RefReadonlyNotField, "F").WithArguments("field", "S.F").WithLocation(9, 16), + // (18,20): error CS8329: Cannot use field 'S.F' as a ref or out value because it is a readonly variable + // M2(ref F); // 3 + Diagnostic(ErrorCode.ERR_RefReadonlyNotField, "F").WithArguments("field", "S.F").WithLocation(18, 20), + // (19,20): error CS8329: Cannot use field 'S.F' as a ref or out value because it is a readonly variable + // M3(out F); // 4 + Diagnostic(ErrorCode.ERR_RefReadonlyNotField, "F").WithArguments("field", "S.F").WithLocation(19, 20), + // (27,16): error CS8329: Cannot use field 'S.F' as a ref or out value because it is a readonly variable + // M2(ref F); // 5 + Diagnostic(ErrorCode.ERR_RefReadonlyNotField, "F").WithArguments("field", "S.F").WithLocation(27, 16), + // (28,16): error CS8329: Cannot use field 'S.F' as a ref or out value because it is a readonly variable + // M3(out F); // 6 + Diagnostic(ErrorCode.ERR_RefReadonlyNotField, "F").WithArguments("field", "S.F").WithLocation(28, 16)); + } + + [Fact] + public void RefParameter_InstanceMethod_ReadonlyRef() + { + var source = +@"ref struct S +{ + public readonly ref T F; + public S(ref T t) + { + F = ref t; + M1(F); + M2(ref F); + M3(out F); + M4(F); + M4(in F); + } + object P + { + init + { + M1(F); + M2(ref F); + M3(out F); + M4(F); + M4(in F); + } + } + void M() + { + M1(F); + M2(ref F); + M3(out F); + M4(F); + M4(in F); + } + static void M1(T t) { } + static void M2(ref T t) { } + static void M3(out T t) { t = default; } + static void M4(in T t) { } +}"; + var comp = CreateCompilation(new[] { source, IsExternalInitTypeDefinition }, runtimeFeature: RuntimeFlag.ByRefFields); + comp.VerifyEmitDiagnostics(); + } + + [Fact] + public void RefParameter_InstanceMethod_ReadonlyRefReadonly() + { + var source = +@"ref struct S +{ + public readonly ref readonly T F; + public S(ref T t) + { + F = ref t; + M1(F); + M2(ref F); // 1 + M3(out F); // 2 + M4(F); + M4(in F); + } + object P + { + init + { + M1(F); + M2(ref F); // 3 + M3(out F); // 4 + M4(F); + M4(in F); + } + } + void M() + { + M1(F); + M2(ref F); // 5 + M3(out F); // 6 + M4(F); + M4(in F); + } + static void M1(T t) { } + static void M2(ref T t) { } + static void M3(out T t) { t = default; } + static void M4(in T t) { } +}"; + var comp = CreateCompilation(new[] { source, IsExternalInitTypeDefinition }, runtimeFeature: RuntimeFlag.ByRefFields); + comp.VerifyEmitDiagnostics( + // (8,16): error CS8329: Cannot use field 'S.F' as a ref or out value because it is a readonly variable + // M2(ref F); // 1 + Diagnostic(ErrorCode.ERR_RefReadonlyNotField, "F").WithArguments("field", "S.F").WithLocation(8, 16), + // (9,16): error CS8329: Cannot use field 'S.F' as a ref or out value because it is a readonly variable + // M3(out F); // 2 + Diagnostic(ErrorCode.ERR_RefReadonlyNotField, "F").WithArguments("field", "S.F").WithLocation(9, 16), + // (18,20): error CS8329: Cannot use field 'S.F' as a ref or out value because it is a readonly variable + // M2(ref F); // 3 + Diagnostic(ErrorCode.ERR_RefReadonlyNotField, "F").WithArguments("field", "S.F").WithLocation(18, 20), + // (19,20): error CS8329: Cannot use field 'S.F' as a ref or out value because it is a readonly variable + // M3(out F); // 4 + Diagnostic(ErrorCode.ERR_RefReadonlyNotField, "F").WithArguments("field", "S.F").WithLocation(19, 20), + // (27,16): error CS8329: Cannot use field 'S.F' as a ref or out value because it is a readonly variable + // M2(ref F); // 5 + Diagnostic(ErrorCode.ERR_RefReadonlyNotField, "F").WithArguments("field", "S.F").WithLocation(27, 16), + // (28,16): error CS8329: Cannot use field 'S.F' as a ref or out value because it is a readonly variable + // M3(out F); // 6 + Diagnostic(ErrorCode.ERR_RefReadonlyNotField, "F").WithArguments("field", "S.F").WithLocation(28, 16)); + } + + [Fact] + public void RefParameter_Ref() + { + var source = +@"ref struct S +{ + public ref T F; +} + +class Program +{ + static void M1(T t) { } + static void M2(ref T t) { } + static void M3(out T t) { t = default; } + static void M4(in T t) { } + + static void FromValue1(S s) { M1(s.F); } + static void FromValue2(S s) { M2(ref s.F); } + static void FromValue3(S s) { M3(out s.F); } + static void FromValue4A(S s) { M4(in s.F); } + static void FromValue4B(S s) { M4(s.F); } + + static void FromRef1(ref S s) { M1(s.F); } + static void FromRef2(ref S s) { M2(ref s.F); } + static void FromRef3(ref S s) { M3(out s.F); } + static void FromRef4A(ref S s) { M4(in s.F); } + static void FromRef4B(ref S s) { M4(s.F); } + + static void FromOut1(out S s) { s = default; M1(s.F); } + static void FromOut2(out S s) { s = default; M2(ref s.F); } + static void FromOut3(out S s) { s = default; M3(out s.F); } + static void FromOut4A(out S s) { s = default; M4(in s.F); } + static void FromOut4B(out S s) { s = default; M4(s.F); } + + static void FromIn1(in S s) { M1(s.F); } + static void FromIn2(in S s) { M2(ref s.F); } + static void FromIn3(in S s) { M3(out s.F); } + static void FromIn4A(in S s) { M4(in s.F); } + static void FromIn4B(in S s) { M4(s.F); } +}"; + var comp = CreateCompilation(source, runtimeFeature: RuntimeFlag.ByRefFields); + comp.VerifyEmitDiagnostics(); + } + + [Fact] + public void RefParameter_RefReadonly() + { + var source = +@"ref struct S +{ + public ref readonly T F; +} + +class Program +{ + static void M1(T t) { } + static void M2(ref T t) { } + static void M3(out T t) { t = default; } + static void M4(in T t) { } + + static void FromValue1(S s) { M1(s.F); } + static void FromValue2(S s) { M2(ref s.F); } // 1 + static void FromValue3(S s) { M3(out s.F); } // 2 + static void FromValue4A(S s) { M4(in s.F); } + static void FromValue4B(S s) { M4(s.F); } + + static void FromRef1(ref S s) { M1(s.F); } + static void FromRef2(ref S s) { M2(ref s.F); } // 3 + static void FromRef3(ref S s) { M3(out s.F); } // 4 + static void FromRef4A(ref S s) { M4(in s.F); } + static void FromRef4B(ref S s) { M4(s.F); } + + static void FromOut1(out S s) { s = default; M1(s.F); } + static void FromOut2(out S s) { s = default; M2(ref s.F); } // 5 + static void FromOut3(out S s) { s = default; M3(out s.F); } // 6 + static void FromOut4A(out S s) { s = default; M4(in s.F); } + static void FromOut4B(out S s) { s = default; M4(s.F); } + + static void FromIn1(in S s) { M1(s.F); } + static void FromIn2(in S s) { M2(ref s.F); } // 7 + static void FromIn3(in S s) { M3(out s.F); } // 8 + static void FromIn4A(in S s) { M4(in s.F); } + static void FromIn4B(in S s) { M4(s.F); } +}"; + var comp = CreateCompilation(source, runtimeFeature: RuntimeFlag.ByRefFields); + comp.VerifyEmitDiagnostics( + // (14,49): error CS8329: Cannot use field 'S.F' as a ref or out value because it is a readonly variable + // static void FromValue2(S s) { M2(ref s.F); } // 1 + Diagnostic(ErrorCode.ERR_RefReadonlyNotField, "s.F").WithArguments("field", "S.F").WithLocation(14, 49), + // (15,49): error CS8329: Cannot use field 'S.F' as a ref or out value because it is a readonly variable + // static void FromValue3(S s) { M3(out s.F); } // 2 + Diagnostic(ErrorCode.ERR_RefReadonlyNotField, "s.F").WithArguments("field", "S.F").WithLocation(15, 49), + // (20,51): error CS8329: Cannot use field 'S.F' as a ref or out value because it is a readonly variable + // static void FromRef2(ref S s) { M2(ref s.F); } // 3 + Diagnostic(ErrorCode.ERR_RefReadonlyNotField, "s.F").WithArguments("field", "S.F").WithLocation(20, 51), + // (21,51): error CS8329: Cannot use field 'S.F' as a ref or out value because it is a readonly variable + // static void FromRef3(ref S s) { M3(out s.F); } // 4 + Diagnostic(ErrorCode.ERR_RefReadonlyNotField, "s.F").WithArguments("field", "S.F").WithLocation(21, 51), + // (26,64): error CS8329: Cannot use field 'S.F' as a ref or out value because it is a readonly variable + // static void FromOut2(out S s) { s = default; M2(ref s.F); } // 5 + Diagnostic(ErrorCode.ERR_RefReadonlyNotField, "s.F").WithArguments("field", "S.F").WithLocation(26, 64), + // (27,64): error CS8329: Cannot use field 'S.F' as a ref or out value because it is a readonly variable + // static void FromOut3(out S s) { s = default; M3(out s.F); } // 6 + Diagnostic(ErrorCode.ERR_RefReadonlyNotField, "s.F").WithArguments("field", "S.F").WithLocation(27, 64), + // (32,49): error CS8329: Cannot use field 'S.F' as a ref or out value because it is a readonly variable + // static void FromIn2(in S s) { M2(ref s.F); } // 7 + Diagnostic(ErrorCode.ERR_RefReadonlyNotField, "s.F").WithArguments("field", "S.F").WithLocation(32, 49), + // (33,49): error CS8329: Cannot use field 'S.F' as a ref or out value because it is a readonly variable + // static void FromIn3(in S s) { M3(out s.F); } // 8 + Diagnostic(ErrorCode.ERR_RefReadonlyNotField, "s.F").WithArguments("field", "S.F").WithLocation(33, 49)); + } + + [Fact] + public void RefParameter_ReadonlyRef() + { + var source = +@"ref struct S +{ + public readonly ref T F; +} + +class Program +{ + static void M1(T t) { } + static void M2(ref T t) { } + static void M3(out T t) { t = default; } + static void M4(in T t) { } + + static void FromValue1(S s) { M1(s.F); } + static void FromValue2(S s) { M2(ref s.F); } + static void FromValue3(S s) { M3(out s.F); } + static void FromValue4A(S s) { M4(in s.F); } + static void FromValue4B(S s) { M4(s.F); } + + static void FromRef1(ref S s) { M1(s.F); } + static void FromRef2(ref S s) { M2(ref s.F); } + static void FromRef3(ref S s) { M3(out s.F); } + static void FromRef4A(ref S s) { M4(in s.F); } + static void FromRef4B(ref S s) { M4(s.F); } + + static void FromOut1(out S s) { s = default; M1(s.F); } + static void FromOut2(out S s) { s = default; M2(ref s.F); } + static void FromOut3(out S s) { s = default; M3(out s.F); } + static void FromOut4A(out S s) { s = default; M4(in s.F); } + static void FromOut4B(out S s) { s = default; M4(s.F); } + + static void FromIn1(in S s) { M1(s.F); } + static void FromIn2(in S s) { M2(ref s.F); } + static void FromIn3(in S s) { M3(out s.F); } + static void FromIn4A(in S s) { M4(in s.F); } + static void FromIn4B(in S s) { M4(s.F); } +}"; + var comp = CreateCompilation(source, runtimeFeature: RuntimeFlag.ByRefFields); + comp.VerifyEmitDiagnostics(); + } + + [Fact] + public void RefParameter_ReadonlyRefReadonly() + { + var source = +@"ref struct S +{ + public readonly ref readonly T F; +} + +class Program +{ + static void M1(T t) { } + static void M2(ref T t) { } + static void M3(out T t) { t = default; } + static void M4(in T t) { } + + static void FromValue1(S s) { M1(s.F); } + static void FromValue2(S s) { M2(ref s.F); } // 1 + static void FromValue3(S s) { M3(out s.F); } // 2 + static void FromValue4A(S s) { M4(in s.F); } + static void FromValue4B(S s) { M4(s.F); } + + static void FromRef1(ref S s) { M1(s.F); } + static void FromRef2(ref S s) { M2(ref s.F); } // 3 + static void FromRef3(ref S s) { M3(out s.F); } // 4 + static void FromRef4A(ref S s) { M4(in s.F); } + static void FromRef4B(ref S s) { M4(s.F); } + + static void FromOut1(out S s) { s = default; M1(s.F); } + static void FromOut2(out S s) { s = default; M2(ref s.F); } // 5 + static void FromOut3(out S s) { s = default; M3(out s.F); } // 6 + static void FromOut4A(out S s) { s = default; M4(in s.F); } + static void FromOut4B(out S s) { s = default; M4(s.F); } + + static void FromIn1(in S s) { M1(s.F); } + static void FromIn2(in S s) { M2(ref s.F); } // 7 + static void FromIn3(in S s) { M3(out s.F); } // 8 + static void FromIn4A(in S s) { M4(in s.F); } + static void FromIn4B(in S s) { M4(s.F); } +}"; + var comp = CreateCompilation(source, runtimeFeature: RuntimeFlag.ByRefFields); + comp.VerifyEmitDiagnostics( + // (14,49): error CS8329: Cannot use field 'S.F' as a ref or out value because it is a readonly variable + // static void FromValue2(S s) { M2(ref s.F); } // 1 + Diagnostic(ErrorCode.ERR_RefReadonlyNotField, "s.F").WithArguments("field", "S.F").WithLocation(14, 49), + // (15,49): error CS8329: Cannot use field 'S.F' as a ref or out value because it is a readonly variable + // static void FromValue3(S s) { M3(out s.F); } // 2 + Diagnostic(ErrorCode.ERR_RefReadonlyNotField, "s.F").WithArguments("field", "S.F").WithLocation(15, 49), + // (20,51): error CS8329: Cannot use field 'S.F' as a ref or out value because it is a readonly variable + // static void FromRef2(ref S s) { M2(ref s.F); } // 3 + Diagnostic(ErrorCode.ERR_RefReadonlyNotField, "s.F").WithArguments("field", "S.F").WithLocation(20, 51), + // (21,51): error CS8329: Cannot use field 'S.F' as a ref or out value because it is a readonly variable + // static void FromRef3(ref S s) { M3(out s.F); } // 4 + Diagnostic(ErrorCode.ERR_RefReadonlyNotField, "s.F").WithArguments("field", "S.F").WithLocation(21, 51), + // (26,64): error CS8329: Cannot use field 'S.F' as a ref or out value because it is a readonly variable + // static void FromOut2(out S s) { s = default; M2(ref s.F); } // 5 + Diagnostic(ErrorCode.ERR_RefReadonlyNotField, "s.F").WithArguments("field", "S.F").WithLocation(26, 64), + // (27,64): error CS8329: Cannot use field 'S.F' as a ref or out value because it is a readonly variable + // static void FromOut3(out S s) { s = default; M3(out s.F); } // 6 + Diagnostic(ErrorCode.ERR_RefReadonlyNotField, "s.F").WithArguments("field", "S.F").WithLocation(27, 64), + // (32,49): error CS8329: Cannot use field 'S.F' as a ref or out value because it is a readonly variable + // static void FromIn2(in S s) { M2(ref s.F); } // 7 + Diagnostic(ErrorCode.ERR_RefReadonlyNotField, "s.F").WithArguments("field", "S.F").WithLocation(32, 49), + // (33,49): error CS8329: Cannot use field 'S.F' as a ref or out value because it is a readonly variable + // static void FromIn3(in S s) { M3(out s.F); } // 8 + Diagnostic(ErrorCode.ERR_RefReadonlyNotField, "s.F").WithArguments("field", "S.F").WithLocation(33, 49)); + } + + [Fact] + public void RefParameter_ReadonlyRefReadonly_PEVerifyCompat() + { + var source = +@"#pragma warning disable 649 +ref struct S +{ + public readonly ref readonly T F; +} + +class Program +{ + static void M1(T t) { } + static void M4(in T t) { } + + static void FromValue1(S s) { M1(s.F); } + static void FromValue4A(S s) { M4(in s.F); } + static void FromValue4B(S s) { M4(s.F); } + + static void FromRef1(ref S s) { M1(s.F); } + static void FromRef4A(ref S s) { M4(in s.F); } + static void FromRef4B(ref S s) { M4(s.F); } + + static void FromOut1(out S s) { s = default; M1(s.F); } + static void FromOut4A(out S s) { s = default; M4(in s.F); } + static void FromOut4B(out S s) { s = default; M4(s.F); } + + static void FromIn1(in S s) { M1(s.F); } + static void FromIn4A(in S s) { M4(in s.F); } + static void FromIn4B(in S s) { M4(s.F); } +}"; + var comp = CreateCompilation(source, parseOptions: TestOptions.RegularPreview.WithFeature("peverify-compat"), runtimeFeature: RuntimeFlag.ByRefFields); + comp.VerifyEmitDiagnostics(); + } + + [Fact] + public void InitobjField() + { + var source = +@"using System; +struct S +{ + public T F; +} +ref struct R +{ + public ref S S; +} +class Program +{ + static void Main() + { + var s = new S(); + scoped var r = new R(); + r.S = ref s; + NewField(ref r); + r.S.F = 42; + Console.WriteLine(s.F); + Console.WriteLine(r.S.F); + } + static void NewField(ref R r) + { + r.S = new S(); + } +}"; + var comp = CreateCompilation(source, options: TestOptions.ReleaseExe, runtimeFeature: RuntimeFlag.ByRefFields); + var verifier = CompileAndVerify(comp, verify: Verification.Skipped, expectedOutput: IncludeExpectedOutput( +@"42 +42 +")); + verifier.VerifyIL("Program.NewField", +@"{ + // Code size 13 (0xd) + .maxstack 1 + IL_0000: ldarg.0 + IL_0001: ldfld ""ref S R.S"" + IL_0006: initobj ""S"" + IL_000c: ret +}"); + } + + [Fact] + public void ReadWriteField() + { + var source = +@"using System; +ref struct S +{ + public ref T F; + public S(ref T t) { F = ref t; } +} +class Program +{ + static void Main() + { + int x = 1; + scoped var s = new S(); + s.F = ref x; + Write(s, 42); + Console.WriteLine(Read(s)); + Console.WriteLine(x); + } + static int Read(S s) + { + return s.F; + } + static void Write(S s, int value) + { + s.F = value; + } +}"; + var comp = CreateCompilation(source, options: TestOptions.ReleaseExe, runtimeFeature: RuntimeFlag.ByRefFields); + var verifier = CompileAndVerify(comp, verify: Verification.Skipped, expectedOutput: IncludeExpectedOutput( +@"42 +42 +")); + verifier.VerifyIL("S..ctor(ref T)", +@"{ + // Code size 8 (0x8) + .maxstack 2 + IL_0000: ldarg.0 + IL_0001: ldarg.1 + IL_0002: stfld ""ref T S.F"" + IL_0007: ret +}"); + verifier.VerifyIL("Program.Read", +@"{ + // Code size 8 (0x8) + .maxstack 1 + IL_0000: ldarg.0 + IL_0001: ldfld ""ref int S.F"" + IL_0006: ldind.i4 + IL_0007: ret +}"); + verifier.VerifyIL("Program.Write", +@"{ + // Code size 9 (0x9) + .maxstack 2 + IL_0000: ldarg.0 + IL_0001: ldfld ""ref int S.F"" + IL_0006: ldarg.1 + IL_0007: stind.i4 + IL_0008: ret +}"); + } + + [Fact] + public void ReadWriteNestedField() + { + var source = +@"using System; +using System.Diagnostics.CodeAnalysis; +ref struct R1 +{ + public ref T F; + public R1(ref T t) { F = ref t; } +} +ref struct R2 +{ + public ref R1 R1; + public R2([UnscopedRef] ref R1 r1) { R1 = ref r1; } +} +class Program +{ + static void Main() + { + int i = 0; + var r1 = new R1(ref i); + var r2 = new R2(ref r1); + r2.R1.F = 42; + Console.WriteLine(Read(r2)); + Console.WriteLine(ReadIn(r2)); + Console.WriteLine(i); + } + static T Read(R2 r2) + { + return r2.R1.F; + } + static T ReadIn(in R2 r2In) + { + return r2In.R1.F; + } +}"; + var comp = CreateCompilation(new[] { source, UnscopedRefAttributeDefinition }, runtimeFeature: RuntimeFlag.ByRefFields); + comp.VerifyEmitDiagnostics( + // (10,12): error CS9050: A ref field cannot refer to a ref struct. + // public ref R1 R1 + Diagnostic(ErrorCode.ERR_RefFieldCannotReferToRefStruct, "ref R1").WithLocation(10, 12)); + } + + [Fact] + public void ReadWriteFieldWithTemp() + { + var source = +@"ref struct S +{ + public ref T F; + private int _other; + public S(int other) : this() { _other = other; } +} +class Program +{ + static T ReadWrite1(ref T t) + { + return new S().F = ref t; + } + static T ReadWrite2(ref T t) + { + return new S(1).F = ref t; + } +}"; + var comp = CreateCompilation(source, runtimeFeature: RuntimeFlag.ByRefFields); + comp.VerifyDiagnostics( + // (11,16): error CS0131: The left-hand side of an assignment must be a variable, property or indexer + // return new S().F = ref t; + Diagnostic(ErrorCode.ERR_AssgLvalueExpected, "new S().F").WithLocation(11, 16), + // (15,16): error CS0131: The left-hand side of an assignment must be a variable, property or indexer + // return new S(1).F = ref t; + Diagnostic(ErrorCode.ERR_AssgLvalueExpected, "new S(1).F").WithLocation(15, 16)); + } + + [WorkItem(62122, "https://github.com/dotnet/roslyn/issues/62122")] + [Fact] + public void ReadAndDiscard() + { + var source = +@"using System; +ref struct S +{ + public ref T F; + public S(ref T t) { F = ref t; } +} +class Program +{ + static void Main() + { + int i = 1; + Try(() => ReadAndDiscard1(ref i)); + Try(() => ReadAndDiscardNoArg()); + Try(() => ReadAndDiscard2(new S(ref i))); + + void Try(Action a) + { + try + { + a(); + } + catch (NullReferenceException) + { + System.Console.WriteLine(""NullReferenceException""); + } + } + } + static void ReadAndDiscard1(ref T t) + { + _ = new S(ref t).F; + } + static void ReadAndDiscardNoArg() + { + _ = new S().F; + } + static void ReadAndDiscard2(in S s) + { + _ = s.F; + } +}"; + var comp = CreateCompilation(source, options: TestOptions.ReleaseExe, runtimeFeature: RuntimeFlag.ByRefFields); + var verifier = CompileAndVerify(comp, verify: Verification.Skipped, expectedOutput: IncludeExpectedOutput("NullReferenceException")); + verifier.VerifyIL("Program.ReadAndDiscard1", """ +{ + // Code size 18 (0x12) + .maxstack 1 + IL_0000: ldarg.0 + IL_0001: newobj "S..ctor(ref T)" + IL_0006: ldfld "ref T S.F" + IL_000b: ldobj "T" + IL_0010: pop + IL_0011: ret +} +"""); + verifier.VerifyIL("Program.ReadAndDiscardNoArg", """ +{ + // Code size 21 (0x15) + .maxstack 1 + .locals init (S V_0) + IL_0000: ldloca.s V_0 + IL_0002: initobj "S" + IL_0008: ldloc.0 + IL_0009: ldfld "ref T S.F" + IL_000e: ldobj "T" + IL_0013: pop + IL_0014: ret +} +"""); + verifier.VerifyIL("Program.ReadAndDiscard2", """ +{ + // Code size 13 (0xd) + .maxstack 1 + IL_0000: ldarg.0 + IL_0001: ldfld "ref T S.F" + IL_0006: ldobj "T" + IL_000b: pop + IL_000c: ret +} +"""); + } + + [Fact] + public void RefReturn_ByValueArg() + { + var source = +@"using System; +ref struct S +{ + public ref T F; + public S(ref T t) { F = ref t; } +} +class Program +{ + static void Main() + { + int i = 1; + var s = new S(ref i); + RefReturn(s) = 2; + i = RefReadonlyReturn(s); + Console.WriteLine(i); + } + static ref T RefReturn(S s) => ref s.F; + static ref readonly T RefReadonlyReturn(S s) => ref s.F; +}"; + var comp = CreateCompilation(source, options: TestOptions.ReleaseExe, runtimeFeature: RuntimeFlag.ByRefFields); + var verifier = CompileAndVerify(comp, verify: Verification.Skipped, expectedOutput: IncludeExpectedOutput("2")); + var expectedIL = +@"{ + // Code size 8 (0x8) + .maxstack 1 + IL_0000: ldarga.s V_0 + IL_0002: ldfld ""ref T S.F"" + IL_0007: ret +}"; + verifier.VerifyIL("Program.RefReturn", expectedIL); + verifier.VerifyIL("Program.RefReadonlyReturn", expectedIL); + } + + [Fact] + public void RefReturn_RefArg() + { + var source = +@"using System; +ref struct S +{ + public ref T F; + public S(ref T t) { F = ref t; } +} +class Program +{ + static void Main() + { + int i = 1; + var s = new S(ref i); + RefReturn(ref s) = 2; + i = RefReadonlyReturn(ref s); + Console.WriteLine(i); + } + static ref T RefReturn(ref S s) => ref s.F; + static ref readonly T RefReadonlyReturn(ref S s) => ref s.F; +}"; + var comp = CreateCompilation(source, options: TestOptions.ReleaseExe, runtimeFeature: RuntimeFlag.ByRefFields); + var verifier = CompileAndVerify(comp, verify: Verification.Skipped, expectedOutput: IncludeExpectedOutput("2")); + var expectedIL = +@"{ + // Code size 7 (0x7) + .maxstack 1 + IL_0000: ldarg.0 + IL_0001: ldfld ""ref T S.F"" + IL_0006: ret +}"; + verifier.VerifyIL("Program.RefReturn", expectedIL); + verifier.VerifyIL("Program.RefReadonlyReturn", expectedIL); + } + + [Fact] + public void RefReturn_InArg() + { + var source = +@"using System; +ref struct S +{ + public ref T F; + public S(ref T t) { F = ref t; } +} +class Program +{ + static void Main() + { + int i = 1; + var s = new S(ref i); + RefReturn(s) = 2; + i = RefReadonlyReturn(s); + Console.WriteLine(i); + } + static ref T RefReturn(in S s) => ref s.F; + static ref readonly T RefReadonlyReturn(in S s) => ref s.F; +}"; + var comp = CreateCompilation(source, options: TestOptions.ReleaseExe, runtimeFeature: RuntimeFlag.ByRefFields); + var verifier = CompileAndVerify(comp, verify: Verification.Skipped, expectedOutput: IncludeExpectedOutput("2")); + var expectedIL = +@"{ + // Code size 7 (0x7) + .maxstack 1 + IL_0000: ldarg.0 + IL_0001: ldfld ""ref T S.F"" + IL_0006: ret +}"; + verifier.VerifyIL("Program.RefReturn", expectedIL); + verifier.VerifyIL("Program.RefReadonlyReturn", expectedIL); + } + + [Fact] + public void RefReturn_OutArg() + { + var source = +@"using System; +ref struct S +{ + public ref T F; + public S(ref T t) { F = ref t; } +} +class Program +{ + static void Main() + { + int i = 1; + scoped S s; + RefReturn(out s, ref i) = 2; + i = RefReadonlyReturn(out s, ref i); + Console.WriteLine(i); + } + static ref T RefReturn(out S s, ref T t) + { + s = new S(ref t); + return ref s.F; + } + static ref readonly T RefReadonlyReturn(out S s, ref T t) + { + s = new S(ref t); + return ref s.F; + } +}"; + var comp = CreateCompilation(source, options: TestOptions.ReleaseExe, runtimeFeature: RuntimeFlag.ByRefFields); + var verifier = CompileAndVerify(comp, verify: Verification.Skipped, expectedOutput: IncludeExpectedOutput("2")); + var expectedIL = +@"{ + // Code size 19 (0x13) + .maxstack 2 + IL_0000: ldarg.0 + IL_0001: ldarg.1 + IL_0002: newobj ""S..ctor(ref T)"" + IL_0007: stobj ""S"" + IL_000c: ldarg.0 + IL_000d: ldfld ""ref T S.F"" + IL_0012: ret +}"; + verifier.VerifyIL("Program.RefReturn", expectedIL); + verifier.VerifyIL("Program.RefReadonlyReturn", expectedIL); + } + + [Fact] + public void CompoundOperations_01() + { + var source = +@"using System; +ref struct S +{ + public ref T F; + public S(ref T t) { F = ref t; } +} +class Program +{ + static void Main() + { + int x = 42; + scoped var s = new S(ref x); + Increment(s); + Console.WriteLine(s.F); + Console.WriteLine(x); + Subtract(s, 10); + Console.WriteLine(s.F); + Console.WriteLine(x); + } + static void Increment(S s) + { + s.F++; + } + static void Subtract(S s, int offset) + { + s.F -= offset; + } +}"; + var comp = CreateCompilation(source, options: TestOptions.ReleaseExe, runtimeFeature: RuntimeFlag.ByRefFields); + var verifier = CompileAndVerify(comp, verify: Verification.Skipped, expectedOutput: IncludeExpectedOutput( +@"43 +43 +33 +33 +")); + verifier.VerifyIL("Program.Increment", +@"{ + // Code size 13 (0xd) + .maxstack 3 + IL_0000: ldarga.s V_0 + IL_0002: ldfld ""ref int S.F"" + IL_0007: dup + IL_0008: ldind.i4 + IL_0009: ldc.i4.1 + IL_000a: add + IL_000b: stind.i4 + IL_000c: ret +}"); + verifier.VerifyIL("Program.Subtract", +@"{ + // Code size 13 (0xd) + .maxstack 3 + IL_0000: ldarga.s V_0 + IL_0002: ldfld ""ref int S.F"" + IL_0007: dup + IL_0008: ldind.i4 + IL_0009: ldarg.1 + IL_000a: sub + IL_000b: stind.i4 + IL_000c: ret +}"); + } + + [Theory] + [InlineData("ref")] + [InlineData("readonly ref")] + public void CompoundOperations_02(string refKind) + { + var source = +$@"using System; +ref struct S +{{ + public {refKind} int F; + public S(ref int i) {{ F = ref i; }} + public void Increment() + {{ + F++; + }} + public void Subtract(int offset) + {{ + F -= offset; + }} +}} +class Program +{{ + static void Main() + {{ + int x = 42; + scoped var s = new S(ref x); + s.Increment(); + Console.WriteLine(s.F); + Console.WriteLine(x); + s.Subtract(10); + Console.WriteLine(s.F); + Console.WriteLine(x); + }} +}}"; + var comp = CreateCompilation(source, options: TestOptions.ReleaseExe, runtimeFeature: RuntimeFlag.ByRefFields); + var verifier = CompileAndVerify(comp, verify: Verification.Skipped, expectedOutput: IncludeExpectedOutput( +@"43 +43 +33 +33 +")); + verifier.VerifyIL("S.Increment", +@"{ + // Code size 17 (0x11) + .maxstack 3 + IL_0000: ldarg.0 + IL_0001: ldfld ""ref int S.F"" + IL_0006: ldarg.0 + IL_0007: ldfld ""ref int S.F"" + IL_000c: ldind.i4 + IL_000d: ldc.i4.1 + IL_000e: add + IL_000f: stind.i4 + IL_0010: ret +}"); + verifier.VerifyIL("S.Subtract", +@"{ + // Code size 17 (0x11) + .maxstack 3 + IL_0000: ldarg.0 + IL_0001: ldfld ""ref int S.F"" + IL_0006: ldarg.0 + IL_0007: ldfld ""ref int S.F"" + IL_000c: ldind.i4 + IL_000d: ldarg.1 + IL_000e: sub + IL_000f: stind.i4 + IL_0010: ret +}"); + } + + [Fact] + public void ConditionalOperator() + { + var source = +@"using System; +ref struct S +{ + public ref T F; + public S(ref T t) { F = ref t; } +} +class Program +{ + static void Main() + { + int x = 1; + int y = 2; + var sx = new S(ref x); + var sy = new S(ref y); + Console.WriteLine(ConditionalOperator(true, sx, sy)); + Console.WriteLine(ConditionalOperator(false, sx, sy)); + ConditionalOperatorRef(true, ref sx, ref sy) = 3; + ConditionalOperatorRef(false, ref sx, ref sy) = 4; + Console.WriteLine(x); + Console.WriteLine(y); + } + static T ConditionalOperator(bool b, S sx, S sy) + { + return b ? sx.F : sy.F; + } + static ref T ConditionalOperatorRef(bool b, ref S sx, ref S sy) + { + return ref b ? ref sx.F : ref sy.F; + } +}"; + var comp = CreateCompilation(source, options: TestOptions.ReleaseExe, runtimeFeature: RuntimeFlag.ByRefFields); + var verifier = CompileAndVerify(comp, verify: Verification.Skipped, expectedOutput: IncludeExpectedOutput( +@"1 +2 +3 +4 +")); + verifier.VerifyIL("Program.ConditionalOperator", +@"{ + // Code size 27 (0x1b) + .maxstack 1 + IL_0000: ldarg.0 + IL_0001: brtrue.s IL_000f + IL_0003: ldarg.2 + IL_0004: ldfld ""ref T S.F"" + IL_0009: ldobj ""T"" + IL_000e: ret + IL_000f: ldarg.1 + IL_0010: ldfld ""ref T S.F"" + IL_0015: ldobj ""T"" + IL_001a: ret +}"); + verifier.VerifyIL("Program.ConditionalOperatorRef", +@"{ + // Code size 17 (0x11) + .maxstack 1 + IL_0000: ldarg.0 + IL_0001: brtrue.s IL_000a + IL_0003: ldarg.2 + IL_0004: ldfld ""ref T S.F"" + IL_0009: ret + IL_000a: ldarg.1 + IL_000b: ldfld ""ref T S.F"" + IL_0010: ret +}"); + } + + [Fact] + public void ConditionalAccess() + { + var source = +@"using System; +ref struct S +{ + public ref T F; + public S(ref T t) { F = ref t; } +} +class Program +{ + static void Main() + { + object o = 1; + int i = 2; + var s1 = new S(ref o); + var s2 = new S(ref i); + Console.WriteLine(ConditionalAccess(s1)); + Console.WriteLine(ConditionalAccess(s2)); + } + static string ConditionalAccess(S s) + { + return s.F?.ToString(); + } +}"; + var comp = CreateCompilation(source, options: TestOptions.ReleaseExe, runtimeFeature: RuntimeFlag.ByRefFields); + var verifier = CompileAndVerify(comp, verify: Verification.Skipped, expectedOutput: IncludeExpectedOutput( +@"1 +2 +")); + verifier.VerifyIL("Program.ConditionalAccess", +@"{ + // Code size 54 (0x36) + .maxstack 2 + .locals init (T V_0) + IL_0000: ldarga.s V_0 + IL_0002: ldfld ""ref T S.F"" + IL_0007: ldloca.s V_0 + IL_0009: initobj ""T"" + IL_000f: ldloc.0 + IL_0010: box ""T"" + IL_0015: brtrue.s IL_002a + IL_0017: ldobj ""T"" + IL_001c: stloc.0 + IL_001d: ldloca.s V_0 + IL_001f: ldloc.0 + IL_0020: box ""T"" + IL_0025: brtrue.s IL_002a + IL_0027: pop + IL_0028: ldnull + IL_0029: ret + IL_002a: constrained. ""T"" + IL_0030: callvirt ""string object.ToString()"" + IL_0035: ret +}"); + } + + [Fact] + public void Deconstruct() + { + var source = +@"using System; +class Pair +{ + public readonly T First; + public readonly U Second; + public Pair(T first, U second) + { + First = first; + Second = second; + } + public void Deconstruct(out T first, out U second) + { + first = First; + second = Second; + } +} +ref struct S +{ + public ref T F; + public S(ref T t) { F = ref t; } +} +class Program +{ + static void Main() + { + int i = 0; + string s = null; + var s1 = new S(ref i); + var s2 = new S(ref s); + Deconstruct(new Pair(1, ""Hello world""), s1, s2); + Console.WriteLine((i, s)); + } + static void Deconstruct(Pair pair, S s1, S s2) + { + (s1.F, s2.F) = pair; + } +}"; + var references = TargetFrameworkUtil.GetReferences(TargetFramework.Standard, additionalReferences: null); + // Note: we use skipExtraValidation so that nobody pulls + // on the compilation or its references before we set the RuntimeSupportsByRefFields flag. + var comp = CreateEmptyCompilation(source, references: CopyWithoutSharingCachedSymbols(references), options: TestOptions.ReleaseExe, skipExtraValidation: true); + comp.Assembly.RuntimeSupportsByRefFields = true; + var verifier = CompileAndVerify(comp, verify: Verification.Skipped, expectedOutput: IncludeExpectedOutput(@"(1, Hello world)")); + verifier.VerifyIL("Program.Deconstruct", +@"{ + // Code size 39 (0x27) + .maxstack 4 + .locals init (T& V_0, + T V_1, + U V_2) + IL_0000: ldarga.s V_1 + IL_0002: ldfld ""ref T S.F"" + IL_0007: stloc.0 + IL_0008: ldarga.s V_2 + IL_000a: ldfld ""ref U S.F"" + IL_000f: ldarg.0 + IL_0010: ldloca.s V_1 + IL_0012: ldloca.s V_2 + IL_0014: callvirt ""void Pair.Deconstruct(out T, out U)"" + IL_0019: ldloc.0 + IL_001a: ldloc.1 + IL_001b: stobj ""T"" + IL_0020: ldloc.2 + IL_0021: stobj ""U"" + IL_0026: ret +}"); + } + + [Fact] + public void InParamReorder() + { + var source = +@"using System; +using System.Diagnostics.CodeAnalysis; +ref struct S +{ + public ref T F; + public S(ref T t) { F = ref t; } +} +class Program +{ + static void Main() + { + int x = 1; + int y = 2; + var sx = new S(ref x); + var sy = new S(ref y); + Reorder(sx, sy); + } + static ref S Get([UnscopedRef] ref S s) + { + return ref s; + } + static void Reorder(scoped S sx, scoped S sy) + { + M(y: in Get(ref sy).F, x: in Get(ref sx).F); + } + static void M(in T x, in T y) + { + Console.WriteLine(x); + Console.WriteLine(y); + } +}"; + var comp = CreateCompilation(new[] { source, UnscopedRefAttributeDefinition }, options: TestOptions.ReleaseExe, runtimeFeature: RuntimeFlag.ByRefFields); + var verifier = CompileAndVerify(comp, verify: Verification.Skipped, expectedOutput: IncludeExpectedOutput( +@"1 +2 +")); + verifier.VerifyIL("Program.Reorder", +@"{ + // Code size 32 (0x20) + .maxstack 2 + .locals init (T& V_0) + IL_0000: ldarga.s V_1 + IL_0002: call ""ref S Program.Get(ref S)"" + IL_0007: ldfld ""ref T S.F"" + IL_000c: stloc.0 + IL_000d: ldarga.s V_0 + IL_000f: call ""ref S Program.Get(ref S)"" + IL_0014: ldfld ""ref T S.F"" + IL_0019: ldloc.0 + IL_001a: call ""void Program.M(in T, in T)"" + IL_001f: ret +}"); + } + + [Fact] + public void ReturnRefToByValueParameter_01() + { + var source = +@" +using System.Diagnostics.CodeAnalysis; +ref struct S +{ +} +class Program +{ + static ref S F1([UnscopedRef] ref S x1) + { + return ref x1; + } + static void F2(S x2) + { + var y2 = F1(ref x2); + } +}"; + + var comp = CreateCompilation(new[] { source, UnscopedRefAttributeDefinition }, parseOptions: TestOptions.Regular10); + comp.VerifyEmitDiagnostics(); + + comp = CreateCompilation(new[] { source, UnscopedRefAttributeDefinition }); + comp.VerifyEmitDiagnostics( + // (14,18): error CS8350: This combination of arguments to 'Program.F1(ref S)' is disallowed because it may expose variables referenced by parameter 'x1' outside of their declaration scope + // var y2 = F1(ref x2); + Diagnostic(ErrorCode.ERR_CallArgMixing, "F1(ref x2)").WithArguments("Program.F1(ref S)", "x1").WithLocation(14, 18), + // (14,25): error CS8166: Cannot return a parameter by reference 'x2' because it is not a ref parameter + // var y2 = F1(ref x2); + Diagnostic(ErrorCode.ERR_RefReturnParameter, "x2").WithArguments("x2").WithLocation(14, 25)); + } + + [Fact] + public void ReturnRefToByValueParameter_02() + { + var source = +@" +using System.Diagnostics.CodeAnalysis; +ref struct S +{ +} +class Program +{ + static ref S F1([UnscopedRef] ref S x1, [UnscopedRef] ref S y1) + { + return ref x1; + } + static void F2(S x2, S y2) + { + var z1 = F1(ref x2, ref y2); + } +}"; + + var comp = CreateCompilation(new[] { source, UnscopedRefAttributeDefinition }, parseOptions: TestOptions.Regular10); + comp.VerifyEmitDiagnostics(); + + comp = CreateCompilation(new[] { source, UnscopedRefAttributeDefinition }); + comp.VerifyEmitDiagnostics( + // (14,18): error CS8350: This combination of arguments to 'Program.F1(ref S, ref S)' is disallowed because it may expose variables referenced by parameter 'x1' outside of their declaration scope + // var z1 = F1(ref x2, ref y2); + Diagnostic(ErrorCode.ERR_CallArgMixing, "F1(ref x2, ref y2)").WithArguments("Program.F1(ref S, ref S)", "x1").WithLocation(14, 18), + // (14,25): error CS8166: Cannot return a parameter by reference 'x2' because it is not a ref parameter + // var z1 = F1(ref x2, ref y2); + Diagnostic(ErrorCode.ERR_RefReturnParameter, "x2").WithArguments("x2").WithLocation(14, 25)); + } + + [WorkItem(62098, "https://github.com/dotnet/roslyn/issues/62098")] + [Fact] + public void RefToContainingType() + { + var source = +@" +using System.Diagnostics.CodeAnalysis; +ref struct R +{ + public ref R Next; +} +class Program +{ + static void F([UnscopedRef] ref R r) + { + r.Next = ref r; + } +}"; + var comp = CreateCompilation(new[] { source, UnscopedRefAttributeDefinition }, runtimeFeature: RuntimeFlag.ByRefFields); + // https://github.com/dotnet/roslyn/issues/62098: Allow ref field of the containing type. + comp.VerifyEmitDiagnostics( + // (5,12): error CS9050: A ref field cannot refer to a ref struct. + // public ref R Next; + Diagnostic(ErrorCode.ERR_RefFieldCannotReferToRefStruct, "ref R").WithLocation(5, 12), + // (5,21): error CS0523: Struct member 'R.Next' of type 'R' causes a cycle in the struct layout + // public ref R Next; + Diagnostic(ErrorCode.ERR_StructLayoutCycle, "Next").WithArguments("R.Next", "R").WithLocation(5, 21)); + } + + /// + /// Ref auto-properties are not supported. + /// + [Fact] + public void RefAutoProperty_01() + { + var source = +@"using System; +ref struct S +{ + public ref T P0 { get; } + public ref T P1 { get; set; } + public ref T P2 { get; init; } + public S(ref T t) + { + P0 = ref t; + P1 = ref t; + P2 = ref t; + } +} +class Program +{ + static void Main() + { + int x = 0; + var s = new S(ref x); + s.P0 = 0; + s.P1 = 1; + s.P2 = 2; + s.P0 = ref x; + s.P1 = ref x; + s.P2 = ref x; + } +}"; + var comp = CreateCompilation(source); + comp.VerifyEmitDiagnostics( + // (4,18): error CS8145: Auto-implemented properties cannot return by reference + // public ref T P0 { get; } + Diagnostic(ErrorCode.ERR_AutoPropertyCannotBeRefReturning, "P0").WithLocation(4, 18), + // (5,18): error CS8145: Auto-implemented properties cannot return by reference + // public ref T P1 { get; set; } + Diagnostic(ErrorCode.ERR_AutoPropertyCannotBeRefReturning, "P1").WithLocation(5, 18), + // (5,28): error CS8147: Properties which return by reference cannot have set accessors + // public ref T P1 { get; set; } + Diagnostic(ErrorCode.ERR_RefPropertyCannotHaveSetAccessor, "set").WithLocation(5, 28), + // (6,18): error CS8145: Auto-implemented properties cannot return by reference + // public ref T P2 { get; init; } + Diagnostic(ErrorCode.ERR_AutoPropertyCannotBeRefReturning, "P2").WithLocation(6, 18), + // (6,28): error CS0518: Predefined type 'System.Runtime.CompilerServices.IsExternalInit' is not defined or imported + // public ref T P2 { get; init; } + Diagnostic(ErrorCode.ERR_PredefinedTypeNotFound, "init").WithArguments("System.Runtime.CompilerServices.IsExternalInit").WithLocation(6, 28), + // (6,28): error CS8147: Properties which return by reference cannot have set accessors + // public ref T P2 { get; init; } + Diagnostic(ErrorCode.ERR_RefPropertyCannotHaveSetAccessor, "init").WithLocation(6, 28), + // (9,9): error CS8373: The left-hand side of a ref assignment must be a ref variable. + // P0 = ref t; + Diagnostic(ErrorCode.ERR_RefLocalOrParamExpected, "P0").WithLocation(9, 9), + // (10,9): error CS8373: The left-hand side of a ref assignment must be a ref variable. + // P1 = ref t; + Diagnostic(ErrorCode.ERR_RefLocalOrParamExpected, "P1").WithLocation(10, 9), + // (11,9): error CS8373: The left-hand side of a ref assignment must be a ref variable. + // P2 = ref t; + Diagnostic(ErrorCode.ERR_RefLocalOrParamExpected, "P2").WithLocation(11, 9), + // (23,9): error CS8373: The left-hand side of a ref assignment must be a ref variable. + // s.P0 = ref x; + Diagnostic(ErrorCode.ERR_RefLocalOrParamExpected, "s.P0").WithLocation(23, 9), + // (24,9): error CS8373: The left-hand side of a ref assignment must be a ref variable. + // s.P1 = ref x; + Diagnostic(ErrorCode.ERR_RefLocalOrParamExpected, "s.P1").WithLocation(24, 9), + // (25,9): error CS8373: The left-hand side of a ref assignment must be a ref variable. + // s.P2 = ref x; + Diagnostic(ErrorCode.ERR_RefLocalOrParamExpected, "s.P2").WithLocation(25, 9)); + } + + /// + /// Ref auto-properties are not supported. + /// + [Fact] + public void RefAutoProperty_02() + { + var source = +@"using System; +ref struct S +{ + public ref readonly T P0 { get; } + public ref readonly T P1 { get; set; } + public ref readonly T P2 { get; init; } + public S(ref T t) + { + P0 = ref t; + P1 = ref t; + P2 = ref t; + } +} +class Program +{ + static void Main() + { + int x = 0; + var s = new S(ref x); + s.P0 = ref x; + s.P1 = ref x; + s.P2 = ref x; + } +}"; + var comp = CreateCompilation(source); + comp.VerifyEmitDiagnostics( + // (4,27): error CS8145: Auto-implemented properties cannot return by reference + // public ref readonly T P0 { get; } + Diagnostic(ErrorCode.ERR_AutoPropertyCannotBeRefReturning, "P0").WithLocation(4, 27), + // (5,27): error CS8145: Auto-implemented properties cannot return by reference + // public ref readonly T P1 { get; set; } + Diagnostic(ErrorCode.ERR_AutoPropertyCannotBeRefReturning, "P1").WithLocation(5, 27), + // (5,37): error CS8147: Properties which return by reference cannot have set accessors + // public ref readonly T P1 { get; set; } + Diagnostic(ErrorCode.ERR_RefPropertyCannotHaveSetAccessor, "set").WithLocation(5, 37), + // (6,27): error CS8145: Auto-implemented properties cannot return by reference + // public ref readonly T P2 { get; init; } + Diagnostic(ErrorCode.ERR_AutoPropertyCannotBeRefReturning, "P2").WithLocation(6, 27), + // (6,37): error CS0518: Predefined type 'System.Runtime.CompilerServices.IsExternalInit' is not defined or imported + // public ref readonly T P2 { get; init; } + Diagnostic(ErrorCode.ERR_PredefinedTypeNotFound, "init").WithArguments("System.Runtime.CompilerServices.IsExternalInit").WithLocation(6, 37), + // (6,37): error CS8147: Properties which return by reference cannot have set accessors + // public ref readonly T P2 { get; init; } + Diagnostic(ErrorCode.ERR_RefPropertyCannotHaveSetAccessor, "init").WithLocation(6, 37), + // (9,9): error CS8373: The left-hand side of a ref assignment must be a ref variable. + // P0 = ref t; + Diagnostic(ErrorCode.ERR_RefLocalOrParamExpected, "P0").WithLocation(9, 9), + // (10,9): error CS8373: The left-hand side of a ref assignment must be a ref variable. + // P1 = ref t; + Diagnostic(ErrorCode.ERR_RefLocalOrParamExpected, "P1").WithLocation(10, 9), + // (11,9): error CS8373: The left-hand side of a ref assignment must be a ref variable. + // P2 = ref t; + Diagnostic(ErrorCode.ERR_RefLocalOrParamExpected, "P2").WithLocation(11, 9), + // (20,9): error CS8373: The left-hand side of a ref assignment must be a ref variable. + // s.P0 = ref x; + Diagnostic(ErrorCode.ERR_RefLocalOrParamExpected, "s.P0").WithLocation(20, 9), + // (21,9): error CS8373: The left-hand side of a ref assignment must be a ref variable. + // s.P1 = ref x; + Diagnostic(ErrorCode.ERR_RefLocalOrParamExpected, "s.P1").WithLocation(21, 9), + // (22,9): error CS8373: The left-hand side of a ref assignment must be a ref variable. + // s.P2 = ref x; + Diagnostic(ErrorCode.ERR_RefLocalOrParamExpected, "s.P2").WithLocation(22, 9)); + } + + [Fact] + public void RefAccessor_Value() + { + var source = +@"using System; +ref struct S +{ + internal T t; + internal ref T F() => ref t; +} +class Program +{ + static void Main() + { + var s = new S(); + s.t = 1; + s.F() = 2; + Console.WriteLine(s.F()); + Console.WriteLine(s.t); + s.t = 3; + Console.WriteLine(s.F()); + Console.WriteLine(s.t); + } +}"; + var comp = CreateCompilation(source); + comp.VerifyEmitDiagnostics( + // (5,31): error CS8170: Struct members cannot return 'this' or other instance members by reference + // internal ref T F() => ref t; + Diagnostic(ErrorCode.ERR_RefReturnStructThis, "t").WithLocation(5, 31)); + } + + [Fact] + public void RefAccessor_Ref() + { + var source = +@"using System; +ref struct S +{ + internal ref T t; + internal ref T F() => ref t; + internal S(ref T t) { this.t = ref t; } +} +class Program +{ + static void Main() + { + int i = 0; + var s = new S(ref i); + s.t = 1; + s.F() = 2; + Console.WriteLine(s.F()); + Console.WriteLine(s.t); + s.t = 3; + Console.WriteLine(s.F()); + Console.WriteLine(s.t); + } +}"; + var comp = CreateCompilation(source, options: TestOptions.ReleaseExe, runtimeFeature: RuntimeFlag.ByRefFields); + var verifier = CompileAndVerify(comp, verify: Verification.Skipped, expectedOutput: IncludeExpectedOutput( +@"2 +2 +3 +3 +")); + verifier.VerifyIL("S.F", +@"{ + // Code size 7 (0x7) + .maxstack 1 + IL_0000: ldarg.0 + IL_0001: ldfld ""ref T S.t"" + IL_0006: ret +}"); + } + + [Theory] + [InlineData(LanguageVersion.CSharp10)] + [InlineData(LanguageVersion.CSharp11)] + public void Span_01(LanguageVersion languageVersion) + { + var source = +@"using System; +class Program +{ + static ref int F1() + { + Span s1 = stackalloc int[10]; + return ref s1[1]; // 1 + } + static ref int F2() + { + Span s2 = new int[10]; + return ref s2[1]; + } +}"; + var comp = CreateCompilationWithSpanAndMemoryExtensions(source, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion)); + comp.VerifyEmitDiagnostics( + // (7,20): error CS8352: Cannot use variable 's1' in this context because it may expose referenced variables outside of their declaration scope + // return ref s1[1]; // 1 + Diagnostic(ErrorCode.ERR_EscapeVariable, "s1").WithArguments("s1").WithLocation(7, 20)); + } + + // A version of above with an explicit definition of Span. + [Theory] + [InlineData(LanguageVersion.CSharp10)] + [InlineData(LanguageVersion.CSharp11)] + public void Span_02(LanguageVersion languageVersion) + { + var sourceA = +@"namespace System +{ + public ref struct Span + { + unsafe public Span(void* ptr, int length) { } + public ref T this[int index] => throw null; + public static implicit operator Span(T[] a) => throw null; + } +}"; + var comp = CreateCompilation(sourceA, parseOptions: TestOptions.Regular10, options: TestOptions.UnsafeReleaseDll); + var refA = comp.EmitToImageReference(); + + var sourceB = +@"using System; +class Program +{ + static ref int F1() + { + Span s1 = stackalloc int[10]; + return ref s1[1]; // 1 + } + static ref int F2() + { + Span s2 = new int[10]; + return ref s2[1]; + } +}"; + comp = CreateCompilation(sourceB, references: new[] { refA }, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion)); + comp.VerifyEmitDiagnostics( + // (7,20): error CS8352: Cannot use variable 's1' in this context because it may expose referenced variables outside of their declaration scope + // return ref s1[1]; // 1 + Diagnostic(ErrorCode.ERR_EscapeVariable, "s1").WithArguments("s1").WithLocation(7, 20)); + } + + // Breaking change in C#11: Cannot return an 'out' parameter by reference. + [Fact] + public void BreakingChange_ReturnOutByRef() + { + var source = +@"class Program +{ + static ref T ReturnOutParamByRef(out T t) + { + t = default; + return ref t; + } +}"; + + var comp = CreateCompilation(source, parseOptions: TestOptions.Regular10); + comp.VerifyDiagnostics(); + + comp = CreateCompilation(source); + comp.VerifyDiagnostics( + // (6,20): error CS8166: Cannot return a parameter by reference 't' because it is not a ref parameter + // return ref t; + Diagnostic(ErrorCode.ERR_RefReturnParameter, "t").WithArguments("t").WithLocation(6, 20)); + } + + // Breaking change in C#11: Instance method on ref struct instance may capture unscoped ref or in arguments. + [Fact] + public void BreakingChange_RefStructInstanceMethodMayCaptureRef() + { + var source = +@"ref struct R +{ + public void MayCaptureArg(ref T t) { } +} +class Program +{ + static R Use(R r) + { + int i = 42; + r.MayCaptureArg(ref i); + return r; + } +}"; + + var comp = CreateCompilation(source, parseOptions: TestOptions.Regular10); + comp.VerifyDiagnostics(); + + comp = CreateCompilation(source); + comp.VerifyDiagnostics( + // (10,9): error CS8350: This combination of arguments to 'R.MayCaptureArg(ref int)' is disallowed because it may expose variables referenced by parameter 't' outside of their declaration scope + // r.MayCaptureArg(ref i); + Diagnostic(ErrorCode.ERR_CallArgMixing, "r.MayCaptureArg(ref i)").WithArguments("R.MayCaptureArg(ref int)", "t").WithLocation(10, 9), + // (10,29): error CS8168: Cannot return local 'i' by reference because it is not a ref local + // r.MayCaptureArg(ref i); + Diagnostic(ErrorCode.ERR_RefReturnLocal, "i").WithArguments("i").WithLocation(10, 29)); + } + + // Breaking change in C#11: The rvalue from a method invocation that + // returns a ref struct is safe-to-escape from ... the ref-safe-to-escape of all ref arguments. + [Fact] + public void BreakingChange_RefStructReturnFromRefArguments_01() + { + var source = +@"ref struct R { } +class Program +{ + static R MayCaptureArg(ref int i) => new R(); + static R MayCaptureDefaultArg(in int i = 0) => new R(); + static R Create() + { + int i = 0; + return MayCaptureArg(ref i); + } + static R CreateDefault() + { + return MayCaptureDefaultArg(); + } +}"; + + var comp = CreateCompilation(source, parseOptions: TestOptions.Regular10); + comp.VerifyDiagnostics(); + + comp = CreateCompilation(source); + comp.VerifyDiagnostics( + // (9,16): error CS8347: Cannot use a result of 'Program.MayCaptureArg(ref int)' in this context because it may expose variables referenced by parameter 'i' outside of their declaration scope + // return MayCaptureArg(ref i); + Diagnostic(ErrorCode.ERR_EscapeCall, "MayCaptureArg(ref i)").WithArguments("Program.MayCaptureArg(ref int)", "i").WithLocation(9, 16), + // (9,34): error CS8168: Cannot return local 'i' by reference because it is not a ref local + // return MayCaptureArg(ref i); + Diagnostic(ErrorCode.ERR_RefReturnLocal, "i").WithArguments("i").WithLocation(9, 34), + // (13,16): error CS8156: An expression cannot be used in this context because it may not be passed or returned by reference + // return MayCaptureDefaultArg(); + Diagnostic(ErrorCode.ERR_RefReturnLvalueExpected, "MayCaptureDefaultArg()").WithLocation(13, 16), + // (13,16): error CS8347: Cannot use a result of 'Program.MayCaptureDefaultArg(in int)' in this context because it may expose variables referenced by parameter 'i' outside of their declaration scope + // return MayCaptureDefaultArg(); + Diagnostic(ErrorCode.ERR_EscapeCall, "MayCaptureDefaultArg()").WithArguments("Program.MayCaptureDefaultArg(in int)", "i").WithLocation(13, 16)); + } + + // Another version of the breaking change above, this time + // with ref structs passed by reference as constructor this. + [WorkItem(62940, "https://github.com/dotnet/roslyn/issues/62940")] + [Fact] + public void BreakingChange_RefStructReturnFromRefArguments_02() + { + var source = +@"ref struct R1 +{ + public R1(ref object o) { } +} +readonly ref struct R2 +{ + public R2(in object o) { } +} +class Program +{ + static R1 F1() + { + var o = new object(); + return new R1(ref o); + } + static R2 F2() + { + return new R2(new object()); + } +}"; + + var comp = CreateCompilation(source, parseOptions: TestOptions.Regular10); + comp.VerifyDiagnostics(); + + comp = CreateCompilation(source); + comp.VerifyDiagnostics( + // (14,16): error CS8347: Cannot use a result of 'R1.R1(ref object)' in this context because it may expose variables referenced by parameter 'o' outside of their declaration scope + // return new R1(ref o); + Diagnostic(ErrorCode.ERR_EscapeCall, "new R1(ref o)").WithArguments("R1.R1(ref object)", "o").WithLocation(14, 16), + // (14,27): error CS8168: Cannot return local 'o' by reference because it is not a ref local + // return new R1(ref o); + Diagnostic(ErrorCode.ERR_RefReturnLocal, "o").WithArguments("o").WithLocation(14, 27), + // (18,16): error CS8347: Cannot use a result of 'R2.R2(in object)' in this context because it may expose variables referenced by parameter 'o' outside of their declaration scope + // return new R2(new object()); + Diagnostic(ErrorCode.ERR_EscapeCall, "new R2(new object())").WithArguments("R2.R2(in object)", "o").WithLocation(18, 16), + // (18,23): error CS8156: An expression cannot be used in this context because it may not be passed or returned by reference + // return new R2(new object()); + Diagnostic(ErrorCode.ERR_RefReturnLvalueExpected, "new object()").WithLocation(18, 23)); + } + + // Breaking change in C#11: A ref to ref struct argument is considered + // an unscoped reference when passed to an __arglist. + [Fact] + public void BreakingChange_RefToRefStructInArglist() + { + var source = +@"ref struct R { } +class Program +{ + static void MayCaptureRef(__arglist) { } + static void Main() + { + var r = new R(); + MayCaptureRef(__arglist(ref r)); // error: may expose variables outside of their declaration scope + } +}"; + + var comp = CreateCompilation(source, parseOptions: TestOptions.Regular10); + comp.VerifyEmitDiagnostics(); + + comp = CreateCompilation(source); + comp.VerifyEmitDiagnostics( + // (8,9): error CS8350: This combination of arguments to 'Program.MayCaptureRef(__arglist)' is disallowed because it may expose variables referenced by parameter '__arglist' outside of their declaration scope + // MayCaptureRef(__arglist(ref r)); // error: may expose variables outside of their declaration scope + Diagnostic(ErrorCode.ERR_CallArgMixing, "MayCaptureRef(__arglist(ref r))").WithArguments("Program.MayCaptureRef(__arglist)", "__arglist").WithLocation(8, 9), + // (8,37): error CS8168: Cannot return local 'r' by reference because it is not a ref local + // MayCaptureRef(__arglist(ref r)); // error: may expose variables outside of their declaration scope + Diagnostic(ErrorCode.ERR_RefReturnLocal, "r").WithArguments("r").WithLocation(8, 37)); + } + + [Theory] + [CombinatorialData] + public void ParameterScope_01(bool useCompilationReference) + { + var sourceA = +@"public ref struct R +{ + public R(ref int i) { } +} +public static class A +{ + public static void F1(R x1, scoped R y1) { } + public static void F2(ref R x2, scoped ref R y2) { } + public static void F3(in R x3, scoped in R y3) { } + public static void F4(out R x4, scoped out R y4) { x4 = default; y4 = default; } +}"; + var comp = CreateCompilation(sourceA, parseOptions: TestOptions.Regular10); + comp.VerifyEmitDiagnostics( + // (7,33): error CS8936: Feature 'ref fields' is not available in C# 10.0. Please use language version 11.0 or greater. + // public static void F1(R x1, scoped R y1) { } + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "scoped").WithArguments("ref fields", "11.0").WithLocation(7, 33), + // (8,37): error CS8936: Feature 'ref fields' is not available in C# 10.0. Please use language version 11.0 or greater. + // public static void F2(ref R x2, scoped ref R y2) { } + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "scoped").WithArguments("ref fields", "11.0").WithLocation(8, 37), + // (9,36): error CS8936: Feature 'ref fields' is not available in C# 10.0. Please use language version 11.0 or greater. + // public static void F3(in R x3, scoped in R y3) { } + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "scoped").WithArguments("ref fields", "11.0").WithLocation(9, 36), + // (10,37): error CS8936: Feature 'ref fields' is not available in C# 10.0. Please use language version 11.0 or greater. + // public static void F4(out R x4, scoped out R y4) { x4 = default; y4 = default; } + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "scoped").WithArguments("ref fields", "11.0").WithLocation(10, 37)); + + verify(comp); + + comp = CreateCompilation(sourceA); + comp.VerifyEmitDiagnostics(); + var refA = AsReference(comp, useCompilationReference); + + var sourceB = +@"static class B +{ + static void F(ref R x) + { + int i = 0; + R y = new R(ref i); + A.F2(ref x, ref y); + } +}"; + comp = CreateCompilation(sourceB, references: new[] { refA }); + comp.VerifyEmitDiagnostics( + // (7,9): error CS8350: This combination of arguments to 'A.F2(ref R, ref R)' is disallowed because it may expose variables referenced by parameter 'y2' outside of their declaration scope + // A.F2(ref x, ref y); + Diagnostic(ErrorCode.ERR_CallArgMixing, "A.F2(ref x, ref y)").WithArguments("A.F2(ref R, ref R)", "y2").WithLocation(7, 9), + // (7,25): error CS8352: Cannot use variable 'y' in this context because it may expose referenced variables outside of their declaration scope + // A.F2(ref x, ref y); + Diagnostic(ErrorCode.ERR_EscapeVariable, "y").WithArguments("y").WithLocation(7, 25)); + + verify(comp); + + static void verify(CSharpCompilation comp) + { + var parameters = comp.GetMember("A.F1").Parameters; + VerifyParameterSymbol(parameters[0], "R x1", RefKind.None, DeclarationScope.Unscoped); + VerifyParameterSymbol(parameters[1], "scoped R y1", RefKind.None, DeclarationScope.ValueScoped); + + parameters = comp.GetMember("A.F2").Parameters; + VerifyParameterSymbol(parameters[0], "ref R x2", RefKind.Ref, DeclarationScope.RefScoped); + VerifyParameterSymbol(parameters[1], "ref R y2", RefKind.Ref, DeclarationScope.RefScoped); + + parameters = comp.GetMember("A.F3").Parameters; + VerifyParameterSymbol(parameters[0], "in R x3", RefKind.In, DeclarationScope.RefScoped); + VerifyParameterSymbol(parameters[1], "in R y3", RefKind.In, DeclarationScope.RefScoped); + + parameters = comp.GetMember("A.F4").Parameters; + VerifyParameterSymbol(parameters[0], "out R x4", RefKind.Out, DeclarationScope.RefScoped); + VerifyParameterSymbol(parameters[1], "out R y4", RefKind.Out, DeclarationScope.RefScoped); + } + } + + [Fact] + public void ParameterScope_02() { var source = -@"ref struct S +@"ref struct A { - public readonly ref readonly T F; - public S(ref T t) { F = ref t; } + A(scoped ref T t) { } + T this[scoped in object o] => default; + public static implicit operator B(scoped in A a) => default; } - -class Program +struct B { - static void AssignValueToValue(S s, T tValue) { s.F = tValue; } // 1 - static void AssignRefToValue(S s, ref T tRef) { s.F = tRef; } // 2 - static void AssignOutToValue(S s, out T tOut) { tOut = default; s.F = tOut; } // 3 - static void AssignInToValue(S s, in T tIn) { s.F = tIn; } // 4 +}"; + var comp = CreateCompilation(source, parseOptions: TestOptions.Regular10); + comp.VerifyEmitDiagnostics( + // (3,7): error CS8936: Feature 'ref fields' is not available in C# 10.0. Please use language version 11.0 or greater. + // A(scoped ref T t) { } + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "scoped").WithArguments("ref fields", "11.0").WithLocation(3, 7), + // (4,12): error CS8936: Feature 'ref fields' is not available in C# 10.0. Please use language version 11.0 or greater. + // T this[scoped in object o] => default; + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "scoped").WithArguments("ref fields", "11.0").WithLocation(4, 12), + // (5,42): error CS8936: Feature 'ref fields' is not available in C# 10.0. Please use language version 11.0 or greater. + // public static implicit operator B(scoped in A a) => default; + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "scoped").WithArguments("ref fields", "11.0").WithLocation(5, 42)); + verify(comp); - static void AssignValueToRef(ref S sRef, T tValue) { sRef.F = tValue; } // 5 - static void AssignRefToRef(ref S sRef, ref T tRef) { sRef.F = tRef; } // 6 - static void AssignOutToRef(ref S sRef, out T tOut) { tOut = default; sRef.F = tOut; } // 7 - static void AssignInToRef(ref S sRef, in T tIn) { sRef.F = tIn; } // 8 + comp = CreateCompilation(source); + comp.VerifyEmitDiagnostics(); + verify(comp); - static void AssignValueToOut(out S sOut, T tValue) { sOut = default; sOut.F = tValue; } // 9 - static void AssignRefToOut(out S sOut, ref T tRef) { sOut = default; sOut.F = tRef; } // 10 - static void AssignOutToOut(out S sOut, out T tOut) { sOut = default; tOut = default; sOut.F = tOut; } // 11 - static void AssignInToOut(out S sOut, in T tIn) { sOut = default; sOut.F = tIn; } // 12 + static void verify(CSharpCompilation comp) + { + VerifyParameterSymbol(comp.GetMember("A").Constructors.Single(c => !c.IsImplicitlyDeclared).Parameters[0], "scoped ref T t", RefKind.Ref, DeclarationScope.RefScoped); + VerifyParameterSymbol(comp.GetMember("A.this[]").GetMethod.Parameters[0], "scoped in System.Object o", RefKind.In, DeclarationScope.RefScoped); + } + } - static void AssignValueToIn(in S sIn, T tValue) { sIn.F = tValue; } // 13 - static void AssignRefToIn(in S sIn, ref T tRef) { sIn.F = tRef; } // 14 - static void AssignOutToIn(in S sIn, out T tOut) { tOut = default; sIn.F = tOut; } // 15 - static void AssignInToIn(in S sIn, in T tIn) { sIn.F = tIn; } // 16 + [Fact] + public void ParameterScope_03() + { + var source = +@"ref struct R { } +class Program +{ + static void Main() + { +#pragma warning disable 8321 + static void L1(R x1, scoped R y1) { } + static void L2(ref int x2, scoped ref int y2) { } + static void L3(in int x3, scoped in int y3) { } + static void L4(out int x4, scoped out int y4) { x4 = 0; y4 = 0; } + static void L5(ref R x5, scoped ref R y5) { } + static void L6(in R x6, scoped in R y6) { } + static void L7(out R x7, scoped out R y7) { x7 = default; y7 = default; } + } }"; - var comp = CreateCompilation(source); + var comp = CreateCompilation(source, parseOptions: TestOptions.Regular10); comp.VerifyEmitDiagnostics( - // (9,59): error CS8331: Cannot assign to field 'S.F' because it is a readonly variable - // static void AssignValueToValue(S s, T tValue) { s.F = tValue; } // 1 - Diagnostic(ErrorCode.ERR_AssignReadonlyNotField, "s.F").WithArguments("field", "S.F").WithLocation(9, 59), - // (10,59): error CS8331: Cannot assign to field 'S.F' because it is a readonly variable - // static void AssignRefToValue(S s, ref T tRef) { s.F = tRef; } // 2 - Diagnostic(ErrorCode.ERR_AssignReadonlyNotField, "s.F").WithArguments("field", "S.F").WithLocation(10, 59), - // (11,75): error CS8331: Cannot assign to field 'S.F' because it is a readonly variable - // static void AssignOutToValue(S s, out T tOut) { tOut = default; s.F = tOut; } // 3 - Diagnostic(ErrorCode.ERR_AssignReadonlyNotField, "s.F").WithArguments("field", "S.F").WithLocation(11, 75), - // (12,59): error CS8331: Cannot assign to field 'S.F' because it is a readonly variable - // static void AssignInToValue(S s, in T tIn) { s.F = tIn; } // 4 - Diagnostic(ErrorCode.ERR_AssignReadonlyNotField, "s.F").WithArguments("field", "S.F").WithLocation(12, 59), - // (14,64): error CS8331: Cannot assign to field 'S.F' because it is a readonly variable - // static void AssignValueToRef(ref S sRef, T tValue) { sRef.F = tValue; } // 5 - Diagnostic(ErrorCode.ERR_AssignReadonlyNotField, "sRef.F").WithArguments("field", "S.F").WithLocation(14, 64), - // (15,64): error CS8331: Cannot assign to field 'S.F' because it is a readonly variable - // static void AssignRefToRef(ref S sRef, ref T tRef) { sRef.F = tRef; } // 6 - Diagnostic(ErrorCode.ERR_AssignReadonlyNotField, "sRef.F").WithArguments("field", "S.F").WithLocation(15, 64), - // (16,80): error CS8331: Cannot assign to field 'S.F' because it is a readonly variable - // static void AssignOutToRef(ref S sRef, out T tOut) { tOut = default; sRef.F = tOut; } // 7 - Diagnostic(ErrorCode.ERR_AssignReadonlyNotField, "sRef.F").WithArguments("field", "S.F").WithLocation(16, 80), - // (17,64): error CS8331: Cannot assign to field 'S.F' because it is a readonly variable - // static void AssignInToRef(ref S sRef, in T tIn) { sRef.F = tIn; } // 8 - Diagnostic(ErrorCode.ERR_AssignReadonlyNotField, "sRef.F").WithArguments("field", "S.F").WithLocation(17, 64), - // (19,80): error CS8331: Cannot assign to field 'S.F' because it is a readonly variable - // static void AssignValueToOut(out S sOut, T tValue) { sOut = default; sOut.F = tValue; } // 9 - Diagnostic(ErrorCode.ERR_AssignReadonlyNotField, "sOut.F").WithArguments("field", "S.F").WithLocation(19, 80), - // (20,80): error CS8331: Cannot assign to field 'S.F' because it is a readonly variable - // static void AssignRefToOut(out S sOut, ref T tRef) { sOut = default; sOut.F = tRef; } // 10 - Diagnostic(ErrorCode.ERR_AssignReadonlyNotField, "sOut.F").WithArguments("field", "S.F").WithLocation(20, 80), - // (21,96): error CS8331: Cannot assign to field 'S.F' because it is a readonly variable - // static void AssignOutToOut(out S sOut, out T tOut) { sOut = default; tOut = default; sOut.F = tOut; } // 11 - Diagnostic(ErrorCode.ERR_AssignReadonlyNotField, "sOut.F").WithArguments("field", "S.F").WithLocation(21, 96), - // (22,80): error CS8331: Cannot assign to field 'S.F' because it is a readonly variable - // static void AssignInToOut(out S sOut, in T tIn) { sOut = default; sOut.F = tIn; } // 12 - Diagnostic(ErrorCode.ERR_AssignReadonlyNotField, "sOut.F").WithArguments("field", "S.F").WithLocation(22, 80), - // (24,61): error CS8331: Cannot assign to field 'S.F' because it is a readonly variable - // static void AssignValueToIn(in S sIn, T tValue) { sIn.F = tValue; } // 13 - Diagnostic(ErrorCode.ERR_AssignReadonlyNotField, "sIn.F").WithArguments("field", "S.F").WithLocation(24, 61), - // (25,61): error CS8331: Cannot assign to field 'S.F' because it is a readonly variable - // static void AssignRefToIn(in S sIn, ref T tRef) { sIn.F = tRef; } // 14 - Diagnostic(ErrorCode.ERR_AssignReadonlyNotField, "sIn.F").WithArguments("field", "S.F").WithLocation(25, 61), - // (26,77): error CS8331: Cannot assign to field 'S.F' because it is a readonly variable - // static void AssignOutToIn(in S sIn, out T tOut) { tOut = default; sIn.F = tOut; } // 15 - Diagnostic(ErrorCode.ERR_AssignReadonlyNotField, "sIn.F").WithArguments("field", "S.F").WithLocation(26, 77), - // (27,61): error CS8331: Cannot assign to field 'S.F' because it is a readonly variable - // static void AssignInToIn(in S sIn, in T tIn) { sIn.F = tIn; } // 16 - Diagnostic(ErrorCode.ERR_AssignReadonlyNotField, "sIn.F").WithArguments("field", "S.F").WithLocation(27, 61)); + // (7,30): error CS8936: Feature 'ref fields' is not available in C# 10.0. Please use language version 11.0 or greater. + // static void L1(R x1, scoped R y1) { } + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "scoped").WithArguments("ref fields", "11.0").WithLocation(7, 30), + // (8,36): error CS8936: Feature 'ref fields' is not available in C# 10.0. Please use language version 11.0 or greater. + // static void L2(ref int x2, scoped ref int y2) { } + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "scoped").WithArguments("ref fields", "11.0").WithLocation(8, 36), + // (9,35): error CS8936: Feature 'ref fields' is not available in C# 10.0. Please use language version 11.0 or greater. + // static void L3(in int x3, scoped in int y3) { } + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "scoped").WithArguments("ref fields", "11.0").WithLocation(9, 35), + // (10,36): error CS8936: Feature 'ref fields' is not available in C# 10.0. Please use language version 11.0 or greater. + // static void L4(out int x4, scoped out int y4) { x4 = 0; y4 = 0; } + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "scoped").WithArguments("ref fields", "11.0").WithLocation(10, 36), + // (11,34): error CS8936: Feature 'ref fields' is not available in C# 10.0. Please use language version 11.0 or greater. + // static void L5(ref R x5, scoped ref R y5) { } + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "scoped").WithArguments("ref fields", "11.0").WithLocation(11, 34), + // (12,33): error CS8936: Feature 'ref fields' is not available in C# 10.0. Please use language version 11.0 or greater. + // static void L6(in R x6, scoped in R y6) { } + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "scoped").WithArguments("ref fields", "11.0").WithLocation(12, 33), + // (13,34): error CS8936: Feature 'ref fields' is not available in C# 10.0. Please use language version 11.0 or greater. + // static void L7(out R x7, scoped out R y7) { x7 = default; y7 = default; } + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "scoped").WithArguments("ref fields", "11.0").WithLocation(13, 34)); + verify(comp); + + comp = CreateCompilation(source); + comp.VerifyEmitDiagnostics(); + verify(comp); + + static void verify(CSharpCompilation comp) + { + var tree = comp.SyntaxTrees[0]; + var model = comp.GetSemanticModel(tree); + var decls = tree.GetRoot().DescendantNodes().OfType().ToArray(); + var localFunctions = decls.Select(d => model.GetDeclaredSymbol(d).GetSymbol()).ToArray(); + + VerifyParameterSymbol(localFunctions[0].Parameters[0], "R x1", RefKind.None, DeclarationScope.Unscoped); + VerifyParameterSymbol(localFunctions[0].Parameters[1], "scoped R y1", RefKind.None, DeclarationScope.ValueScoped); + VerifyParameterSymbol(localFunctions[1].Parameters[0], "ref System.Int32 x2", RefKind.Ref, DeclarationScope.Unscoped); + VerifyParameterSymbol(localFunctions[1].Parameters[1], "scoped ref System.Int32 y2", RefKind.Ref, DeclarationScope.RefScoped); + VerifyParameterSymbol(localFunctions[2].Parameters[0], "in System.Int32 x3", RefKind.In, DeclarationScope.Unscoped); + VerifyParameterSymbol(localFunctions[2].Parameters[1], "scoped in System.Int32 y3", RefKind.In, DeclarationScope.RefScoped); + VerifyParameterSymbol(localFunctions[3].Parameters[0], "out System.Int32 x4", RefKind.Out, DeclarationScope.RefScoped); + VerifyParameterSymbol(localFunctions[3].Parameters[1], "out System.Int32 y4", RefKind.Out, DeclarationScope.RefScoped); + VerifyParameterSymbol(localFunctions[4].Parameters[0], "ref R x5", RefKind.Ref, DeclarationScope.RefScoped); + VerifyParameterSymbol(localFunctions[4].Parameters[1], "ref R y5", RefKind.Ref, DeclarationScope.RefScoped); + VerifyParameterSymbol(localFunctions[5].Parameters[0], "in R x6", RefKind.In, DeclarationScope.RefScoped); + VerifyParameterSymbol(localFunctions[5].Parameters[1], "in R y6", RefKind.In, DeclarationScope.RefScoped); + VerifyParameterSymbol(localFunctions[6].Parameters[0], "out R x7", RefKind.Out, DeclarationScope.RefScoped); + VerifyParameterSymbol(localFunctions[6].Parameters[1], "out R y7", RefKind.Out, DeclarationScope.RefScoped); + } } [Fact] - public void AssignRefTo_RefField() + public void ParameterScope_04() { var source = -@"ref struct S -{ - public ref T F; - public S(ref T t) { F = ref t; } -} - +@"ref struct R { } class Program { - static void AssignValueToValue(S s, T tValue) { s.F = ref tValue; } // 1 - static void AssignRefToValue(S s, ref T tRef) { s.F = ref tRef; } - static void AssignOutToValue(S s, out T tOut) { tOut = default; s.F = ref tOut; } // 2 - static void AssignInToValue(S s, in T tIn) { s.F = ref tIn; } // 3 + static void Main() + { + var f1 = (R x1, scoped R y1) => { }; + var f2 = (ref int x2, scoped ref int y2) => { }; + var f3 = (in int x3, scoped in int y3) => { }; + var f4 = (out int x4, scoped out int y4) => { x4 = 0; y4 = 0; }; + var f5 = (ref R x5, scoped ref R y5) => { }; + var f6 = (in R x6, scoped in R y6) => { }; + var f7 = (out R x7, scoped out R y7) => { x7 = default; y7 = default; }; + } +}"; + var comp = CreateCompilation(source, parseOptions: TestOptions.Regular10); + comp.VerifyEmitDiagnostics( + // (6,25): error CS8936: Feature 'ref fields' is not available in C# 10.0. Please use language version 11.0 or greater. + // var f1 = (R x1, scoped R y1) => { }; + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "scoped").WithArguments("ref fields", "11.0").WithLocation(6, 25), + // (7,31): error CS8936: Feature 'ref fields' is not available in C# 10.0. Please use language version 11.0 or greater. + // var f2 = (ref int x2, scoped ref int y2) => { }; + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "scoped").WithArguments("ref fields", "11.0").WithLocation(7, 31), + // (8,30): error CS8936: Feature 'ref fields' is not available in C# 10.0. Please use language version 11.0 or greater. + // var f3 = (in int x3, scoped in int y3) => { }; + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "scoped").WithArguments("ref fields", "11.0").WithLocation(8, 30), + // (9,31): error CS8936: Feature 'ref fields' is not available in C# 10.0. Please use language version 11.0 or greater. + // var f4 = (out int x4, scoped out int y4) => { x4 = 0; y4 = 0; }; + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "scoped").WithArguments("ref fields", "11.0").WithLocation(9, 31), + // (10,29): error CS8936: Feature 'ref fields' is not available in C# 10.0. Please use language version 11.0 or greater. + // var f5 = (ref R x5, scoped ref R y5) => { }; + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "scoped").WithArguments("ref fields", "11.0").WithLocation(10, 29), + // (11,28): error CS8936: Feature 'ref fields' is not available in C# 10.0. Please use language version 11.0 or greater. + // var f6 = (in R x6, scoped in R y6) => { }; + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "scoped").WithArguments("ref fields", "11.0").WithLocation(11, 28), + // (12,29): error CS8936: Feature 'ref fields' is not available in C# 10.0. Please use language version 11.0 or greater. + // var f7 = (out R x7, scoped out R y7) => { x7 = default; y7 = default; }; + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "scoped").WithArguments("ref fields", "11.0").WithLocation(12, 29)); + verify(comp); - static void AssignValueToRef(ref S sRef, T tValue) { sRef.F = ref tValue; } // 4 - static void AssignRefToRef(ref S sRef, ref T tRef) { sRef.F = ref tRef; } - static void AssignOutToRef(ref S sRef, out T tOut) { tOut = default; sRef.F = ref tOut; } // 5 - static void AssignInToRef(ref S sRef, in T tIn) { sRef.F = ref tIn; } // 6 + comp = CreateCompilation(source); + comp.VerifyEmitDiagnostics(); + verify(comp); - static void AssignValueToOut(out S sOut, T tValue) { sOut = default; sOut.F = ref tValue; } // 7 - static void AssignRefToOut(out S sOut, ref T tRef) { sOut = default; sOut.F = ref tRef; } - static void AssignOutToOut(out S sOut, out T tOut) { sOut = default; tOut = default; sOut.F = ref tOut; } // 8 - static void AssignInToOut(out S sOut, in T tIn) { sOut = default; sOut.F = ref tIn; } // 9 + static void verify(CSharpCompilation comp) + { + var tree = comp.SyntaxTrees[0]; + var model = comp.GetSemanticModel(tree); + var delegateTypesAndLambdas = tree.GetRoot().DescendantNodes().OfType().Select(d => getDelegateTypeAndLambda(model, d)).ToArray(); - static void AssignValueToIn(in S sIn, T tValue) { sIn.F = ref tValue; } // 10 - static void AssignRefToIn(in S sIn, ref T tRef) { sIn.F = ref tRef; } // 11 - static void AssignOutToIn(in S sIn, out T tOut) { tOut = default; sIn.F = ref tOut; } // 12 - static void AssignInToIn(in S sIn, in T tIn) { sIn.F = ref tIn; } // 13 -}"; - var comp = CreateCompilation(source); + verifyParameter(delegateTypesAndLambdas[0], 0, "R", "x1", RefKind.None, DeclarationScope.Unscoped); + verifyParameter(delegateTypesAndLambdas[0], 1, "scoped R", "y1", RefKind.None, DeclarationScope.ValueScoped); + verifyParameter(delegateTypesAndLambdas[1], 0, "ref System.Int32", "x2", RefKind.Ref, DeclarationScope.Unscoped); + verifyParameter(delegateTypesAndLambdas[1], 1, "scoped ref System.Int32", "y2", RefKind.Ref, DeclarationScope.RefScoped); + verifyParameter(delegateTypesAndLambdas[2], 0, "in System.Int32", "x3", RefKind.In, DeclarationScope.Unscoped); + verifyParameter(delegateTypesAndLambdas[2], 1, "scoped in System.Int32", "y3", RefKind.In, DeclarationScope.RefScoped); + verifyParameter(delegateTypesAndLambdas[3], 0, "out System.Int32", "x4", RefKind.Out, DeclarationScope.RefScoped); + verifyParameter(delegateTypesAndLambdas[3], 1, "out System.Int32", "y4", RefKind.Out, DeclarationScope.RefScoped); + verifyParameter(delegateTypesAndLambdas[4], 0, "ref R", "x5", RefKind.Ref, DeclarationScope.RefScoped); + verifyParameter(delegateTypesAndLambdas[4], 1, "ref R", "y5", RefKind.Ref, DeclarationScope.RefScoped); + verifyParameter(delegateTypesAndLambdas[5], 0, "in R", "x6", RefKind.In, DeclarationScope.RefScoped); + verifyParameter(delegateTypesAndLambdas[5], 1, "in R", "y6", RefKind.In, DeclarationScope.RefScoped); + verifyParameter(delegateTypesAndLambdas[6], 0, "out R", "x7", RefKind.Out, DeclarationScope.RefScoped); + verifyParameter(delegateTypesAndLambdas[6], 1, "out R", "y7", RefKind.Out, DeclarationScope.RefScoped); + } + + static void verifyParameter((NamedTypeSymbol, LambdaSymbol) delegateTypeAndLambda, int parameterIndex, string expectedDisplayType, string expectedDisplayName, RefKind expectedRefKind, DeclarationScope expectedScope) + { + var (delegateType, lambda) = delegateTypeAndLambda; + VerifyParameterSymbol(delegateType.DelegateInvokeMethod.Parameters[parameterIndex], expectedDisplayType, expectedRefKind, expectedScope); + VerifyParameterSymbol(lambda.Parameters[parameterIndex], $"{expectedDisplayType} {expectedDisplayName}", expectedRefKind, expectedScope); + } + + static (NamedTypeSymbol, LambdaSymbol) getDelegateTypeAndLambda(SemanticModel model, VariableDeclaratorSyntax decl) + { + var delegateType = (NamedTypeSymbol)model.GetDeclaredSymbol(decl).GetSymbol().Type; + var value = decl.DescendantNodes().OfType().Single(); + var lambda = model.GetSymbolInfo(value).Symbol.GetSymbol(); + return (delegateType, lambda); + } + } + + [Fact] + public void ParameterScope_05() + { + var source = +@"ref struct R { } +delegate void D1(scoped R r1); +delegate void D2(scoped ref R r2); +"; + var comp = CreateCompilation(source, parseOptions: TestOptions.Regular10); comp.VerifyEmitDiagnostics( - // (9,59): error CS8374: Cannot ref-assign 'tValue' to 'F' because 'tValue' has a narrower escape scope than 'F'. - // static void AssignValueToValue(S s, T tValue) { s.F = ref tValue; } // 1 - Diagnostic(ErrorCode.ERR_RefAssignNarrower, "s.F = ref tValue").WithArguments("F", "tValue").WithLocation(9, 59), - // (11,75): error CS8374: Cannot ref-assign 'tOut' to 'F' because 'tOut' has a narrower escape scope than 'F'. - // static void AssignOutToValue(S s, out T tOut) { tOut = default; s.F = ref tOut; } // 2 - Diagnostic(ErrorCode.ERR_RefAssignNarrower, "s.F = ref tOut").WithArguments("F", "tOut").WithLocation(11, 75), - // (12,69): error CS8331: Cannot assign to variable 'in T' because it is a readonly variable - // static void AssignInToValue(S s, in T tIn) { s.F = ref tIn; } // 3 - Diagnostic(ErrorCode.ERR_AssignReadonlyNotField, "tIn").WithArguments("variable", "in T").WithLocation(12, 69), - // (14,64): error CS8374: Cannot ref-assign 'tValue' to 'F' because 'tValue' has a narrower escape scope than 'F'. - // static void AssignValueToRef(ref S sRef, T tValue) { sRef.F = ref tValue; } // 4 - Diagnostic(ErrorCode.ERR_RefAssignNarrower, "sRef.F = ref tValue").WithArguments("F", "tValue").WithLocation(14, 64), - // (16,80): error CS8374: Cannot ref-assign 'tOut' to 'F' because 'tOut' has a narrower escape scope than 'F'. - // static void AssignOutToRef(ref S sRef, out T tOut) { tOut = default; sRef.F = ref tOut; } // 5 - Diagnostic(ErrorCode.ERR_RefAssignNarrower, "sRef.F = ref tOut").WithArguments("F", "tOut").WithLocation(16, 80), - // (17,77): error CS8331: Cannot assign to variable 'in T' because it is a readonly variable - // static void AssignInToRef(ref S sRef, in T tIn) { sRef.F = ref tIn; } // 6 - Diagnostic(ErrorCode.ERR_AssignReadonlyNotField, "tIn").WithArguments("variable", "in T").WithLocation(17, 77), - // (19,80): error CS8374: Cannot ref-assign 'tValue' to 'F' because 'tValue' has a narrower escape scope than 'F'. - // static void AssignValueToOut(out S sOut, T tValue) { sOut = default; sOut.F = ref tValue; } // 7 - Diagnostic(ErrorCode.ERR_RefAssignNarrower, "sOut.F = ref tValue").WithArguments("F", "tValue").WithLocation(19, 80), - // (21,96): error CS8374: Cannot ref-assign 'tOut' to 'F' because 'tOut' has a narrower escape scope than 'F'. - // static void AssignOutToOut(out S sOut, out T tOut) { sOut = default; tOut = default; sOut.F = ref tOut; } // 8 - Diagnostic(ErrorCode.ERR_RefAssignNarrower, "sOut.F = ref tOut").WithArguments("F", "tOut").WithLocation(21, 96), - // (22,93): error CS8331: Cannot assign to variable 'in T' because it is a readonly variable - // static void AssignInToOut(out S sOut, in T tIn) { sOut = default; sOut.F = ref tIn; } // 9 - Diagnostic(ErrorCode.ERR_AssignReadonlyNotField, "tIn").WithArguments("variable", "in T").WithLocation(22, 93), - // (24,61): error CS8332: Cannot assign to a member of variable 'in S' because it is a readonly variable - // static void AssignValueToIn(in S sIn, T tValue) { sIn.F = ref tValue; } // 10 - Diagnostic(ErrorCode.ERR_AssignReadonlyNotField2, "sIn.F").WithArguments("variable", "in S").WithLocation(24, 61), - // (25,61): error CS8332: Cannot assign to a member of variable 'in S' because it is a readonly variable - // static void AssignRefToIn(in S sIn, ref T tRef) { sIn.F = ref tRef; } // 11 - Diagnostic(ErrorCode.ERR_AssignReadonlyNotField2, "sIn.F").WithArguments("variable", "in S").WithLocation(25, 61), - // (26,77): error CS8332: Cannot assign to a member of variable 'in S' because it is a readonly variable - // static void AssignOutToIn(in S sIn, out T tOut) { tOut = default; sIn.F = ref tOut; } // 12 - Diagnostic(ErrorCode.ERR_AssignReadonlyNotField2, "sIn.F").WithArguments("variable", "in S").WithLocation(26, 77), - // (27,61): error CS8332: Cannot assign to a member of variable 'in S' because it is a readonly variable - // static void AssignInToIn(in S sIn, in T tIn) { sIn.F = ref tIn; } // 13 - Diagnostic(ErrorCode.ERR_AssignReadonlyNotField2, "sIn.F").WithArguments("variable", "in S").WithLocation(27, 61)); + // (2,18): error CS8936: Feature 'ref fields' is not available in C# 10.0. Please use language version 11.0 or greater. + // delegate void D1(scoped R r1); + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "scoped").WithArguments("ref fields", "11.0").WithLocation(2, 18), + // (3,18): error CS8936: Feature 'ref fields' is not available in C# 10.0. Please use language version 11.0 or greater. + // delegate void D2(scoped ref R r2); + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "scoped").WithArguments("ref fields", "11.0").WithLocation(3, 18)); + verify(comp); - // Valid cases from above. - source = -@"using System; + comp = CreateCompilation(source); + comp.VerifyEmitDiagnostics(); + verify(comp); -ref struct S -{ - public ref T F; - public S(ref T t) { F = ref t; } -} + static void verify(CSharpCompilation comp) + { + VerifyParameterSymbol(comp.GetMember("D1").DelegateInvokeMethod.Parameters[0], "scoped R r1", RefKind.None, DeclarationScope.ValueScoped); + VerifyParameterSymbol(comp.GetMember("D2").DelegateInvokeMethod.Parameters[0], "ref R r2", RefKind.Ref, DeclarationScope.RefScoped); + } + } + [Fact] + public void ParameterScope_06() + { + var source = +@"ref struct R { } class Program { - static void AssignRefToValue(S s, ref T tRef) { s.F = ref tRef; } + static void F1(scoped R r1) { } + static void F2(ref scoped R x, scoped ref int y) { } + static ref R F3(ref R r) => throw null; + static unsafe void Main() + { + delegate* f1 = &F1; + delegate* f2 = &F2; + delegate* f3 = &F3; + } +}"; + var comp = CreateCompilation(source, parseOptions: TestOptions.Regular10, options: TestOptions.UnsafeReleaseExe); + comp.VerifyEmitDiagnostics( + // (4,20): error CS8936: Feature 'ref fields' is not available in C# 10.0. Please use language version 11.0 or greater. + // static void F1(scoped R r1) { } + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "scoped").WithArguments("ref fields", "11.0").WithLocation(4, 20), + // (5,24): error CS8936: Feature 'ref fields' is not available in C# 10.0. Please use language version 11.0 or greater. + // static void F2(ref scoped R x, scoped ref int y) { } + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "scoped").WithArguments("ref fields", "11.0").WithLocation(5, 24), + // (5,24): error CS8339: The parameter modifier 'scoped' cannot follow 'ref' + // static void F2(ref scoped R x, scoped ref int y) { } + Diagnostic(ErrorCode.ERR_BadParameterModifiersOrder, "scoped").WithArguments("scoped", "ref").WithLocation(5, 24), + // (5,36): error CS8936: Feature 'ref fields' is not available in C# 10.0. Please use language version 11.0 or greater. + // static void F2(ref scoped R x, scoped ref int y) { } + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "scoped").WithArguments("ref fields", "11.0").WithLocation(5, 36), + // (9,19): error CS8755: 'scoped' cannot be used as a modifier on a function pointer parameter. + // delegate* f1 = &F1; + Diagnostic(ErrorCode.ERR_BadFuncPointerParamModifier, "scoped").WithArguments("scoped").WithLocation(9, 19), + // (9,40): error CS8986: The 'scoped' modifier of parameter 'r1' doesn't match target 'delegate*'. + // delegate* f1 = &F1; + Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfTarget, "&F1").WithArguments("r1", "delegate*").WithLocation(9, 40), + // (10,23): error CS8755: 'scoped' cannot be used as a modifier on a function pointer parameter. + // delegate* f2 = &F2; + Diagnostic(ErrorCode.ERR_BadFuncPointerParamModifier, "scoped").WithArguments("scoped").WithLocation(10, 23), + // (10,33): error CS8755: 'scoped' cannot be used as a modifier on a function pointer parameter. + // delegate* f2 = &F2; + Diagnostic(ErrorCode.ERR_BadFuncPointerParamModifier, "scoped").WithArguments("scoped").WithLocation(10, 33), + // (10,60): error CS8986: The 'scoped' modifier of parameter 'y' doesn't match target 'delegate*'. + // delegate* f2 = &F2; + Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfTarget, "&F2").WithArguments("y", "delegate*").WithLocation(10, 60)); + verify(comp); - static void AssignRefToRef(ref S sRef, ref T tRef) { sRef.F = ref tRef; } + comp = CreateCompilation(source, options: TestOptions.UnsafeReleaseExe); + comp.VerifyEmitDiagnostics( + // (5,24): error CS8339: The parameter modifier 'scoped' cannot follow 'ref' + // static void F2(ref scoped R x, scoped ref int y) { } + Diagnostic(ErrorCode.ERR_BadParameterModifiersOrder, "scoped").WithArguments("scoped", "ref").WithLocation(5, 24), + // (9,19): error CS8755: 'scoped' cannot be used as a modifier on a function pointer parameter. + // delegate* f1 = &F1; + Diagnostic(ErrorCode.ERR_BadFuncPointerParamModifier, "scoped").WithArguments("scoped").WithLocation(9, 19), + // (9,40): error CS8986: The 'scoped' modifier of parameter 'r1' doesn't match target 'delegate*'. + // delegate* f1 = &F1; + Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfTarget, "&F1").WithArguments("r1", "delegate*").WithLocation(9, 40), + // (10,23): error CS8755: 'scoped' cannot be used as a modifier on a function pointer parameter. + // delegate* f2 = &F2; + Diagnostic(ErrorCode.ERR_BadFuncPointerParamModifier, "scoped").WithArguments("scoped").WithLocation(10, 23), + // (10,33): error CS8755: 'scoped' cannot be used as a modifier on a function pointer parameter. + // delegate* f2 = &F2; + Diagnostic(ErrorCode.ERR_BadFuncPointerParamModifier, "scoped").WithArguments("scoped").WithLocation(10, 33), + // (10,60): error CS8986: The 'scoped' modifier of parameter 'y' doesn't match target 'delegate*'. + // delegate* f2 = &F2; + Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfTarget, "&F2").WithArguments("y", "delegate*").WithLocation(10, 60)); + verify(comp); - static void AssignRefToOut(out S sOut, ref T tRef) { sOut = default; sOut.F = ref tRef; } + static void verify(CSharpCompilation comp) + { + var tree = comp.SyntaxTrees[0]; + var model = comp.GetSemanticModel(tree); + var decls = tree.GetRoot().DescendantNodes().OfType().ToArray(); + var methods = decls.Select(d => ((FunctionPointerTypeSymbol)model.GetDeclaredSymbol(d).GetSymbol().Type).Signature).ToArray(); - static void Main() - { - int x, y; - scoped S s; + VerifyParameterSymbol(methods[0].Parameters[0], "R", RefKind.None, DeclarationScope.Unscoped); + VerifyParameterSymbol(methods[1].Parameters[0], "ref R", RefKind.Ref, DeclarationScope.RefScoped); + VerifyParameterSymbol(methods[1].Parameters[1], "ref System.Int32", RefKind.Ref, DeclarationScope.Unscoped); + VerifyParameterSymbol(methods[2].Parameters[0], "ref R", RefKind.Ref, DeclarationScope.RefScoped); + } + } - x = 1; y = 2; - s = new S(ref x); - AssignRefToValue(s, ref y); - Console.WriteLine(s.F); + [Fact] + public void ParameterScope_07() + { + var source = +@"ref struct R { } +class Program +{ + static void F0(scoped scoped R r) { } + static void F1(ref scoped scoped R r) { } + static void F2(scoped ref scoped R r) { } + static void F3(scoped scoped ref R r) { } + static void F4(in scoped scoped R r) { } + static void F5(scoped in scoped R r) { } + static void F6(scoped scoped in R r) { } + static void F7(out scoped scoped R r) { r = default; } + static void F8(scoped out scoped R r) { r = default; } + static void F9(scoped scoped out R r) { r = default; } +}"; + var comp = CreateCompilation(source); + comp.VerifyEmitDiagnostics( + // (4,27): error CS1107: A parameter can only have one 'scoped' modifier + // static void F0(scoped scoped R r) { } + Diagnostic(ErrorCode.ERR_DupParamMod, "scoped").WithArguments("scoped").WithLocation(4, 27), + // (5,24): error CS8339: The parameter modifier 'scoped' cannot follow 'ref' + // static void F1(ref scoped scoped R r) { } + Diagnostic(ErrorCode.ERR_BadParameterModifiersOrder, "scoped").WithArguments("scoped", "ref").WithLocation(5, 24), + // (5,31): error CS8339: The parameter modifier 'scoped' cannot follow 'ref' + // static void F1(ref scoped scoped R r) { } + Diagnostic(ErrorCode.ERR_BadParameterModifiersOrder, "scoped").WithArguments("scoped", "ref").WithLocation(5, 31), + // (6,31): error CS8339: The parameter modifier 'scoped' cannot follow 'ref' + // static void F2(scoped ref scoped R r) { } + Diagnostic(ErrorCode.ERR_BadParameterModifiersOrder, "scoped").WithArguments("scoped", "ref").WithLocation(6, 31), + // (7,27): error CS1107: A parameter can only have one 'scoped' modifier + // static void F3(scoped scoped ref R r) { } + Diagnostic(ErrorCode.ERR_DupParamMod, "scoped").WithArguments("scoped").WithLocation(7, 27), + // (8,23): error CS8339: The parameter modifier 'scoped' cannot follow 'in' + // static void F4(in scoped scoped R r) { } + Diagnostic(ErrorCode.ERR_BadParameterModifiersOrder, "scoped").WithArguments("scoped", "in").WithLocation(8, 23), + // (8,30): error CS8339: The parameter modifier 'scoped' cannot follow 'in' + // static void F4(in scoped scoped R r) { } + Diagnostic(ErrorCode.ERR_BadParameterModifiersOrder, "scoped").WithArguments("scoped", "in").WithLocation(8, 30), + // (9,30): error CS8339: The parameter modifier 'scoped' cannot follow 'in' + // static void F5(scoped in scoped R r) { } + Diagnostic(ErrorCode.ERR_BadParameterModifiersOrder, "scoped").WithArguments("scoped", "in").WithLocation(9, 30), + // (10,27): error CS1107: A parameter can only have one 'scoped' modifier + // static void F6(scoped scoped in R r) { } + Diagnostic(ErrorCode.ERR_DupParamMod, "scoped").WithArguments("scoped").WithLocation(10, 27), + // (11,24): error CS8339: The parameter modifier 'scoped' cannot follow 'out' + // static void F7(out scoped scoped R r) { r = default; } + Diagnostic(ErrorCode.ERR_BadParameterModifiersOrder, "scoped").WithArguments("scoped", "out").WithLocation(11, 24), + // (11,31): error CS8339: The parameter modifier 'scoped' cannot follow 'out' + // static void F7(out scoped scoped R r) { r = default; } + Diagnostic(ErrorCode.ERR_BadParameterModifiersOrder, "scoped").WithArguments("scoped", "out").WithLocation(11, 31), + // (12,31): error CS8339: The parameter modifier 'scoped' cannot follow 'out' + // static void F8(scoped out scoped R r) { r = default; } + Diagnostic(ErrorCode.ERR_BadParameterModifiersOrder, "scoped").WithArguments("scoped", "out").WithLocation(12, 31), + // (13,27): error CS1107: A parameter can only have one 'scoped' modifier + // static void F9(scoped scoped out R r) { r = default; } + Diagnostic(ErrorCode.ERR_DupParamMod, "scoped").WithArguments("scoped").WithLocation(13, 27)); - x = 3; y = 4; - s = new S(ref x); - AssignRefToRef(ref s, ref y); - Console.WriteLine(s.F); + VerifyParameterSymbol(comp.GetMember("Program.F0").Parameters[0], "scoped R r", RefKind.None, DeclarationScope.ValueScoped); + VerifyParameterSymbol(comp.GetMember("Program.F1").Parameters[0], "ref R r", RefKind.Ref, DeclarationScope.RefScoped); + VerifyParameterSymbol(comp.GetMember("Program.F2").Parameters[0], "ref R r", RefKind.Ref, DeclarationScope.RefScoped); + VerifyParameterSymbol(comp.GetMember("Program.F3").Parameters[0], "ref R r", RefKind.Ref, DeclarationScope.RefScoped); + VerifyParameterSymbol(comp.GetMember("Program.F4").Parameters[0], "in R r", RefKind.In, DeclarationScope.RefScoped); + VerifyParameterSymbol(comp.GetMember("Program.F5").Parameters[0], "in R r", RefKind.In, DeclarationScope.RefScoped); + VerifyParameterSymbol(comp.GetMember("Program.F6").Parameters[0], "in R r", RefKind.In, DeclarationScope.RefScoped); + VerifyParameterSymbol(comp.GetMember("Program.F7").Parameters[0], "out R r", RefKind.Out, DeclarationScope.RefScoped); + VerifyParameterSymbol(comp.GetMember("Program.F8").Parameters[0], "out R r", RefKind.Out, DeclarationScope.RefScoped); + VerifyParameterSymbol(comp.GetMember("Program.F9").Parameters[0], "out R r", RefKind.Out, DeclarationScope.RefScoped); + } - x = 5; y = 6; - s = new S(ref x); - AssignRefToOut(out s, ref y); - Console.WriteLine(s.F); + [Fact] + public void ParameterScope_08() + { + var source = +@"ref struct R { } +class Program +{ + static void Main() + { + var f1 = (scoped scoped R r) => { }; + var f2 = (ref scoped scoped R r) => { }; + var f3 = (scoped scoped ref R r) => { }; } }"; - var verifier = CompileAndVerify(source, verify: Verification.Skipped, expectedOutput: IncludeExpectedOutput( -@"1 -4 -6")); - verifier.VerifyILMultiple( - "Program.AssignRefToValue", -@"{ - // Code size 9 (0x9) - .maxstack 2 - IL_0000: ldarga.s V_0 - IL_0002: ldarg.1 - IL_0003: stfld ""ref T S.F"" - IL_0008: ret -}", - "Program.AssignRefToRef", -@"{ - // Code size 8 (0x8) - .maxstack 2 - IL_0000: ldarg.0 - IL_0001: ldarg.1 - IL_0002: stfld ""ref T S.F"" - IL_0007: ret -}", - "Program.AssignRefToOut", -@"{ - // Code size 15 (0xf) - .maxstack 2 - IL_0000: ldarg.0 - IL_0001: initobj ""S"" - IL_0007: ldarg.0 - IL_0008: ldarg.1 - IL_0009: stfld ""ref T S.F"" - IL_000e: ret -}"); + var comp = CreateCompilation(source); + comp.VerifyEmitDiagnostics( + // (6,26): error CS1107: A parameter can only have one 'scoped' modifier + // var f1 = (scoped scoped R r) => { }; + Diagnostic(ErrorCode.ERR_DupParamMod, "scoped").WithArguments("scoped").WithLocation(6, 26), + // (7,23): error CS8339: The parameter modifier 'scoped' cannot follow 'ref' + // var f2 = (ref scoped scoped R r) => { }; + Diagnostic(ErrorCode.ERR_BadParameterModifiersOrder, "scoped").WithArguments("scoped", "ref").WithLocation(7, 23), + // (7,30): error CS8339: The parameter modifier 'scoped' cannot follow 'ref' + // var f2 = (ref scoped scoped R r) => { }; + Diagnostic(ErrorCode.ERR_BadParameterModifiersOrder, "scoped").WithArguments("scoped", "ref").WithLocation(7, 30), + // (8,26): error CS1107: A parameter can only have one 'scoped' modifier + // var f3 = (scoped scoped ref R r) => { }; + Diagnostic(ErrorCode.ERR_DupParamMod, "scoped").WithArguments("scoped").WithLocation(8, 26)); } [Fact] - public void AssignRefTo_RefReadonlyField() + public void ParameterScope_09() { var source = -@"ref struct S -{ - public ref readonly T F; - public S(ref T t) { F = ref t; } -} - +@"ref struct @scoped { } class Program { - static void AssignValueToValue(S s, T tValue) { s.F = ref tValue; } // 1 - static void AssignRefToValue(S s, ref T tRef) { s.F = ref tRef; } - static void AssignOutToValue(S s, out T tOut) { tOut = default; s.F = ref tOut; } // 2 - static void AssignInToValue(S s, in T tIn) { s.F = ref tIn; } - - static void AssignValueToRef(ref S sRef, T tValue) { sRef.F = ref tValue; } // 3 - static void AssignRefToRef(ref S sRef, ref T tRef) { sRef.F = ref tRef; } - static void AssignOutToRef(ref S sRef, out T tOut) { tOut = default; sRef.F = ref tOut; } // 4 - static void AssignInToRef(ref S sRef, in T tIn) { sRef.F = ref tIn; } - - static void AssignValueToOut(out S sOut, T tValue) { sOut = default; sOut.F = ref tValue; } // 5 - static void AssignRefToOut(out S sOut, ref T tRef) { sOut = default; sOut.F = ref tRef; } - static void AssignOutToOut(out S sOut, out T tOut) { sOut = default; tOut = default; sOut.F = ref tOut; } // 6 - static void AssignInToOut(out S sOut, in T tIn) { sOut = default; sOut.F = ref tIn; } - - static void AssignValueToIn(in S sIn, T tValue) { sIn.F = ref tValue; } // 7 - static void AssignRefToIn(in S sIn, ref T tRef) { sIn.F = ref tRef; } // 8 - static void AssignOutToIn(in S sIn, out T tOut) { tOut = default; sIn.F = ref tOut; } // 9 - static void AssignInToIn(in S sIn, in T tIn) { sIn.F = ref tIn; } // 10 + static void F0(scoped s) { } + static void F1(scoped scoped s) { } + static void F2(ref scoped s) { } + static void F3(ref scoped scoped s) { } + static void F4(scoped ref scoped s) { } + static void F5(in scoped s) { } + static void F6(in scoped scoped s) { } + static void F7(scoped in scoped s) { } + static void F8(out scoped s) { s = default; } + static void F9(out scoped scoped s) { s = default; } + static void FA(scoped out scoped s) { s = default; } }"; var comp = CreateCompilation(source); comp.VerifyEmitDiagnostics( - // (9,59): error CS8374: Cannot ref-assign 'tValue' to 'F' because 'tValue' has a narrower escape scope than 'F'. - // static void AssignValueToValue(S s, T tValue) { s.F = ref tValue; } // 1 - Diagnostic(ErrorCode.ERR_RefAssignNarrower, "s.F = ref tValue").WithArguments("F", "tValue").WithLocation(9, 59), - // (11,75): error CS8374: Cannot ref-assign 'tOut' to 'F' because 'tOut' has a narrower escape scope than 'F'. - // static void AssignOutToValue(S s, out T tOut) { tOut = default; s.F = ref tOut; } // 2 - Diagnostic(ErrorCode.ERR_RefAssignNarrower, "s.F = ref tOut").WithArguments("F", "tOut").WithLocation(11, 75), - // (14,64): error CS8374: Cannot ref-assign 'tValue' to 'F' because 'tValue' has a narrower escape scope than 'F'. - // static void AssignValueToRef(ref S sRef, T tValue) { sRef.F = ref tValue; } // 3 - Diagnostic(ErrorCode.ERR_RefAssignNarrower, "sRef.F = ref tValue").WithArguments("F", "tValue").WithLocation(14, 64), - // (16,80): error CS8374: Cannot ref-assign 'tOut' to 'F' because 'tOut' has a narrower escape scope than 'F'. - // static void AssignOutToRef(ref S sRef, out T tOut) { tOut = default; sRef.F = ref tOut; } // 4 - Diagnostic(ErrorCode.ERR_RefAssignNarrower, "sRef.F = ref tOut").WithArguments("F", "tOut").WithLocation(16, 80), - // (19,80): error CS8374: Cannot ref-assign 'tValue' to 'F' because 'tValue' has a narrower escape scope than 'F'. - // static void AssignValueToOut(out S sOut, T tValue) { sOut = default; sOut.F = ref tValue; } // 5 - Diagnostic(ErrorCode.ERR_RefAssignNarrower, "sOut.F = ref tValue").WithArguments("F", "tValue").WithLocation(19, 80), - // (21,96): error CS8374: Cannot ref-assign 'tOut' to 'F' because 'tOut' has a narrower escape scope than 'F'. - // static void AssignOutToOut(out S sOut, out T tOut) { sOut = default; tOut = default; sOut.F = ref tOut; } // 6 - Diagnostic(ErrorCode.ERR_RefAssignNarrower, "sOut.F = ref tOut").WithArguments("F", "tOut").WithLocation(21, 96), - // (24,61): error CS8332: Cannot assign to a member of variable 'in S' because it is a readonly variable - // static void AssignValueToIn(in S sIn, T tValue) { sIn.F = ref tValue; } // 7 - Diagnostic(ErrorCode.ERR_AssignReadonlyNotField2, "sIn.F").WithArguments("variable", "in S").WithLocation(24, 61), - // (25,61): error CS8332: Cannot assign to a member of variable 'in S' because it is a readonly variable - // static void AssignRefToIn(in S sIn, ref T tRef) { sIn.F = ref tRef; } // 8 - Diagnostic(ErrorCode.ERR_AssignReadonlyNotField2, "sIn.F").WithArguments("variable", "in S").WithLocation(25, 61), - // (26,77): error CS8332: Cannot assign to a member of variable 'in S' because it is a readonly variable - // static void AssignOutToIn(in S sIn, out T tOut) { tOut = default; sIn.F = ref tOut; } // 9 - Diagnostic(ErrorCode.ERR_AssignReadonlyNotField2, "sIn.F").WithArguments("variable", "in S").WithLocation(26, 77), - // (27,61): error CS8332: Cannot assign to a member of variable 'in S' because it is a readonly variable - // static void AssignInToIn(in S sIn, in T tIn) { sIn.F = ref tIn; } // 10 - Diagnostic(ErrorCode.ERR_AssignReadonlyNotField2, "sIn.F").WithArguments("variable", "in S").WithLocation(27, 61)); - - // Valid cases from above. - source = -@"using System; + // (7,24): error CS8339: The parameter modifier 'scoped' cannot follow 'ref' + // static void F3(ref scoped scoped s) { } + Diagnostic(ErrorCode.ERR_BadParameterModifiersOrder, "scoped").WithArguments("scoped", "ref").WithLocation(7, 24), + // (10,23): error CS8339: The parameter modifier 'scoped' cannot follow 'in' + // static void F6(in scoped scoped s) { } + Diagnostic(ErrorCode.ERR_BadParameterModifiersOrder, "scoped").WithArguments("scoped", "in").WithLocation(10, 23), + // (13,24): error CS8339: The parameter modifier 'scoped' cannot follow 'out' + // static void F9(out scoped scoped s) { s = default; } + Diagnostic(ErrorCode.ERR_BadParameterModifiersOrder, "scoped").WithArguments("scoped", "out").WithLocation(13, 24)); -ref struct S -{ - public ref readonly T F; - public S(ref T t) { F = ref t; } -} + VerifyParameterSymbol(comp.GetMember("Program.F0").Parameters[0], "scoped s", RefKind.None, DeclarationScope.Unscoped); + VerifyParameterSymbol(comp.GetMember("Program.F1").Parameters[0], "scoped scoped s", RefKind.None, DeclarationScope.ValueScoped); + VerifyParameterSymbol(comp.GetMember("Program.F2").Parameters[0], "ref scoped s", RefKind.Ref, DeclarationScope.RefScoped); + VerifyParameterSymbol(comp.GetMember("Program.F3").Parameters[0], "ref scoped s", RefKind.Ref, DeclarationScope.RefScoped); + VerifyParameterSymbol(comp.GetMember("Program.F4").Parameters[0], "ref scoped s", RefKind.Ref, DeclarationScope.RefScoped); + VerifyParameterSymbol(comp.GetMember("Program.F5").Parameters[0], "in scoped s", RefKind.In, DeclarationScope.RefScoped); + VerifyParameterSymbol(comp.GetMember("Program.F6").Parameters[0], "in scoped s", RefKind.In, DeclarationScope.RefScoped); + VerifyParameterSymbol(comp.GetMember("Program.F7").Parameters[0], "in scoped s", RefKind.In, DeclarationScope.RefScoped); + VerifyParameterSymbol(comp.GetMember("Program.F8").Parameters[0], "out scoped s", RefKind.Out, DeclarationScope.RefScoped); + VerifyParameterSymbol(comp.GetMember("Program.F9").Parameters[0], "out scoped s", RefKind.Out, DeclarationScope.RefScoped); + VerifyParameterSymbol(comp.GetMember("Program.FA").Parameters[0], "out scoped s", RefKind.Out, DeclarationScope.RefScoped); + } + [WorkItem(62080, "https://github.com/dotnet/roslyn/issues/62080")] + [Fact] + public void ParameterScope_11() + { + var source = +@"ref struct R { } +delegate R D1(R r); +delegate R D2(scoped R r); class Program { - static void AssignRefToValue(S s, ref T tRef) { s.F = ref tRef; } - static void AssignInToValue(S s, in T tIn) { s.F = ref tIn; } + static void Main() + { + D1 d1 = r1 => r1; + D2 d2 = r2 => r2; + } +}"; + var comp = CreateCompilation(source); + // https://github.com/dotnet/roslyn/issues/62080: Lambda parameter r2 should be inferred as 'scoped R' rather than 'R'. + comp.VerifyEmitDiagnostics( + // (9,17): error CS8986: The 'scoped' modifier of parameter 'r2' doesn't match target 'D2'. + // D2 d2 = r2 => r2; + Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfTarget, "r2 => r2").WithArguments("r2", "D2").WithLocation(9, 17)); - static void AssignRefToRef(ref S sRef, ref T tRef) { sRef.F = ref tRef; } - static void AssignInToRef(ref S sRef, in T tIn) { sRef.F = ref tIn; } + var tree = comp.SyntaxTrees[0]; + var model = comp.GetSemanticModel(tree); + var lambdas = tree.GetRoot().DescendantNodes().OfType().Select(e => model.GetSymbolInfo(e).Symbol.GetSymbol()).ToArray(); - static void AssignRefToOut(out S sOut, ref T tRef) { sOut = default; sOut.F = ref tRef; } - static void AssignInToOut(out S sOut, in T tIn) { sOut = default; sOut.F = ref tIn; } + VerifyParameterSymbol(lambdas[0].Parameters[0], "R r1", RefKind.None, DeclarationScope.Unscoped); + VerifyParameterSymbol(lambdas[1].Parameters[0], "R r2", RefKind.None, DeclarationScope.Unscoped); + } + + [Fact] + public void ParameterScope_12() + { + var source0 = +@".class private System.Runtime.CompilerServices.ScopedRefAttribute extends [mscorlib]System.Attribute +{ + .method public hidebysig specialname rtspecialname instance void .ctor() cil managed { ret } +} +.class public A +{ + .method public static void F1([out] int32& i) + { + .param [1] + .custom instance void System.Runtime.CompilerServices.ScopedRefAttribute::.ctor() = ( 01 00 00 00 ) // ScopedRefAttribute() + ldnull + throw + } +} +"; + var ref0 = CompileIL(source0); + var source1 = +@"class Program +{ static void Main() { - int x, y; - scoped S s; + int i; + A.F1(out i); + } +}"; + var comp = CreateCompilation(source1, references: new[] { ref0 }); + comp.VerifyDiagnostics(); - x = 1; y = 2; - s = new S(ref x); - AssignRefToValue(s, ref y); - Console.WriteLine(s.F); - x = 1; y = 2; - s = new S(ref x); - AssignInToValue(s, y); - Console.WriteLine(s.F); + VerifyParameterSymbol(comp.GetMember("A.F1").Parameters[0], "out System.Int32 i", RefKind.Out, DeclarationScope.RefScoped); + } - x = 3; y = 4; - s = new S(ref x); - AssignRefToRef(ref s, ref y); - Console.WriteLine(s.F); - x = 3; y = 4; - s = new S(ref x); - AssignInToRef(ref s, y); - Console.WriteLine(s.F); + [WorkItem(62691, "https://github.com/dotnet/roslyn/issues/62691")] + [CombinatorialData] + [Theory] + public void RefToRefStructParameter_01(bool useCompilationReference) + { + var sourceA = +@"public ref struct R { } +public class A +{ + public static void F(R a, ref R b, in R c, out R d) { d = default; } +}"; + var comp = CreateCompilation(sourceA); + comp.VerifyDiagnostics(); + var refA = AsReference(comp, useCompilationReference); - x = 5; y = 6; - s = new S(ref x); - AssignRefToOut(out s, ref y); - Console.WriteLine(s.F); - x = 5; y = 6; - s = new S(ref x); - AssignInToOut(out s, y); - Console.WriteLine(s.F); + var sourceB = +@"class B +{ + static void Main() + { + R a = new R(); + R b = new R(); + R c = new R(); + R d; + A.F(a, ref b, in c, out d); } }"; - var verifier = CompileAndVerify(source, verify: Verification.Skipped, expectedOutput: IncludeExpectedOutput( -@"1 -1 -4 -4 -6 -6")); - verifier.VerifyILMultiple( - "Program.AssignRefToValue", -@"{ - // Code size 9 (0x9) - .maxstack 2 - IL_0000: ldarga.s V_0 - IL_0002: ldarg.1 - IL_0003: stfld ""ref readonly T S.F"" - IL_0008: ret -}", - "Program.AssignInToValue", -@"{ - // Code size 9 (0x9) - .maxstack 2 - IL_0000: ldarga.s V_0 - IL_0002: ldarg.1 - IL_0003: stfld ""ref readonly T S.F"" - IL_0008: ret -}", - "Program.AssignRefToRef", -@"{ - // Code size 8 (0x8) - .maxstack 2 - IL_0000: ldarg.0 - IL_0001: ldarg.1 - IL_0002: stfld ""ref readonly T S.F"" - IL_0007: ret -}", - "Program.AssignInToRef", -@"{ - // Code size 8 (0x8) - .maxstack 2 - IL_0000: ldarg.0 - IL_0001: ldarg.1 - IL_0002: stfld ""ref readonly T S.F"" - IL_0007: ret -}", - "Program.AssignRefToOut", -@"{ - // Code size 15 (0xf) - .maxstack 2 - IL_0000: ldarg.0 - IL_0001: initobj ""S"" - IL_0007: ldarg.0 - IL_0008: ldarg.1 - IL_0009: stfld ""ref readonly T S.F"" - IL_000e: ret -}", - "Program.AssignInToOut", -@"{ - // Code size 15 (0xf) - .maxstack 2 - IL_0000: ldarg.0 - IL_0001: initobj ""S"" - IL_0007: ldarg.0 - IL_0008: ldarg.1 - IL_0009: stfld ""ref readonly T S.F"" - IL_000e: ret -}"); + comp = CreateCompilation(sourceB, references: new[] { refA }); + comp.VerifyEmitDiagnostics(); + + var parameters = comp.GetMember("A.F").Parameters; + VerifyParameterSymbol(parameters[0], "R a", RefKind.None, DeclarationScope.Unscoped); + VerifyParameterSymbol(parameters[1], "ref R b", RefKind.Ref, DeclarationScope.RefScoped); + VerifyParameterSymbol(parameters[2], "in R c", RefKind.In, DeclarationScope.RefScoped); + VerifyParameterSymbol(parameters[3], "out R d", RefKind.Out, DeclarationScope.RefScoped); + + // https://github.com/dotnet/roslyn/issues/62780: Test additional cases with [UnscopedRef]. } + [WorkItem(62691, "https://github.com/dotnet/roslyn/issues/62691")] [Fact] - public void AssignRefTo_ReadonlyRefField() + public void RefToRefStructParameter_02() { var source = -@"ref struct S +@"ref struct R { - public readonly ref T F; - public S(ref T t) { F = ref t; } + public ref int F; + public R(ref int i) { F = ref i; } } - class Program { - static void AssignValueToValue(S s, T tValue) { s.F = ref tValue; } // 1 - static void AssignRefToValue(S s, ref T tRef) { s.F = ref tRef; } // 2 - static void AssignOutToValue(S s, out T tOut) { tOut = default; s.F = ref tOut; } // 3 - static void AssignInToValue(S s, in T tIn) { s.F = ref tIn; } // 4 - - static void AssignValueToRef(ref S sRef, T tValue) { sRef.F = ref tValue; } // 5 - static void AssignRefToRef(ref S sRef, ref T tRef) { sRef.F = ref tRef; } // 6 - static void AssignOutToRef(ref S sRef, out T tOut) { tOut = default; sRef.F = ref tOut; } // 7 - static void AssignInToRef(ref S sRef, in T tIn) { sRef.F = ref tIn; } // 8 - - static void AssignValueToOut(out S sOut, T tValue) { sOut = default; sOut.F = ref tValue; } // 9 - static void AssignRefToOut(out S sOut, ref T tRef) { sOut = default; sOut.F = ref tRef; } // 10 - static void AssignOutToOut(out S sOut, out T tOut) { sOut = default; tOut = default; sOut.F = ref tOut; } // 11 - static void AssignInToOut(out S sOut, in T tIn) { sOut = default; sOut.F = ref tIn; } // 12 - - static void AssignValueToIn(in S sIn, T tValue) { sIn.F = ref tValue; } // 13 - static void AssignRefToIn(in S sIn, ref T tRef) { sIn.F = ref tRef; } // 14 - static void AssignOutToIn(in S sIn, out T tOut) { tOut = default; sIn.F = ref tOut; } // 15 - static void AssignInToIn(in S sIn, in T tIn) { sIn.F = ref tIn; } // 16 + static ref R F1() + { + int i = 42; + var r1 = new R(ref i); + return ref ReturnRef(ref r1); // 1 + } + static ref R F2(ref int i) + { + var r2 = new R(ref i); + return ref ReturnRef(ref r2); + } + static ref R ReturnRef(ref R r) => throw null; }"; - var comp = CreateCompilation(source); - comp.VerifyEmitDiagnostics( - // (9,59): error CS0191: A readonly field cannot be assigned to (except in a constructor or init-only setter of the type in which the field is defined or a variable initializer) - // static void AssignValueToValue(S s, T tValue) { s.F = ref tValue; } // 1 - Diagnostic(ErrorCode.ERR_AssgReadonly, "s.F").WithLocation(9, 59), - // (10,59): error CS0191: A readonly field cannot be assigned to (except in a constructor or init-only setter of the type in which the field is defined or a variable initializer) - // static void AssignRefToValue(S s, ref T tRef) { s.F = ref tRef; } // 2 - Diagnostic(ErrorCode.ERR_AssgReadonly, "s.F").WithLocation(10, 59), - // (11,75): error CS0191: A readonly field cannot be assigned to (except in a constructor or init-only setter of the type in which the field is defined or a variable initializer) - // static void AssignOutToValue(S s, out T tOut) { tOut = default; s.F = ref tOut; } // 3 - Diagnostic(ErrorCode.ERR_AssgReadonly, "s.F").WithLocation(11, 75), - // (12,59): error CS0191: A readonly field cannot be assigned to (except in a constructor or init-only setter of the type in which the field is defined or a variable initializer) - // static void AssignInToValue(S s, in T tIn) { s.F = ref tIn; } // 4 - Diagnostic(ErrorCode.ERR_AssgReadonly, "s.F").WithLocation(12, 59), - // (14,64): error CS0191: A readonly field cannot be assigned to (except in a constructor or init-only setter of the type in which the field is defined or a variable initializer) - // static void AssignValueToRef(ref S sRef, T tValue) { sRef.F = ref tValue; } // 5 - Diagnostic(ErrorCode.ERR_AssgReadonly, "sRef.F").WithLocation(14, 64), - // (15,64): error CS0191: A readonly field cannot be assigned to (except in a constructor or init-only setter of the type in which the field is defined or a variable initializer) - // static void AssignRefToRef(ref S sRef, ref T tRef) { sRef.F = ref tRef; } // 6 - Diagnostic(ErrorCode.ERR_AssgReadonly, "sRef.F").WithLocation(15, 64), - // (16,80): error CS0191: A readonly field cannot be assigned to (except in a constructor or init-only setter of the type in which the field is defined or a variable initializer) - // static void AssignOutToRef(ref S sRef, out T tOut) { tOut = default; sRef.F = ref tOut; } // 7 - Diagnostic(ErrorCode.ERR_AssgReadonly, "sRef.F").WithLocation(16, 80), - // (17,64): error CS0191: A readonly field cannot be assigned to (except in a constructor or init-only setter of the type in which the field is defined or a variable initializer) - // static void AssignInToRef(ref S sRef, in T tIn) { sRef.F = ref tIn; } // 8 - Diagnostic(ErrorCode.ERR_AssgReadonly, "sRef.F").WithLocation(17, 64), - // (19,80): error CS0191: A readonly field cannot be assigned to (except in a constructor or init-only setter of the type in which the field is defined or a variable initializer) - // static void AssignValueToOut(out S sOut, T tValue) { sOut = default; sOut.F = ref tValue; } // 9 - Diagnostic(ErrorCode.ERR_AssgReadonly, "sOut.F").WithLocation(19, 80), - // (20,80): error CS0191: A readonly field cannot be assigned to (except in a constructor or init-only setter of the type in which the field is defined or a variable initializer) - // static void AssignRefToOut(out S sOut, ref T tRef) { sOut = default; sOut.F = ref tRef; } // 10 - Diagnostic(ErrorCode.ERR_AssgReadonly, "sOut.F").WithLocation(20, 80), - // (21,96): error CS0191: A readonly field cannot be assigned to (except in a constructor or init-only setter of the type in which the field is defined or a variable initializer) - // static void AssignOutToOut(out S sOut, out T tOut) { sOut = default; tOut = default; sOut.F = ref tOut; } // 11 - Diagnostic(ErrorCode.ERR_AssgReadonly, "sOut.F").WithLocation(21, 96), - // (22,80): error CS0191: A readonly field cannot be assigned to (except in a constructor or init-only setter of the type in which the field is defined or a variable initializer) - // static void AssignInToOut(out S sOut, in T tIn) { sOut = default; sOut.F = ref tIn; } // 12 - Diagnostic(ErrorCode.ERR_AssgReadonly, "sOut.F").WithLocation(22, 80), - // (24,61): error CS0191: A readonly field cannot be assigned to (except in a constructor or init-only setter of the type in which the field is defined or a variable initializer) - // static void AssignValueToIn(in S sIn, T tValue) { sIn.F = ref tValue; } // 13 - Diagnostic(ErrorCode.ERR_AssgReadonly, "sIn.F").WithLocation(24, 61), - // (25,61): error CS0191: A readonly field cannot be assigned to (except in a constructor or init-only setter of the type in which the field is defined or a variable initializer) - // static void AssignRefToIn(in S sIn, ref T tRef) { sIn.F = ref tRef; } // 14 - Diagnostic(ErrorCode.ERR_AssgReadonly, "sIn.F").WithLocation(25, 61), - // (26,77): error CS0191: A readonly field cannot be assigned to (except in a constructor or init-only setter of the type in which the field is defined or a variable initializer) - // static void AssignOutToIn(in S sIn, out T tOut) { tOut = default; sIn.F = ref tOut; } // 15 - Diagnostic(ErrorCode.ERR_AssgReadonly, "sIn.F").WithLocation(26, 77), - // (27,61): error CS0191: A readonly field cannot be assigned to (except in a constructor or init-only setter of the type in which the field is defined or a variable initializer) - // static void AssignInToIn(in S sIn, in T tIn) { sIn.F = ref tIn; } // 16 - Diagnostic(ErrorCode.ERR_AssgReadonly, "sIn.F").WithLocation(27, 61)); + var comp = CreateCompilation(source, runtimeFeature: RuntimeFlag.ByRefFields); + comp.VerifyDiagnostics( + // (12,20): error CS8347: Cannot use a result of 'Program.ReturnRef(ref R)' in this context because it may expose variables referenced by parameter 'r' outside of their declaration scope + // return ref ReturnRef(ref r1); // 1 + Diagnostic(ErrorCode.ERR_EscapeCall, "ReturnRef(ref r1)").WithArguments("Program.ReturnRef(ref R)", "r").WithLocation(12, 20), + // (12,34): error CS8352: Cannot use variable 'r1' in this context because it may expose referenced variables outside of their declaration scope + // return ref ReturnRef(ref r1); // 1 + Diagnostic(ErrorCode.ERR_EscapeVariable, "r1").WithArguments("r1").WithLocation(12, 34)); + + VerifyParameterSymbol(comp.GetMember("Program.ReturnRef").Parameters[0], "ref R r", RefKind.Ref, DeclarationScope.RefScoped); } [Fact] - public void AssignRefTo_ReadonlyRefReadonlyField() + public void ThisScope() { var source = -@"ref struct S +@"class C { - public readonly ref readonly T F; - public S(ref T t) { F = ref t; } + public C() { } + void F1() { } } - -class Program +struct S1 { - static void AssignValueToValue(S s, T tValue) { s.F = ref tValue; } // 1 - static void AssignRefToValue(S s, ref T tRef) { s.F = ref tRef; } // 2 - static void AssignOutToValue(S s, out T tOut) { tOut = default; s.F = ref tOut; } // 3 - static void AssignInToValue(S s, in T tIn) { s.F = ref tIn; } // 4 - - static void AssignValueToRef(ref S sRef, T tValue) { sRef.F = ref tValue; } // 5 - static void AssignRefToRef(ref S sRef, ref T tRef) { sRef.F = ref tRef; } // 6 - static void AssignOutToRef(ref S sRef, out T tOut) { tOut = default; sRef.F = ref tOut; } // 7 - static void AssignInToRef(ref S sRef, in T tIn) { sRef.F = ref tIn; } // 8 - - static void AssignValueToOut(out S sOut, T tValue) { sOut = default; sOut.F = ref tValue; } // 9 - static void AssignRefToOut(out S sOut, ref T tRef) { sOut = default; sOut.F = ref tRef; } // 10 - static void AssignOutToOut(out S sOut, out T tOut) { sOut = default; tOut = default; sOut.F = ref tOut; } // 11 - static void AssignInToOut(out S sOut, in T tIn) { sOut = default; sOut.F = ref tIn; } // 12 - - static void AssignValueToIn(in S sIn, T tValue) { sIn.F = ref tValue; } // 13 - static void AssignRefToIn(in S sIn, ref T tRef) { sIn.F = ref tRef; } // 14 - static void AssignOutToIn(in S sIn, out T tOut) { tOut = default; sIn.F = ref tOut; } // 15 - static void AssignInToIn(in S sIn, in T tIn) { sIn.F = ref tIn; } // 16 + public S1() { } + void F1() { } + readonly void F2() { } +} +ref struct R1 +{ + public R1() { } + void F1() { } + readonly void F2() { } +} +readonly struct S2 +{ + public S2() { } + void F1() { } + readonly void F2() { } +} +readonly ref struct R2 +{ + public R2() { } + void F1() { } + readonly void F2() { } }"; var comp = CreateCompilation(source); - comp.VerifyEmitDiagnostics( - // (9,59): error CS0191: A readonly field cannot be assigned to (except in a constructor or init-only setter of the type in which the field is defined or a variable initializer) - // static void AssignValueToValue(S s, T tValue) { s.F = ref tValue; } // 1 - Diagnostic(ErrorCode.ERR_AssgReadonly, "s.F").WithLocation(9, 59), - // (10,59): error CS0191: A readonly field cannot be assigned to (except in a constructor or init-only setter of the type in which the field is defined or a variable initializer) - // static void AssignRefToValue(S s, ref T tRef) { s.F = ref tRef; } // 2 - Diagnostic(ErrorCode.ERR_AssgReadonly, "s.F").WithLocation(10, 59), - // (11,75): error CS0191: A readonly field cannot be assigned to (except in a constructor or init-only setter of the type in which the field is defined or a variable initializer) - // static void AssignOutToValue(S s, out T tOut) { tOut = default; s.F = ref tOut; } // 3 - Diagnostic(ErrorCode.ERR_AssgReadonly, "s.F").WithLocation(11, 75), - // (12,59): error CS0191: A readonly field cannot be assigned to (except in a constructor or init-only setter of the type in which the field is defined or a variable initializer) - // static void AssignInToValue(S s, in T tIn) { s.F = ref tIn; } // 4 - Diagnostic(ErrorCode.ERR_AssgReadonly, "s.F").WithLocation(12, 59), - // (14,64): error CS0191: A readonly field cannot be assigned to (except in a constructor or init-only setter of the type in which the field is defined or a variable initializer) - // static void AssignValueToRef(ref S sRef, T tValue) { sRef.F = ref tValue; } // 5 - Diagnostic(ErrorCode.ERR_AssgReadonly, "sRef.F").WithLocation(14, 64), - // (15,64): error CS0191: A readonly field cannot be assigned to (except in a constructor or init-only setter of the type in which the field is defined or a variable initializer) - // static void AssignRefToRef(ref S sRef, ref T tRef) { sRef.F = ref tRef; } // 6 - Diagnostic(ErrorCode.ERR_AssgReadonly, "sRef.F").WithLocation(15, 64), - // (16,80): error CS0191: A readonly field cannot be assigned to (except in a constructor or init-only setter of the type in which the field is defined or a variable initializer) - // static void AssignOutToRef(ref S sRef, out T tOut) { tOut = default; sRef.F = ref tOut; } // 7 - Diagnostic(ErrorCode.ERR_AssgReadonly, "sRef.F").WithLocation(16, 80), - // (17,64): error CS0191: A readonly field cannot be assigned to (except in a constructor or init-only setter of the type in which the field is defined or a variable initializer) - // static void AssignInToRef(ref S sRef, in T tIn) { sRef.F = ref tIn; } // 8 - Diagnostic(ErrorCode.ERR_AssgReadonly, "sRef.F").WithLocation(17, 64), - // (19,80): error CS0191: A readonly field cannot be assigned to (except in a constructor or init-only setter of the type in which the field is defined or a variable initializer) - // static void AssignValueToOut(out S sOut, T tValue) { sOut = default; sOut.F = ref tValue; } // 9 - Diagnostic(ErrorCode.ERR_AssgReadonly, "sOut.F").WithLocation(19, 80), - // (20,80): error CS0191: A readonly field cannot be assigned to (except in a constructor or init-only setter of the type in which the field is defined or a variable initializer) - // static void AssignRefToOut(out S sOut, ref T tRef) { sOut = default; sOut.F = ref tRef; } // 10 - Diagnostic(ErrorCode.ERR_AssgReadonly, "sOut.F").WithLocation(20, 80), - // (21,96): error CS0191: A readonly field cannot be assigned to (except in a constructor or init-only setter of the type in which the field is defined or a variable initializer) - // static void AssignOutToOut(out S sOut, out T tOut) { sOut = default; tOut = default; sOut.F = ref tOut; } // 11 - Diagnostic(ErrorCode.ERR_AssgReadonly, "sOut.F").WithLocation(21, 96), - // (22,80): error CS0191: A readonly field cannot be assigned to (except in a constructor or init-only setter of the type in which the field is defined or a variable initializer) - // static void AssignInToOut(out S sOut, in T tIn) { sOut = default; sOut.F = ref tIn; } // 12 - Diagnostic(ErrorCode.ERR_AssgReadonly, "sOut.F").WithLocation(22, 80), - // (24,61): error CS0191: A readonly field cannot be assigned to (except in a constructor or init-only setter of the type in which the field is defined or a variable initializer) - // static void AssignValueToIn(in S sIn, T tValue) { sIn.F = ref tValue; } // 13 - Diagnostic(ErrorCode.ERR_AssgReadonly, "sIn.F").WithLocation(24, 61), - // (25,61): error CS0191: A readonly field cannot be assigned to (except in a constructor or init-only setter of the type in which the field is defined or a variable initializer) - // static void AssignRefToIn(in S sIn, ref T tRef) { sIn.F = ref tRef; } // 14 - Diagnostic(ErrorCode.ERR_AssgReadonly, "sIn.F").WithLocation(25, 61), - // (26,77): error CS0191: A readonly field cannot be assigned to (except in a constructor or init-only setter of the type in which the field is defined or a variable initializer) - // static void AssignOutToIn(in S sIn, out T tOut) { tOut = default; sIn.F = ref tOut; } // 15 - Diagnostic(ErrorCode.ERR_AssgReadonly, "sIn.F").WithLocation(26, 77), - // (27,61): error CS0191: A readonly field cannot be assigned to (except in a constructor or init-only setter of the type in which the field is defined or a variable initializer) - // static void AssignInToIn(in S sIn, in T tIn) { sIn.F = ref tIn; } // 16 - Diagnostic(ErrorCode.ERR_AssgReadonly, "sIn.F").WithLocation(27, 61)); + comp.VerifyEmitDiagnostics(); + + VerifyParameterSymbol(comp.GetMember("C..ctor").ThisParameter, "C this", RefKind.None, DeclarationScope.Unscoped); + VerifyParameterSymbol(comp.GetMember("C.F1").ThisParameter, "C this", RefKind.None, DeclarationScope.Unscoped); + VerifyParameterSymbol(comp.GetMember("S1..ctor").ThisParameter, "out S1 this", RefKind.Out, DeclarationScope.RefScoped); + VerifyParameterSymbol(comp.GetMember("S1.F1").ThisParameter, "ref S1 this", RefKind.Ref, DeclarationScope.RefScoped); + VerifyParameterSymbol(comp.GetMember("S1.F2").ThisParameter, "in S1 this", RefKind.In, DeclarationScope.RefScoped); + VerifyParameterSymbol(comp.GetMember("R1..ctor").ThisParameter, "out R1 this", RefKind.Out, DeclarationScope.RefScoped); + VerifyParameterSymbol(comp.GetMember("R1.F1").ThisParameter, "ref R1 this", RefKind.Ref, DeclarationScope.RefScoped); + VerifyParameterSymbol(comp.GetMember("R1.F2").ThisParameter, "in R1 this", RefKind.In, DeclarationScope.RefScoped); + VerifyParameterSymbol(comp.GetMember("S2..ctor").ThisParameter, "out S2 this", RefKind.Out, DeclarationScope.RefScoped); + VerifyParameterSymbol(comp.GetMember("S2.F1").ThisParameter, "in S2 this", RefKind.In, DeclarationScope.RefScoped); + VerifyParameterSymbol(comp.GetMember("S2.F2").ThisParameter, "in S2 this", RefKind.In, DeclarationScope.RefScoped); + VerifyParameterSymbol(comp.GetMember("R2..ctor").ThisParameter, "out R2 this", RefKind.Out, DeclarationScope.RefScoped); + VerifyParameterSymbol(comp.GetMember("R2.F1").ThisParameter, "in R2 this", RefKind.In, DeclarationScope.RefScoped); + VerifyParameterSymbol(comp.GetMember("R2.F2").ThisParameter, "in R2 this", RefKind.In, DeclarationScope.RefScoped); + + // https://github.com/dotnet/roslyn/issues/62780: Test additional cases with [UnscopedRef]. } [Fact] - public void AssignOutParameterFrom_RefField() + public void ExtensionThisScope() { var source = -@"#pragma warning disable 649 -ref struct S -{ - public ref T Ref; - public ref readonly T RefReadonly; - public readonly ref T ReadonlyRef; - public readonly ref readonly T ReadonlyRefReadonly; -} - -class Program +@"ref struct R { } +static class Extensions { - static void FromValueRef(S s, out T t) { t = s.Ref; } - static void FromValueRefReadonly(S s, out T t) { t = s.RefReadonly; } - static void FromValueReadonlyRef(S s, out T t) { t = s.ReadonlyRef; } - static void FromValueReadonlyRefReadonly(S s, out T t) { t = s.ReadonlyRefReadonly; } - - static void FromRefRef(ref S s, out T t) { t = s.Ref; } - static void FromRefRefReadonly(ref S s, out T t) { t = s.RefReadonly; } - static void FromRefReadonlyRef(ref S s, out T t) { t = s.ReadonlyRef; } - static void FromRefReadonlyRefReadonly(ref S s, out T t) { t = s.ReadonlyRefReadonly; } - - static void FromOutRef(out S s, out T t) { s = default; t = s.Ref; } - static void FromOutRefReadonly(out S s, out T t) { s = default; t = s.RefReadonly; } - static void FromOutReadonlyRef(out S s, out T t) { s = default; t = s.ReadonlyRef; } - static void FromOutReadonlyRefReadonly(out S s, out T t) { s = default; t = s.ReadonlyRefReadonly; } - - static void FromInRef(in S s, out T t) { t = s.Ref; } - static void FromInRefReadonly(in S s, out T t) { t = s.RefReadonly; } - static void FromInReadonlyRef(in S s, out T t) { t = s.ReadonlyRef; } - static void FromInReadonlyRefReadonly(in S s, out T t) { t = s.ReadonlyRefReadonly; } + static void F0(this R r) { } + static void F1(this scoped R r) { } + static void F2(scoped this R r) { } + static void F3(this scoped ref T t) where T : struct { } }"; var comp = CreateCompilation(source); comp.VerifyEmitDiagnostics(); + + VerifyParameterSymbol(comp.GetMember("Extensions.F0").Parameters[0], "R r", RefKind.None, DeclarationScope.Unscoped); + VerifyParameterSymbol(comp.GetMember("Extensions.F1").Parameters[0], "scoped R r", RefKind.None, DeclarationScope.ValueScoped); + VerifyParameterSymbol(comp.GetMember("Extensions.F2").Parameters[0], "scoped R r", RefKind.None, DeclarationScope.ValueScoped); + VerifyParameterSymbol(comp.GetMember("Extensions.F3").Parameters[0], "scoped ref T t", RefKind.Ref, DeclarationScope.RefScoped); } [Fact] - public void AssignRefLocalFrom_RefField() + public void ParamsScope() { var source = -@"ref struct S +@"class Program { - public ref T Ref; - public ref readonly T RefReadonly; - public readonly ref T ReadonlyRef; - public readonly ref readonly T ReadonlyRefReadonly; -} + static void F1(scoped params object[] args) { } + static void F2(params scoped object[] args) { } +}"; + var comp = CreateCompilation(source); + comp.VerifyEmitDiagnostics( + // (3,20): error CS8986: The 'scoped' modifier can be used for refs and ref struct values only. + // static void F1(scoped params object[] args) { } + Diagnostic(ErrorCode.ERR_ScopedRefAndRefStructOnly, "scoped params object[] args").WithLocation(3, 20), + // (4,20): error CS8986: The 'scoped' modifier can be used for refs and ref struct values only. + // static void F2(params scoped object[] args) { } + Diagnostic(ErrorCode.ERR_ScopedRefAndRefStructOnly, "params scoped object[] args").WithLocation(4, 20)); + + VerifyParameterSymbol(comp.GetMember("Program.F1").Parameters[0], "scoped params System.Object[] args", RefKind.None, DeclarationScope.ValueScoped); + VerifyParameterSymbol(comp.GetMember("Program.F2").Parameters[0], "scoped params System.Object[] args", RefKind.None, DeclarationScope.ValueScoped); + } + [Theory] + [InlineData(LanguageVersion.CSharp10)] + [InlineData(LanguageVersion.CSharp11)] + public void ReturnTypeScope(LanguageVersion langVersion) + { + var source = +@"ref struct R { } class Program { - static void FromValueRef(S s) { ref T t = ref s.Ref; } - static void FromValueRefReadonly(S s) { ref T t = ref s.RefReadonly; } // 1 - static void FromValueReadonlyRef(S s) { ref T t = ref s.ReadonlyRef; } - static void FromValueReadonlyRefReadonly(S s) { ref T t = ref s.ReadonlyRefReadonly; } // 2 - - static void FromRefRef(ref S s) { ref T t = ref s.Ref; } - static void FromRefRefReadonly(ref S s) { ref T t = ref s.RefReadonly; } // 3 - static void FromRefReadonlyRef(ref S s) { ref T t = ref s.ReadonlyRef; } - static void FromRefReadonlyRefReadonly(ref S s) { ref T t = ref s.ReadonlyRefReadonly; } // 4 - - static void FromOutRef(out S s) { s = default; ref T t = ref s.Ref; } - static void FromOutRefReadonly(out S s) { s = default; ref T t = ref s.RefReadonly; } // 5 - static void FromOutReadonlyRef(out S s) { s = default; ref T t = ref s.ReadonlyRef; } - static void FromOutReadonlyRefReadonly(out S s) { s = default; ref T t = ref s.ReadonlyRefReadonly; } // 6 - - static void FromInRef(in S s) { ref T t = ref s.Ref; } - static void FromInRefReadonly(in S s) { ref T t = ref s.RefReadonly; } // 7 - static void FromInReadonlyRef(in S s) { ref T t = ref s.ReadonlyRef; } - static void FromInReadonlyRefReadonly(in S s) { ref T t = ref s.ReadonlyRefReadonly; } // 8 + static scoped R F1() => throw null; + static scoped ref R F2() => throw null; + static void Main() + { +#pragma warning disable 8321 + static scoped R L1() => throw null; + static scoped ref readonly R L2() => throw null; + } }"; - var comp = CreateCompilation(source); - comp.VerifyEmitDiagnostics( - // (12,73): error CS8329: Cannot use field 'S.RefReadonly' as a ref or out value because it is a readonly variable - // static void FromValueRefReadonly(S s) { ref T t = ref s.RefReadonly; } // 1 - Diagnostic(ErrorCode.ERR_RefReadonlyNotField, "s.RefReadonly").WithArguments("field", "S.RefReadonly").WithLocation(12, 73), - // (14,73): error CS8329: Cannot use field 'S.ReadonlyRefReadonly' as a ref or out value because it is a readonly variable - // static void FromValueReadonlyRefReadonly(S s) { ref T t = ref s.ReadonlyRefReadonly; } // 2 - Diagnostic(ErrorCode.ERR_RefReadonlyNotField, "s.ReadonlyRefReadonly").WithArguments("field", "S.ReadonlyRefReadonly").WithLocation(14, 73), - // (17,75): error CS8329: Cannot use field 'S.RefReadonly' as a ref or out value because it is a readonly variable - // static void FromRefRefReadonly(ref S s) { ref T t = ref s.RefReadonly; } // 3 - Diagnostic(ErrorCode.ERR_RefReadonlyNotField, "s.RefReadonly").WithArguments("field", "S.RefReadonly").WithLocation(17, 75), - // (19,75): error CS8329: Cannot use field 'S.ReadonlyRefReadonly' as a ref or out value because it is a readonly variable - // static void FromRefReadonlyRefReadonly(ref S s) { ref T t = ref s.ReadonlyRefReadonly; } // 4 - Diagnostic(ErrorCode.ERR_RefReadonlyNotField, "s.ReadonlyRefReadonly").WithArguments("field", "S.ReadonlyRefReadonly").WithLocation(19, 75), - // (22,88): error CS8329: Cannot use field 'S.RefReadonly' as a ref or out value because it is a readonly variable - // static void FromOutRefReadonly(out S s) { s = default; ref T t = ref s.RefReadonly; } // 5 - Diagnostic(ErrorCode.ERR_RefReadonlyNotField, "s.RefReadonly").WithArguments("field", "S.RefReadonly").WithLocation(22, 88), - // (24,88): error CS8329: Cannot use field 'S.ReadonlyRefReadonly' as a ref or out value because it is a readonly variable - // static void FromOutReadonlyRefReadonly(out S s) { s = default; ref T t = ref s.ReadonlyRefReadonly; } // 6 - Diagnostic(ErrorCode.ERR_RefReadonlyNotField, "s.ReadonlyRefReadonly").WithArguments("field", "S.ReadonlyRefReadonly").WithLocation(24, 88), - // (27,73): error CS8329: Cannot use field 'S.RefReadonly' as a ref or out value because it is a readonly variable - // static void FromInRefReadonly(in S s) { ref T t = ref s.RefReadonly; } // 7 - Diagnostic(ErrorCode.ERR_RefReadonlyNotField, "s.RefReadonly").WithArguments("field", "S.RefReadonly").WithLocation(27, 73), - // (29,73): error CS8329: Cannot use field 'S.ReadonlyRefReadonly' as a ref or out value because it is a readonly variable - // static void FromInReadonlyRefReadonly(in S s) { ref T t = ref s.ReadonlyRefReadonly; } // 8 - Diagnostic(ErrorCode.ERR_RefReadonlyNotField, "s.ReadonlyRefReadonly").WithArguments("field", "S.ReadonlyRefReadonly").WithLocation(29, 73)); + var comp = CreateCompilation(source, parseOptions: TestOptions.Regular.WithLanguageVersion(langVersion)); + comp.VerifyDiagnostics( + // (4,21): error CS0106: The modifier 'scoped' is not valid for this item + // static scoped R F1() => throw null; + Diagnostic(ErrorCode.ERR_BadMemberFlag, "F1").WithArguments("scoped").WithLocation(4, 21), + // (5,25): error CS0106: The modifier 'scoped' is not valid for this item + // static scoped ref R F2() => throw null; + Diagnostic(ErrorCode.ERR_BadMemberFlag, "F2").WithArguments("scoped").WithLocation(5, 25), + // (9,16): error CS0106: The modifier 'scoped' is not valid for this item + // static scoped R L1() => throw null; + Diagnostic(ErrorCode.ERR_BadMemberFlag, "scoped").WithArguments("scoped").WithLocation(9, 16), + // (10,16): error CS0106: The modifier 'scoped' is not valid for this item + // static scoped ref readonly R L2() => throw null; + Diagnostic(ErrorCode.ERR_BadMemberFlag, "scoped").WithArguments("scoped").WithLocation(10, 16)); + } + + [Theory] + [InlineData(LanguageVersion.CSharp10)] + [InlineData(LanguageVersion.CSharp11)] + public void DelegateReturnTypeScope(LanguageVersion langVersion) + { + var source = +@"ref struct R { } +delegate ref scoped R D(); +"; + var comp = CreateCompilation(source, parseOptions: TestOptions.Regular.WithLanguageVersion(langVersion)); + comp.VerifyEmitDiagnostics( + // (2,14): error CS9061: Unexpected contextual keyword 'scoped'. Did you mean 'scoped ref' or '@scoped'? + // delegate ref scoped R D(); + Diagnostic(ErrorCode.ERR_MisplacedScoped, "scoped").WithLocation(2, 14)); } - [Fact] - public void AssignRefReadonlyLocalFrom_RefField() + [Theory] + [InlineData(LanguageVersion.CSharp10)] + [InlineData(LanguageVersion.CSharp11)] + public void TypeScopeModifier_01(LanguageVersion langVersion) { var source = -@"ref struct S -{ - public ref T Ref; - public ref readonly T RefReadonly; - public readonly ref T ReadonlyRef; - public readonly ref readonly T ReadonlyRefReadonly; -} +@"scoped struct A { } +scoped ref struct B { } +scoped readonly ref struct C { } +"; + var comp = CreateCompilation(source, parseOptions: TestOptions.Regular.WithLanguageVersion(langVersion)); + comp.VerifyDiagnostics( + // (1,15): error CS0106: The modifier 'scoped' is not valid for this item + // scoped struct A { } + Diagnostic(ErrorCode.ERR_BadMemberFlag, "A").WithArguments("scoped").WithLocation(1, 15), + // (2,19): error CS0106: The modifier 'scoped' is not valid for this item + // scoped ref struct B { } + Diagnostic(ErrorCode.ERR_BadMemberFlag, "B").WithArguments("scoped").WithLocation(2, 19), + // (3,28): error CS0106: The modifier 'scoped' is not valid for this item + // scoped readonly ref struct C { } + Diagnostic(ErrorCode.ERR_BadMemberFlag, "C").WithArguments("scoped").WithLocation(3, 28)); + } -class Program -{ - static void FromValueRef(S s) { ref readonly T t = ref s.Ref; } - static void FromValueRefReadonly(S s) { ref readonly T t = ref s.RefReadonly; } - static void FromValueReadonlyRef(S s) { ref readonly T t = ref s.ReadonlyRef; } - static void FromValueReadonlyRefReadonly(S s) { ref readonly T t = ref s.ReadonlyRefReadonly; } + [Theory] + [InlineData(LanguageVersion.CSharp10)] + [InlineData(LanguageVersion.CSharp11)] + public void TypeScopeModifier_02(LanguageVersion langVersion) + { + var source = +@"scoped record A { } +scoped readonly record struct B; +readonly scoped record struct C(); +"; + var comp = CreateCompilation(source, parseOptions: TestOptions.Regular.WithLanguageVersion(langVersion)); + comp.VerifyDiagnostics( + // (1,15): error CS0106: The modifier 'scoped' is not valid for this item + // scoped record A { } + Diagnostic(ErrorCode.ERR_BadMemberFlag, "A").WithArguments("scoped").WithLocation(1, 15), + // (2,31): error CS0106: The modifier 'scoped' is not valid for this item + // scoped readonly record struct B; + Diagnostic(ErrorCode.ERR_BadMemberFlag, "B").WithArguments("scoped").WithLocation(2, 31), + // (3,31): error CS0106: The modifier 'scoped' is not valid for this item + // readonly scoped record struct C(); + Diagnostic(ErrorCode.ERR_BadMemberFlag, "C").WithArguments("scoped").WithLocation(3, 31)); + } - static void FromRefRef(ref S s) { ref readonly T t = ref s.Ref; } - static void FromRefRefReadonly(ref S s) { ref readonly T t = ref s.RefReadonly; } - static void FromRefReadonlyRef(ref S s) { ref readonly T t = ref s.ReadonlyRef; } - static void FromRefReadonlyRefReadonly(ref S s) { ref readonly T t = ref s.ReadonlyRefReadonly; } + [Fact] + public void FieldTypeScope() + { + var source = +@"#pragma warning disable 169 +ref struct R1 { } +ref struct R2 +{ + scoped R1 F1; + scoped ref int F3; +}"; - static void FromOutRef(out S s) { s = default; ref readonly T t = ref s.Ref; } - static void FromOutRefReadonly(out S s) { s = default; ref readonly T t = ref s.RefReadonly; } - static void FromOutReadonlyRef(out S s) { s = default; ref readonly T t = ref s.ReadonlyRef; } - static void FromOutReadonlyRefReadonly(out S s) { s = default; ref readonly T t = ref s.ReadonlyRefReadonly; } + var comp = CreateCompilation(source, parseOptions: TestOptions.Regular10, runtimeFeature: RuntimeFlag.ByRefFields); + comp.VerifyDiagnostics( + // (5,15): error CS0106: The modifier 'scoped' is not valid for this item + // scoped R1 F1; + Diagnostic(ErrorCode.ERR_BadMemberFlag, "F1").WithArguments("scoped").WithLocation(5, 15), + // (6,12): error CS8936: Feature 'ref fields' is not available in C# 10.0. Please use language version 11.0 or greater. + // scoped ref int F3; + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "ref int").WithArguments("ref fields", "11.0").WithLocation(6, 12), + // (6,20): error CS0106: The modifier 'scoped' is not valid for this item + // scoped ref int F3; + Diagnostic(ErrorCode.ERR_BadMemberFlag, "F3").WithArguments("scoped").WithLocation(6, 20)); - static void FromInRef(in S s) { ref readonly T t = ref s.Ref; } - static void FromInRefReadonly(in S s) { ref readonly T t = ref s.RefReadonly; } - static void FromInReadonlyRef(in S s) { ref readonly T t = ref s.ReadonlyRef; } - static void FromInReadonlyRefReadonly(in S s) { ref readonly T t = ref s.ReadonlyRefReadonly; } -}"; - var comp = CreateCompilation(source); - comp.VerifyEmitDiagnostics(); + comp = CreateCompilation(source, runtimeFeature: RuntimeFlag.ByRefFields); + comp.VerifyDiagnostics( + // (5,15): error CS0106: The modifier 'scoped' is not valid for this item + // scoped R1 F1; + Diagnostic(ErrorCode.ERR_BadMemberFlag, "F1").WithArguments("scoped").WithLocation(5, 15), + // (6,20): error CS0106: The modifier 'scoped' is not valid for this item + // scoped ref int F3; + Diagnostic(ErrorCode.ERR_BadMemberFlag, "F3").WithArguments("scoped").WithLocation(6, 20)); } - [Fact] - public void RefReturn() + [Theory] + [InlineData(LanguageVersion.CSharp10)] + [InlineData(LanguageVersion.CSharp11)] + public void PropertyTypeScope(LanguageVersion langVersion) { var source = -@"class Program +@"ref struct R1 { } +ref struct R2 { - static ref T F1(T t) => ref t; // 1 - static ref T F2(ref T t) => ref t; - static ref T F3(out T t) { t = default; return ref t; } // 2 - static ref T F4(in T t) => ref t; // 3 - static ref readonly T F5(T t) => ref t; // 4 - static ref readonly T F6(ref T t) => ref t; - static ref readonly T F7(out T t) { t = default; return ref t; } // 5 - static ref readonly T F8(in T t) => ref t; + scoped R1 P1 { get; } + scoped R1 P2 { get; init; } + scoped R1 P3 { set { } } + scoped ref int P5 => throw null; }"; - var comp = CreateCompilation(source); - comp.VerifyEmitDiagnostics( - // (3,36): error CS8166: Cannot return a parameter by reference 't' because it is not a ref parameter - // static ref T F1(T t) => ref t; // 1 - Diagnostic(ErrorCode.ERR_RefReturnParameter, "t").WithArguments("t").WithLocation(3, 36), - // (5,59): error CS8166: Cannot return a parameter by reference 't' because it is not a ref parameter - // static ref T F3(out T t) { t = default; return ref t; } // 2 - Diagnostic(ErrorCode.ERR_RefReturnParameter, "t").WithArguments("t").WithLocation(5, 59), - // (6,39): error CS8333: Cannot return variable 'in T' by writable reference because it is a readonly variable - // static ref T F4(in T t) => ref t; // 3 - Diagnostic(ErrorCode.ERR_RefReturnReadonlyNotField, "t").WithArguments("variable", "in T").WithLocation(6, 39), - // (7,45): error CS8166: Cannot return a parameter by reference 't' because it is not a ref parameter - // static ref readonly T F5(T t) => ref t; // 4 - Diagnostic(ErrorCode.ERR_RefReturnParameter, "t").WithArguments("t").WithLocation(7, 45), - // (9,68): error CS8166: Cannot return a parameter by reference 't' because it is not a ref parameter - // static ref readonly T F7(out T t) { t = default; return ref t; } // 5 - Diagnostic(ErrorCode.ERR_RefReturnParameter, "t").WithArguments("t").WithLocation(9, 68)); + var comp = CreateCompilation(new[] { source, IsExternalInitTypeDefinition }, parseOptions: TestOptions.Regular.WithLanguageVersion(langVersion)); + comp.VerifyDiagnostics( + // (4,15): error CS0106: The modifier 'scoped' is not valid for this item + // scoped R1 P1 { get; } + Diagnostic(ErrorCode.ERR_BadMemberFlag, "P1").WithArguments("scoped").WithLocation(4, 15), + // (5,15): error CS0106: The modifier 'scoped' is not valid for this item + // scoped R1 P2 { get; init; } + Diagnostic(ErrorCode.ERR_BadMemberFlag, "P2").WithArguments("scoped").WithLocation(5, 15), + // (6,15): error CS0106: The modifier 'scoped' is not valid for this item + // scoped R1 P3 { set { } } + Diagnostic(ErrorCode.ERR_BadMemberFlag, "P3").WithArguments("scoped").WithLocation(6, 15), + // (7,20): error CS0106: The modifier 'scoped' is not valid for this item + // scoped ref int P5 => throw null; + Diagnostic(ErrorCode.ERR_BadMemberFlag, "P5").WithArguments("scoped").WithLocation(7, 20)); + verify(comp); + + static void verify(CSharpCompilation comp) + { + verifyValueParameter(comp.GetMember("R2.P2"), "R1 value", RefKind.None, DeclarationScope.Unscoped); + verifyValueParameter(comp.GetMember("R2.P3"), "R1 value", RefKind.None, DeclarationScope.Unscoped); + } + + static void verifyValueParameter(PropertySymbol property, string expectedDisplayString, RefKind expectedRefKind, DeclarationScope expectedScope) + { + Assert.Equal(expectedRefKind, property.RefKind); + VerifyParameterSymbol(property.SetMethod.Parameters[0], expectedDisplayString, expectedRefKind, expectedScope); + } } [Fact] - public void RefReturn_Ref() + public void SubstitutedParameter() { var source = -@"ref struct S +@"ref struct R { } +class A { - public ref T F; - public ref T F1() => ref F; - public ref readonly T F2() => ref F; + public static void F(scoped R x, scoped in T y) { } } -class Program +class B : A { - static ref T F3(S s) => ref s.F; - static ref T F4(ref S s) => ref s.F; - static ref T F5(out S s) { s = default; return ref s.F; } - static ref T F6(in S s) => ref s.F; - static ref readonly T F7(S s) => ref s.F; - static ref readonly T F8(ref S s) => ref s.F; - static ref readonly T F9(out S s) { s = default; return ref s.F; } - static ref readonly T F10(in S s) => ref s.F; }"; var comp = CreateCompilation(source); comp.VerifyEmitDiagnostics(); + + var method = (MethodSymbol)comp.GetMember("B").BaseTypeNoUseSiteDiagnostics.GetMember("F"); + VerifyParameterSymbol(method.Parameters[0], "scoped R x", RefKind.None, DeclarationScope.ValueScoped); + VerifyParameterSymbol(method.Parameters[1], "scoped in System.Int32 y", RefKind.In, DeclarationScope.RefScoped); } [Fact] - public void RefReturn_RefReadonly() + public void RetargetingParameter() { - var source = -@"ref struct S + var sourceA = +@"public ref struct R { } +public class A { - public ref readonly T F; - public ref T F1() => ref F; - public ref readonly T F2() => ref F; + public static void F(scoped R x, scoped in int y) { } } -class Program +"; + var comp = CreateCompilation(sourceA, targetFramework: TargetFramework.Mscorlib40); + var refA = comp.ToMetadataReference(); + + var sourceB = +@"class B { - static ref T F3(S s) => ref s.F; - static ref T F4(ref S s) => ref s.F; - static ref T F5(out S s) { s = default; return ref s.F; } - static ref T F6(in S s) => ref s.F; - static ref readonly T F7(S s) => ref s.F; - static ref readonly T F8(ref S s) => ref s.F; - static ref readonly T F9(out S s) { s = default; return ref s.F; } - static ref readonly T F10(in S s) => ref s.F; + static void Main() + { + A.F(default, 0); + } }"; - var comp = CreateCompilation(source); - comp.VerifyEmitDiagnostics( - // (4,30): error CS8333: Cannot return field 'S.F' by writable reference because it is a readonly variable - // public ref T F1() => ref F; - Diagnostic(ErrorCode.ERR_RefReturnReadonlyNotField, "F").WithArguments("field", "S.F").WithLocation(4, 30), - // (9,39): error CS8333: Cannot return field 'S.F' by writable reference because it is a readonly variable - // static ref T F3(S s) => ref s.F; - Diagnostic(ErrorCode.ERR_RefReturnReadonlyNotField, "s.F").WithArguments("field", "S.F").WithLocation(9, 39), - // (10,43): error CS8333: Cannot return field 'S.F' by writable reference because it is a readonly variable - // static ref T F4(ref S s) => ref s.F; - Diagnostic(ErrorCode.ERR_RefReturnReadonlyNotField, "s.F").WithArguments("field", "S.F").WithLocation(10, 43), - // (11,62): error CS8333: Cannot return field 'S.F' by writable reference because it is a readonly variable - // static ref T F5(out S s) { s = default; return ref s.F; } - Diagnostic(ErrorCode.ERR_RefReturnReadonlyNotField, "s.F").WithArguments("field", "S.F").WithLocation(11, 62), - // (12,42): error CS8333: Cannot return field 'S.F' by writable reference because it is a readonly variable - // static ref T F6(in S s) => ref s.F; - Diagnostic(ErrorCode.ERR_RefReturnReadonlyNotField, "s.F").WithArguments("field", "S.F").WithLocation(12, 42)); + comp = CreateCompilation(sourceB, new[] { refA }, targetFramework: TargetFramework.Mscorlib45); + comp.VerifyEmitDiagnostics(); + CompileAndVerify(comp); + + var tree = comp.SyntaxTrees[0]; + var model = comp.GetSemanticModel(tree); + var expr = tree.GetRoot().DescendantNodes().OfType().Single().Expression; + var method = model.GetSymbolInfo(expr).Symbol.GetSymbol(); + + VerifyParameterSymbol(method.Parameters[0], "scoped R x", RefKind.None, DeclarationScope.ValueScoped); + VerifyParameterSymbol(method.Parameters[1], "scoped in System.Int32 y", RefKind.In, DeclarationScope.RefScoped); + } + + private static readonly SymbolDisplayFormat displayFormatWithScoped = SymbolDisplayFormat.TestFormat. + WithCompilerInternalOptions(SymbolDisplayCompilerInternalOptions.IncludeScoped). + AddLocalOptions(SymbolDisplayLocalOptions.IncludeRef); + + private static void VerifyParameterSymbol(ParameterSymbol parameter, string expectedDisplayString, RefKind expectedRefKind, DeclarationScope expectedScope) + { + Assert.Equal(expectedRefKind, parameter.RefKind); + Assert.Equal(expectedScope, parameter.EffectiveScope); + Assert.Equal(expectedDisplayString, parameter.ToDisplayString(displayFormatWithScoped)); + + var attribute = parameter.GetAttributes().FirstOrDefault(a => a.GetTargetAttributeSignatureIndex(parameter, AttributeDescription.ScopedRefAttribute) != -1); + Assert.Null(attribute); + + VerifyParameterSymbol(parameter.GetPublicSymbol(), expectedDisplayString, expectedRefKind, expectedScope); + } + + private static void VerifyParameterSymbol(IParameterSymbol parameter, string expectedDisplayString, RefKind expectedRefKind, DeclarationScope expectedScope) + { + Assert.Equal(expectedRefKind, parameter.RefKind); + // https://github.com/dotnet/roslyn/issues/61647: Use public API. + //Assert.Equal(expectedScope == DeclarationScope.RefScoped, parameter.IsRefScoped); + //Assert.Equal(expectedScope == DeclarationScope.ValueScoped, parameter.IsValueScoped); + Assert.Equal(expectedDisplayString, parameter.ToDisplayString(displayFormatWithScoped)); } [Fact] - public void RefReturn_ReadonlyRef() + public void LocalScope_01() { var source = -@"ref struct S -{ - public readonly ref T F; - public ref T F1() => ref F; - public ref readonly T F2() => ref F; -} +@"#pragma warning disable 219 +ref struct R { } class Program { - static ref T F3(S s) => ref s.F; - static ref T F4(ref S s) => ref s.F; - static ref T F5(out S s) { s = default; return ref s.F; } - static ref T F6(in S s) => ref s.F; - static ref readonly T F7(S s) => ref s.F; - static ref readonly T F8(ref S s) => ref s.F; - static ref readonly T F9(out S s) { s = default; return ref s.F; } - static ref readonly T F10(in S s) => ref s.F; + static void F(ref R r) + { + scoped R r1 = default; + scoped ref R r2 = ref r; + scoped ref readonly R r5 = ref r; + } }"; - var comp = CreateCompilation(source); + var comp = CreateCompilation(source, parseOptions: TestOptions.Regular10); + comp.VerifyEmitDiagnostics( + // (7,9): error CS8936: Feature 'ref fields' is not available in C# 10.0. Please use language version 11.0 or greater. + // scoped R r1 = default; + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "scoped").WithArguments("ref fields", "11.0").WithLocation(7, 9), + // (8,9): error CS8936: Feature 'ref fields' is not available in C# 10.0. Please use language version 11.0 or greater. + // scoped ref R r2 = ref r; + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "scoped").WithArguments("ref fields", "11.0").WithLocation(8, 9), + // (9,9): error CS8936: Feature 'ref fields' is not available in C# 10.0. Please use language version 11.0 or greater. + // scoped ref readonly R r5 = ref r; + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "scoped").WithArguments("ref fields", "11.0").WithLocation(9, 9)); + verify(comp, useUpdatedEscapeRules: false); + + comp = CreateCompilation(source); comp.VerifyEmitDiagnostics(); + verify(comp, useUpdatedEscapeRules: true); + + static void verify(CSharpCompilation comp, bool useUpdatedEscapeRules) + { + var tree = comp.SyntaxTrees[0]; + var model = comp.GetSemanticModel(tree); + var decls = tree.GetRoot().DescendantNodes().OfType().ToArray(); + var locals = decls.Select(d => model.GetDeclaredSymbol(d).GetSymbol()).ToArray(); + + VerifyLocalSymbol(locals[0], "scoped R r1", RefKind.None, DeclarationScope.ValueScoped); + VerifyLocalSymbol(locals[1], "scoped ref R r2", RefKind.Ref, DeclarationScope.RefScoped); + VerifyLocalSymbol(locals[2], "scoped ref readonly R r5", RefKind.RefReadOnly, DeclarationScope.RefScoped); + } } [Fact] - public void RefReturn_ReadonlyRefReadonly() + public void LocalScope_02() { var source = -@"ref struct S -{ - public readonly ref readonly T F; - public ref T F1() => ref F; - public ref readonly T F2() => ref F; -} +@"ref struct R { } class Program { - static ref T F3(S s) => ref s.F; - static ref T F4(ref S s) => ref s.F; - static ref T F5(out S s) { s = default; return ref s.F; } - static ref T F6(in S s) => ref s.F; - static ref readonly T F7(S s) => ref s.F; - static ref readonly T F8(ref S s) => ref s.F; - static ref readonly T F9(out S s) { s = default; return ref s.F; } - static ref readonly T F10(in S s) => ref s.F; + static void Main() + { + scoped scoped R x = default; + scoped scoped ref R z = ref x; + } }"; var comp = CreateCompilation(source); - comp.VerifyEmitDiagnostics( - // (4,30): error CS8333: Cannot return field 'S.F' by writable reference because it is a readonly variable - // public ref T F1() => ref F; - Diagnostic(ErrorCode.ERR_RefReturnReadonlyNotField, "F").WithArguments("field", "S.F").WithLocation(4, 30), - // (9,39): error CS8333: Cannot return field 'S.F' by writable reference because it is a readonly variable - // static ref T F3(S s) => ref s.F; - Diagnostic(ErrorCode.ERR_RefReturnReadonlyNotField, "s.F").WithArguments("field", "S.F").WithLocation(9, 39), - // (10,43): error CS8333: Cannot return field 'S.F' by writable reference because it is a readonly variable - // static ref T F4(ref S s) => ref s.F; - Diagnostic(ErrorCode.ERR_RefReturnReadonlyNotField, "s.F").WithArguments("field", "S.F").WithLocation(10, 43), - // (11,62): error CS8333: Cannot return field 'S.F' by writable reference because it is a readonly variable - // static ref T F5(out S s) { s = default; return ref s.F; } - Diagnostic(ErrorCode.ERR_RefReturnReadonlyNotField, "s.F").WithArguments("field", "S.F").WithLocation(11, 62), - // (12,42): error CS8333: Cannot return field 'S.F' by writable reference because it is a readonly variable - // static ref T F6(in S s) => ref s.F; - Diagnostic(ErrorCode.ERR_RefReturnReadonlyNotField, "s.F").WithArguments("field", "S.F").WithLocation(12, 42)); + // Duplicate scoped modifiers result are parse errors rather than binding errors. + comp.VerifyDiagnostics( + // (6,16): error CS1031: Type expected + // scoped scoped R x = default; + Diagnostic(ErrorCode.ERR_TypeExpected, "scoped").WithLocation(6, 16), + // (7,9): error CS0118: 'scoped' is a variable but is used like a type + // scoped scoped ref R z = ref x; + Diagnostic(ErrorCode.ERR_BadSKknown, "scoped").WithArguments("scoped", "variable", "type").WithLocation(7, 9), + // (7,16): warning CS0168: The variable 'scoped' is declared but never used + // scoped scoped ref R z = ref x; + Diagnostic(ErrorCode.WRN_UnreferencedVar, "scoped").WithArguments("scoped").WithLocation(7, 16), + // (7,23): error CS1002: ; expected + // scoped scoped ref R z = ref x; + Diagnostic(ErrorCode.ERR_SemicolonExpected, "ref").WithLocation(7, 23)); } [Fact] - public void RefParameter_InstanceMethod_Ref() + public void LocalScope_03() { var source = -@"ref struct S -{ - public ref T F; - public S(ref T t) - { - F = ref t; - M1(F); - M2(ref F); - M3(out F); - M4(F); - M4(in F); - } - object P - { - init - { - M1(F); - M2(ref F); - M3(out F); - M4(F); - M4(in F); - } - } - void M() - { - M1(F); - M2(ref F); - M3(out F); - M4(F); - M4(in F); - } - static void M1(T t) { } - static void M2(ref T t) { } - static void M3(out T t) { t = default; } - static void M4(in T t) { } -}"; - var comp = CreateCompilation(new[] { source, IsExternalInitTypeDefinition }); - comp.VerifyEmitDiagnostics(); +@"scoped scoped R x = default; +scoped scoped ref R z = ref x; +ref struct R { } +"; + var comp = CreateCompilation(source); + // Duplicate scoped modifiers result are parse errors rather than binding errors. + comp.VerifyDiagnostics( + // (1,8): error CS1031: Type expected + // scoped scoped R x = default; + Diagnostic(ErrorCode.ERR_TypeExpected, "scoped").WithLocation(1, 8), + // (1,17): warning CS0219: The variable 'x' is assigned but its value is never used + // scoped scoped R x = default; + Diagnostic(ErrorCode.WRN_UnreferencedVarAssg, "x").WithArguments("x").WithLocation(1, 17), + // (2,1): error CS0118: 'scoped' is a variable but is used like a type + // scoped scoped ref R z = ref x; + Diagnostic(ErrorCode.ERR_BadSKknown, "scoped").WithArguments("scoped", "variable", "type").WithLocation(2, 1), + // (2,8): warning CS0168: The variable 'scoped' is declared but never used + // scoped scoped ref R z = ref x; + Diagnostic(ErrorCode.WRN_UnreferencedVar, "scoped").WithArguments("scoped").WithLocation(2, 8), + // (2,15): error CS1003: Syntax error, ',' expected + // scoped scoped ref R z = ref x; + Diagnostic(ErrorCode.ERR_SyntaxError, "ref").WithArguments(",").WithLocation(2, 15)); } [Fact] - public void RefParameter_InstanceMethod_RefReadonly() + public void LocalScope_04() { var source = -@"ref struct S -{ - public ref readonly T F; - public S(ref T t) - { - F = ref t; - M1(F); - M2(ref F); // 1 - M3(out F); // 2 - M4(F); - M4(in F); - } - object P - { - init - { - M1(F); - M2(ref F); // 3 - M3(out F); // 4 - M4(F); - M4(in F); - } - } - void M() - { - M1(F); - M2(ref F); // 5 - M3(out F); // 6 - M4(F); - M4(in F); - } - static void M1(T t) { } - static void M2(ref T t) { } - static void M3(out T t) { t = default; } - static void M4(in T t) { } -}"; - var comp = CreateCompilation(new[] { source, IsExternalInitTypeDefinition }); +@"scoped s1 = default; +ref scoped s2 = ref s1; // 1 +ref @scoped s3 = ref s1; +scoped scoped s4 = default; // 2 +scoped ref scoped s5 = ref s1; // 3 +scoped ref @scoped s6 = ref s1; // 4 +ref struct @scoped { } // 5 +"; + var comp = CreateCompilation(source, parseOptions: TestOptions.Regular10); comp.VerifyEmitDiagnostics( - // (8,16): error CS8329: Cannot use field 'S.F' as a ref or out value because it is a readonly variable - // M2(ref F); // 1 - Diagnostic(ErrorCode.ERR_RefReadonlyNotField, "F").WithArguments("field", "S.F").WithLocation(8, 16), - // (9,16): error CS8329: Cannot use field 'S.F' as a ref or out value because it is a readonly variable - // M3(out F); // 2 - Diagnostic(ErrorCode.ERR_RefReadonlyNotField, "F").WithArguments("field", "S.F").WithLocation(9, 16), - // (18,20): error CS8329: Cannot use field 'S.F' as a ref or out value because it is a readonly variable - // M2(ref F); // 3 - Diagnostic(ErrorCode.ERR_RefReadonlyNotField, "F").WithArguments("field", "S.F").WithLocation(18, 20), - // (19,20): error CS8329: Cannot use field 'S.F' as a ref or out value because it is a readonly variable - // M3(out F); // 4 - Diagnostic(ErrorCode.ERR_RefReadonlyNotField, "F").WithArguments("field", "S.F").WithLocation(19, 20), - // (27,16): error CS8329: Cannot use field 'S.F' as a ref or out value because it is a readonly variable - // M2(ref F); // 5 - Diagnostic(ErrorCode.ERR_RefReadonlyNotField, "F").WithArguments("field", "S.F").WithLocation(27, 16), - // (28,16): error CS8329: Cannot use field 'S.F' as a ref or out value because it is a readonly variable - // M3(out F); // 6 - Diagnostic(ErrorCode.ERR_RefReadonlyNotField, "F").WithArguments("field", "S.F").WithLocation(28, 16)); + // (2,5): error CS9061: Unexpected contextual keyword 'scoped'. Did you mean 'scoped ref' or '@scoped'? + // ref scoped s2 = ref s1; // 1 + Diagnostic(ErrorCode.ERR_MisplacedScoped, "scoped").WithLocation(2, 5), + // (2,15): error CS1525: Invalid expression term '=' + // ref scoped s2 = ref s1; // 1 + Diagnostic(ErrorCode.ERR_InvalidExprTerm, "=").WithArguments("=").WithLocation(2, 15), + // (4,1): error CS8936: Feature 'ref fields' is not available in C# 10.0. Please use language version 11.0 or greater. + // scoped scoped s4 = default; // 2 + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "scoped").WithArguments("ref fields", "11.0").WithLocation(4, 1), + // (4,15): warning CS0219: The variable 's4' is assigned but its value is never used + // scoped scoped s4 = default; // 2 + Diagnostic(ErrorCode.WRN_UnreferencedVarAssg, "s4").WithArguments("s4").WithLocation(4, 15), + // (5,12): error CS9061: Unexpected contextual keyword 'scoped'. Did you mean 'scoped ref' or '@scoped'? + // scoped ref scoped s5 = ref s1; // 3 + Diagnostic(ErrorCode.ERR_MisplacedScoped, "scoped").WithLocation(5, 12), + // (5,22): error CS1525: Invalid expression term '=' + // scoped ref scoped s5 = ref s1; // 3 + Diagnostic(ErrorCode.ERR_InvalidExprTerm, "=").WithArguments("=").WithLocation(5, 22), + // (6,1): error CS8936: Feature 'ref fields' is not available in C# 10.0. Please use language version 11.0 or greater. + // scoped ref @scoped s6 = ref s1; // 4 + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "scoped").WithArguments("ref fields", "11.0").WithLocation(6, 1)); + verify(comp); + + comp = CreateCompilation(source); + comp.VerifyDiagnostics( + // (2,5): error CS9061: Unexpected contextual keyword 'scoped'. Did you mean 'scoped ref' or '@scoped'? + // ref scoped s2 = ref s1; // 1 + Diagnostic(ErrorCode.ERR_MisplacedScoped, "scoped").WithLocation(2, 5), + // (2,15): error CS1525: Invalid expression term '=' + // ref scoped s2 = ref s1; // 1 + Diagnostic(ErrorCode.ERR_InvalidExprTerm, "=").WithArguments("=").WithLocation(2, 15), + // (4,15): warning CS0219: The variable 's4' is assigned but its value is never used + // scoped scoped s4 = default; // 2 + Diagnostic(ErrorCode.WRN_UnreferencedVarAssg, "s4").WithArguments("s4").WithLocation(4, 15), + // (5,12): error CS9061: Unexpected contextual keyword 'scoped'. Did you mean 'scoped ref' or '@scoped'? + // scoped ref scoped s5 = ref s1; // 3 + Diagnostic(ErrorCode.ERR_MisplacedScoped, "scoped").WithLocation(5, 12), + // (5,22): error CS1525: Invalid expression term '=' + // scoped ref scoped s5 = ref s1; // 3 + Diagnostic(ErrorCode.ERR_InvalidExprTerm, "=").WithArguments("=").WithLocation(5, 22)); + verify(comp); + + static void verify(CSharpCompilation comp) + { + var tree = comp.SyntaxTrees[0]; + var model = comp.GetSemanticModel(tree); + var decls = tree.GetRoot().DescendantNodes().OfType().ToArray(); + var locals = decls.Select(d => model.GetDeclaredSymbol(d).GetSymbol()).ToArray(); + + VerifyLocalSymbol(locals[0], "scoped s1", RefKind.None, DeclarationScope.Unscoped); + VerifyLocalSymbol(locals[1], "ref scoped s3", RefKind.Ref, DeclarationScope.Unscoped); + VerifyLocalSymbol(locals[2], "scoped scoped s4", RefKind.None, DeclarationScope.ValueScoped); + VerifyLocalSymbol(locals[3], "scoped ref scoped s6", RefKind.Ref, DeclarationScope.RefScoped); + } } - [Fact] - public void RefParameter_InstanceMethod_ReadonlyRef() + [Theory] + [InlineData(LanguageVersion.CSharp10)] + [InlineData(LanguageVersion.CSharp11)] + public void LocalScope_05(LanguageVersion langVersion) { var source = -@"ref struct S -{ - public readonly ref T F; - public S(ref T t) - { - F = ref t; - M1(F); - M2(ref F); - M3(out F); - M4(F); - M4(in F); - } - object P - { - init - { - M1(F); - M2(ref F); - M3(out F); - M4(F); - M4(in F); +@"bool scoped; +scoped = true; +"; + var comp = CreateCompilation(source, parseOptions: TestOptions.Regular.WithLanguageVersion(langVersion)); + comp.VerifyDiagnostics( + // (1,6): warning CS0219: The variable 'scoped' is assigned but its value is never used + // bool scoped; + Diagnostic(ErrorCode.WRN_UnreferencedVarAssg, "scoped").WithArguments("scoped").WithLocation(1, 6)); + + var tree = comp.SyntaxTrees[0]; + var model = comp.GetSemanticModel(tree); + var decls = tree.GetRoot().DescendantNodes().OfType().ToArray(); + var locals = decls.Select(d => model.GetDeclaredSymbol(d).GetSymbol()).ToArray(); + + VerifyLocalSymbol(locals[0], "System.Boolean scoped", RefKind.None, DeclarationScope.Unscoped); } - } - void M() + + [Fact] + public void LocalScope_06() + { + var source = +@"ref struct R { } +class Program +{ + static void M(R r0) { - M1(F); - M2(ref F); - M3(out F); - M4(F); - M4(in F); + scoped var r1 = new R(); + scoped ref var r3 = ref r0; } - static void M1(T t) { } - static void M2(ref T t) { } - static void M3(out T t) { t = default; } - static void M4(in T t) { } }"; - var comp = CreateCompilation(new[] { source, IsExternalInitTypeDefinition }); - comp.VerifyEmitDiagnostics(); + var comp = CreateCompilation(source); + comp.VerifyDiagnostics( + // (6,20): warning CS0219: The variable 'r1' is assigned but its value is never used + // scoped var r1 = new R(); + Diagnostic(ErrorCode.WRN_UnreferencedVarAssg, "r1").WithArguments("r1").WithLocation(6, 20) + ); + + var tree = comp.SyntaxTrees[0]; + var model = comp.GetSemanticModel(tree); + var decls = tree.GetRoot().DescendantNodes().OfType().ToArray(); + var locals = decls.Select(d => model.GetDeclaredSymbol(d).GetSymbol()).ToArray(); + + VerifyLocalSymbol(locals[0], "scoped R r1", RefKind.None, DeclarationScope.ValueScoped); + VerifyLocalSymbol(locals[1], "scoped ref R r3", RefKind.Ref, DeclarationScope.RefScoped); } [Fact] - public void RefParameter_InstanceMethod_ReadonlyRefReadonly() + public void LocalScopeAndInitializer_01() { var source = -@"ref struct S +@"ref struct R { } +class Program { - public readonly ref readonly T F; - public S(ref T t) - { - F = ref t; - M1(F); - M2(ref F); // 1 - M3(out F); // 2 - M4(F); - M4(in F); - } - object P + static void Values(R r1, scoped R r2) { - init - { - M1(F); - M2(ref F); // 3 - M3(out F); // 4 - M4(F); - M4(in F); - } + R r11 = r1; + R r12 = r2; + scoped R r21 = r1; + scoped R r22 = r2; } - void M() + static void Refs(ref R r1, scoped ref R r2) { - M1(F); - M2(ref F); // 5 - M3(out F); // 6 - M4(F); - M4(in F); + ref R r31 = ref r1; + ref R r32 = ref r2; + scoped ref R r41 = ref r1; + scoped ref R r42 = ref r2; } - static void M1(T t) { } - static void M2(ref T t) { } - static void M3(out T t) { t = default; } - static void M4(in T t) { } }"; - var comp = CreateCompilation(new[] { source, IsExternalInitTypeDefinition }); - comp.VerifyEmitDiagnostics( - // (8,16): error CS8329: Cannot use field 'S.F' as a ref or out value because it is a readonly variable - // M2(ref F); // 1 - Diagnostic(ErrorCode.ERR_RefReadonlyNotField, "F").WithArguments("field", "S.F").WithLocation(8, 16), - // (9,16): error CS8329: Cannot use field 'S.F' as a ref or out value because it is a readonly variable - // M3(out F); // 2 - Diagnostic(ErrorCode.ERR_RefReadonlyNotField, "F").WithArguments("field", "S.F").WithLocation(9, 16), - // (18,20): error CS8329: Cannot use field 'S.F' as a ref or out value because it is a readonly variable - // M2(ref F); // 3 - Diagnostic(ErrorCode.ERR_RefReadonlyNotField, "F").WithArguments("field", "S.F").WithLocation(18, 20), - // (19,20): error CS8329: Cannot use field 'S.F' as a ref or out value because it is a readonly variable - // M3(out F); // 4 - Diagnostic(ErrorCode.ERR_RefReadonlyNotField, "F").WithArguments("field", "S.F").WithLocation(19, 20), - // (27,16): error CS8329: Cannot use field 'S.F' as a ref or out value because it is a readonly variable - // M2(ref F); // 5 - Diagnostic(ErrorCode.ERR_RefReadonlyNotField, "F").WithArguments("field", "S.F").WithLocation(27, 16), - // (28,16): error CS8329: Cannot use field 'S.F' as a ref or out value because it is a readonly variable - // M3(out F); // 6 - Diagnostic(ErrorCode.ERR_RefReadonlyNotField, "F").WithArguments("field", "S.F").WithLocation(28, 16)); - } + var comp = CreateCompilation(source); + comp.VerifyEmitDiagnostics(); - [Fact] - public void RefParameter_Ref() - { - var source = -@"ref struct S -{ - public ref T F; -} + var tree = comp.SyntaxTrees[0]; + var model = comp.GetSemanticModel(tree); + var decls = tree.GetRoot().DescendantNodes().OfType().ToArray(); + var locals = decls.Select(d => model.GetDeclaredSymbol(d).GetSymbol()).ToArray(); -class Program -{ - static void M1(T t) { } - static void M2(ref T t) { } - static void M3(out T t) { t = default; } - static void M4(in T t) { } + VerifyLocalSymbol(locals[0], "R r11", RefKind.None, DeclarationScope.Unscoped); + VerifyLocalSymbol(locals[1], "R r12", RefKind.None, DeclarationScope.Unscoped); + VerifyLocalSymbol(locals[2], "scoped R r21", RefKind.None, DeclarationScope.ValueScoped); + VerifyLocalSymbol(locals[3], "scoped R r22", RefKind.None, DeclarationScope.ValueScoped); - static void FromValue1(S s) { M1(s.F); } - static void FromValue2(S s) { M2(ref s.F); } - static void FromValue3(S s) { M3(out s.F); } - static void FromValue4A(S s) { M4(in s.F); } - static void FromValue4B(S s) { M4(s.F); } + VerifyLocalSymbol(locals[4], "ref R r31", RefKind.Ref, DeclarationScope.Unscoped); + VerifyLocalSymbol(locals[5], "ref R r32", RefKind.Ref, DeclarationScope.Unscoped); + VerifyLocalSymbol(locals[6], "scoped ref R r41", RefKind.Ref, DeclarationScope.RefScoped); + VerifyLocalSymbol(locals[7], "scoped ref R r42", RefKind.Ref, DeclarationScope.RefScoped); + } - static void FromRef1(ref S s) { M1(s.F); } - static void FromRef2(ref S s) { M2(ref s.F); } - static void FromRef3(ref S s) { M3(out s.F); } - static void FromRef4A(ref S s) { M4(in s.F); } - static void FromRef4B(ref S s) { M4(s.F); } + private static void VerifyLocalSymbol(LocalSymbol local, string expectedDisplayString, RefKind expectedRefKind, DeclarationScope expectedScope) + { + Assert.Equal(expectedRefKind, local.RefKind); + Assert.Equal(expectedScope, local.Scope); + Assert.Equal(expectedDisplayString, local.ToDisplayString(displayFormatWithScoped)); - static void FromOut1(out S s) { s = default; M1(s.F); } - static void FromOut2(out S s) { s = default; M2(ref s.F); } - static void FromOut3(out S s) { s = default; M3(out s.F); } - static void FromOut4A(out S s) { s = default; M4(in s.F); } - static void FromOut4B(out S s) { s = default; M4(s.F); } + VerifyLocalSymbol(local.GetPublicSymbol(), expectedDisplayString, expectedRefKind, expectedScope); + } - static void FromIn1(in S s) { M1(s.F); } - static void FromIn2(in S s) { M2(ref s.F); } - static void FromIn3(in S s) { M3(out s.F); } - static void FromIn4A(in S s) { M4(in s.F); } - static void FromIn4B(in S s) { M4(s.F); } -}"; - var comp = CreateCompilation(source); - comp.VerifyEmitDiagnostics(); + private static void VerifyLocalSymbol(ILocalSymbol local, string expectedDisplayString, RefKind expectedRefKind, DeclarationScope expectedScope) + { + Assert.Equal(expectedRefKind, local.RefKind); + // https://github.com/dotnet/roslyn/issues/61647: Use public API. + //Assert.Equal(expectedScope == DeclarationScope.RefScoped, local.IsRefScoped); + //Assert.Equal(expectedScope == DeclarationScope.ValueScoped, local.IsValueScoped); + Assert.Equal(expectedDisplayString, local.ToDisplayString(displayFormatWithScoped)); } - [Fact] - public void RefParameter_RefReadonly() + [ConditionalFact(typeof(WindowsDesktopOnly), Reason = ConditionalSkipReason.NoPiaNeedsDesktop)] + public void ParameterScope_EmbeddedMethod() { - var source = -@"ref struct S + var sourceA = +@"using System.Runtime.InteropServices; +[assembly: ImportedFromTypeLib(""_.dll"")] +[assembly: Guid(""DB204C34-AE89-49C6-9174-09F72E7F7F10"")] +[ComImport()] +[Guid(""933FEEE7-2728-4F87-A802-953F3CF1B1E9"")] +public interface I { - public ref readonly T F; + void M(scoped ref int i); } +"; + var comp = CreateCompilation(sourceA); + var refA = comp.EmitToImageReference(embedInteropTypes: true); + var sourceB = +@"class C : I +{ + public void M(scoped ref int i) { } +} class Program { - static void M1(T t) { } - static void M2(ref T t) { } - static void M3(out T t) { t = default; } - static void M4(in T t) { } - - static void FromValue1(S s) { M1(s.F); } - static void FromValue2(S s) { M2(ref s.F); } // 1 - static void FromValue3(S s) { M3(out s.F); } // 2 - static void FromValue4A(S s) { M4(in s.F); } - static void FromValue4B(S s) { M4(s.F); } - - static void FromRef1(ref S s) { M1(s.F); } - static void FromRef2(ref S s) { M2(ref s.F); } // 3 - static void FromRef3(ref S s) { M3(out s.F); } // 4 - static void FromRef4A(ref S s) { M4(in s.F); } - static void FromRef4B(ref S s) { M4(s.F); } - - static void FromOut1(out S s) { s = default; M1(s.F); } - static void FromOut2(out S s) { s = default; M2(ref s.F); } // 5 - static void FromOut3(out S s) { s = default; M3(out s.F); } // 6 - static void FromOut4A(out S s) { s = default; M4(in s.F); } - static void FromOut4B(out S s) { s = default; M4(s.F); } - - static void FromIn1(in S s) { M1(s.F); } - static void FromIn2(in S s) { M2(ref s.F); } // 7 - static void FromIn3(in S s) { M3(out s.F); } // 8 - static void FromIn4A(in S s) { M4(in s.F); } - static void FromIn4B(in S s) { M4(s.F); } + static void Main() + { + } }"; - var comp = CreateCompilation(source); - comp.VerifyEmitDiagnostics( - // (14,49): error CS8329: Cannot use field 'S.F' as a ref or out value because it is a readonly variable - // static void FromValue2(S s) { M2(ref s.F); } // 1 - Diagnostic(ErrorCode.ERR_RefReadonlyNotField, "s.F").WithArguments("field", "S.F").WithLocation(14, 49), - // (15,49): error CS8329: Cannot use field 'S.F' as a ref or out value because it is a readonly variable - // static void FromValue3(S s) { M3(out s.F); } // 2 - Diagnostic(ErrorCode.ERR_RefReadonlyNotField, "s.F").WithArguments("field", "S.F").WithLocation(15, 49), - // (20,51): error CS8329: Cannot use field 'S.F' as a ref or out value because it is a readonly variable - // static void FromRef2(ref S s) { M2(ref s.F); } // 3 - Diagnostic(ErrorCode.ERR_RefReadonlyNotField, "s.F").WithArguments("field", "S.F").WithLocation(20, 51), - // (21,51): error CS8329: Cannot use field 'S.F' as a ref or out value because it is a readonly variable - // static void FromRef3(ref S s) { M3(out s.F); } // 4 - Diagnostic(ErrorCode.ERR_RefReadonlyNotField, "s.F").WithArguments("field", "S.F").WithLocation(21, 51), - // (26,64): error CS8329: Cannot use field 'S.F' as a ref or out value because it is a readonly variable - // static void FromOut2(out S s) { s = default; M2(ref s.F); } // 5 - Diagnostic(ErrorCode.ERR_RefReadonlyNotField, "s.F").WithArguments("field", "S.F").WithLocation(26, 64), - // (27,64): error CS8329: Cannot use field 'S.F' as a ref or out value because it is a readonly variable - // static void FromOut3(out S s) { s = default; M3(out s.F); } // 6 - Diagnostic(ErrorCode.ERR_RefReadonlyNotField, "s.F").WithArguments("field", "S.F").WithLocation(27, 64), - // (32,49): error CS8329: Cannot use field 'S.F' as a ref or out value because it is a readonly variable - // static void FromIn2(in S s) { M2(ref s.F); } // 7 - Diagnostic(ErrorCode.ERR_RefReadonlyNotField, "s.F").WithArguments("field", "S.F").WithLocation(32, 49), - // (33,49): error CS8329: Cannot use field 'S.F' as a ref or out value because it is a readonly variable - // static void FromIn3(in S s) { M3(out s.F); } // 8 - Diagnostic(ErrorCode.ERR_RefReadonlyNotField, "s.F").WithArguments("field", "S.F").WithLocation(33, 49)); + CompileAndVerify(sourceB, references: new[] { refA }, + symbolValidator: module => + { + var method = module.GlobalNamespace.GetMember("I.M"); + // Attribute is not included for the parameter from the embedded method. + VerifyParameterSymbol(method.Parameters[0], "ref System.Int32 i", RefKind.Ref, DeclarationScope.Unscoped); + }); } [Fact] - public void RefParameter_ReadonlyRef() + public void Conversions_01() { var source = -@"ref struct S -{ - public readonly ref T F; -} - +@"ref struct R { } class Program { - static void M1(T t) { } - static void M2(ref T t) { } - static void M3(out T t) { t = default; } - static void M4(in T t) { } - - static void FromValue1(S s) { M1(s.F); } - static void FromValue2(S s) { M2(ref s.F); } - static void FromValue3(S s) { M3(out s.F); } - static void FromValue4A(S s) { M4(in s.F); } - static void FromValue4B(S s) { M4(s.F); } - - static void FromRef1(ref S s) { M1(s.F); } - static void FromRef2(ref S s) { M2(ref s.F); } - static void FromRef3(ref S s) { M3(out s.F); } - static void FromRef4A(ref S s) { M4(in s.F); } - static void FromRef4B(ref S s) { M4(s.F); } - - static void FromOut1(out S s) { s = default; M1(s.F); } - static void FromOut2(out S s) { s = default; M2(ref s.F); } - static void FromOut3(out S s) { s = default; M3(out s.F); } - static void FromOut4A(out S s) { s = default; M4(in s.F); } - static void FromOut4B(out S s) { s = default; M4(s.F); } - - static void FromIn1(in S s) { M1(s.F); } - static void FromIn2(in S s) { M2(ref s.F); } - static void FromIn3(in S s) { M3(out s.F); } - static void FromIn4A(in S s) { M4(in s.F); } - static void FromIn4B(in S s) { M4(s.F); } + static R Implicit1(scoped R r) => r; + static R Implicit2(ref R r) => r; + static R Implicit4(scoped ref R r) => r; + static R Explicit1(scoped R r) => (R)r; + static R Explicit2(ref R r) => (R)r; + static R Explicit4(scoped ref R r) => (R)r; }"; var comp = CreateCompilation(source); - comp.VerifyEmitDiagnostics(); + comp.VerifyDiagnostics( + // (4,39): error CS8352: Cannot use variable 'R' in this context because it may expose referenced variables outside of their declaration scope + // static R Implicit1(scoped R r) => r; + Diagnostic(ErrorCode.ERR_EscapeVariable, "r").WithArguments("R").WithLocation(4, 39), + // (7,39): error CS8352: Cannot use variable 'R' in this context because it may expose referenced variables outside of their declaration scope + // static R Explicit1(scoped R r) => (R)r; + Diagnostic(ErrorCode.ERR_EscapeVariable, "(R)r").WithArguments("R").WithLocation(7, 39)); } [Fact] - public void RefParameter_ReadonlyRefReadonly() + public void DelegateConversions_01() { var source = -@"ref struct S -{ - public readonly ref readonly T F; -} - +@"ref struct R { } +delegate R D1(R x, R y); +delegate R D2(R x, scoped R y); +delegate ref R D5(ref R x, scoped ref R y); class Program { - static void M1(T t) { } - static void M2(ref T t) { } - static void M3(out T t) { t = default; } - static void M4(in T t) { } - - static void FromValue1(S s) { M1(s.F); } - static void FromValue2(S s) { M2(ref s.F); } // 1 - static void FromValue3(S s) { M3(out s.F); } // 2 - static void FromValue4A(S s) { M4(in s.F); } - static void FromValue4B(S s) { M4(s.F); } - - static void FromRef1(ref S s) { M1(s.F); } - static void FromRef2(ref S s) { M2(ref s.F); } // 3 - static void FromRef3(ref S s) { M3(out s.F); } // 4 - static void FromRef4A(ref S s) { M4(in s.F); } - static void FromRef4B(ref S s) { M4(s.F); } - - static void FromOut1(out S s) { s = default; M1(s.F); } - static void FromOut2(out S s) { s = default; M2(ref s.F); } // 5 - static void FromOut3(out S s) { s = default; M3(out s.F); } // 6 - static void FromOut4A(out S s) { s = default; M4(in s.F); } - static void FromOut4B(out S s) { s = default; M4(s.F); } - - static void FromIn1(in S s) { M1(s.F); } - static void FromIn2(in S s) { M2(ref s.F); } // 7 - static void FromIn3(in S s) { M3(out s.F); } // 8 - static void FromIn4A(in S s) { M4(in s.F); } - static void FromIn4B(in S s) { M4(s.F); } + static void Implicit() + { + D1 d1 = (R x, scoped R y) => x; + D2 d2 = (R x, R y) => x; + D5 d5 = (ref R x, ref R y) => ref x; + } + static void Explicit() + { + var d1 = (D1)((R x, scoped R y) => x); + var d2 = (D2)((R x, R y) => x); + var d5 = (D5)((ref R x, ref R y) => ref x); + } + static void New() + { + var d1 = new D1((R x, scoped R y) => x); + var d2 = new D2((R x, R y) => x); + var d5 = new D5((ref R x, ref R y) => ref x); + } }"; var comp = CreateCompilation(source); - comp.VerifyEmitDiagnostics( - // (14,49): error CS8329: Cannot use field 'S.F' as a ref or out value because it is a readonly variable - // static void FromValue2(S s) { M2(ref s.F); } // 1 - Diagnostic(ErrorCode.ERR_RefReadonlyNotField, "s.F").WithArguments("field", "S.F").WithLocation(14, 49), - // (15,49): error CS8329: Cannot use field 'S.F' as a ref or out value because it is a readonly variable - // static void FromValue3(S s) { M3(out s.F); } // 2 - Diagnostic(ErrorCode.ERR_RefReadonlyNotField, "s.F").WithArguments("field", "S.F").WithLocation(15, 49), - // (20,51): error CS8329: Cannot use field 'S.F' as a ref or out value because it is a readonly variable - // static void FromRef2(ref S s) { M2(ref s.F); } // 3 - Diagnostic(ErrorCode.ERR_RefReadonlyNotField, "s.F").WithArguments("field", "S.F").WithLocation(20, 51), - // (21,51): error CS8329: Cannot use field 'S.F' as a ref or out value because it is a readonly variable - // static void FromRef3(ref S s) { M3(out s.F); } // 4 - Diagnostic(ErrorCode.ERR_RefReadonlyNotField, "s.F").WithArguments("field", "S.F").WithLocation(21, 51), - // (26,64): error CS8329: Cannot use field 'S.F' as a ref or out value because it is a readonly variable - // static void FromOut2(out S s) { s = default; M2(ref s.F); } // 5 - Diagnostic(ErrorCode.ERR_RefReadonlyNotField, "s.F").WithArguments("field", "S.F").WithLocation(26, 64), - // (27,64): error CS8329: Cannot use field 'S.F' as a ref or out value because it is a readonly variable - // static void FromOut3(out S s) { s = default; M3(out s.F); } // 6 - Diagnostic(ErrorCode.ERR_RefReadonlyNotField, "s.F").WithArguments("field", "S.F").WithLocation(27, 64), - // (32,49): error CS8329: Cannot use field 'S.F' as a ref or out value because it is a readonly variable - // static void FromIn2(in S s) { M2(ref s.F); } // 7 - Diagnostic(ErrorCode.ERR_RefReadonlyNotField, "s.F").WithArguments("field", "S.F").WithLocation(32, 49), - // (33,49): error CS8329: Cannot use field 'S.F' as a ref or out value because it is a readonly variable - // static void FromIn3(in S s) { M3(out s.F); } // 8 - Diagnostic(ErrorCode.ERR_RefReadonlyNotField, "s.F").WithArguments("field", "S.F").WithLocation(33, 49)); + comp.VerifyDiagnostics( + // (9,17): error CS8986: The 'scoped' modifier of parameter 'y' doesn't match target 'D1'. + // D1 d1 = (R x, scoped R y) => x; + Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfTarget, "(R x, scoped R y) => x").WithArguments("y", "D1").WithLocation(9, 17), + // (10,17): error CS8986: The 'scoped' modifier of parameter 'y' doesn't match target 'D2'. + // D2 d2 = (R x, R y) => x; + Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfTarget, "(R x, R y) => x").WithArguments("y", "D2").WithLocation(10, 17), + // (11,43): error CS8166: Cannot return a parameter by reference 'x' because it is not a ref parameter + // D5 d5 = (ref R x, ref R y) => ref x; + Diagnostic(ErrorCode.ERR_RefReturnParameter, "x").WithArguments("x").WithLocation(11, 43), + // (15,18): error CS8986: The 'scoped' modifier of parameter 'y' doesn't match target 'D1'. + // var d1 = (D1)((R x, scoped R y) => x); + Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfTarget, "(D1)((R x, scoped R y) => x)").WithArguments("y", "D1").WithLocation(15, 18), + // (16,18): error CS8986: The 'scoped' modifier of parameter 'y' doesn't match target 'D2'. + // var d2 = (D2)((R x, R y) => x); + Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfTarget, "(D2)((R x, R y) => x)").WithArguments("y", "D2").WithLocation(16, 18), + // (17,49): error CS8166: Cannot return a parameter by reference 'x' because it is not a ref parameter + // var d5 = (D5)((ref R x, ref R y) => ref x); + Diagnostic(ErrorCode.ERR_RefReturnParameter, "x").WithArguments("x").WithLocation(17, 49), + // (21,25): error CS8986: The 'scoped' modifier of parameter 'y' doesn't match target 'D1'. + // var d1 = new D1((R x, scoped R y) => x); + Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfTarget, "(R x, scoped R y) => x").WithArguments("y", "D1").WithLocation(21, 25), + // (22,25): error CS8986: The 'scoped' modifier of parameter 'y' doesn't match target 'D2'. + // var d2 = new D2((R x, R y) => x); + Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfTarget, "(R x, R y) => x").WithArguments("y", "D2").WithLocation(22, 25), + // (23,51): error CS8166: Cannot return a parameter by reference 'x' because it is not a ref parameter + // var d5 = new D5((ref R x, ref R y) => ref x); + Diagnostic(ErrorCode.ERR_RefReturnParameter, "x").WithArguments("x").WithLocation(23, 51)); } [Fact] - public void RefParameter_ReadonlyRefReadonly_PEVerifyCompat() + public void DelegateConversions_02() { var source = -@"#pragma warning disable 649 -ref struct S +@"ref struct R { } +delegate R D1(R x, R y); +delegate R D2(R x, scoped R y); +delegate ref R D5(ref R x, scoped ref R y); +class Program { - public readonly ref readonly T F; -} + static R M1(R x, R y) => x; + static R M2(R x, scoped R y) => x; + static ref R M3(ref R x, ref R y) => ref x; + static ref R M5(ref R x, scoped ref R y) => ref x; + static void Implicit() + { + D1 dA = M2; + D2 d2 = M1; + D5 d5 = M3; + } + static void Explicit() + { + var d1 = (D1)M2; + var d2 = (D2)M1; + var d5 = (D5)M3; + } + static void New() + { + var d1 = new D1(M2); + var d2 = new D2(M1); + var d5 = new D5(M3); + } +}"; + var comp = CreateCompilation(source); + comp.VerifyDiagnostics( + // (9,46): error CS8166: Cannot return a parameter by reference 'x' because it is not a ref parameter + // static ref R M3(ref R x, ref R y) => ref x; + Diagnostic(ErrorCode.ERR_RefReturnParameter, "x").WithArguments("x").WithLocation(9, 46), + // (10,53): error CS8166: Cannot return a parameter by reference 'x' because it is not a ref parameter + // static ref R M5(ref R x, scoped ref R y) => ref x; + Diagnostic(ErrorCode.ERR_RefReturnParameter, "x").WithArguments("x").WithLocation(10, 53), + // (13,17): error CS8986: The 'scoped' modifier of parameter 'y' doesn't match target 'D1'. + // D1 dA = M2; + Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfTarget, "M2").WithArguments("y", "D1").WithLocation(13, 17), + // (14,17): error CS8986: The 'scoped' modifier of parameter 'y' doesn't match target 'D2'. + // D2 d2 = M1; + Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfTarget, "M1").WithArguments("y", "D2").WithLocation(14, 17), + // (19,18): error CS8986: The 'scoped' modifier of parameter 'y' doesn't match target 'D1'. + // var d1 = (D1)M2; + Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfTarget, "(D1)M2").WithArguments("y", "D1").WithLocation(19, 18), + // (20,18): error CS8986: The 'scoped' modifier of parameter 'y' doesn't match target 'D2'. + // var d2 = (D2)M1; + Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfTarget, "(D2)M1").WithArguments("y", "D2").WithLocation(20, 18), + // (25,25): error CS8986: The 'scoped' modifier of parameter 'y' doesn't match target 'D1'. + // var d1 = new D1(M2); + Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfTarget, "M2").WithArguments("y", "D1").WithLocation(25, 25), + // (26,25): error CS8986: The 'scoped' modifier of parameter 'y' doesn't match target 'D2'. + // var d2 = new D2(M1); + Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfTarget, "M1").WithArguments("y", "D2").WithLocation(26, 25)); + } + [Fact] + public void DelegateConversions_03() + { + var source = +@"delegate ref int D1(ref int x, ref int y); +delegate ref int D2(scoped ref int x, ref int y); +delegate D1 D1R(); +delegate D2 D2R(); class Program { - static void M1(T t) { } - static void M4(in T t) { } - - static void FromValue1(S s) { M1(s.F); } - static void FromValue4A(S s) { M4(in s.F); } - static void FromValue4B(S s) { M4(s.F); } - - static void FromRef1(ref S s) { M1(s.F); } - static void FromRef4A(ref S s) { M4(in s.F); } - static void FromRef4B(ref S s) { M4(s.F); } - - static void FromOut1(out S s) { s = default; M1(s.F); } - static void FromOut4A(out S s) { s = default; M4(in s.F); } - static void FromOut4B(out S s) { s = default; M4(s.F); } + static void Implicit() + { + D1R d1 = () => (scoped ref int x, ref int y) => ref y; + D2R d2 = () => (ref int x, ref int y) => ref x; + } + static void Explicit() + { + var d1 = (D1R)(() => (scoped ref int x, ref int y) => ref y); + var d2 = (D2R)(() => (ref int x, ref int y) => ref x); + } + static void New() + { + var d1 = new D1R(() => (scoped ref int x, ref int y) => ref y); + var d2 = new D2R(() => (ref int x, ref int y) => ref x); + } +}"; + var comp = CreateCompilation(source); + comp.VerifyDiagnostics( + // (9,24): error CS8986: The 'scoped' modifier of parameter 'x' doesn't match target 'D1'. + // D1R d1 = () => (scoped ref int x, ref int y) => ref y; + Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfTarget, "(scoped ref int x, ref int y) => ref y").WithArguments("x", "D1").WithLocation(9, 24), + // (10,24): error CS8986: The 'scoped' modifier of parameter 'x' doesn't match target 'D2'. + // D2R d2 = () => (ref int x, ref int y) => ref x; + Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfTarget, "(ref int x, ref int y) => ref x").WithArguments("x", "D2").WithLocation(10, 24), + // (14,30): error CS8986: The 'scoped' modifier of parameter 'x' doesn't match target 'D1'. + // var d1 = (D1R)(() => (scoped ref int x, ref int y) => ref y); + Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfTarget, "(scoped ref int x, ref int y) => ref y").WithArguments("x", "D1").WithLocation(14, 30), + // (15,30): error CS8986: The 'scoped' modifier of parameter 'x' doesn't match target 'D2'. + // var d2 = (D2R)(() => (ref int x, ref int y) => ref x); + Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfTarget, "(ref int x, ref int y) => ref x").WithArguments("x", "D2").WithLocation(15, 30), + // (19,32): error CS8986: The 'scoped' modifier of parameter 'x' doesn't match target 'D1'. + // var d1 = new D1R(() => (scoped ref int x, ref int y) => ref y); + Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfTarget, "(scoped ref int x, ref int y) => ref y").WithArguments("x", "D1").WithLocation(19, 32), + // (20,32): error CS8986: The 'scoped' modifier of parameter 'x' doesn't match target 'D2'. + // var d2 = new D2R(() => (ref int x, ref int y) => ref x); + Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfTarget, "(ref int x, ref int y) => ref x").WithArguments("x", "D2").WithLocation(20, 32)); + } - static void FromIn1(in S s) { M1(s.F); } - static void FromIn4A(in S s) { M4(in s.F); } - static void FromIn4B(in S s) { M4(s.F); } + [Fact] + public void DelegateConversions_04() + { + var source = +@"delegate ref int D1(ref int x, ref int y); +delegate ref int D2(scoped ref int x, ref int y); +delegate D1 D1R(); +delegate D2 D2R(); +class Program +{ + static ref int M1(ref int x, ref int y) => ref x; + static ref int M2(scoped ref int x, ref int y) => ref y; + static void Implicit() + { + D1R d1 = () => M2; + D2R d2 = () => M1; + } + static void Explicit() + { + var d1 = (D1R)M2; + var d2 = (D2R)M1; + } + static void New() + { + var d1 = new D1R(M2); + var d2 = new D2R(M1); + } }"; - var comp = CreateCompilation(source, parseOptions: TestOptions.RegularPreview.WithFeature("peverify-compat")); - comp.VerifyEmitDiagnostics(); + var comp = CreateCompilation(source); + comp.VerifyDiagnostics( + // (11,24): error CS8986: The 'scoped' modifier of parameter 'x' doesn't match target 'D1'. + // D1R d1 = () => M2; + Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfTarget, "M2").WithArguments("x", "D1").WithLocation(11, 24), + // (12,24): error CS8986: The 'scoped' modifier of parameter 'x' doesn't match target 'D2'. + // D2R d2 = () => M1; + Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfTarget, "M1").WithArguments("x", "D2").WithLocation(12, 24), + // (16,18): error CS0123: No overload for 'M2' matches delegate 'D1R' + // var d1 = (D1R)M2; + Diagnostic(ErrorCode.ERR_MethDelegateMismatch, "(D1R)M2").WithArguments("M2", "D1R").WithLocation(16, 18), + // (17,18): error CS0123: No overload for 'M1' matches delegate 'D2R' + // var d2 = (D2R)M1; + Diagnostic(ErrorCode.ERR_MethDelegateMismatch, "(D2R)M1").WithArguments("M1", "D2R").WithLocation(17, 18), + // (21,18): error CS0123: No overload for 'M2' matches delegate 'D1R' + // var d1 = new D1R(M2); + Diagnostic(ErrorCode.ERR_MethDelegateMismatch, "new D1R(M2)").WithArguments("M2", "D1R").WithLocation(21, 18), + // (22,18): error CS0123: No overload for 'M1' matches delegate 'D2R' + // var d2 = new D2R(M1); + Diagnostic(ErrorCode.ERR_MethDelegateMismatch, "new D2R(M1)").WithArguments("M1", "D2R").WithLocation(22, 18)); } [Fact] - public void InitobjField() + public void DelegateConversions_05() { var source = -@"using System; -struct S -{ - public T F; -} -ref struct R -{ - public ref S S; -} +@"ref struct R { } +delegate R D1(R x, R y); +delegate R D2(R x, scoped R y); +delegate ref R D5(ref R x, scoped ref R y); class Program { - static void Main() + static void Implicit() { - var s = new S(); - scoped var r = new R(); - r.S = ref s; - NewField(ref r); - r.S.F = 42; - Console.WriteLine(s.F); - Console.WriteLine(r.S.F); + D1 d1 = delegate(R x, scoped R y) { return x; }; + D2 d2 = delegate(R x, R y) { return x; }; + D5 d5 = delegate(ref R x, ref R y) { return ref x; }; } - static void NewField(ref R r) + static void Explicit() { - r.S = new S(); + var d1 = (D1)(delegate(R x, scoped R y) { return x; }); + var d2 = (D2)(delegate(R x, R y) { return x; }); + var d5 = (D5)(delegate(ref R x, ref R y) { return ref x; }); + } + static void New() + { + var d1 = new D1(delegate(R x, scoped R y) { return x; }); + var d2 = new D2(delegate(R x, R y) { return x; }); + var d5 = new D5(delegate(ref R x, ref R y) { return ref x; }); } }"; - var verifier = CompileAndVerify(source, verify: Verification.Skipped, expectedOutput: IncludeExpectedOutput( -@"42 -42 -")); - verifier.VerifyIL("Program.NewField", -@"{ - // Code size 13 (0xd) - .maxstack 1 - IL_0000: ldarg.0 - IL_0001: ldfld ""ref S R.S"" - IL_0006: initobj ""S"" - IL_000c: ret -}"); + var comp = CreateCompilation(source); + comp.VerifyDiagnostics( + // (9,17): error CS8986: The 'scoped' modifier of parameter 'y' doesn't match target 'D1'. + // D1 d1 = delegate(R x, scoped R y) { return x; }; + Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfTarget, "delegate(R x, scoped R y) { return x; }").WithArguments("y", "D1").WithLocation(9, 17), + // (10,17): error CS8986: The 'scoped' modifier of parameter 'y' doesn't match target 'D2'. + // D2 d2 = delegate(R x, R y) { return x; }; + Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfTarget, "delegate(R x, R y) { return x; }").WithArguments("y", "D2").WithLocation(10, 17), + // (11,57): error CS8166: Cannot return a parameter by reference 'x' because it is not a ref parameter + // D5 d5 = delegate(ref R x, ref R y) { return ref x; }; + Diagnostic(ErrorCode.ERR_RefReturnParameter, "x").WithArguments("x").WithLocation(11, 57), + // (15,18): error CS8986: The 'scoped' modifier of parameter 'y' doesn't match target 'D1'. + // var d1 = (D1)(delegate(R x, scoped R y) { return x; }); + Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfTarget, "(D1)(delegate(R x, scoped R y) { return x; })").WithArguments("y", "D1").WithLocation(15, 18), + // (16,18): error CS8986: The 'scoped' modifier of parameter 'y' doesn't match target 'D2'. + // var d2 = (D2)(delegate(R x, R y) { return x; }); + Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfTarget, "(D2)(delegate(R x, R y) { return x; })").WithArguments("y", "D2").WithLocation(16, 18), + // (17,63): error CS8166: Cannot return a parameter by reference 'x' because it is not a ref parameter + // var d5 = (D5)(delegate(ref R x, ref R y) { return ref x; }); + Diagnostic(ErrorCode.ERR_RefReturnParameter, "x").WithArguments("x").WithLocation(17, 63), + // (21,25): error CS8986: The 'scoped' modifier of parameter 'y' doesn't match target 'D1'. + // var d1 = new D1(delegate(R x, scoped R y) { return x; }); + Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfTarget, "delegate(R x, scoped R y) { return x; }").WithArguments("y", "D1").WithLocation(21, 25), + // (22,25): error CS8986: The 'scoped' modifier of parameter 'y' doesn't match target 'D2'. + // var d2 = new D2(delegate(R x, R y) { return x; }); + Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfTarget, "delegate(R x, R y) { return x; }").WithArguments("y", "D2").WithLocation(22, 25), + // (23,65): error CS8166: Cannot return a parameter by reference 'x' because it is not a ref parameter + // var d5 = new D5(delegate(ref R x, ref R y) { return ref x; }); + Diagnostic(ErrorCode.ERR_RefReturnParameter, "x").WithArguments("x").WithLocation(23, 65)); } [Fact] - public void ReadWriteField() + public void DelegateConversions_06() { var source = -@"using System; -ref struct S -{ - public ref T F; - public S(ref T t) { F = ref t; } -} +@"using System.Linq.Expressions; +ref struct R { } +delegate R D1(R x, R y); +delegate R D2(R x, scoped R y); +delegate ref int D3(ref int x, ref int y); +delegate ref int D4(ref int x, scoped ref int y); class Program { - static void Main() - { - int x = 1; - scoped var s = new S(); - s.F = ref x; - Write(s, 42); - Console.WriteLine(Read(s)); - Console.WriteLine(x); - } - static int Read(S s) + static void Implicit() { - return s.F; + Expression e1 = (R x, scoped R y) => x; + Expression e2 = (R x, R y) => x; + Expression e3 = (ref int x, scoped ref int y) => ref x; + Expression e4 = (ref int x, ref int y) => ref x; } - static void Write(S s, int value) + static void Explicit() { - s.F = value; + var e1 = (Expression)((R x, scoped R y) => x); + var e2 = (Expression)((R x, R y) => x); + var e3 = (Expression)((ref int x, scoped ref int y) => ref x); + var e4 = (Expression)((ref int x, ref int y) => ref x); } }"; - var verifier = CompileAndVerify(source, verify: Verification.Skipped, expectedOutput: IncludeExpectedOutput( -@"42 -42 -")); - verifier.VerifyIL("S..ctor(ref T)", -@"{ - // Code size 8 (0x8) - .maxstack 2 - IL_0000: ldarg.0 - IL_0001: ldarg.1 - IL_0002: stfld ""ref T S.F"" - IL_0007: ret -}"); - verifier.VerifyIL("Program.Read", -@"{ - // Code size 8 (0x8) - .maxstack 1 - IL_0000: ldarg.0 - IL_0001: ldfld ""ref int S.F"" - IL_0006: ldind.i4 - IL_0007: ret -}"); - verifier.VerifyIL("Program.Write", -@"{ - // Code size 9 (0x9) - .maxstack 2 - IL_0000: ldarg.0 - IL_0001: ldfld ""ref int S.F"" - IL_0006: ldarg.1 - IL_0007: stind.i4 - IL_0008: ret -}"); + var comp = CreateCompilation(source); + comp.VerifyDiagnostics( + // (11,29): error CS8986: The 'scoped' modifier of parameter 'y' doesn't match target 'Expression'. + // Expression e1 = (R x, scoped R y) => x; + Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfTarget, "(R x, scoped R y) => x").WithArguments("y", "System.Linq.Expressions.Expression").WithLocation(11, 29), + // (11,32): error CS8640: Expression tree cannot contain value of ref struct or restricted type 'R'. + // Expression e1 = (R x, scoped R y) => x; + Diagnostic(ErrorCode.ERR_ExpressionTreeCantContainRefStruct, "x").WithArguments("R").WithLocation(11, 32), + // (11,44): error CS8640: Expression tree cannot contain value of ref struct or restricted type 'R'. + // Expression e1 = (R x, scoped R y) => x; + Diagnostic(ErrorCode.ERR_ExpressionTreeCantContainRefStruct, "y").WithArguments("R").WithLocation(11, 44), + // (11,50): error CS8640: Expression tree cannot contain value of ref struct or restricted type 'R'. + // Expression e1 = (R x, scoped R y) => x; + Diagnostic(ErrorCode.ERR_ExpressionTreeCantContainRefStruct, "x").WithArguments("R").WithLocation(11, 50), + // (12,29): error CS8986: The 'scoped' modifier of parameter 'y' doesn't match target 'Expression'. + // Expression e2 = (R x, R y) => x; + Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfTarget, "(R x, R y) => x").WithArguments("y", "System.Linq.Expressions.Expression").WithLocation(12, 29), + // (12,32): error CS8640: Expression tree cannot contain value of ref struct or restricted type 'R'. + // Expression e2 = (R x, R y) => x; + Diagnostic(ErrorCode.ERR_ExpressionTreeCantContainRefStruct, "x").WithArguments("R").WithLocation(12, 32), + // (12,37): error CS8640: Expression tree cannot contain value of ref struct or restricted type 'R'. + // Expression e2 = (R x, R y) => x; + Diagnostic(ErrorCode.ERR_ExpressionTreeCantContainRefStruct, "y").WithArguments("R").WithLocation(12, 37), + // (12,43): error CS8640: Expression tree cannot contain value of ref struct or restricted type 'R'. + // Expression e2 = (R x, R y) => x; + Diagnostic(ErrorCode.ERR_ExpressionTreeCantContainRefStruct, "x").WithArguments("R").WithLocation(12, 43), + // (13,29): error CS8986: The 'scoped' modifier of parameter 'y' doesn't match target 'Expression'. + // Expression e3 = (ref int x, scoped ref int y) => ref x; + Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfTarget, "(ref int x, scoped ref int y) => ref x").WithArguments("y", "System.Linq.Expressions.Expression").WithLocation(13, 29), + // (13,29): error CS8155: Lambda expressions that return by reference cannot be converted to expression trees + // Expression e3 = (ref int x, scoped ref int y) => ref x; + Diagnostic(ErrorCode.ERR_BadRefReturnExpressionTree, "(ref int x, scoped ref int y) => ref x").WithLocation(13, 29), + // (13,38): error CS1951: An expression tree lambda may not contain a ref, in or out parameter + // Expression e3 = (ref int x, scoped ref int y) => ref x; + Diagnostic(ErrorCode.ERR_ByRefParameterInExpressionTree, "x").WithLocation(13, 38), + // (13,56): error CS1951: An expression tree lambda may not contain a ref, in or out parameter + // Expression e3 = (ref int x, scoped ref int y) => ref x; + Diagnostic(ErrorCode.ERR_ByRefParameterInExpressionTree, "y").WithLocation(13, 56), + // (14,29): error CS8986: The 'scoped' modifier of parameter 'y' doesn't match target 'Expression'. + // Expression e4 = (ref int x, ref int y) => ref x; + Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfTarget, "(ref int x, ref int y) => ref x").WithArguments("y", "System.Linq.Expressions.Expression").WithLocation(14, 29), + // (14,29): error CS8155: Lambda expressions that return by reference cannot be converted to expression trees + // Expression e4 = (ref int x, ref int y) => ref x; + Diagnostic(ErrorCode.ERR_BadRefReturnExpressionTree, "(ref int x, ref int y) => ref x").WithLocation(14, 29), + // (14,38): error CS1951: An expression tree lambda may not contain a ref, in or out parameter + // Expression e4 = (ref int x, ref int y) => ref x; + Diagnostic(ErrorCode.ERR_ByRefParameterInExpressionTree, "x").WithLocation(14, 38), + // (14,49): error CS1951: An expression tree lambda may not contain a ref, in or out parameter + // Expression e4 = (ref int x, ref int y) => ref x; + Diagnostic(ErrorCode.ERR_ByRefParameterInExpressionTree, "y").WithLocation(14, 49), + // (18,18): error CS8986: The 'scoped' modifier of parameter 'y' doesn't match target 'Expression'. + // var e1 = (Expression)((R x, scoped R y) => x); + Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfTarget, "(Expression)((R x, scoped R y) => x)").WithArguments("y", "System.Linq.Expressions.Expression").WithLocation(18, 18), + // (18,38): error CS8640: Expression tree cannot contain value of ref struct or restricted type 'R'. + // var e1 = (Expression)((R x, scoped R y) => x); + Diagnostic(ErrorCode.ERR_ExpressionTreeCantContainRefStruct, "x").WithArguments("R").WithLocation(18, 38), + // (18,50): error CS8640: Expression tree cannot contain value of ref struct or restricted type 'R'. + // var e1 = (Expression)((R x, scoped R y) => x); + Diagnostic(ErrorCode.ERR_ExpressionTreeCantContainRefStruct, "y").WithArguments("R").WithLocation(18, 50), + // (18,56): error CS8640: Expression tree cannot contain value of ref struct or restricted type 'R'. + // var e1 = (Expression)((R x, scoped R y) => x); + Diagnostic(ErrorCode.ERR_ExpressionTreeCantContainRefStruct, "x").WithArguments("R").WithLocation(18, 56), + // (19,18): error CS8986: The 'scoped' modifier of parameter 'y' doesn't match target 'Expression'. + // var e2 = (Expression)((R x, R y) => x); + Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfTarget, "(Expression)((R x, R y) => x)").WithArguments("y", "System.Linq.Expressions.Expression").WithLocation(19, 18), + // (19,38): error CS8640: Expression tree cannot contain value of ref struct or restricted type 'R'. + // var e2 = (Expression)((R x, R y) => x); + Diagnostic(ErrorCode.ERR_ExpressionTreeCantContainRefStruct, "x").WithArguments("R").WithLocation(19, 38), + // (19,43): error CS8640: Expression tree cannot contain value of ref struct or restricted type 'R'. + // var e2 = (Expression)((R x, R y) => x); + Diagnostic(ErrorCode.ERR_ExpressionTreeCantContainRefStruct, "y").WithArguments("R").WithLocation(19, 43), + // (19,49): error CS8640: Expression tree cannot contain value of ref struct or restricted type 'R'. + // var e2 = (Expression)((R x, R y) => x); + Diagnostic(ErrorCode.ERR_ExpressionTreeCantContainRefStruct, "x").WithArguments("R").WithLocation(19, 49), + // (20,18): error CS8986: The 'scoped' modifier of parameter 'y' doesn't match target 'Expression'. + // var e3 = (Expression)((ref int x, scoped ref int y) => ref x); + Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfTarget, "(Expression)((ref int x, scoped ref int y) => ref x)").WithArguments("y", "System.Linq.Expressions.Expression").WithLocation(20, 18), + // (20,35): error CS8155: Lambda expressions that return by reference cannot be converted to expression trees + // var e3 = (Expression)((ref int x, scoped ref int y) => ref x); + Diagnostic(ErrorCode.ERR_BadRefReturnExpressionTree, "(ref int x, scoped ref int y) => ref x").WithLocation(20, 35), + // (20,44): error CS1951: An expression tree lambda may not contain a ref, in or out parameter + // var e3 = (Expression)((ref int x, scoped ref int y) => ref x); + Diagnostic(ErrorCode.ERR_ByRefParameterInExpressionTree, "x").WithLocation(20, 44), + // (20,62): error CS1951: An expression tree lambda may not contain a ref, in or out parameter + // var e3 = (Expression)((ref int x, scoped ref int y) => ref x); + Diagnostic(ErrorCode.ERR_ByRefParameterInExpressionTree, "y").WithLocation(20, 62), + // (21,18): error CS8986: The 'scoped' modifier of parameter 'y' doesn't match target 'Expression'. + // var e4 = (Expression)((ref int x, ref int y) => ref x); + Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfTarget, "(Expression)((ref int x, ref int y) => ref x)").WithArguments("y", "System.Linq.Expressions.Expression").WithLocation(21, 18), + // (21,35): error CS8155: Lambda expressions that return by reference cannot be converted to expression trees + // var e4 = (Expression)((ref int x, ref int y) => ref x); + Diagnostic(ErrorCode.ERR_BadRefReturnExpressionTree, "(ref int x, ref int y) => ref x").WithLocation(21, 35), + // (21,44): error CS1951: An expression tree lambda may not contain a ref, in or out parameter + // var e4 = (Expression)((ref int x, ref int y) => ref x); + Diagnostic(ErrorCode.ERR_ByRefParameterInExpressionTree, "x").WithLocation(21, 44), + // (21,55): error CS1951: An expression tree lambda may not contain a ref, in or out parameter + // var e4 = (Expression)((ref int x, ref int y) => ref x); + Diagnostic(ErrorCode.ERR_ByRefParameterInExpressionTree, "y").WithLocation(21, 55)); } [Fact] - public void ReadWriteNestedField() + public void DelegateConversions_Out() { var source = -@"using System; -ref struct R1 -{ - public ref T F; - public R1(ref T t) { F = ref t; } -} -ref struct R2 -{ - public ref R1 R1; - public R2(ref R1 r1) { R1 = ref r1; } -} +@"ref struct R { } +delegate void D1(out int x, scoped out int y); +delegate void D2(out R x, scoped out R y); class Program { - static void Main() + static void Implicit() { - int i = 0; - var r1 = new R1(ref i); - var r2 = new R2(ref r1); - r2.R1.F = 42; - Console.WriteLine(Read(r2)); - Console.WriteLine(ReadIn(r2)); - Console.WriteLine(i); + D1 d1 = (scoped out int x, out int y) => { x = 0; y = 0; }; + D2 d2 = (scoped out R x, out R y) => { x = default; y = default; }; } - static T Read(R2 r2) + static void Explicit() { - return r2.R1.F; + var d1 = (D1)((scoped out int x, out int y) => { x = 0; y = 0; }); + var d2 = (D2)((scoped out R x, out R y) => { x = default; y = default; }); } - static T ReadIn(in R2 r2In) + static void New() { - return r2In.R1.F; + var d1 = new D1((scoped out int x, out int y) => { x = 0; y = 0; }); + var d2 = new D2((scoped out R x, out R y) => { x = default; y = default; }); } }"; var comp = CreateCompilation(source); - comp.VerifyEmitDiagnostics( - // (9,12): error CS9050: A ref field cannot refer to a ref struct. - // public ref R1 R1; - Diagnostic(ErrorCode.ERR_RefFieldCannotReferToRefStruct, "ref R1").WithLocation(9, 12)); + comp.VerifyDiagnostics(); } [Fact] - public void ReadWriteFieldWithTemp() + public void FunctionPointerConversions() { var source = -@"ref struct S -{ - public ref T F; - private int _other; - public S(int other) : this() { _other = other; } -} -class Program +@"ref struct R { } +unsafe class Program { - static T ReadWrite1(ref T t) + static R F1(R x, scoped R y) => x; + static ref readonly int F3(in int x, scoped in int y) => ref x; + static void Implicit() { - return new S().F = ref t; + delegate* d1 = &F1; + delegate* d3 = &F3; } - static T ReadWrite2(ref T t) + static void Explicit() { - return new S(1).F = ref t; + var d1 = (delegate*)&F1; + var d3 = (delegate*)&F3; } }"; - var comp = CreateCompilation(source); + var comp = CreateCompilation(source, options: TestOptions.UnsafeReleaseDll); comp.VerifyDiagnostics( - // (11,16): error CS0131: The left-hand side of an assignment must be a variable, property or indexer - // return new S().F = ref t; - Diagnostic(ErrorCode.ERR_AssgLvalueExpected, "new S().F").WithLocation(11, 16), - // (15,16): error CS0131: The left-hand side of an assignment must be a variable, property or indexer - // return new S(1).F = ref t; - Diagnostic(ErrorCode.ERR_AssgLvalueExpected, "new S(1).F").WithLocation(15, 16)); + // (8,33): error CS8986: The 'scoped' modifier of parameter 'y' doesn't match target 'delegate*'. + // delegate* d1 = &F1; + Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfTarget, "&F1").WithArguments("y", "delegate*").WithLocation(8, 33), + // (9,58): error CS8986: The 'scoped' modifier of parameter 'y' doesn't match target 'delegate*'. + // delegate* d3 = &F3; + Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfTarget, "&F3").WithArguments("y", "delegate*").WithLocation(9, 58), + // (13,18): error CS8986: The 'scoped' modifier of parameter 'y' doesn't match target 'delegate*'. + // var d1 = (delegate*)&F1; + Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfTarget, "(delegate*)&F1").WithArguments("y", "delegate*").WithLocation(13, 18), + // (14,18): error CS8986: The 'scoped' modifier of parameter 'y' doesn't match target 'delegate*'. + // var d3 = (delegate*)&F3; + Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfTarget, "(delegate*)&F3").WithArguments("y", "delegate*").WithLocation(14, 18)); } - [WorkItem(62122, "https://github.com/dotnet/roslyn/issues/62122")] [Fact] - public void ReadAndDiscard() + public void FunctionPointerConversions_Out() { var source = -@"ref struct S -{ - public ref T F; - public S(ref T t) { F = ref t; } -} -class Program +@"unsafe class Program { - static void Main() - { - int i = 1; - ReadAndDiscard1(ref i); - ReadAndDiscardNoArg(); - ReadAndDiscard2(new S(ref i)); - } - static void ReadAndDiscard1(ref T t) - { - _ = new S(ref t).F; - } - static void ReadAndDiscardNoArg() + static void F(out int x, scoped out int y) { x = 0; y = 0; } + static void Implicit() { - _ = new S().F; + delegate* d = &F; } - static void ReadAndDiscard2(in S s) + static void Explicit() { - _ = s.F; + var d = (delegate*)&F; } }"; - // https://github.com/dotnet/roslyn/issues/62122: The dereference of a ref field - // should be emitted to IL, even if the value is ignored, because the behavior - // may be observable as a NullReferenceException. - var verifier = CompileAndVerify(source, verify: Verification.Skipped, expectedOutput: IncludeExpectedOutput("")); - verifier.VerifyIL("Program.ReadAndDiscard1", -@"{ - // Code size 8 (0x8) - .maxstack 1 - IL_0000: ldarg.0 - IL_0001: newobj ""S..ctor(ref T)"" - IL_0006: pop - IL_0007: ret -}"); - verifier.VerifyIL("Program.ReadAndDiscardNoArg", -@"{ - // Code size 1 (0x1) - .maxstack 0 - IL_0000: ret -}"); - verifier.VerifyIL("Program.ReadAndDiscard2", -@"{ - // Code size 1 (0x1) - .maxstack 0 - IL_0000: ret -}"); + var comp = CreateCompilation(source, options: TestOptions.UnsafeReleaseDll); + comp.VerifyDiagnostics(); } [Fact] - public void RefReturn_ByValueArg() + public void DuplicateMethodSignatures() { var source = -@"using System; -ref struct S -{ - public ref T F; - public S(ref T t) { F = ref t; } -} -class Program +@"ref struct R { } +class C { - static void Main() - { - int i = 1; - var s = new S(ref i); - RefReturn(s) = 2; - i = RefReadonlyReturn(s); - Console.WriteLine(i); - } - static ref T RefReturn(S s) => ref s.F; - static ref readonly T RefReadonlyReturn(S s) => ref s.F; -}"; - var verifier = CompileAndVerify(source, verify: Verification.Skipped, expectedOutput: IncludeExpectedOutput("2")); - var expectedIL = -@"{ - // Code size 8 (0x8) - .maxstack 1 - IL_0000: ldarga.s V_0 - IL_0002: ldfld ""ref T S.F"" - IL_0007: ret + static void M1(R r) { } + void M2(scoped R r) { } + object this[R r] => null; + static void M1(scoped R r) { } // 1 + void M2(R r) { } // 2 + object this[scoped R r] => null; // 3 }"; - verifier.VerifyIL("Program.RefReturn", expectedIL); - verifier.VerifyIL("Program.RefReadonlyReturn", expectedIL); + var comp = CreateCompilation(source); + comp.VerifyEmitDiagnostics( + // (7,17): error CS0111: Type 'C' already defines a member called 'M1' with the same parameter types + // static void M1(scoped R r) { } // 1 + Diagnostic(ErrorCode.ERR_MemberAlreadyExists, "M1").WithArguments("M1", "C").WithLocation(7, 17), + // (8,10): error CS0111: Type 'C' already defines a member called 'M2' with the same parameter types + // void M2(R r) { } // 2 + Diagnostic(ErrorCode.ERR_MemberAlreadyExists, "M2").WithArguments("M2", "C").WithLocation(8, 10), + // (9,12): error CS0111: Type 'C' already defines a member called 'this' with the same parameter types + // object this[scoped R r] => null; // 3 + Diagnostic(ErrorCode.ERR_MemberAlreadyExists, "this").WithArguments("this", "C").WithLocation(9, 12)); } [Fact] - public void RefReturn_RefArg() + public void Overloads() { var source = -@"using System; -ref struct S -{ - public ref T F; - public S(ref T t) { F = ref t; } -} -class Program +@"ref struct R { } +class C { - static void Main() - { - int i = 1; - var s = new S(ref i); - RefReturn(ref s) = 2; - i = RefReadonlyReturn(ref s); - Console.WriteLine(i); - } - static ref T RefReturn(ref S s) => ref s.F; - static ref readonly T RefReadonlyReturn(ref S s) => ref s.F; -}"; - var verifier = CompileAndVerify(source, verify: Verification.Skipped, expectedOutput: IncludeExpectedOutput("2")); - var expectedIL = -@"{ - // Code size 7 (0x7) - .maxstack 1 - IL_0000: ldarg.0 - IL_0001: ldfld ""ref T S.F"" - IL_0006: ret + static void M1(R r) { } + static void M2(scoped R r) { } + static void M3(ref R r) { } + static void M4(ref scoped R r) { } // 1 + static void M5(scoped ref R r) { } + static void M1(scoped R r) { } // 2 + static void M2(R r) { } // 3 + static void M3(ref scoped R r) { } // 4 + static void M4(scoped ref R r) { } // 5 + static void M5(ref R r) { } // 6 }"; - verifier.VerifyIL("Program.RefReturn", expectedIL); - verifier.VerifyIL("Program.RefReadonlyReturn", expectedIL); + var comp = CreateCompilation(source); + comp.VerifyEmitDiagnostics( + // (7,24): error CS8339: The parameter modifier 'scoped' cannot follow 'ref' + // static void M4(ref scoped R r) { } // 1 + Diagnostic(ErrorCode.ERR_BadParameterModifiersOrder, "scoped").WithArguments("scoped", "ref").WithLocation(7, 24), + // (9,17): error CS0111: Type 'C' already defines a member called 'M1' with the same parameter types + // static void M1(scoped R r) { } // 2 + Diagnostic(ErrorCode.ERR_MemberAlreadyExists, "M1").WithArguments("M1", "C").WithLocation(9, 17), + // (10,17): error CS0111: Type 'C' already defines a member called 'M2' with the same parameter types + // static void M2(R r) { } // 3 + Diagnostic(ErrorCode.ERR_MemberAlreadyExists, "M2").WithArguments("M2", "C").WithLocation(10, 17), + // (11,17): error CS0111: Type 'C' already defines a member called 'M3' with the same parameter types + // static void M3(ref scoped R r) { } // 4 + Diagnostic(ErrorCode.ERR_MemberAlreadyExists, "M3").WithArguments("M3", "C").WithLocation(11, 17), + // (11,24): error CS8339: The parameter modifier 'scoped' cannot follow 'ref' + // static void M3(ref scoped R r) { } // 4 + Diagnostic(ErrorCode.ERR_BadParameterModifiersOrder, "scoped").WithArguments("scoped", "ref").WithLocation(11, 24), + // (12,17): error CS0111: Type 'C' already defines a member called 'M4' with the same parameter types + // static void M4(scoped ref R r) { } // 5 + Diagnostic(ErrorCode.ERR_MemberAlreadyExists, "M4").WithArguments("M4", "C").WithLocation(12, 17), + // (13,17): error CS0111: Type 'C' already defines a member called 'M5' with the same parameter types + // static void M5(ref R r) { } // 6 + Diagnostic(ErrorCode.ERR_MemberAlreadyExists, "M5").WithArguments("M5", "C").WithLocation(13, 17)); } [Fact] - public void RefReturn_InArg() + public void PartialMethods() { - var source = -@"using System; -ref struct S + var sourceA = +@"ref struct R { } +partial class C { - public ref T F; - public S(ref T t) { F = ref t; } -} -class Program + static partial void M1(R r); + static partial void M2(scoped R r); + static partial void M3(ref R r); + static partial void M5(scoped ref R r); +}"; + var sourceB1 = +@"partial class C { - static void Main() - { - int i = 1; - var s = new S(ref i); - RefReturn(s) = 2; - i = RefReadonlyReturn(s); - Console.WriteLine(i); - } - static ref T RefReturn(in S s) => ref s.F; - static ref readonly T RefReadonlyReturn(in S s) => ref s.F; + static partial void M1(R r) { } + static partial void M2(scoped R r) { } + static partial void M3(ref R r) { } + static partial void M5(scoped ref R r) { } }"; - var verifier = CompileAndVerify(source, verify: Verification.Skipped, expectedOutput: IncludeExpectedOutput("2")); - var expectedIL = -@"{ - // Code size 7 (0x7) - .maxstack 1 - IL_0000: ldarg.0 - IL_0001: ldfld ""ref T S.F"" - IL_0006: ret + var sourceB2 = +@"partial class C +{ + static partial void M1(scoped R r) { } // 1 + static partial void M2(R r) { } // 2 + static partial void M3(ref scoped R r) { } // 3 + static partial void M5(ref R r) { } }"; - verifier.VerifyIL("Program.RefReturn", expectedIL); - verifier.VerifyIL("Program.RefReadonlyReturn", expectedIL); + var comp = CreateCompilation(new[] { sourceA, sourceB1 }); + comp.VerifyEmitDiagnostics(); + + var expectedDiagnostics = new[] + { + // (3,25): error CS8988: The 'scoped' modifier of parameter 'r' doesn't match partial method declaration. + // static partial void M1(scoped R r) { } // 1 + Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfPartial, "M1").WithArguments("r").WithLocation(3, 25), + // (4,25): error CS8988: The 'scoped' modifier of parameter 'r' doesn't match partial method declaration. + // static partial void M2(R r) { } // 2 + Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfPartial, "M2").WithArguments("r").WithLocation(4, 25), + // (5,32): error CS8339: The parameter modifier 'scoped' cannot follow 'ref' + // static partial void M3(ref scoped R r) { } // 3 + Diagnostic(ErrorCode.ERR_BadParameterModifiersOrder, "scoped").WithArguments("scoped", "ref").WithLocation(5, 32) + }; + + comp = CreateCompilation(new[] { sourceA, sourceB2 }); + comp.VerifyEmitDiagnostics(expectedDiagnostics); + + comp = CreateCompilation(new[] { sourceB2, sourceA }); + comp.VerifyEmitDiagnostics(expectedDiagnostics); } [Fact] - public void RefReturn_OutArg() + public void PartialMethods_Out() { var source = -@"using System; -ref struct S -{ - public ref T F; - public S(ref T t) { F = ref t; } -} -class Program +@"ref struct R { } +partial class C { - static void Main() - { - int i = 1; - S s; - RefReturn(out s, ref i) = 2; - i = RefReadonlyReturn(out s, ref i); - Console.WriteLine(i); - } - static ref T RefReturn(out S s, ref T t) - { - s = new S(ref t); - return ref s.F; - } - static ref readonly T RefReadonlyReturn(out S s, ref T t) - { - s = new S(ref t); - return ref s.F; - } -}"; - var verifier = CompileAndVerify(source, verify: Verification.Skipped, expectedOutput: IncludeExpectedOutput("2")); - var expectedIL = -@"{ - // Code size 19 (0x13) - .maxstack 2 - IL_0000: ldarg.0 - IL_0001: ldarg.1 - IL_0002: newobj ""S..ctor(ref T)"" - IL_0007: stobj ""S"" - IL_000c: ldarg.0 - IL_000d: ldfld ""ref T S.F"" - IL_0012: ret + private partial void F1(out int i); + private partial void F2(scoped out int i); + private partial void F1(scoped out int i) { i = 0; } + private partial void F2(out int i) { i = 0; } }"; - verifier.VerifyIL("Program.RefReturn", expectedIL); - verifier.VerifyIL("Program.RefReadonlyReturn", expectedIL); + var comp = CreateCompilation(source); + comp.VerifyEmitDiagnostics(); } - [Fact] - public void CompoundOperations_01() + [CombinatorialData] + [Theory] + public void Hiding(bool useCompilationReference) { - var source = -@"using System; -ref struct S + var sourceA = +@"public ref struct R { } +public class A { - public ref T F; - public S(ref T t) { F = ref t; } + public void M1(R r) { } + public void M2(scoped R r) { } + public void M3(ref R r) { } + public object this[R r] { get { return null; } set { } } + public object this[int x, scoped R y] => null; +}"; + var comp = CreateCompilation(sourceA); + comp.VerifyEmitDiagnostics(); + var refA = AsReference(comp, useCompilationReference); + + var sourceB = +@"class B1 : A +{ + public new void M1(scoped R r) { } + public new void M2(R r) { } + public new void M3(ref R r) { } + public new object this[scoped R r] { get { return null; } set { } } + public new object this[int x, R y] => null; } -class Program +class B2 : A { - static void Main() - { - int x = 42; - scoped var s = new S(ref x); - Increment(s); - Console.WriteLine(s.F); - Console.WriteLine(x); - Subtract(s, 10); - Console.WriteLine(s.F); - Console.WriteLine(x); - } - static void Increment(S s) - { - s.F++; - } - static void Subtract(S s, int offset) - { - s.F -= offset; - } + public void M1(scoped R r) { } // 1 + public void M2(R r) { } // 2 + public void M3(scoped ref R r) { } // 3 + public object this[scoped R r] { get { return null; } set { } } // 4 + public object this[int x, R y] => null; // 5 }"; - var verifier = CompileAndVerify(source, verify: Verification.Skipped, expectedOutput: IncludeExpectedOutput( -@"43 -43 -33 -33 -")); - verifier.VerifyIL("Program.Increment", -@"{ - // Code size 13 (0xd) - .maxstack 3 - IL_0000: ldarga.s V_0 - IL_0002: ldfld ""ref int S.F"" - IL_0007: dup - IL_0008: ldind.i4 - IL_0009: ldc.i4.1 - IL_000a: add - IL_000b: stind.i4 - IL_000c: ret -}"); - verifier.VerifyIL("Program.Subtract", -@"{ - // Code size 13 (0xd) - .maxstack 3 - IL_0000: ldarga.s V_0 - IL_0002: ldfld ""ref int S.F"" - IL_0007: dup - IL_0008: ldind.i4 - IL_0009: ldarg.1 - IL_000a: sub - IL_000b: stind.i4 - IL_000c: ret -}"); + comp = CreateCompilation(sourceB, references: new[] { refA }); + comp.VerifyEmitDiagnostics( + // (11,17): warning CS0108: 'B2.M1(R)' hides inherited member 'A.M1(R)'. Use the new keyword if hiding was intended. + // public void M1(scoped R r) { } // 1 + Diagnostic(ErrorCode.WRN_NewRequired, "M1").WithArguments("B2.M1(R)", "A.M1(R)").WithLocation(11, 17), + // (12,17): warning CS0108: 'B2.M2(R)' hides inherited member 'A.M2(R)'. Use the new keyword if hiding was intended. + // public void M2(R r) { } // 2 + Diagnostic(ErrorCode.WRN_NewRequired, "M2").WithArguments("B2.M2(R)", "A.M2(R)").WithLocation(12, 17), + // (13,17): warning CS0108: 'B2.M3(ref R)' hides inherited member 'A.M3(ref R)'. Use the new keyword if hiding was intended. + // public void M3(scoped ref R r) { } // 3 + Diagnostic(ErrorCode.WRN_NewRequired, "M3").WithArguments("B2.M3(ref R)", "A.M3(ref R)").WithLocation(13, 17), + // (14,19): warning CS0108: 'B2.this[R]' hides inherited member 'A.this[R]'. Use the new keyword if hiding was intended. + // public object this[scoped R r] { get { return null; } set { } } // 4 + Diagnostic(ErrorCode.WRN_NewRequired, "this").WithArguments("B2.this[R]", "A.this[R]").WithLocation(14, 19), + // (15,19): warning CS0108: 'B2.this[int, R]' hides inherited member 'A.this[int, R]'. Use the new keyword if hiding was intended. + // public object this[int x, R y] => null; // 5 + Diagnostic(ErrorCode.WRN_NewRequired, "this").WithArguments("B2.this[int, R]", "A.this[int, R]").WithLocation(15, 19)); } + [CombinatorialData] [Theory] - [InlineData("ref")] - [InlineData("readonly ref")] - public void CompoundOperations_02(string refKind) + public void Overrides(bool useCompilationReference) { - var source = -$@"using System; -ref struct S -{{ - public {refKind} int F; - public S(ref int i) {{ F = ref i; }} - public void Increment() - {{ - F++; - }} - public void Subtract(int offset) - {{ - F -= offset; - }} -}} -class Program -{{ - static void Main() - {{ - int x = 42; - scoped var s = new S(ref x); - s.Increment(); - Console.WriteLine(s.F); - Console.WriteLine(x); - s.Subtract(10); - Console.WriteLine(s.F); - Console.WriteLine(x); - }} -}}"; - var verifier = CompileAndVerify(source, verify: Verification.Skipped, expectedOutput: IncludeExpectedOutput( -@"43 -43 -33 -33 -")); - verifier.VerifyIL("S.Increment", -@"{ - // Code size 17 (0x11) - .maxstack 3 - IL_0000: ldarg.0 - IL_0001: ldfld ""ref int S.F"" - IL_0006: ldarg.0 - IL_0007: ldfld ""ref int S.F"" - IL_000c: ldind.i4 - IL_000d: ldc.i4.1 - IL_000e: add - IL_000f: stind.i4 - IL_0010: ret -}"); - verifier.VerifyIL("S.Subtract", -@"{ - // Code size 17 (0x11) - .maxstack 3 - IL_0000: ldarg.0 - IL_0001: ldfld ""ref int S.F"" - IL_0006: ldarg.0 - IL_0007: ldfld ""ref int S.F"" - IL_000c: ldind.i4 - IL_000d: ldarg.1 - IL_000e: sub - IL_000f: stind.i4 - IL_0010: ret -}"); + var sourceA = +@"public ref struct R { } +public abstract class A +{ + public abstract R F1(R r); + public abstract R F2(scoped R r); + public abstract R F3(ref R r); + public abstract R F4(scoped ref R r); + public abstract object this[R r] { get; set; } + public abstract object this[int x, scoped R y] { get; } +}"; + var comp = CreateCompilation(sourceA); + comp.VerifyEmitDiagnostics(); + var refA = AsReference(comp, useCompilationReference); + + var sourceB = +@"class B1 : A +{ + public override R F1(R r) => default; + public override R F2(scoped R r) => default; + public override R F3(ref R r) => default; + public override R F4(scoped ref R r) => default; + public override object this[R r] { get { return null; } set { } } + public override object this[int x, scoped R y] => null; +} +class B2 : A +{ + public override R F1(scoped R r) => default; // 1 + public override R F2(R r) => default; // 2 + public override R F3(scoped ref R r) => default; + public override R F4(ref R r) => default; + public override object this[scoped R r] { get { return null; } set { } } // 3 + public override object this[int x, R y] => null; // 4 +}"; + comp = CreateCompilation(sourceB, references: new[] { refA }); + comp.VerifyEmitDiagnostics( + // (12,31): error CS8987: The 'scoped' modifier of parameter 'r' doesn't match overridden or implemented member. + // public override R F1(scoped R r) => default; // 1 + Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfOverrideOrImplementation, "F1").WithArguments("r").WithLocation(12, 31), + // (13,31): error CS8987: The 'scoped' modifier of parameter 'r' doesn't match overridden or implemented member. + // public override R F2(R r) => default; // 2 + Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfOverrideOrImplementation, "F2").WithArguments("r").WithLocation(13, 31), + // (16,76): error CS8987: The 'scoped' modifier of parameter 'r' doesn't match overridden or implemented member. + // public override object this[scoped R r] { get { return null; } set { } } // 3 + Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfOverrideOrImplementation, "set").WithArguments("r").WithLocation(16, 76), + // (17,56): error CS8987: The 'scoped' modifier of parameter 'y' doesn't match overridden or implemented member. + // public override object this[int x, R y] => null; // 4 + Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfOverrideOrImplementation, "null").WithArguments("y").WithLocation(17, 56)); } - [Fact] - public void ConditionalOperator() + [CombinatorialData] + [Theory] + public void InterfaceImplementations(bool useCompilationReference) { - var source = -@"using System; -ref struct S + var sourceA = +@"public ref struct R { } +public interface I { - public ref T F; - public S(ref T t) { F = ref t; } + R F1(R r); + R F2(scoped R r); + R F3(ref R r); + R F4(scoped ref R r); + object this[R r] { get; set; } + object this[int x, scoped R y] { get; } + object this[object x, in R y] { get; set; } + object this[scoped in R x, int y] { get; } +}"; + var comp = CreateCompilation(sourceA); + comp.VerifyEmitDiagnostics(); + var refA = AsReference(comp, useCompilationReference); + + var sourceB1 = +@"class C1 : I +{ + public R F1(R r) => default; + public R F2(scoped R r) => default; + public R F3(ref R r) => default; + public R F4(scoped ref R r) => default; + public object this[R r] { get { return null; } set { } } + public object this[int x, scoped R y] => null; + public object this[object x, in R y] { get { return null; } set { } } + public object this[scoped in R x, int y] => null; } -class Program +class C2 : I { - static void Main() - { - int x = 1; - int y = 2; - var sx = new S(ref x); - var sy = new S(ref y); - Console.WriteLine(ConditionalOperator(true, sx, sy)); - Console.WriteLine(ConditionalOperator(false, sx, sy)); - ConditionalOperatorRef(true, ref sx, ref sy) = 3; - ConditionalOperatorRef(false, ref sx, ref sy) = 4; - Console.WriteLine(x); - Console.WriteLine(y); - } - static T ConditionalOperator(bool b, S sx, S sy) - { - return b ? sx.F : sy.F; - } - static ref T ConditionalOperatorRef(bool b, ref S sx, ref S sy) - { - return ref b ? ref sx.F : ref sy.F; - } + public R F1(scoped R r) => default; // 1 + public R F2(R r) => default; // 2 + public R F3(scoped ref R r) => default; + public R F4(ref R r) => default; + public object this[scoped R r] { get { return null; } set { } } // 3 + public object this[int x, R y] => null; // 4 + public object this[object x, scoped in R y] { get { return null; } set { } } + public object this[in R x, int y] => null; }"; - var verifier = CompileAndVerify(source, verify: Verification.Skipped, expectedOutput: IncludeExpectedOutput( -@"1 -2 -3 -4 -")); - verifier.VerifyIL("Program.ConditionalOperator", -@"{ - // Code size 27 (0x1b) - .maxstack 1 - IL_0000: ldarg.0 - IL_0001: brtrue.s IL_000f - IL_0003: ldarg.2 - IL_0004: ldfld ""ref T S.F"" - IL_0009: ldobj ""T"" - IL_000e: ret - IL_000f: ldarg.1 - IL_0010: ldfld ""ref T S.F"" - IL_0015: ldobj ""T"" - IL_001a: ret -}"); - verifier.VerifyIL("Program.ConditionalOperatorRef", -@"{ - // Code size 17 (0x11) - .maxstack 1 - IL_0000: ldarg.0 - IL_0001: brtrue.s IL_000a - IL_0003: ldarg.2 - IL_0004: ldfld ""ref T S.F"" - IL_0009: ret - IL_000a: ldarg.1 - IL_000b: ldfld ""ref T S.F"" - IL_0010: ret -}"); + comp = CreateCompilation(sourceB1, references: new[] { refA }); + comp.VerifyEmitDiagnostics( + // (14,22): error CS8987: The 'scoped' modifier of parameter 'r' doesn't match overridden or implemented member. + // public R F1(scoped R r) => default; // 1 + Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfOverrideOrImplementation, "F1").WithArguments("r").WithLocation(14, 22), + // (15,22): error CS8987: The 'scoped' modifier of parameter 'r' doesn't match overridden or implemented member. + // public R F2(R r) => default; // 2 + Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfOverrideOrImplementation, "F2").WithArguments("r").WithLocation(15, 22), + // (18,67): error CS8987: The 'scoped' modifier of parameter 'r' doesn't match overridden or implemented member. + // public object this[scoped R r] { get { return null; } set { } } // 3 + Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfOverrideOrImplementation, "set").WithArguments("r").WithLocation(18, 67), + // (19,47): error CS8987: The 'scoped' modifier of parameter 'y' doesn't match overridden or implemented member. + // public object this[int x, R y] => null; // 4 + Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfOverrideOrImplementation, "null").WithArguments("y").WithLocation(19, 47)); + + var sourceB2 = +@"class C3 : I +{ + R I.F1(R r) => default; + R I.F2(scoped R r) => default; + R I.F3(ref R r) => default; + R I.F4(scoped ref R r) => default; + object I.this[R r] { get { return null; } set { } } + object I.this[int x, scoped R y] => null; + object I.this[object x, in R y] { get { return null; } set { } } + object I.this[scoped in R x, int y] => null; +} +class C4 : I +{ + R I.F1(scoped R r) => default; // 1 + R I.F2(R r) => default; // 2 + R I.F3(scoped ref R r) => default; + R I.F4(ref R r) => default; + object I.this[scoped R r] { get { return null; } set { } } // 3 + object I.this[int x, R y] => null; // 4 + object I.this[object x, scoped in R y] { get { return null; } set { } } + object I.this[in R x, int y] => null; +}"; + comp = CreateCompilation(sourceB2, references: new[] { refA }); + comp.VerifyEmitDiagnostics( + // (14,25): error CS8987: The 'scoped' modifier of parameter 'r' doesn't match overridden or implemented member. + // R I.F1(scoped R r) => default; // 1 + Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfOverrideOrImplementation, "F1").WithArguments("r").WithLocation(14, 25), + // (15,25): error CS8987: The 'scoped' modifier of parameter 'r' doesn't match overridden or implemented member. + // R I.F2(R r) => default; // 2 + Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfOverrideOrImplementation, "F2").WithArguments("r").WithLocation(15, 25), + // (18,70): error CS8987: The 'scoped' modifier of parameter 'r' doesn't match overridden or implemented member. + // object I.this[scoped R r] { get { return null; } set { } } // 3 + Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfOverrideOrImplementation, "set").WithArguments("r").WithLocation(18, 70), + // (19,50): error CS8987: The 'scoped' modifier of parameter 'y' doesn't match overridden or implemented member. + // object I.this[int x, R y] => null; // 4 + Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfOverrideOrImplementation, "null").WithArguments("y").WithLocation(19, 50)); } - [Fact] - public void ConditionalAccess() + [CombinatorialData] + [Theory] + public void OverridesAndInterfaceImplementations_Out_01(bool useCompilationReference) { - var source = -@"using System; -ref struct S + var sourceA = +@"public abstract class A { - public ref T F; - public S(ref T t) { F = ref t; } + public abstract void F1(out T t); } -class Program +public interface I { - static void Main() - { - object o = 1; - int i = 2; - var s1 = new S(ref o); - var s2 = new S(ref i); - Console.WriteLine(ConditionalAccess(s1)); - Console.WriteLine(ConditionalAccess(s2)); - } - static string ConditionalAccess(S s) - { - return s.F?.ToString(); - } + void F2(out T t); }"; - var verifier = CompileAndVerify(source, verify: Verification.Skipped, expectedOutput: IncludeExpectedOutput( -@"1 -2 -")); - verifier.VerifyIL("Program.ConditionalAccess", -@"{ - // Code size 54 (0x36) - .maxstack 2 - .locals init (T V_0) - IL_0000: ldarga.s V_0 - IL_0002: ldfld ""ref T S.F"" - IL_0007: ldloca.s V_0 - IL_0009: initobj ""T"" - IL_000f: ldloc.0 - IL_0010: box ""T"" - IL_0015: brtrue.s IL_002a - IL_0017: ldobj ""T"" - IL_001c: stloc.0 - IL_001d: ldloca.s V_0 - IL_001f: ldloc.0 - IL_0020: box ""T"" - IL_0025: brtrue.s IL_002a - IL_0027: pop - IL_0028: ldnull - IL_0029: ret - IL_002a: constrained. ""T"" - IL_0030: callvirt ""string object.ToString()"" - IL_0035: ret -}"); + var comp = CreateCompilation(sourceA, parseOptions: TestOptions.Regular10); + comp.VerifyEmitDiagnostics(); + var refA = AsReference(comp, useCompilationReference); + + var sourceB = +@"class B1 : A, I +{ + public override void F1(scoped out int i) { i = 0; } + public void F2(scoped out int i) { i = 0; } +} +class B2 : I +{ + void I.F2(scoped out string s) { s = null; } +}"; + comp = CreateCompilation(sourceB, references: new[] { refA }); + comp.VerifyEmitDiagnostics(); } [Fact] - public void Deconstruct() + public void OverridesAndInterfaceImplementations_Out_02() { var source = -@"using System; -class Pair -{ - public readonly T First; - public readonly U Second; - public Pair(T first, U second) - { - First = first; - Second = second; - } - public void Deconstruct(out T first, out U second) - { - first = First; - second = Second; - } -} -ref struct S +@"ref struct R { } +abstract class A { - public ref T F; - public S(ref T t) { F = ref t; } + public abstract void F1(out int i); + public abstract void F2(scoped out int i); } -class Program +class B : A { - static void Main() - { - int i = 0; - string s = null; - var s1 = new S(ref i); - var s2 = new S(ref s); - Deconstruct(new Pair(1, ""Hello world""), s1, s2); - Console.WriteLine((i, s)); - } - static void Deconstruct(Pair pair, S s1, S s2) - { - (s1.F, s2.F) = pair; - } -}"; - var verifier = CompileAndVerify(source, verify: Verification.Skipped, expectedOutput: IncludeExpectedOutput(@"(1, Hello world)")); - verifier.VerifyIL("Program.Deconstruct", -@"{ - // Code size 39 (0x27) - .maxstack 4 - .locals init (T& V_0, - T V_1, - U V_2) - IL_0000: ldarga.s V_1 - IL_0002: ldfld ""ref T S.F"" - IL_0007: stloc.0 - IL_0008: ldarga.s V_2 - IL_000a: ldfld ""ref U S.F"" - IL_000f: ldarg.0 - IL_0010: ldloca.s V_1 - IL_0012: ldloca.s V_2 - IL_0014: callvirt ""void Pair.Deconstruct(out T, out U)"" - IL_0019: ldloc.0 - IL_001a: ldloc.1 - IL_001b: stobj ""T"" - IL_0020: ldloc.2 - IL_0021: stobj ""U"" - IL_0026: ret -}"); + public override void F1(scoped out int i) { i = 0; } + public override void F2(out int i) { i = 0; } +}"; + var comp = CreateCompilation(source); + comp.VerifyEmitDiagnostics(); } [Fact] - public void InParamReorder() + public void OverridesAndInterfaceImplementations_Out_03() { var source = -@"using System; -ref struct S +@"ref struct R { } +interface I { - public ref T F; - public S(ref T t) { F = ref t; } + void F1(out int i); + void F2(scoped out int i); } -class Program +class C1 : I { - static void Main() - { - int x = 1; - int y = 2; - var sx = new S(ref x); - var sy = new S(ref y); - Reorder(sx, sy); - } - static ref S Get(ref S s) - { - return ref s; - } - static void Reorder(S sx, S sy) - { - M(y: in Get(ref sy).F, x: in Get(ref sx).F); - } - static void M(in T x, in T y) - { - Console.WriteLine(x); - Console.WriteLine(y); - } + public void F1(out int i) { i = 0; } + public void F2(scoped out int i) { i = 0; } +} +class C2 : I +{ + void I.F1(out int i) { i = 0; } + void I.F2(scoped out int i) { i = 0; } }"; - var verifier = CompileAndVerify(source, verify: Verification.Skipped, expectedOutput: IncludeExpectedOutput( -@"1 -2 -")); - verifier.VerifyIL("Program.Reorder", -@"{ - // Code size 32 (0x20) - .maxstack 2 - .locals init (T& V_0) - IL_0000: ldarga.s V_1 - IL_0002: call ""ref S Program.Get(ref S)"" - IL_0007: ldfld ""ref T S.F"" - IL_000c: stloc.0 - IL_000d: ldarga.s V_0 - IL_000f: call ""ref S Program.Get(ref S)"" - IL_0014: ldfld ""ref T S.F"" - IL_0019: ldloc.0 - IL_001a: call ""void Program.M(in T, in T)"" - IL_001f: ret -}"); + var comp = CreateCompilation(source); + comp.VerifyEmitDiagnostics(); } [Fact] - public void ReturnRefToByValueParameter_01() + public void OverridesAndInterfaceImplementations_Out_04() { var source = -@"ref struct S +@"#nullable enable +abstract class A { + public abstract void F1(out T t); + public abstract void F2(out T? t); } -class Program +class B1 : A { - static ref S F1(ref S x1) - { - return ref x1; - } - static void F2(S x2) - { - var y2 = F1(ref x2); - } + public override void F1(out T t) { t = default!; } + public override void F2(out T? t) where T : default { t = default; } +} +class B2 : A +{ + public override void F1(out T? t) where T : default { t = default; } + public override void F2(out T t) { t = default!; } }"; + var comp = CreateCompilation(source); + comp.VerifyEmitDiagnostics( + // (14,26): warning CS8765: Nullability of type of parameter 't' doesn't match overridden member (possibly because of nullability attributes). + // public override void F1(out T? t) where T : default { t = default; } + Diagnostic(ErrorCode.WRN_TopLevelNullabilityMismatchInParameterTypeOnOverride, "F1").WithArguments("t").WithLocation(14, 26)); - var comp = CreateCompilation(source, parseOptions: TestOptions.Regular10); - comp.VerifyEmitDiagnostics(); - - comp = CreateCompilation(source); - comp.VerifyEmitDiagnostics(); + // https://github.com/dotnet/roslyn/issues/62780: Test with [UnscopedRef]. } [Fact] - public void ReturnRefToByValueParameter_02() + public void OverridesAndInterfaceImplementations_Out_05() { var source = -@"ref struct S +@"#nullable enable +interface I { + void F1(out T t); + void F2(out T? t); } -class Program +class C1 : I { - static ref S F1(ref S x1, ref S y1) - { - return ref x1; - } - static void F2(S x2, S y2) - { - var z1 = F1(ref x2, ref y2); - } + public void F1(out T t) { t = default!; } + public void F2(out T? t) { t = default; } +} +class C2 : I +{ + public void F1(out T? t) { t = default; } + public void F2(out T t) { t = default!; } +} +class C3 : I +{ + void I.F1(out T t) { t = default!; } + void I.F2(out T? t) where T : default { t = default; } +} +class C4 : I +{ + void I.F1(out T? t) where T : default { t = default; } + void I.F2(out T t) { t = default!; } }"; + var comp = CreateCompilation(source); + comp.VerifyEmitDiagnostics( + // (14,17): warning CS8767: Nullability of reference types in type of parameter 't' of 'void C2.F1(out T? t)' doesn't match implicitly implemented member 'void I.F1(out T t)' (possibly because of nullability attributes). + // public void F1(out T? t) { t = default; } + Diagnostic(ErrorCode.WRN_TopLevelNullabilityMismatchInParameterTypeOnImplicitImplementation, "F1").WithArguments("t", "void C2.F1(out T? t)", "void I.F1(out T t)").WithLocation(14, 17), + // (24,12): warning CS8769: Nullability of reference types in type of parameter 't' doesn't match implemented member 'void I.F1(out T t)' (possibly because of nullability attributes). + // void I.F1(out T? t) where T : default { t = default; } + Diagnostic(ErrorCode.WRN_TopLevelNullabilityMismatchInParameterTypeOnExplicitImplementation, "F1").WithArguments("t", "void I.F1(out T t)").WithLocation(24, 12)); - var comp = CreateCompilation(source, parseOptions: TestOptions.Regular10); - comp.VerifyEmitDiagnostics(); - - comp = CreateCompilation(source); - comp.VerifyEmitDiagnostics(); + // https://github.com/dotnet/roslyn/issues/62780: Test with [UnscopedRef]. } - [WorkItem(62098, "https://github.com/dotnet/roslyn/issues/62098")] [Fact] - public void RefToContainingType() + public void Overrides_Example() { var source = -@"ref struct R +@"ref struct R { - public ref R Next; + public ref int F; + public R(ref int i) { F = ref i; } +} +abstract class A +{ + public abstract R F1(scoped R r); + public abstract R F2(R r); +} +class B : A +{ + public override R F1(R r) => r; + public override R F2(scoped R r) => default; } class Program { - static void F(ref R r) + static R F1(A a) { - r.Next = ref r; + int i = 0; + return a.F1(new R(ref i)); + } + static R F2(B b) + { + int i = 0; + return b.F2(new R(ref i)); // unsafe + } + static void Main() + { + R r1 = F1(new B()); // unsafe + R r2 = F2(new B()); } }"; - var comp = CreateCompilation(source); - // https://github.com/dotnet/roslyn/issues/62098: Allow ref field of the containing type. + var comp = CreateCompilation(source, runtimeFeature: RuntimeFlag.ByRefFields); comp.VerifyEmitDiagnostics( - // (3,12): error CS9050: A ref field cannot refer to a ref struct. - // public ref R Next; - Diagnostic(ErrorCode.ERR_RefFieldCannotReferToRefStruct, "ref R").WithLocation(3, 12), - // (3,21): error CS0523: Struct member 'R.Next' of type 'R' causes a cycle in the struct layout - // public ref R Next; - Diagnostic(ErrorCode.ERR_StructLayoutCycle, "Next").WithArguments("R.Next", "R").WithLocation(3, 21)); + // (13,23): error CS8987: The 'scoped' modifier of parameter 'r' doesn't match overridden or implemented member. + // public override R F1(R r) => r; + Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfOverrideOrImplementation, "F1").WithArguments("r").WithLocation(13, 23), + // (14,23): error CS8987: The 'scoped' modifier of parameter 'r' doesn't match overridden or implemented member. + // public override R F2(scoped R r) => default; + Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfOverrideOrImplementation, "F2").WithArguments("r").WithLocation(14, 23)); } - /// - /// Ref auto-properties are not supported. - /// [Fact] - public void RefAutoProperty_01() + public void Delegates_Example() { var source = -@"using System; -ref struct S +@"ref struct R { - public ref T P0 { get; } - public ref T P1 { get; set; } - public ref T P2 { get; init; } - public S(ref T t) - { - P0 = ref t; - P1 = ref t; - P2 = ref t; - } + public ref int F; + public R(ref int i) { F = ref i; } } +delegate R D1(scoped R x); +delegate R D2(R x); class Program { + static R F1(D1 d1) + { + int i = 0; + return d1(new R(ref i)); + } + static R F2(D2 d2) + { + int i = 0; + return d2(new R(ref i)); + } static void Main() { - int x = 0; - var s = new S(ref x); - s.P0 = 0; - s.P1 = 1; - s.P2 = 2; - s.P0 = ref x; - s.P1 = ref x; - s.P2 = ref x; + R r1 = F1((R x) => x); // unsafe + R r2 = F2((scoped R x) => default); } }"; - var comp = CreateCompilation(source); + var comp = CreateCompilation(source, runtimeFeature: RuntimeFlag.ByRefFields); comp.VerifyEmitDiagnostics( - // (4,18): error CS8145: Auto-implemented properties cannot return by reference - // public ref T P0 { get; } - Diagnostic(ErrorCode.ERR_AutoPropertyCannotBeRefReturning, "P0").WithLocation(4, 18), - // (5,18): error CS8145: Auto-implemented properties cannot return by reference - // public ref T P1 { get; set; } - Diagnostic(ErrorCode.ERR_AutoPropertyCannotBeRefReturning, "P1").WithLocation(5, 18), - // (5,28): error CS8147: Properties which return by reference cannot have set accessors - // public ref T P1 { get; set; } - Diagnostic(ErrorCode.ERR_RefPropertyCannotHaveSetAccessor, "set").WithLocation(5, 28), - // (6,18): error CS8145: Auto-implemented properties cannot return by reference - // public ref T P2 { get; init; } - Diagnostic(ErrorCode.ERR_AutoPropertyCannotBeRefReturning, "P2").WithLocation(6, 18), - // (6,28): error CS0518: Predefined type 'System.Runtime.CompilerServices.IsExternalInit' is not defined or imported - // public ref T P2 { get; init; } - Diagnostic(ErrorCode.ERR_PredefinedTypeNotFound, "init").WithArguments("System.Runtime.CompilerServices.IsExternalInit").WithLocation(6, 28), - // (6,28): error CS8147: Properties which return by reference cannot have set accessors - // public ref T P2 { get; init; } - Diagnostic(ErrorCode.ERR_RefPropertyCannotHaveSetAccessor, "init").WithLocation(6, 28), - // (9,9): error CS8373: The left-hand side of a ref assignment must be a ref variable. - // P0 = ref t; - Diagnostic(ErrorCode.ERR_RefLocalOrParamExpected, "P0").WithLocation(9, 9), - // (10,9): error CS8373: The left-hand side of a ref assignment must be a ref variable. - // P1 = ref t; - Diagnostic(ErrorCode.ERR_RefLocalOrParamExpected, "P1").WithLocation(10, 9), - // (11,9): error CS8373: The left-hand side of a ref assignment must be a ref variable. - // P2 = ref t; - Diagnostic(ErrorCode.ERR_RefLocalOrParamExpected, "P2").WithLocation(11, 9), - // (23,9): error CS8373: The left-hand side of a ref assignment must be a ref variable. - // s.P0 = ref x; - Diagnostic(ErrorCode.ERR_RefLocalOrParamExpected, "s.P0").WithLocation(23, 9), - // (24,9): error CS8373: The left-hand side of a ref assignment must be a ref variable. - // s.P1 = ref x; - Diagnostic(ErrorCode.ERR_RefLocalOrParamExpected, "s.P1").WithLocation(24, 9), - // (25,9): error CS8373: The left-hand side of a ref assignment must be a ref variable. - // s.P2 = ref x; - Diagnostic(ErrorCode.ERR_RefLocalOrParamExpected, "s.P2").WithLocation(25, 9)); + // (18,16): error CS8347: Cannot use a result of 'D2.Invoke(R)' in this context because it may expose variables referenced by parameter 'x' outside of their declaration scope + // return d2(new R(ref i)); + Diagnostic(ErrorCode.ERR_EscapeCall, "d2(new R(ref i))").WithArguments("D2.Invoke(R)", "x").WithLocation(18, 16), + // (18,19): error CS8347: Cannot use a result of 'R.R(ref int)' in this context because it may expose variables referenced by parameter 'i' outside of their declaration scope + // return d2(new R(ref i)); + Diagnostic(ErrorCode.ERR_EscapeCall, "new R(ref i)").WithArguments("R.R(ref int)", "i").WithLocation(18, 19), + // (18,29): error CS8168: Cannot return local 'i' by reference because it is not a ref local + // return d2(new R(ref i)); + Diagnostic(ErrorCode.ERR_RefReturnLocal, "i").WithArguments("i").WithLocation(18, 29), + // (22,19): error CS8989: The 'scoped' modifier of parameter 'x' doesn't match target 'D1'. + // R r1 = F1((R x) => x); // unsafe + Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfTarget, "(R x) => x").WithArguments("x", "D1").WithLocation(22, 19), + // (23,19): error CS8989: The 'scoped' modifier of parameter 'x' doesn't match target 'D2'. + // R r2 = F2((scoped R x) => default); + Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfTarget, "(scoped R x) => default").WithArguments("x", "D2").WithLocation(23, 19)); + } + + [Fact] + public void BestCommonType_01() + { + var source = +@"ref struct R { } +class Program +{ + static R F1(bool b, R x, scoped R y) => b ? x : y; + static R F2(bool b, R x, scoped R y) => b ? y : x; +}"; + var comp = CreateCompilation(source); + comp.VerifyDiagnostics( + // (4,53): error CS8352: Cannot use variable 'R' in this context because it may expose referenced variables outside of their declaration scope + // static R F1(bool b, R x, scoped R y) => b ? x : y; + Diagnostic(ErrorCode.ERR_EscapeVariable, "y").WithArguments("R").WithLocation(4, 53), + // (5,49): error CS8352: Cannot use variable 'R' in this context because it may expose referenced variables outside of their declaration scope + // static R F2(bool b, R x, scoped R y) => b ? y : x; + Diagnostic(ErrorCode.ERR_EscapeVariable, "y").WithArguments("R").WithLocation(5, 49)); } - /// - /// Ref auto-properties are not supported. - /// [Fact] - public void RefAutoProperty_02() + public void BestCommonType_03() { var source = -@"using System; -ref struct S +@"class Program { - public ref readonly T P0 { get; } - public ref readonly T P1 { get; set; } - public ref readonly T P2 { get; init; } - public S(ref T t) - { - P0 = ref t; - P1 = ref t; - P2 = ref t; - } -} + static ref int F1(bool b, scoped ref int x, ref int y) => ref b ? ref x : ref y; + static ref int F2(bool b, scoped ref int x, ref int y) => ref b ? ref y : ref x; +}"; + var comp = CreateCompilation(source); + comp.VerifyDiagnostics( + // (3,75): error CS8166: Cannot return a parameter by reference 'x' because it is not a ref parameter + // static ref int F1(bool b, scoped ref int x, ref int y) => ref b ? ref x : ref y; + Diagnostic(ErrorCode.ERR_RefReturnParameter, "x").WithArguments("x").WithLocation(3, 75), + // (4,83): error CS8166: Cannot return a parameter by reference 'x' because it is not a ref parameter + // static ref int F2(bool b, scoped ref int x, ref int y) => ref b ? ref y : ref x; + Diagnostic(ErrorCode.ERR_RefReturnParameter, "x").WithArguments("x").WithLocation(4, 83)); + } + + [Fact] + public void BestCommonType_04() + { + var source = +@"ref struct R { } class Program { static void Main() { - int x = 0; - var s = new S(ref x); - s.P0 = ref x; - s.P1 = ref x; - s.P2 = ref x; + var f1 = new[] { (R r) => { }, (scoped R r) => { } }[0]; // 1 + var f2 = new[] { (scoped R r) => { }, (scoped R r) => { } }[0]; + var f3 = new[] { (ref R r) => { }, (scoped ref R r) => { } }[0]; + var f4 = new[] { (scoped ref R r) => { }, (scoped ref R r) => { } }[0]; } }"; var comp = CreateCompilation(source); - comp.VerifyEmitDiagnostics( - // (4,27): error CS8145: Auto-implemented properties cannot return by reference - // public ref readonly T P0 { get; } - Diagnostic(ErrorCode.ERR_AutoPropertyCannotBeRefReturning, "P0").WithLocation(4, 27), - // (5,27): error CS8145: Auto-implemented properties cannot return by reference - // public ref readonly T P1 { get; set; } - Diagnostic(ErrorCode.ERR_AutoPropertyCannotBeRefReturning, "P1").WithLocation(5, 27), - // (5,37): error CS8147: Properties which return by reference cannot have set accessors - // public ref readonly T P1 { get; set; } - Diagnostic(ErrorCode.ERR_RefPropertyCannotHaveSetAccessor, "set").WithLocation(5, 37), - // (6,27): error CS8145: Auto-implemented properties cannot return by reference - // public ref readonly T P2 { get; init; } - Diagnostic(ErrorCode.ERR_AutoPropertyCannotBeRefReturning, "P2").WithLocation(6, 27), - // (6,37): error CS0518: Predefined type 'System.Runtime.CompilerServices.IsExternalInit' is not defined or imported - // public ref readonly T P2 { get; init; } - Diagnostic(ErrorCode.ERR_PredefinedTypeNotFound, "init").WithArguments("System.Runtime.CompilerServices.IsExternalInit").WithLocation(6, 37), - // (6,37): error CS8147: Properties which return by reference cannot have set accessors - // public ref readonly T P2 { get; init; } - Diagnostic(ErrorCode.ERR_RefPropertyCannotHaveSetAccessor, "init").WithLocation(6, 37), - // (9,9): error CS8373: The left-hand side of a ref assignment must be a ref variable. - // P0 = ref t; - Diagnostic(ErrorCode.ERR_RefLocalOrParamExpected, "P0").WithLocation(9, 9), - // (10,9): error CS8373: The left-hand side of a ref assignment must be a ref variable. - // P1 = ref t; - Diagnostic(ErrorCode.ERR_RefLocalOrParamExpected, "P1").WithLocation(10, 9), - // (11,9): error CS8373: The left-hand side of a ref assignment must be a ref variable. - // P2 = ref t; - Diagnostic(ErrorCode.ERR_RefLocalOrParamExpected, "P2").WithLocation(11, 9), - // (20,9): error CS8373: The left-hand side of a ref assignment must be a ref variable. - // s.P0 = ref x; - Diagnostic(ErrorCode.ERR_RefLocalOrParamExpected, "s.P0").WithLocation(20, 9), - // (21,9): error CS8373: The left-hand side of a ref assignment must be a ref variable. - // s.P1 = ref x; - Diagnostic(ErrorCode.ERR_RefLocalOrParamExpected, "s.P1").WithLocation(21, 9), - // (22,9): error CS8373: The left-hand side of a ref assignment must be a ref variable. - // s.P2 = ref x; - Diagnostic(ErrorCode.ERR_RefLocalOrParamExpected, "s.P2").WithLocation(22, 9)); + comp.VerifyDiagnostics( + // (6,18): error CS0826: No best type found for implicitly-typed array + // var f1 = new[] { (R r) => { }, (scoped R r) => { } }[0]; // 1 + Diagnostic(ErrorCode.ERR_ImplicitlyTypedArrayNoBestType, "new[] { (R r) => { }, (scoped R r) => { } }").WithLocation(6, 18)); } [Fact] - public void RefAccessor_Value() + public void InferredDelegateTypes_01() { var source = -@"using System; -ref struct S -{ - internal T t; - internal ref T F() => ref t; -} +@"ref struct R { } class Program { - static void Main() + static void F1(R x1, scoped R y1) { - var s = new S(); - s.t = 1; - s.F() = 2; - Console.WriteLine(s.F()); - Console.WriteLine(s.t); - s.t = 3; - Console.WriteLine(s.F()); - Console.WriteLine(s.t); + var f = (R x, scoped R y) => x; + R z; + z = f(x1, y1); + z = f(y1, x1); // 1 + } + static void F3(ref int x3, scoped ref int y3) + { + var f = (ref int x, scoped ref int y) => ref x; + int z; + z = f(ref x3, ref y3); + z = f(ref y3, ref x3); } }"; var comp = CreateCompilation(source); - comp.VerifyEmitDiagnostics( - // (5,31): error CS8170: Struct members cannot return 'this' or other instance members by reference - // internal ref T F() => ref t; - Diagnostic(ErrorCode.ERR_RefReturnStructThis, "t").WithLocation(5, 31)); + // https://github.com/dotnet/roslyn/issues/62768: Improve error message for `scoped ref` parameter returned by reference. + comp.VerifyDiagnostics( + // (9,13): error CS8347: Cannot use a result of '.Invoke(R, R)' in this context because it may expose variables referenced by parameter '0' outside of their declaration scope + // z = f(y1, x1); // 1 + Diagnostic(ErrorCode.ERR_EscapeCall, "f(y1, x1)").WithArguments(".Invoke(R, R)", "0").WithLocation(9, 13), + // (9,15): error CS8352: Cannot use variable 'R' in this context because it may expose referenced variables outside of their declaration scope + // z = f(y1, x1); // 1 + Diagnostic(ErrorCode.ERR_EscapeVariable, "y1").WithArguments("R").WithLocation(9, 15)); + + var tree = comp.SyntaxTrees[0]; + var model = comp.GetSemanticModel(tree); + var decls = tree.GetRoot().DescendantNodes().OfType().Where(v => v.Identifier.Text == "f").ToArray(); + var delegateInvokeMethods = decls.Select(d => ((ILocalSymbol)model.GetDeclaredSymbol(d)).Type.GetSymbol().DelegateInvokeMethod).ToArray(); + + VerifyParameterSymbol(delegateInvokeMethods[0].Parameters[0], "R", RefKind.None, DeclarationScope.Unscoped); + VerifyParameterSymbol(delegateInvokeMethods[0].Parameters[1], "scoped R", RefKind.None, DeclarationScope.ValueScoped); + VerifyParameterSymbol(delegateInvokeMethods[1].Parameters[1], "scoped ref System.Int32", RefKind.Ref, DeclarationScope.RefScoped); } [Fact] - public void RefAccessor_Ref() + public void InferredDelegateTypes_02() { var source = -@"using System; -ref struct S +@"ref struct R { } +static class E1 { - internal ref T t; - internal ref T F() => ref t; - internal S(ref T t) { this.t = ref t; } + public static void F1(this object o, R r) { } + public static void F2(this object o, ref R r) { } +} +static class E2 +{ + public static void F1(this object o, scoped R r) { } + public static void F2(this object o, scoped ref R r) { } } class Program { static void Main() { - int i = 0; - var s = new S(ref i); - s.t = 1; - s.F() = 2; - Console.WriteLine(s.F()); - Console.WriteLine(s.t); - s.t = 3; - Console.WriteLine(s.F()); - Console.WriteLine(s.t); + object o = new object(); + var d1 = o.F1; + var d2 = o.F2; } }"; - var verifier = CompileAndVerify(source, verify: Verification.Skipped, expectedOutput: IncludeExpectedOutput( -@"2 -2 -3 -3 -")); - verifier.VerifyIL("S.F", -@"{ - // Code size 7 (0x7) - .maxstack 1 - IL_0000: ldarg.0 - IL_0001: ldfld ""ref T S.t"" - IL_0006: ret -}"); + var comp = CreateCompilation(source); + comp.VerifyDiagnostics( + // (17,18): error CS0121: The call is ambiguous between the following methods or properties: 'E1.F1(object, R)' and 'E2.F1(object, R)' + // var d1 = o.F1; + Diagnostic(ErrorCode.ERR_AmbigCall, "o.F1").WithArguments("E1.F1(object, R)", "E2.F1(object, R)").WithLocation(17, 18), + // (18,18): error CS0121: The call is ambiguous between the following methods or properties: 'E1.F2(object, ref R)' and 'E2.F2(object, ref R)' + // var d2 = o.F2; + Diagnostic(ErrorCode.ERR_AmbigCall, "o.F2").WithArguments("E1.F2(object, ref R)", "E2.F2(object, ref R)").WithLocation(18, 18)); } - [Theory] - [InlineData(LanguageVersion.CSharp10)] - [InlineData(LanguageVersionFacts.CSharpNext)] - public void Span(LanguageVersion languageVersion) + [Fact] + public void ScopedRefAndRefStructOnly_01() { var source = -@"using System; +@"struct S { } class Program { - static ref int F1() - { - Span s1 = stackalloc int[10]; - return ref s1[1]; // 1 - } - static ref int F2() + static void F1(scoped S s) { } + static void F2(ref scoped S s) { } + static void F3(scoped ref S s) { } + static void F4(scoped ref scoped S s) { } + static void F5(ref scoped int i) { } + static void F6(in scoped int i) { } + static void F7(out scoped int i) { i = 0; } +}"; + var comp = CreateCompilation(source); + comp.VerifyDiagnostics( + // (4,20): error CS9048: The 'scoped' modifier can be used for refs and ref struct values only. + // static void F1(scoped S s) { } + Diagnostic(ErrorCode.ERR_ScopedRefAndRefStructOnly, "scoped S s").WithLocation(4, 20), + // (5,24): error CS8339: The parameter modifier 'scoped' cannot follow 'ref' + // static void F2(ref scoped S s) { } + Diagnostic(ErrorCode.ERR_BadParameterModifiersOrder, "scoped").WithArguments("scoped", "ref").WithLocation(5, 24), + // (7,31): error CS8339: The parameter modifier 'scoped' cannot follow 'ref' + // static void F4(scoped ref scoped S s) { } + Diagnostic(ErrorCode.ERR_BadParameterModifiersOrder, "scoped").WithArguments("scoped", "ref").WithLocation(7, 31), + // (8,24): error CS8339: The parameter modifier 'scoped' cannot follow 'ref' + // static void F5(ref scoped int i) { } + Diagnostic(ErrorCode.ERR_BadParameterModifiersOrder, "scoped").WithArguments("scoped", "ref").WithLocation(8, 24), + // (9,23): error CS8339: The parameter modifier 'scoped' cannot follow 'in' + // static void F6(in scoped int i) { } + Diagnostic(ErrorCode.ERR_BadParameterModifiersOrder, "scoped").WithArguments("scoped", "in").WithLocation(9, 23), + // (10,24): error CS8339: The parameter modifier 'scoped' cannot follow 'out' + // static void F7(out scoped int i) { i = 0; } + Diagnostic(ErrorCode.ERR_BadParameterModifiersOrder, "scoped").WithArguments("scoped", "out").WithLocation(10, 24)); + } + + [Fact] + public void ScopedRefAndRefStructOnly_02() + { + var source = +@"struct S { } +interface I +{ + void F1(scoped T t); + void F2(scoped T t) where T : class; + void F3(scoped T t) where T : struct; + void F4(scoped T t) where T : unmanaged; +}"; + var comp = CreateCompilation(source); + comp.VerifyDiagnostics( + // (4,16): error CS9048: The 'scoped' modifier can be used for refs and ref struct values only. + // void F1(scoped T t); + Diagnostic(ErrorCode.ERR_ScopedRefAndRefStructOnly, "scoped T t").WithLocation(4, 16), + // (5,16): error CS9048: The 'scoped' modifier can be used for refs and ref struct values only. + // void F2(scoped T t) where T : class; + Diagnostic(ErrorCode.ERR_ScopedRefAndRefStructOnly, "scoped T t").WithLocation(5, 16), + // (6,16): error CS9048: The 'scoped' modifier can be used for refs and ref struct values only. + // void F3(scoped T t) where T : struct; + Diagnostic(ErrorCode.ERR_ScopedRefAndRefStructOnly, "scoped T t").WithLocation(6, 16), + // (7,16): error CS9048: The 'scoped' modifier can be used for refs and ref struct values only. + // void F4(scoped T t) where T : unmanaged; + Diagnostic(ErrorCode.ERR_ScopedRefAndRefStructOnly, "scoped T t").WithLocation(7, 16)); + } + + [Fact] + public void ScopedRefAndRefStructOnly_03() + { + var source = +@"enum E { } +class Program +{ + static void Main() { - Span s2 = new int[10]; - return ref s2[1]; + var f = (scoped ref E x, scoped E y) => { }; +#pragma warning disable 8321 + static void L(scoped ref E x, scoped E y) { } } }"; - var comp = CreateCompilationWithSpanAndMemoryExtensions(source, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion)); + var comp = CreateCompilation(source); comp.VerifyDiagnostics( - // (7,20): error CS8352: Cannot use variable 's1' in this context because it may expose referenced variables outside of their declaration scope - // return ref s1[1]; // 1 - Diagnostic(ErrorCode.ERR_EscapeVariable, "s1").WithArguments("s1").WithLocation(7, 20)); + // (6,43): error CS9048: The 'scoped' modifier can be used for refs and ref struct values only. + // var f = (scoped ref E x, scoped E y) => { }; + Diagnostic(ErrorCode.ERR_ScopedRefAndRefStructOnly, "y").WithLocation(6, 43), + // (8,39): error CS9048: The 'scoped' modifier can be used for refs and ref struct values only. + // static void L(scoped ref E x, scoped E y) { } + Diagnostic(ErrorCode.ERR_ScopedRefAndRefStructOnly, "scoped E y").WithLocation(8, 39)); } - // Breaking change in C#11: Cannot return an 'out' parameter by reference. [Fact] - public void BreakingChange_ReturnOutByRef() + public void ScopedRefAndRefStructOnly_04() { var source = -@"class Program +@"delegate void D(scoped C c); +class C { - static ref T ReturnOutParamByRef(out T t) + static unsafe void Main() { - t = default; - return ref t; + delegate* d = default; } }"; + var comp = CreateCompilation(source, options: TestOptions.UnsafeReleaseExe); + comp.VerifyDiagnostics( + // (1,17): error CS9048: The 'scoped' modifier can be used for refs and ref struct values only. + // delegate void D(scoped C c); + Diagnostic(ErrorCode.ERR_ScopedRefAndRefStructOnly, "scoped C c").WithLocation(1, 17), + // (6,19): error CS8755: 'scoped' cannot be used as a modifier on a function pointer parameter. + // delegate* d = default; + Diagnostic(ErrorCode.ERR_BadFuncPointerParamModifier, "scoped").WithArguments("scoped").WithLocation(6, 19)); + } - var comp = CreateCompilation(source, parseOptions: TestOptions.Regular10); + [Theory] + [InlineData("ref ")] + [InlineData("ref readonly")] + public void ScopedRefAndRefStructOnly_05(string refModifier) + { + var source = +$@"struct S {{ }} +class Program +{{ + static void F(S s) + {{ + scoped {refModifier} S s2 = ref s; + }} +}}"; + var comp = CreateCompilation(source); comp.VerifyDiagnostics(); + } - comp = CreateCompilation(source); + [Theory] + [InlineData("ref ")] + [InlineData("ref readonly")] + public void ScopedRefAndRefStructOnly_05_RefScoped(string refModifier) + { + var source = +$@"struct S {{ }} +class Program +{{ + static void F(S s) + {{ + {refModifier} scoped S s1 = ref s; + scoped {refModifier} scoped S s3 = ref s; + }} +}}"; + var comp = CreateCompilation(source); comp.VerifyDiagnostics( - // (6,20): error CS8166: Cannot return a parameter by reference 't' because it is not a ref parameter - // return ref t; - Diagnostic(ErrorCode.ERR_RefReturnParameter, "t").WithArguments("t").WithLocation(6, 20)); + // (6,22): error CS9061: Unexpected contextual keyword 'scoped'. Did you mean 'scoped ref' or '@scoped'? + // ref scoped S s1 = ref s; + Diagnostic(ErrorCode.ERR_MisplacedScoped, "scoped").WithLocation(6, 22), + // (7,29): error CS9061: Unexpected contextual keyword 'scoped'. Did you mean 'scoped ref' or '@scoped'? + // scoped ref scoped S s3 = ref s; + Diagnostic(ErrorCode.ERR_MisplacedScoped, "scoped").WithLocation(7, 29)); } - // Breaking change in C#11: The rvalue from a method invocation that - // returns a ref struct is safe-to-escape from ... the ref-safe-to-escape of all ref arguments. [Fact] - public void BreakingChange_RefStructReturnFromRefArguments() + public void ScopedRefAndRefStructOnly_06() { var source = -@"ref struct R { } +@"ref struct R { } +struct S { } class Program { - static R MayCaptureArg(ref int i) => new R(); - static R MayCaptureDefaultArg(in int i = 0) => new R(); - static R Create() + static void Main() { - int i = 0; - return MayCaptureArg(ref i); + scoped var x1 = new R(); + scoped ref var x3 = ref x1; // 1 + scoped var y1 = new S(); // 2 + scoped ref var y3 = ref y1; } - static R CreateDefault() +}"; + var comp = CreateCompilation(source); + comp.VerifyDiagnostics( + // (8,33): error CS8352: Cannot use variable 'x1' in this context because it may expose referenced variables outside of their declaration scope + // scoped ref var x3 = ref x1; // 1 + Diagnostic(ErrorCode.ERR_EscapeVariable, "x1").WithArguments("x1").WithLocation(8, 33), + // (9,16): error CS9048: The 'scoped' modifier can be used for refs and ref struct values only. + // scoped var y1 = new S(); // 2 + Diagnostic(ErrorCode.ERR_ScopedRefAndRefStructOnly, "var").WithLocation(9, 16)); + } + + [Fact] + public void ScopedRefAndRefStructOnly_07() + { + var source = +@"ref struct R { } +class Program +{ + static void F1(scoped Unknown x, scoped R y) { - return MayCaptureDefaultArg(); + var f = (scoped ref Unknown u) => { }; + scoped R z = y; + scoped var v = F2(); } }"; - - var comp = CreateCompilation(source, parseOptions: TestOptions.Regular10); - comp.VerifyDiagnostics(); - - comp = CreateCompilation(source); + var comp = CreateCompilation(source); comp.VerifyDiagnostics( - // (9,16): error CS8347: Cannot use a result of 'Program.MayCaptureArg(ref int)' in this context because it may expose variables referenced by parameter 'i' outside of their declaration scope - // return MayCaptureArg(ref i); - Diagnostic(ErrorCode.ERR_EscapeCall, "MayCaptureArg(ref i)").WithArguments("Program.MayCaptureArg(ref int)", "i").WithLocation(9, 16), - // (9,34): error CS8168: Cannot return local 'i' by reference because it is not a ref local - // return MayCaptureArg(ref i); - Diagnostic(ErrorCode.ERR_RefReturnLocal, "i").WithArguments("i").WithLocation(9, 34), - // (13,16): error CS8156: An expression cannot be used in this context because it may not be passed or returned by reference - // return MayCaptureDefaultArg(); - Diagnostic(ErrorCode.ERR_RefReturnLvalueExpected, "MayCaptureDefaultArg()").WithLocation(13, 16), - // (13,16): error CS8347: Cannot use a result of 'Program.MayCaptureDefaultArg(in int)' in this context because it may expose variables referenced by parameter 'i' outside of their declaration scope - // return MayCaptureDefaultArg(); - Diagnostic(ErrorCode.ERR_EscapeCall, "MayCaptureDefaultArg()").WithArguments("Program.MayCaptureDefaultArg(in int)", "i").WithLocation(13, 16)); + // (4,20): error CS9048: The 'scoped' modifier can be used for refs and ref struct values only. + // static void F1(scoped Unknown x, scoped R y) + Diagnostic(ErrorCode.ERR_ScopedRefAndRefStructOnly, "scoped Unknown x").WithLocation(4, 20), + // (4,27): error CS0246: The type or namespace name 'Unknown' could not be found (are you missing a using directive or an assembly reference?) + // static void F1(scoped Unknown x, scoped R y) + Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "Unknown").WithArguments("Unknown").WithLocation(4, 27), + // (4,47): error CS0246: The type or namespace name 'Unknown' could not be found (are you missing a using directive or an assembly reference?) + // static void F1(scoped Unknown x, scoped R y) + Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "Unknown").WithArguments("Unknown").WithLocation(4, 47), + // (6,29): error CS0246: The type or namespace name 'Unknown' could not be found (are you missing a using directive or an assembly reference?) + // var f = (scoped ref Unknown u) => { }; + Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "Unknown").WithArguments("Unknown").WithLocation(6, 29), + // (7,18): error CS0246: The type or namespace name 'Unknown' could not be found (are you missing a using directive or an assembly reference?) + // scoped R z = y; + Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "Unknown").WithArguments("Unknown").WithLocation(7, 18), + // (8,24): error CS0103: The name 'F2' does not exist in the current context + // scoped var v = F2(); + Diagnostic(ErrorCode.ERR_NameNotInContext, "F2").WithArguments("F2").WithLocation(8, 24)); } - [Theory] - [CombinatorialData] - public void ParameterScope_01(bool useCompilationReference) + [Fact] + public void Local_SequencePoints() { - var sourceA = -@"public ref struct R + var source = +@"using System; +ref struct R { - public R(ref int i) { } + public ref T F; + public R(ref T t) { F = ref t; } } -public static class A -{ - public static void F1(R x1, scoped R y1) { } - public static void F2(ref R x2, scoped ref R y2, ref scoped R z2) { } - public static void F3(in R x3, scoped in R y3, in scoped R z3) { } - public static void F4(out R x4, scoped out R y4, out scoped R z4) { x4 = default; y4 = default; z4 = default; } -}"; - var comp = CreateCompilation(sourceA, parseOptions: TestOptions.Regular10); - comp.VerifyEmitDiagnostics( - // (7,33): error CS8652: The feature 'ref fields' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. - // public static void F1(R x1, scoped R y1) { } - Diagnostic(ErrorCode.ERR_FeatureInPreview, "scoped").WithArguments("ref fields").WithLocation(7, 33), - // (8,37): error CS8652: The feature 'ref fields' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. - // public static void F2(ref R x2, scoped ref R y2, ref scoped R z2) { } - Diagnostic(ErrorCode.ERR_FeatureInPreview, "scoped").WithArguments("ref fields").WithLocation(8, 37), - // (8,58): error CS8652: The feature 'ref fields' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. - // public static void F2(ref R x2, scoped ref R y2, ref scoped R z2) { } - Diagnostic(ErrorCode.ERR_FeatureInPreview, "scoped").WithArguments("ref fields").WithLocation(8, 58), - // (9,36): error CS8652: The feature 'ref fields' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. - // public static void F3(in R x3, scoped in R y3, in scoped R z3) { } - Diagnostic(ErrorCode.ERR_FeatureInPreview, "scoped").WithArguments("ref fields").WithLocation(9, 36), - // (9,55): error CS8652: The feature 'ref fields' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. - // public static void F3(in R x3, scoped in R y3, in scoped R z3) { } - Diagnostic(ErrorCode.ERR_FeatureInPreview, "scoped").WithArguments("ref fields").WithLocation(9, 55), - // (10,37): error CS8652: The feature 'ref fields' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. - // public static void F4(out R x4, scoped out R y4, out scoped R z4) { x4 = default; y4 = default; z4 = default; } - Diagnostic(ErrorCode.ERR_FeatureInPreview, "scoped").WithArguments("ref fields").WithLocation(10, 37), - // (10,58): error CS8652: The feature 'ref fields' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. - // public static void F4(out R x4, scoped out R y4, out scoped R z4) { x4 = default; y4 = default; z4 = default; } - Diagnostic(ErrorCode.ERR_FeatureInPreview, "scoped").WithArguments("ref fields").WithLocation(10, 58)); - - verify(comp); - - comp = CreateCompilation(sourceA); - comp.VerifyEmitDiagnostics(); - var refA = AsReference(comp, useCompilationReference); - - var sourceB = -@"static class B +class Program { - static void F(ref R x) + static void Main() { - int i = 0; - R y = new R(ref i); - A.F2(ref x, ref y, ref y); + int x = 1; + scoped R y = new R(ref x); + ref R z = ref y; + z.F = 2; + Console.WriteLine(x); } }"; - comp = CreateCompilation(sourceB, references: new[] { refA }); - comp.VerifyEmitDiagnostics( - // (7,9): error CS8350: This combination of arguments to 'A.F2(ref R, ref R, ref R)' is disallowed because it may expose variables referenced by parameter 'y2' outside of their declaration scope - // A.F2(ref x, ref y, ref y); - Diagnostic(ErrorCode.ERR_CallArgMixing, "A.F2(ref x, ref y, ref y)").WithArguments("A.F2(ref R, ref R, ref R)", "y2").WithLocation(7, 9), - // (7,25): error CS8352: Cannot use variable 'y' in this context because it may expose referenced variables outside of their declaration scope - // A.F2(ref x, ref y, ref y); - Diagnostic(ErrorCode.ERR_EscapeVariable, "y").WithArguments("y").WithLocation(7, 25)); - - verify(comp); - - static void verify(CSharpCompilation comp) - { - var parameters = comp.GetMember("A.F1").Parameters; - VerifyParameterSymbol(parameters[0], "R x1", RefKind.None, DeclarationScope.Unscoped); - VerifyParameterSymbol(parameters[1], "scoped R y1", RefKind.None, DeclarationScope.ValueScoped); - - parameters = comp.GetMember("A.F2").Parameters; - VerifyParameterSymbol(parameters[0], "ref R x2", RefKind.Ref, DeclarationScope.Unscoped); - VerifyParameterSymbol(parameters[1], "scoped ref R y2", RefKind.Ref, DeclarationScope.RefScoped); - VerifyParameterSymbol(parameters[2], "ref scoped R z2", RefKind.Ref, DeclarationScope.ValueScoped); - - parameters = comp.GetMember("A.F3").Parameters; - VerifyParameterSymbol(parameters[0], "in R x3", RefKind.In, DeclarationScope.Unscoped); - VerifyParameterSymbol(parameters[1], "scoped in R y3", RefKind.In, DeclarationScope.RefScoped); - VerifyParameterSymbol(parameters[2], "in scoped R z3", RefKind.In, DeclarationScope.ValueScoped); - - parameters = comp.GetMember("A.F4").Parameters; - VerifyParameterSymbol(parameters[0], "out R x4", RefKind.Out, DeclarationScope.RefScoped); - VerifyParameterSymbol(parameters[1], "out R y4", RefKind.Out, DeclarationScope.RefScoped); - VerifyParameterSymbol(parameters[2], "out scoped R z4", RefKind.Out, DeclarationScope.ValueScoped); - } + var comp = CreateCompilation(source, options: TestOptions.DebugExe, runtimeFeature: RuntimeFlag.ByRefFields); + var verifier = CompileAndVerify(comp, verify: Verification.Skipped); + verifier.VerifyIL("Program.Main", + source: source, + sequencePoints: "Program.Main", + expectedIL: +@"{ + // Code size 30 (0x1e) + .maxstack 2 + .locals init (int V_0, //x + R V_1, //y + R& V_2) //z + // sequence point: { + IL_0000: nop + // sequence point: int x = 1; + IL_0001: ldc.i4.1 + IL_0002: stloc.0 + // sequence point: scoped R y = new R(ref x); + IL_0003: ldloca.s V_0 + IL_0005: newobj ""R..ctor(ref int)"" + IL_000a: stloc.1 + // sequence point: ref R z = ref y; + IL_000b: ldloca.s V_1 + IL_000d: stloc.2 + // sequence point: z.F = 2; + IL_000e: ldloc.2 + IL_000f: ldfld ""ref int R.F"" + IL_0014: ldc.i4.2 + IL_0015: stind.i4 + // sequence point: Console.WriteLine(x); + IL_0016: ldloc.0 + IL_0017: call ""void System.Console.WriteLine(int)"" + IL_001c: nop + // sequence point: } + IL_001d: ret +}"); } [Fact] - public void ParameterScope_02() + public void SafeToEscape_01() { var source = -@"ref struct A -{ - A(scoped ref T t) { } - T this[scoped in object o] => default; - public static implicit operator B(in scoped A a) => default; -} -struct B +@"ref struct R { } +class Program { + static R F0(R r0) => r0; + static R F1(scoped R r1) => r1; // 1 + static R F2(ref R r2) => r2; + static R F3(scoped ref R r3) => r3; }"; - var comp = CreateCompilation(source, parseOptions: TestOptions.Regular10); - comp.VerifyEmitDiagnostics( - // (3,7): error CS8652: The feature 'ref fields' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. - // A(scoped ref T t) { } - Diagnostic(ErrorCode.ERR_FeatureInPreview, "scoped").WithArguments("ref fields").WithLocation(3, 7), - // (4,12): error CS8652: The feature 'ref fields' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. - // T this[scoped in object o] => default; - Diagnostic(ErrorCode.ERR_FeatureInPreview, "scoped").WithArguments("ref fields").WithLocation(4, 12), - // (5,45): error CS8652: The feature 'ref fields' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. - // public static implicit operator B(in scoped A a) => default; - Diagnostic(ErrorCode.ERR_FeatureInPreview, "scoped").WithArguments("ref fields").WithLocation(5, 45)); - verify(comp); - - comp = CreateCompilation(source); - comp.VerifyEmitDiagnostics(); - verify(comp); - - static void verify(CSharpCompilation comp) - { - VerifyParameterSymbol(comp.GetMember("A").Constructors.Single(c => !c.IsImplicitlyDeclared).Parameters[0], "scoped ref T t", RefKind.Ref, DeclarationScope.RefScoped); - VerifyParameterSymbol(comp.GetMember("A.this[]").GetMethod.Parameters[0], "scoped in System.Object o", RefKind.In, DeclarationScope.RefScoped); - VerifyParameterSymbol(comp.GetMember("A.op_Implicit").Parameters[0], "in scoped A a", RefKind.In, DeclarationScope.ValueScoped); - } + var comp = CreateCompilation(source); + comp.VerifyDiagnostics( + // (5,43): error CS8352: Cannot use variable 'R' in this context because it may expose referenced variables outside of their declaration scope + // static R F1(scoped R r1) => r1; // 1 + Diagnostic(ErrorCode.ERR_EscapeVariable, "r1").WithArguments("R").WithLocation(5, 43)); } [Fact] - public void ParameterScope_03() + public void RefSafeToEscape_01() { var source = -@"ref struct R { } +@"ref struct R { } class Program { - static void Main() - { -#pragma warning disable 8321 - static void L1(scoped R x1) { } - static void L2(scoped ref int x2) { } - static void L3(scoped in int x3) { } - static void L4(scoped out int x4) { x4 = 0; } - static void L5(object o, ref scoped R x5) { } - } + static ref R F0(R r0) => ref r0; // 1 + static ref R F1(scoped R r1) => ref r1; // 2 + static ref R F2(ref R r2) => ref r2; + static ref R F3(scoped ref R r3) => ref r3; // 3 }"; - var comp = CreateCompilation(source, parseOptions: TestOptions.Regular10); - comp.VerifyEmitDiagnostics( - // (7,24): error CS8652: The feature 'ref fields' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. - // static void L1(scoped R x1) { } - Diagnostic(ErrorCode.ERR_FeatureInPreview, "scoped").WithArguments("ref fields").WithLocation(7, 24), - // (8,24): error CS8652: The feature 'ref fields' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. - // static void L2(scoped ref int x2) { } - Diagnostic(ErrorCode.ERR_FeatureInPreview, "scoped").WithArguments("ref fields").WithLocation(8, 24), - // (9,24): error CS8652: The feature 'ref fields' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. - // static void L3(scoped in int x3) { } - Diagnostic(ErrorCode.ERR_FeatureInPreview, "scoped").WithArguments("ref fields").WithLocation(9, 24), - // (10,24): error CS8652: The feature 'ref fields' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. - // static void L4(scoped out int x4) { x4 = 0; } - Diagnostic(ErrorCode.ERR_FeatureInPreview, "scoped").WithArguments("ref fields").WithLocation(10, 24), - // (11,38): error CS8652: The feature 'ref fields' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. - // static void L5(object o, ref scoped R x5) { } - Diagnostic(ErrorCode.ERR_FeatureInPreview, "scoped").WithArguments("ref fields").WithLocation(11, 38)); - verify(comp); - - comp = CreateCompilation(source); - comp.VerifyEmitDiagnostics(); - verify(comp); - - static void verify(CSharpCompilation comp) - { - var tree = comp.SyntaxTrees[0]; - var model = comp.GetSemanticModel(tree); - var decls = tree.GetRoot().DescendantNodes().OfType().ToArray(); - var localFunctions = decls.Select(d => model.GetDeclaredSymbol(d).GetSymbol()).ToArray(); + var comp = CreateCompilation(source); + comp.VerifyDiagnostics( + // (4,44): error CS8166: Cannot return a parameter by reference 'r0' because it is not a ref parameter + // static ref R F0(R r0) => ref r0; // 1 + Diagnostic(ErrorCode.ERR_RefReturnParameter, "r0").WithArguments("r0").WithLocation(4, 44), + // (5,51): error CS8166: Cannot return a parameter by reference 'r1' because it is not a ref parameter + // static ref R F1(scoped R r1) => ref r1; // 2 + Diagnostic(ErrorCode.ERR_RefReturnParameter, "r1").WithArguments("r1").WithLocation(5, 51), + // (6,48): error CS8166: Cannot return a parameter by reference 'r2' because it is not a ref parameter + // static ref R F2(ref R r2) => ref r2; + Diagnostic(ErrorCode.ERR_RefReturnParameter, "r2").WithArguments("r2").WithLocation(6, 48), + // (7,55): error CS8166: Cannot return a parameter by reference 'r3' because it is not a ref parameter + // static ref R F3(scoped ref R r3) => ref r3; // 3 + Diagnostic(ErrorCode.ERR_RefReturnParameter, "r3").WithArguments("r3").WithLocation(7, 55)); - VerifyParameterSymbol(localFunctions[0].Parameters[0], "scoped R x1", RefKind.None, DeclarationScope.ValueScoped); - VerifyParameterSymbol(localFunctions[1].Parameters[0], "scoped ref System.Int32 x2", RefKind.Ref, DeclarationScope.RefScoped); - VerifyParameterSymbol(localFunctions[2].Parameters[0], "scoped in System.Int32 x3", RefKind.In, DeclarationScope.RefScoped); - VerifyParameterSymbol(localFunctions[3].Parameters[0], "out System.Int32 x4", RefKind.Out, DeclarationScope.RefScoped); - VerifyParameterSymbol(localFunctions[4].Parameters[1], "ref scoped R x5", RefKind.Ref, DeclarationScope.ValueScoped); - } + // https://github.com/dotnet/roslyn/issues/62780: Test additional cases with [UnscopedRef]. } [Fact] - public void ParameterScope_04() + public void SafeToEscape_02() { var source = -@"ref struct R { } +@"ref struct R { } class Program { - static void Main() + static R F0(R r0) + { + R l0 = r0; + return l0; + } + static R F1(scoped R r1) + { + R l1 = r1; + return l1; // 1 + } + static R F2(ref R r2) + { + R l2 = r2; + return l2; + } + static R F3(scoped ref R r3) { - var f1 = (scoped R x1) => { }; - var f2 = (scoped ref int x2) => { }; - var f3 = (scoped in int x3) => { }; - var f4 = (scoped out int x4) => { x4 = 0; }; - var f5 = (object o, ref scoped R x5) => { }; + R l3 = r3; + return l3; } }"; - var comp = CreateCompilation(source, parseOptions: TestOptions.Regular10); - comp.VerifyEmitDiagnostics( - // (6,19): error CS8652: The feature 'ref fields' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. - // var f1 = (scoped R x1) => { }; - Diagnostic(ErrorCode.ERR_FeatureInPreview, "scoped").WithArguments("ref fields").WithLocation(6, 19), - // (7,19): error CS8652: The feature 'ref fields' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. - // var f2 = (scoped ref int x2) => { }; - Diagnostic(ErrorCode.ERR_FeatureInPreview, "scoped").WithArguments("ref fields").WithLocation(7, 19), - // (8,19): error CS8652: The feature 'ref fields' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. - // var f3 = (scoped in int x3) => { }; - Diagnostic(ErrorCode.ERR_FeatureInPreview, "scoped").WithArguments("ref fields").WithLocation(8, 19), - // (9,19): error CS8652: The feature 'ref fields' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. - // var f4 = (scoped out int x4) => { x4 = 0; }; - Diagnostic(ErrorCode.ERR_FeatureInPreview, "scoped").WithArguments("ref fields").WithLocation(9, 19), - // (10,33): error CS8652: The feature 'ref fields' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. - // var f5 = (object o, ref scoped R x5) => { }; - Diagnostic(ErrorCode.ERR_FeatureInPreview, "scoped").WithArguments("ref fields").WithLocation(10, 33)); - verify(comp); - - comp = CreateCompilation(source); - comp.VerifyEmitDiagnostics(); - verify(comp); - - static void verify(CSharpCompilation comp) - { - var tree = comp.SyntaxTrees[0]; - var model = comp.GetSemanticModel(tree); - var delegateTypesAndLambdas = tree.GetRoot().DescendantNodes().OfType().Select(d => getDelegateTypeAndLambda(model, d)).ToArray(); - - verifyParameter(delegateTypesAndLambdas[0], 0, "scoped R", "x1", RefKind.None, DeclarationScope.ValueScoped); - verifyParameter(delegateTypesAndLambdas[1], 0, "scoped ref System.Int32", "x2", RefKind.Ref, DeclarationScope.RefScoped); - verifyParameter(delegateTypesAndLambdas[2], 0, "scoped in System.Int32", "x3", RefKind.In, DeclarationScope.RefScoped); - verifyParameter(delegateTypesAndLambdas[3], 0, "out System.Int32", "x4", RefKind.Out, DeclarationScope.RefScoped); - verifyParameter(delegateTypesAndLambdas[4], 1, "ref scoped R", "x5", RefKind.Ref, DeclarationScope.ValueScoped); - } - - static void verifyParameter((NamedTypeSymbol, LambdaSymbol) delegateTypeAndLambda, int parameterIndex, string expectedDisplayType, string expectedDisplayName, RefKind expectedRefKind, DeclarationScope expectedScope) - { - var (delegateType, lambda) = delegateTypeAndLambda; - VerifyParameterSymbol(delegateType.DelegateInvokeMethod.Parameters[parameterIndex], expectedDisplayType, expectedRefKind, expectedScope); - VerifyParameterSymbol(lambda.Parameters[parameterIndex], $"{expectedDisplayType} {expectedDisplayName}", expectedRefKind, expectedScope); - } - - static (NamedTypeSymbol, LambdaSymbol) getDelegateTypeAndLambda(SemanticModel model, VariableDeclaratorSyntax decl) - { - var delegateType = (NamedTypeSymbol)model.GetDeclaredSymbol(decl).GetSymbol().Type; - var value = decl.DescendantNodes().OfType().Single(); - var lambda = model.GetSymbolInfo(value).Symbol.GetSymbol(); - return (delegateType, lambda); - } - } - - [Fact] - public void ParameterScope_05() - { - var source = -@"ref struct R { } -delegate void D1(scoped R r1); -delegate void D2(scoped ref R r2); -delegate void D3(object o, ref scoped R r3); -"; - var comp = CreateCompilation(source, parseOptions: TestOptions.Regular10); - comp.VerifyEmitDiagnostics( - // (2,18): error CS8652: The feature 'ref fields' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. - // delegate void D1(scoped R r1); - Diagnostic(ErrorCode.ERR_FeatureInPreview, "scoped").WithArguments("ref fields").WithLocation(2, 18), - // (3,18): error CS8652: The feature 'ref fields' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. - // delegate void D2(scoped ref R r2); - Diagnostic(ErrorCode.ERR_FeatureInPreview, "scoped").WithArguments("ref fields").WithLocation(3, 18), - // (4,32): error CS8652: The feature 'ref fields' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. - // delegate void D3(object o, ref scoped R r3); - Diagnostic(ErrorCode.ERR_FeatureInPreview, "scoped").WithArguments("ref fields").WithLocation(4, 32)); - verify(comp); - - comp = CreateCompilation(source); - comp.VerifyEmitDiagnostics(); - verify(comp); - - static void verify(CSharpCompilation comp) - { - VerifyParameterSymbol(comp.GetMember("D1").DelegateInvokeMethod.Parameters[0], "scoped R r1", RefKind.None, DeclarationScope.ValueScoped); - VerifyParameterSymbol(comp.GetMember("D2").DelegateInvokeMethod.Parameters[0], "scoped ref R r2", RefKind.Ref, DeclarationScope.RefScoped); - VerifyParameterSymbol(comp.GetMember("D3").DelegateInvokeMethod.Parameters[1], "ref scoped R r3", RefKind.Ref, DeclarationScope.ValueScoped); - } + var comp = CreateCompilation(source); + comp.VerifyDiagnostics( + // (12,16): error CS8352: Cannot use variable 'l1' in this context because it may expose referenced variables outside of their declaration scope + // return l1; // 1 + Diagnostic(ErrorCode.ERR_EscapeVariable, "l1").WithArguments("l1").WithLocation(12, 16)); } [Fact] - public void ParameterScope_06() + public void RefSafeToEscape_02() { var source = -@"ref struct R { } +@"ref struct R { } class Program { - static void F1(scoped R r1) { } - static void F2(ref scoped R x, scoped ref int y) { } - static unsafe void Main() + static ref R F0(R r0) { - delegate* f1 = &F1; - delegate* f2 = &F2; + R l0 = r0; + return ref l0; // 1 + } + static ref R F1(scoped R r1) + { + R l1 = r1; + return ref l1; // 2 + } + static ref R F2(ref R r2) + { + R l2 = r2; + return ref l2; // 3 + } + static ref R F3(scoped ref R r3) + { + R l3 = r3; + return ref l3; // 4 } }"; - var comp = CreateCompilation(source, parseOptions: TestOptions.Regular10, options: TestOptions.UnsafeReleaseExe); - comp.VerifyEmitDiagnostics( - // (4,20): error CS8652: The feature 'ref fields' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. - // static void F1(scoped R r1) { } - Diagnostic(ErrorCode.ERR_FeatureInPreview, "scoped").WithArguments("ref fields").WithLocation(4, 20), - // (5,24): error CS8652: The feature 'ref fields' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. - // static void F2(ref scoped R x, scoped ref int y) { } - Diagnostic(ErrorCode.ERR_FeatureInPreview, "scoped").WithArguments("ref fields").WithLocation(5, 24), - // (5,36): error CS8652: The feature 'ref fields' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. - // static void F2(ref scoped R x, scoped ref int y) { } - Diagnostic(ErrorCode.ERR_FeatureInPreview, "scoped").WithArguments("ref fields").WithLocation(5, 36), - // (8,19): error CS8755: 'scoped' cannot be used as a modifier on a function pointer parameter. - // delegate* f1 = &F1; - Diagnostic(ErrorCode.ERR_BadFuncPointerParamModifier, "scoped").WithArguments("scoped").WithLocation(8, 19), - // (8,40): error CS8986: The 'scoped' modifier of parameter 'r1' doesn't match target 'delegate*'. - // delegate* f1 = &F1; - Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfTarget, "&F1").WithArguments("r1", "delegate*").WithLocation(8, 40), - // (9,23): error CS8755: 'scoped' cannot be used as a modifier on a function pointer parameter. - // delegate* f2 = &F2; - Diagnostic(ErrorCode.ERR_BadFuncPointerParamModifier, "scoped").WithArguments("scoped").WithLocation(9, 23), - // (9,33): error CS8755: 'scoped' cannot be used as a modifier on a function pointer parameter. - // delegate* f2 = &F2; - Diagnostic(ErrorCode.ERR_BadFuncPointerParamModifier, "scoped").WithArguments("scoped").WithLocation(9, 33), - // (9,60): error CS8986: The 'scoped' modifier of parameter 'x' doesn't match target 'delegate*'. - // delegate* f2 = &F2; - Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfTarget, "&F2").WithArguments("x", "delegate*").WithLocation(9, 60), - // (9,60): error CS8986: The 'scoped' modifier of parameter 'y' doesn't match target 'delegate*'. - // delegate* f2 = &F2; - Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfTarget, "&F2").WithArguments("y", "delegate*").WithLocation(9, 60)); - verify(comp); - - comp = CreateCompilation(source, options: TestOptions.UnsafeReleaseExe); - comp.VerifyEmitDiagnostics( - // (8,19): error CS8755: 'scoped' cannot be used as a modifier on a function pointer parameter. - // delegate* f1 = &F1; - Diagnostic(ErrorCode.ERR_BadFuncPointerParamModifier, "scoped").WithArguments("scoped").WithLocation(8, 19), - // (8,40): error CS8986: The 'scoped' modifier of parameter 'r1' doesn't match target 'delegate*'. - // delegate* f1 = &F1; - Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfTarget, "&F1").WithArguments("r1", "delegate*").WithLocation(8, 40), - // (9,23): error CS8755: 'scoped' cannot be used as a modifier on a function pointer parameter. - // delegate* f2 = &F2; - Diagnostic(ErrorCode.ERR_BadFuncPointerParamModifier, "scoped").WithArguments("scoped").WithLocation(9, 23), - // (9,33): error CS8755: 'scoped' cannot be used as a modifier on a function pointer parameter. - // delegate* f2 = &F2; - Diagnostic(ErrorCode.ERR_BadFuncPointerParamModifier, "scoped").WithArguments("scoped").WithLocation(9, 33), - // (9,60): error CS8986: The 'scoped' modifier of parameter 'x' doesn't match target 'delegate*'. - // delegate* f2 = &F2; - Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfTarget, "&F2").WithArguments("x", "delegate*").WithLocation(9, 60), - // (9,60): error CS8986: The 'scoped' modifier of parameter 'y' doesn't match target 'delegate*'. - // delegate* f2 = &F2; - Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfTarget, "&F2").WithArguments("y", "delegate*").WithLocation(9, 60)); - verify(comp); - - static void verify(CSharpCompilation comp) - { - var tree = comp.SyntaxTrees[0]; - var model = comp.GetSemanticModel(tree); - var decls = tree.GetRoot().DescendantNodes().OfType().ToArray(); - var methods = decls.Select(d => ((FunctionPointerTypeSymbol)model.GetDeclaredSymbol(d).GetSymbol().Type).Signature).ToArray(); - - VerifyParameterSymbol(methods[0].Parameters[0], "R", RefKind.None, DeclarationScope.Unscoped); - VerifyParameterSymbol(methods[1].Parameters[0], "ref R", RefKind.Ref, DeclarationScope.Unscoped); - VerifyParameterSymbol(methods[1].Parameters[1], "ref System.Int32", RefKind.Ref, DeclarationScope.Unscoped); - } + var comp = CreateCompilation(source); + comp.VerifyDiagnostics( + // (7,20): error CS8168: Cannot return local 'l0' by reference because it is not a ref local + // return ref l0; // 1 + Diagnostic(ErrorCode.ERR_RefReturnLocal, "l0").WithArguments("l0").WithLocation(7, 20), + // (12,20): error CS8168: Cannot return local 'l1' by reference because it is not a ref local + // return ref l1; // 2 + Diagnostic(ErrorCode.ERR_RefReturnLocal, "l1").WithArguments("l1").WithLocation(12, 20), + // (17,20): error CS8168: Cannot return local 'l2' by reference because it is not a ref local + // return ref l2; // 3 + Diagnostic(ErrorCode.ERR_RefReturnLocal, "l2").WithArguments("l2").WithLocation(17, 20), + // (22,20): error CS8168: Cannot return local 'l3' by reference because it is not a ref local + // return ref l3; // 4 + Diagnostic(ErrorCode.ERR_RefReturnLocal, "l3").WithArguments("l3").WithLocation(22, 20)); } [Fact] - public void ParameterScope_07() + public void SafeToEscape_03() { var source = -@"ref struct R { } +@"ref struct R { } class Program { - static void F0(scoped scoped R r) { } - static void F1(ref scoped scoped R r) { } - static void F2(scoped ref scoped R r) { } - static void F3(scoped scoped ref R r) { } - static void F4(in scoped scoped R r) { } - static void F5(scoped in scoped R r) { } - static void F6(scoped scoped in R r) { } - static void F7(out scoped scoped R r) { r = default; } - static void F8(scoped out scoped R r) { r = default; } - static void F9(scoped scoped out R r) { r = default; } + static R F0(R r0) + { + scoped R l0 = r0; + return l0; // 1 + } + static R F1(scoped R r1) + { + scoped R l1 = r1; + return l1; // 2 + } + static R F2(ref R r2) + { + scoped R l2 = r2; + return l2; // 3 + } + static R F3(scoped ref R r3) + { + scoped R l3 = r3; + return l3; // 4 + } }"; var comp = CreateCompilation(source); - comp.VerifyEmitDiagnostics( - // (4,27): error CS1107: A parameter can only have one 'scoped' modifier - // static void F0(scoped scoped R r) { } - Diagnostic(ErrorCode.ERR_DupParamMod, "scoped").WithArguments("scoped").WithLocation(4, 27), - // (5,31): error CS1107: A parameter can only have one 'scoped' modifier - // static void F1(ref scoped scoped R r) { } - Diagnostic(ErrorCode.ERR_DupParamMod, "scoped").WithArguments("scoped").WithLocation(5, 31), - // (7,27): error CS1107: A parameter can only have one 'scoped' modifier - // static void F3(scoped scoped ref R r) { } - Diagnostic(ErrorCode.ERR_DupParamMod, "scoped").WithArguments("scoped").WithLocation(7, 27), - // (8,30): error CS1107: A parameter can only have one 'scoped' modifier - // static void F4(in scoped scoped R r) { } - Diagnostic(ErrorCode.ERR_DupParamMod, "scoped").WithArguments("scoped").WithLocation(8, 30), - // (10,27): error CS1107: A parameter can only have one 'scoped' modifier - // static void F6(scoped scoped in R r) { } - Diagnostic(ErrorCode.ERR_DupParamMod, "scoped").WithArguments("scoped").WithLocation(10, 27), - // (11,31): error CS1107: A parameter can only have one 'scoped' modifier - // static void F7(out scoped scoped R r) { r = default; } - Diagnostic(ErrorCode.ERR_DupParamMod, "scoped").WithArguments("scoped").WithLocation(11, 31), - // (13,27): error CS1107: A parameter can only have one 'scoped' modifier - // static void F9(scoped scoped out R r) { r = default; } - Diagnostic(ErrorCode.ERR_DupParamMod, "scoped").WithArguments("scoped").WithLocation(13, 27)); - - VerifyParameterSymbol(comp.GetMember("Program.F0").Parameters[0], "scoped R r", RefKind.None, DeclarationScope.ValueScoped); - VerifyParameterSymbol(comp.GetMember("Program.F1").Parameters[0], "ref scoped R r", RefKind.Ref, DeclarationScope.ValueScoped); - VerifyParameterSymbol(comp.GetMember("Program.F2").Parameters[0], "ref scoped R r", RefKind.Ref, DeclarationScope.ValueScoped); - VerifyParameterSymbol(comp.GetMember("Program.F3").Parameters[0], "scoped ref R r", RefKind.Ref, DeclarationScope.RefScoped); - VerifyParameterSymbol(comp.GetMember("Program.F4").Parameters[0], "in scoped R r", RefKind.In, DeclarationScope.ValueScoped); - VerifyParameterSymbol(comp.GetMember("Program.F5").Parameters[0], "in scoped R r", RefKind.In, DeclarationScope.ValueScoped); - VerifyParameterSymbol(comp.GetMember("Program.F6").Parameters[0], "scoped in R r", RefKind.In, DeclarationScope.RefScoped); - VerifyParameterSymbol(comp.GetMember("Program.F7").Parameters[0], "out scoped R r", RefKind.Out, DeclarationScope.ValueScoped); - VerifyParameterSymbol(comp.GetMember("Program.F8").Parameters[0], "out scoped R r", RefKind.Out, DeclarationScope.ValueScoped); - VerifyParameterSymbol(comp.GetMember("Program.F9").Parameters[0], "out R r", RefKind.Out, DeclarationScope.RefScoped); + comp.VerifyDiagnostics( + // (7,16): error CS8352: Cannot use variable 'l0' in this context because it may expose referenced variables outside of their declaration scope + // return l0; // 1 + Diagnostic(ErrorCode.ERR_EscapeVariable, "l0").WithArguments("l0").WithLocation(7, 16), + // (12,16): error CS8352: Cannot use variable 'l1' in this context because it may expose referenced variables outside of their declaration scope + // return l1; // 2 + Diagnostic(ErrorCode.ERR_EscapeVariable, "l1").WithArguments("l1").WithLocation(12, 16), + // (17,16): error CS8352: Cannot use variable 'l2' in this context because it may expose referenced variables outside of their declaration scope + // return l2; // 3 + Diagnostic(ErrorCode.ERR_EscapeVariable, "l2").WithArguments("l2").WithLocation(17, 16), + // (22,16): error CS8352: Cannot use variable 'l3' in this context because it may expose referenced variables outside of their declaration scope + // return l3; // 4 + Diagnostic(ErrorCode.ERR_EscapeVariable, "l3").WithArguments("l3").WithLocation(22, 16)); } [Fact] - public void ParameterScope_08() + public void RefSafeToEscape_03() { var source = -@"ref struct R { } +@"ref struct R { } class Program { - static void Main() + static ref R F0(R r0) { - var f1 = (scoped scoped R r) => { }; - var f2 = (ref scoped scoped R r) => { }; - var f3 = (scoped scoped ref R r) => { }; + scoped R l0 = r0; + return ref l0; // 1 + } + static ref R F1(scoped R r1) + { + scoped R l1 = r1; + return ref l1; // 2 + } + static ref R F2(ref R r2) + { + scoped R l2 = r2; + return ref l2; // 3 + } + static ref R F3(scoped ref R r3) + { + scoped R l3 = r3; + return ref l3; // 4 } }"; var comp = CreateCompilation(source); - comp.VerifyEmitDiagnostics( - // (6,26): error CS1107: A parameter can only have one 'scoped' modifier - // var f1 = (scoped scoped R r) => { }; - Diagnostic(ErrorCode.ERR_DupParamMod, "scoped").WithArguments("scoped").WithLocation(6, 26), - // (7,30): error CS1107: A parameter can only have one 'scoped' modifier - // var f2 = (ref scoped scoped R r) => { }; - Diagnostic(ErrorCode.ERR_DupParamMod, "scoped").WithArguments("scoped").WithLocation(7, 30), - // (8,26): error CS1107: A parameter can only have one 'scoped' modifier - // var f3 = (scoped scoped ref R r) => { }; - Diagnostic(ErrorCode.ERR_DupParamMod, "scoped").WithArguments("scoped").WithLocation(8, 26)); + comp.VerifyDiagnostics( + // (7,20): error CS8168: Cannot return local 'l0' by reference because it is not a ref local + // return ref l0; // 1 + Diagnostic(ErrorCode.ERR_RefReturnLocal, "l0").WithArguments("l0").WithLocation(7, 20), + // (12,20): error CS8168: Cannot return local 'l1' by reference because it is not a ref local + // return ref l1; // 2 + Diagnostic(ErrorCode.ERR_RefReturnLocal, "l1").WithArguments("l1").WithLocation(12, 20), + // (17,20): error CS8168: Cannot return local 'l2' by reference because it is not a ref local + // return ref l2; // 3 + Diagnostic(ErrorCode.ERR_RefReturnLocal, "l2").WithArguments("l2").WithLocation(17, 20), + // (22,20): error CS8168: Cannot return local 'l3' by reference because it is not a ref local + // return ref l3; // 4 + Diagnostic(ErrorCode.ERR_RefReturnLocal, "l3").WithArguments("l3").WithLocation(22, 20)); } [Fact] - public void ParameterScope_09() + public void SafeToEscape_04() { var source = -@"ref struct scoped { } +@"ref struct R { } class Program { - static void F0(scoped s) { } - static void F1(scoped scoped s) { } - static void F2(ref scoped s) { } - static void F3(ref scoped scoped s) { } - static void F4(scoped ref scoped s) { } - static void F5(in scoped s) { } - static void F6(in scoped scoped s) { } - static void F7(scoped in scoped s) { } - static void F8(out scoped s) { s = default; } - static void F9(out scoped scoped s) { s = default; } - static void FA(scoped out scoped s) { s = default; } + static R F0(R r0) + { + ref R l0 = ref r0; + return l0; + } + static R F1(scoped R r1) + { + ref R l1 = ref r1; + return l1; // 1 + } + static R F2(ref R r2) + { + ref R l2 = ref r2; + return l2; + } + static R F3(scoped ref R r3) + { + ref R l3 = ref r3; + return l3; + } }"; var comp = CreateCompilation(source); - comp.VerifyEmitDiagnostics( - // (1,12): warning CS8981: The type name 'scoped' only contains lower-cased ascii characters. Such names may become reserved for the language. - // ref struct scoped { } - Diagnostic(ErrorCode.WRN_LowerCaseTypeName, "scoped").WithArguments("scoped").WithLocation(1, 12)); - - VerifyParameterSymbol(comp.GetMember("Program.F0").Parameters[0], "scoped s", RefKind.None, DeclarationScope.Unscoped); - VerifyParameterSymbol(comp.GetMember("Program.F1").Parameters[0], "scoped scoped s", RefKind.None, DeclarationScope.ValueScoped); - VerifyParameterSymbol(comp.GetMember("Program.F2").Parameters[0], "ref scoped s", RefKind.Ref, DeclarationScope.Unscoped); - VerifyParameterSymbol(comp.GetMember("Program.F3").Parameters[0], "ref scoped scoped s", RefKind.Ref, DeclarationScope.ValueScoped); - VerifyParameterSymbol(comp.GetMember("Program.F4").Parameters[0], "scoped ref scoped s", RefKind.Ref, DeclarationScope.RefScoped); - VerifyParameterSymbol(comp.GetMember("Program.F5").Parameters[0], "in scoped s", RefKind.In, DeclarationScope.Unscoped); - VerifyParameterSymbol(comp.GetMember("Program.F6").Parameters[0], "in scoped scoped s", RefKind.In, DeclarationScope.ValueScoped); - VerifyParameterSymbol(comp.GetMember("Program.F7").Parameters[0], "scoped in scoped s", RefKind.In, DeclarationScope.RefScoped); - VerifyParameterSymbol(comp.GetMember("Program.F8").Parameters[0], "out scoped s", RefKind.Out, DeclarationScope.RefScoped); - VerifyParameterSymbol(comp.GetMember("Program.F9").Parameters[0], "out scoped scoped s", RefKind.Out, DeclarationScope.ValueScoped); - VerifyParameterSymbol(comp.GetMember("Program.FA").Parameters[0], "out scoped s", RefKind.Out, DeclarationScope.RefScoped); + comp.VerifyDiagnostics( + // (12,16): error CS8352: Cannot use variable 'l1' in this context because it may expose referenced variables outside of their declaration scope + // return l1; // 1 + Diagnostic(ErrorCode.ERR_EscapeVariable, "l1").WithArguments("l1").WithLocation(12, 16)); } [Fact] - public void ParameterScope_10() + public void RefSafeToEscape_04() { - var source0 = -@".class private System.Runtime.CompilerServices.LifetimeAnnotationAttribute extends [mscorlib]System.Attribute -{ - .method public hidebysig specialname rtspecialname instance void .ctor(bool isRefScoped, bool isValueScoped) cil managed { ret } -} -.class public sealed R extends [mscorlib]System.ValueType -{ - .custom instance void [mscorlib]System.Runtime.CompilerServices.IsByRefLikeAttribute::.ctor() = (01 00 00 00) - .field public int32& modreq(int32) F -} -.class public A -{ - .method public static void F(valuetype R r) - { - .param [1] - .custom instance void System.Runtime.CompilerServices.LifetimeAnnotationAttribute::.ctor(bool, bool) = ( 01 00 00 00 00 00 ) // LifetimeAnnotationAttribute(isRefScoped: false, isValueScoped: false) - ret - } -} -"; - var ref0 = CompileIL(source0); - - var source1 = -@"class Program + var source = +@"ref struct R { } +class Program { - static void Main() + static ref R F0(R r0) { - var r = new R(); - A.F(r); + ref R l0 = ref r0; + return ref l0; // 1 + } + static ref R F1(scoped R r1) + { + ref R l1 = ref r1; + return ref l1; // 2 + } + static ref R F2(ref R r2) + { + ref R l2 = ref r2; + return ref l2; // 3 + } + static ref R F3(scoped ref R r3) + { + ref R l3 = ref r3; + return ref l3; // 4 } }"; - var comp = CreateCompilation(source1, references: new[] { ref0 }); - comp.VerifyDiagnostics(); + var comp = CreateCompilation(source); + comp.VerifyDiagnostics( + // (7,20): error CS8157: Cannot return 'l0' by reference because it was initialized to a value that cannot be returned by reference + // return ref l0; // 1 + Diagnostic(ErrorCode.ERR_RefReturnNonreturnableLocal, "l0").WithArguments("l0").WithLocation(7, 20), + // (12,20): error CS8157: Cannot return 'l1' by reference because it was initialized to a value that cannot be returned by reference + // return ref l1; // 2 + Diagnostic(ErrorCode.ERR_RefReturnNonreturnableLocal, "l1").WithArguments("l1").WithLocation(12, 20), + // (17,20): error CS8157: Cannot return 'l2' by reference because it was initialized to a value that cannot be returned by reference + // return ref l2; // 3 + Diagnostic(ErrorCode.ERR_RefReturnNonreturnableLocal, "l2").WithArguments("l2").WithLocation(17, 20), + // (22,20): error CS8157: Cannot return 'l3' by reference because it was initialized to a value that cannot be returned by reference + // return ref l3; // 4 + Diagnostic(ErrorCode.ERR_RefReturnNonreturnableLocal, "l3").WithArguments("l3").WithLocation(22, 20)); - var method = comp.GetMember("A.F"); - VerifyParameterSymbol(method.Parameters[0], "R r", RefKind.None, DeclarationScope.Unscoped); + // https://github.com/dotnet/roslyn/issues/62780: Test additional cases with [UnscopedRef]. } - [WorkItem(62080, "https://github.com/dotnet/roslyn/issues/62080")] [Fact] - public void ParameterScope_11() + public void SafeToEscape_05() { var source = -@"ref struct R { } -delegate R D1(R r); -delegate R D2(scoped R r); +@"ref struct R { } class Program { - static void Main() + static R F0(R r0) { - D1 d1 = r1 => r1; - D2 d2 = r2 => r2; + scoped ref R l0 = ref r0; + return l0; + } + static R F1(scoped R r1) + { + scoped ref R l1 = ref r1; // 1 + return l1; + } + static R F2(ref R r2) + { + scoped ref R l2 = ref r2; + return l2; } }"; var comp = CreateCompilation(source); - // https://github.com/dotnet/roslyn/issues/62080: Lambda parameter r2 should be inferred as 'scoped R' rather than 'R'. - comp.VerifyEmitDiagnostics( - // (9,17): error CS8986: The 'scoped' modifier of parameter 'r2' doesn't match target 'D2'. - // D2 d2 = r2 => r2; - Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfTarget, "r2 => r2").WithArguments("r2", "D2").WithLocation(9, 17)); - - var tree = comp.SyntaxTrees[0]; - var model = comp.GetSemanticModel(tree); - var lambdas = tree.GetRoot().DescendantNodes().OfType().Select(e => model.GetSymbolInfo(e).Symbol.GetSymbol()).ToArray(); - - VerifyParameterSymbol(lambdas[0].Parameters[0], "R r1", RefKind.None, DeclarationScope.Unscoped); - VerifyParameterSymbol(lambdas[1].Parameters[0], "R r2", RefKind.None, DeclarationScope.Unscoped); + comp.VerifyDiagnostics( + // (11,36): error CS8352: Cannot use variable 'R' in this context because it may expose referenced variables outside of their declaration scope + // scoped ref R l1 = ref r1; // 1 + Diagnostic(ErrorCode.ERR_EscapeVariable, "r1").WithArguments("R").WithLocation(11, 36)); } [Fact] - public void ParameterScope_12() + public void RefSafeToEscape_05() { - var source0 = -@".class private System.Runtime.CompilerServices.LifetimeAnnotationAttribute extends [mscorlib]System.Attribute -{ - .method public hidebysig specialname rtspecialname instance void .ctor(bool isRefScoped, bool isValueScoped) cil managed { ret } -} -.class public A -{ - .method public static void F1([out] int32& i) - { - .param [1] - .custom instance void System.Runtime.CompilerServices.LifetimeAnnotationAttribute::.ctor(bool, bool) = ( 01 00 01 00 00 00 ) // LifetimeAnnotationAttribute(isRefScoped: true, isValueScoped: false) - ldnull - throw - } - .method public static void F2([out] int32& i) - { - .param [1] - .custom instance void System.Runtime.CompilerServices.LifetimeAnnotationAttribute::.ctor(bool, bool) = ( 01 00 00 00 00 00 ) // LifetimeAnnotationAttribute(isRefScoped: false, isValueScoped: false) - ldnull - throw - } -} -"; - var ref0 = CompileIL(source0); - - var source1 = -@"class Program + var source = +@"ref struct R { } +class Program { - static void Main() + static ref R F0(R r0) { - int i; - A.F1(out i); - A.F2(out i); + scoped ref R l0 = ref r0; + return ref l0; // 1 + } + static ref R F1(scoped R r1) + { + scoped ref R l1 = ref r1; // 2 + return ref l1; // 3 + } + static ref R F2(ref R r2) + { + scoped ref R l2 = ref r2; + return ref l2; // 4 + } + static ref R F3(scoped ref R r3) + { + scoped ref R l3 = ref r3; + return ref l3; // 5 } }"; - var comp = CreateCompilation(source1, references: new[] { ref0 }); - comp.VerifyDiagnostics(); - - VerifyParameterSymbol(comp.GetMember("A.F1").Parameters[0], "out System.Int32 i", RefKind.Out, DeclarationScope.RefScoped); - VerifyParameterSymbol(comp.GetMember("A.F2").Parameters[0], "out System.Int32 i", RefKind.Out, DeclarationScope.Unscoped); + var comp = CreateCompilation(source); + comp.VerifyDiagnostics( + // (7,20): error CS8157: Cannot return 'l0' by reference because it was initialized to a value that cannot be returned by reference + // return ref l0; // 1 + Diagnostic(ErrorCode.ERR_RefReturnNonreturnableLocal, "l0").WithArguments("l0").WithLocation(7, 20), + // (11,36): error CS8352: Cannot use variable 'R' in this context because it may expose referenced variables outside of their declaration scope + // scoped ref R l1 = ref r1; // 2 + Diagnostic(ErrorCode.ERR_EscapeVariable, "r1").WithArguments("R").WithLocation(11, 36), + // (12,20): error CS8157: Cannot return 'l1' by reference because it was initialized to a value that cannot be returned by reference + // return ref l1; // 3 + Diagnostic(ErrorCode.ERR_RefReturnNonreturnableLocal, "l1").WithArguments("l1").WithLocation(12, 20), + // (17,20): error CS8157: Cannot return 'l2' by reference because it was initialized to a value that cannot be returned by reference + // return ref l2; // 4 + Diagnostic(ErrorCode.ERR_RefReturnNonreturnableLocal, "l2").WithArguments("l2").WithLocation(17, 20), + // (22,20): error CS8157: Cannot return 'l3' by reference because it was initialized to a value that cannot be returned by reference + // return ref l3; // 5 + Diagnostic(ErrorCode.ERR_RefReturnNonreturnableLocal, "l3").WithArguments("l3").WithLocation(22, 20)); } [Fact] - public void ThisScope() + public void ReturnValueField_01() { var source = -@"class C -{ - public C() { } - void F1() { } -} -struct S1 -{ - public S1() { } - void F1() { } - readonly void F2() { } -} -ref struct R1 -{ - public R1() { } - void F1() { } - readonly void F2() { } -} -readonly struct S2 -{ - public S2() { } - void F1() { } - readonly void F2() { } -} -readonly ref struct R2 +@"ref struct R { - public R2() { } - void F1() { } - readonly void F2() { } + public T F; + public T GetValue() => F; + public ref T GetRef() => ref F; // 1 + public ref readonly T GetRefReadonly() => ref F; // 2 }"; var comp = CreateCompilation(source); - comp.VerifyEmitDiagnostics(); - - VerifyParameterSymbol(comp.GetMember("C..ctor").ThisParameter, "C this", RefKind.None, DeclarationScope.Unscoped); - VerifyParameterSymbol(comp.GetMember("C.F1").ThisParameter, "C this", RefKind.None, DeclarationScope.Unscoped); - VerifyParameterSymbol(comp.GetMember("S1..ctor").ThisParameter, "out S1 this", RefKind.Out, DeclarationScope.RefScoped); - VerifyParameterSymbol(comp.GetMember("S1.F1").ThisParameter, "scoped ref S1 this", RefKind.Ref, DeclarationScope.RefScoped); - VerifyParameterSymbol(comp.GetMember("S1.F2").ThisParameter, "scoped in S1 this", RefKind.In, DeclarationScope.RefScoped); - VerifyParameterSymbol(comp.GetMember("R1..ctor").ThisParameter, "out R1 this", RefKind.Out, DeclarationScope.RefScoped); - VerifyParameterSymbol(comp.GetMember("R1.F1").ThisParameter, "scoped ref R1 this", RefKind.Ref, DeclarationScope.RefScoped); - VerifyParameterSymbol(comp.GetMember("R1.F2").ThisParameter, "scoped in R1 this", RefKind.In, DeclarationScope.RefScoped); - VerifyParameterSymbol(comp.GetMember("S2..ctor").ThisParameter, "out S2 this", RefKind.Out, DeclarationScope.RefScoped); - VerifyParameterSymbol(comp.GetMember("S2.F1").ThisParameter, "scoped in S2 this", RefKind.In, DeclarationScope.RefScoped); - VerifyParameterSymbol(comp.GetMember("S2.F2").ThisParameter, "scoped in S2 this", RefKind.In, DeclarationScope.RefScoped); - VerifyParameterSymbol(comp.GetMember("R2..ctor").ThisParameter, "out R2 this", RefKind.Out, DeclarationScope.RefScoped); - VerifyParameterSymbol(comp.GetMember("R2.F1").ThisParameter, "scoped in R2 this", RefKind.In, DeclarationScope.RefScoped); - VerifyParameterSymbol(comp.GetMember("R2.F2").ThisParameter, "scoped in R2 this", RefKind.In, DeclarationScope.RefScoped); + comp.VerifyDiagnostics( + // (5,34): error CS8170: Struct members cannot return 'this' or other instance members by reference + // public ref T GetRef() => ref F; // 1 + Diagnostic(ErrorCode.ERR_RefReturnStructThis, "F").WithLocation(5, 34), + // (6,51): error CS8170: Struct members cannot return 'this' or other instance members by reference + // public ref readonly T GetRefReadonly() => ref F; // 2 + Diagnostic(ErrorCode.ERR_RefReturnStructThis, "F").WithLocation(6, 51)); } [Fact] - public void ExtensionThisScope() + public void ReturnValueField_02() { var source = -@"ref struct R { } -static class Extensions +@"struct S { - static void F0(this R r) { } - static void F1(this scoped R r) { } - static void F2(scoped this R r) { } - static void F3(this scoped ref T t) where T : struct { } - static void F4(this ref scoped R r) { } + public T F; + public T GetValue() => F; + public ref T GetRef() => ref F; // 1 + public ref readonly T GetRefReadonly() => ref F; // 2 }"; var comp = CreateCompilation(source); - comp.VerifyEmitDiagnostics(); - - VerifyParameterSymbol(comp.GetMember("Extensions.F0").Parameters[0], "R r", RefKind.None, DeclarationScope.Unscoped); - VerifyParameterSymbol(comp.GetMember("Extensions.F1").Parameters[0], "scoped R r", RefKind.None, DeclarationScope.ValueScoped); - VerifyParameterSymbol(comp.GetMember("Extensions.F2").Parameters[0], "scoped R r", RefKind.None, DeclarationScope.ValueScoped); - VerifyParameterSymbol(comp.GetMember("Extensions.F3").Parameters[0], "scoped ref T t", RefKind.Ref, DeclarationScope.RefScoped); - VerifyParameterSymbol(comp.GetMember("Extensions.F4").Parameters[0], "ref scoped R r", RefKind.Ref, DeclarationScope.ValueScoped); + comp.VerifyDiagnostics( + // (5,34): error CS8170: Struct members cannot return 'this' or other instance members by reference + // public ref T GetRef() => ref F; // 1 + Diagnostic(ErrorCode.ERR_RefReturnStructThis, "F").WithLocation(5, 34), + // (6,51): error CS8170: Struct members cannot return 'this' or other instance members by reference + // public ref readonly T GetRefReadonly() => ref F; // 2 + Diagnostic(ErrorCode.ERR_RefReturnStructThis, "F").WithLocation(6, 51)); } [Fact] - public void ParamsScope() + public void ReturnRefField() { var source = -@"class Program +@"ref struct R { - static void F1(scoped params object[] args) { } - static void F2(params scoped object[] args) { } + public ref T F; + public T GetValue() => F; + public ref T GetRef() => ref F; + public ref readonly T GetRefReadonly() => ref F; }"; - var comp = CreateCompilation(source); - comp.VerifyEmitDiagnostics( - // (3,20): error CS8986: The 'scoped' modifier can be used for refs and ref struct values only. - // static void F1(scoped params object[] args) { } - Diagnostic(ErrorCode.ERR_ScopedRefAndRefStructOnly, "scoped params object[] args").WithLocation(3, 20), - // (4,20): error CS8986: The 'scoped' modifier can be used for refs and ref struct values only. - // static void F2(params scoped object[] args) { } - Diagnostic(ErrorCode.ERR_ScopedRefAndRefStructOnly, "params scoped object[] args").WithLocation(4, 20)); + var comp = CreateCompilation(source, runtimeFeature: RuntimeFlag.ByRefFields); + comp.VerifyDiagnostics(); + } - VerifyParameterSymbol(comp.GetMember("Program.F1").Parameters[0], "scoped params System.Object[] args", RefKind.None, DeclarationScope.ValueScoped); - VerifyParameterSymbol(comp.GetMember("Program.F2").Parameters[0], "scoped params System.Object[] args", RefKind.None, DeclarationScope.ValueScoped); + [Fact] + public void ReturnRefReadonlyField() + { + var source = +@"ref struct R +{ + public ref readonly T F; + public T GetValue() => F; + public ref T GetRef() => ref F; // 1 + public ref readonly T GetRefReadonly() => ref F; +}"; + var comp = CreateCompilation(source, runtimeFeature: RuntimeFlag.ByRefFields); + comp.VerifyDiagnostics( + // (5,34): error CS8333: Cannot return field 'R.F' by writable reference because it is a readonly variable + // public ref T GetRef() => ref F; // 1 + Diagnostic(ErrorCode.ERR_RefReturnReadonlyNotField, "F").WithArguments("field", "R.F").WithLocation(5, 34)); } - [Theory] - [InlineData(LanguageVersion.CSharp10)] - [InlineData(LanguageVersionFacts.CSharpNext)] - public void ReturnTypeScope(LanguageVersion langVersion) + [Fact] + public void ReturnValueFieldByValue() { var source = -@"ref struct R { } +@"#pragma warning disable 649 +ref struct R +{ + public T F; +} class Program { - static scoped R F1() => throw null; - static scoped ref R F2() => throw null; - static ref scoped R F3() => throw null; - static void Main() - { -#pragma warning disable 8321 - static scoped R L1() => throw null; - static scoped ref readonly R L2() => throw null; - static ref readonly scoped R L3() => throw null; - } + static T F0(R r0) => r0.F; + static T F1(scoped R r1) => r1.F; + static T F2(ref R r2) => r2.F; + static T F3(scoped ref R r3) => r3.F; }"; - var comp = CreateCompilation(source, parseOptions: TestOptions.Regular.WithLanguageVersion(langVersion)); - comp.VerifyDiagnostics( - // (4,21): error CS0106: The modifier 'scoped' is not valid for this item - // static scoped R F1() => throw null; - Diagnostic(ErrorCode.ERR_BadMemberFlag, "F1").WithArguments("scoped").WithLocation(4, 21), - // (5,25): error CS0106: The modifier 'scoped' is not valid for this item - // static scoped ref R F2() => throw null; - Diagnostic(ErrorCode.ERR_BadMemberFlag, "F2").WithArguments("scoped").WithLocation(5, 25), - // (6,16): error CS0106: The modifier 'scoped' is not valid for this item - // static ref scoped R F3() => throw null; - Diagnostic(ErrorCode.ERR_BadMemberFlag, "scoped").WithArguments("scoped").WithLocation(6, 16), - // (10,16): error CS0106: The modifier 'scoped' is not valid for this item - // static scoped R L1() => throw null; - Diagnostic(ErrorCode.ERR_BadMemberFlag, "scoped").WithArguments("scoped").WithLocation(10, 16), - // (11,16): error CS0106: The modifier 'scoped' is not valid for this item - // static scoped ref readonly R L2() => throw null; - Diagnostic(ErrorCode.ERR_BadMemberFlag, "scoped").WithArguments("scoped").WithLocation(11, 16), - // (12,29): error CS0106: The modifier 'scoped' is not valid for this item - // static ref readonly scoped R L3() => throw null; - Diagnostic(ErrorCode.ERR_BadMemberFlag, "scoped").WithArguments("scoped").WithLocation(12, 29)); + var comp = CreateCompilation(source); + comp.VerifyDiagnostics(); } - [Theory] - [InlineData(LanguageVersion.CSharp10)] - [InlineData(LanguageVersionFacts.CSharpNext)] - public void DelegateReturnTypeScope(LanguageVersion langVersion) + [Fact] + public void ReturnValueFieldByRef() { var source = -@"ref struct R { } -delegate ref scoped R D(); -"; - var comp = CreateCompilation(source, parseOptions: TestOptions.Regular.WithLanguageVersion(langVersion)); - comp.VerifyEmitDiagnostics( - // (2,14): error CS0106: The modifier 'scoped' is not valid for this item - // delegate ref scoped R D(); - Diagnostic(ErrorCode.ERR_BadMemberFlag, "scoped").WithArguments("scoped").WithLocation(2, 14)); +@"ref struct R +{ + public T F; +} +class Program +{ + static ref T F0(R r0) => ref r0.F; // 1 + static ref T F1(scoped R r1) => ref r1.F; // 2 + static ref T F2(ref R r2) => ref r2.F; + static ref T F3(scoped ref R r3) => ref r3.F; // 3 +}"; + var comp = CreateCompilation(source); + comp.VerifyDiagnostics( + // (7,40): error CS8167: Cannot return by reference a member of parameter 'r0' because it is not a ref or out parameter + // static ref T F0(R r0) => ref r0.F; // 1 + Diagnostic(ErrorCode.ERR_RefReturnParameter2, "r0").WithArguments("r0").WithLocation(7, 40), + // (8,47): error CS8167: Cannot return by reference a member of parameter 'r1' because it is not a ref or out parameter + // static ref T F1(scoped R r1) => ref r1.F; // 2 + Diagnostic(ErrorCode.ERR_RefReturnParameter2, "r1").WithArguments("r1").WithLocation(8, 47), + // (9,44): error CS8167: Cannot return by reference a member of parameter 'r2' because it is not a ref or out parameter + // static ref T F2(ref R r2) => ref r2.F; + Diagnostic(ErrorCode.ERR_RefReturnParameter2, "r2").WithArguments("r2").WithLocation(9, 44), + // (10,51): error CS8167: Cannot return by reference a member of parameter 'r3' because it is not a ref or out parameter + // static ref T F3(scoped ref R r3) => ref r3.F; // 3 + Diagnostic(ErrorCode.ERR_RefReturnParameter2, "r3").WithArguments("r3").WithLocation(10, 51)); + + // https://github.com/dotnet/roslyn/issues/62780: Test additional cases with [UnscopedRef]. } [Theory] - [InlineData(LanguageVersion.CSharp10)] - [InlineData(LanguageVersionFacts.CSharpNext)] - public void TypeScopeModifier_01(LanguageVersion langVersion) + [InlineData("ref ")] + [InlineData("ref readonly")] + public void ReturnRefFieldByValue(string refOrRefReadonly) { var source = -@"scoped struct A { } -scoped ref struct B { } -scoped readonly ref struct C { } -"; - var comp = CreateCompilation(source, parseOptions: TestOptions.Regular.WithLanguageVersion(langVersion)); - comp.VerifyDiagnostics( - // (1,15): error CS0106: The modifier 'scoped' is not valid for this item - // scoped struct A { } - Diagnostic(ErrorCode.ERR_BadMemberFlag, "A").WithArguments("scoped").WithLocation(1, 15), - // (2,19): error CS0106: The modifier 'scoped' is not valid for this item - // scoped ref struct B { } - Diagnostic(ErrorCode.ERR_BadMemberFlag, "B").WithArguments("scoped").WithLocation(2, 19), - // (3,28): error CS0106: The modifier 'scoped' is not valid for this item - // scoped readonly ref struct C { } - Diagnostic(ErrorCode.ERR_BadMemberFlag, "C").WithArguments("scoped").WithLocation(3, 28)); +$@"ref struct R +{{ + public {refOrRefReadonly} T F; + public R(ref T t) {{ F = ref t; }} +}} +class Program +{{ + static T F0(R r) => r.F; + static T F1(ref R r) => r.F; + static T F2(out R r) {{ r = default; return r.F; }} + static T F3(in R r) => r.F; + static T F4(scoped R r) => r.F; + static T F5(scoped ref R r) => r.F; + static T F6(scoped out R r) {{ r = default; return r.F; }} + static T F7(scoped in R r) => r.F; +}}"; + var comp = CreateCompilation(source, runtimeFeature: RuntimeFlag.ByRefFields); + comp.VerifyDiagnostics(); } [Theory] - [InlineData(LanguageVersion.CSharp10)] - [InlineData(LanguageVersionFacts.CSharpNext)] - public void TypeScopeModifier_02(LanguageVersion langVersion) + [InlineData("ref ")] + [InlineData("ref readonly")] + public void ReturnRefFieldByRef_01(string refOrRefReadonly) { var source = -@"scoped record A { } -scoped readonly record struct B; -readonly scoped record struct C(); -"; - var comp = CreateCompilation(source, parseOptions: TestOptions.Regular.WithLanguageVersion(langVersion)); - comp.VerifyDiagnostics( - // (1,15): error CS0106: The modifier 'scoped' is not valid for this item - // scoped record A { } - Diagnostic(ErrorCode.ERR_BadMemberFlag, "A").WithArguments("scoped").WithLocation(1, 15), - // (2,31): error CS0106: The modifier 'scoped' is not valid for this item - // scoped readonly record struct B; - Diagnostic(ErrorCode.ERR_BadMemberFlag, "B").WithArguments("scoped").WithLocation(2, 31), - // (3,31): error CS0106: The modifier 'scoped' is not valid for this item - // readonly scoped record struct C(); - Diagnostic(ErrorCode.ERR_BadMemberFlag, "C").WithArguments("scoped").WithLocation(3, 31)); +$@"ref struct R +{{ + public {refOrRefReadonly} T F; + public R(ref T t) {{ F = ref t; }} +}} +class Program +{{ + static {refOrRefReadonly} T F0(R r) => ref r.F; + static {refOrRefReadonly} T F1(ref R r) => ref r.F; + static {refOrRefReadonly} T F2(out R r) {{ r = default; return ref r.F; }} + static {refOrRefReadonly} T F3(in R r) => ref r.F; + static {refOrRefReadonly} T F4(scoped R r) => ref r.F; // 1 + static {refOrRefReadonly} T F5(scoped ref R r) => ref r.F; + static {refOrRefReadonly} T F6(scoped out R r) {{ r = default; return ref r.F; }} + static {refOrRefReadonly} T F7(scoped in R r) => ref r.F; +}}"; + var comp = CreateCompilation(source, runtimeFeature: RuntimeFlag.ByRefFields); + comp.VerifyDiagnostics( + // (12,55): error CS8352: Cannot use variable 'R' in this context because it may expose referenced variables outside of their declaration scope + // static ref T F4(scoped R r) => ref r.F; // 1 + Diagnostic(ErrorCode.ERR_EscapeVariable, "r.F").WithArguments("R").WithLocation(12, 55)); } [Fact] - public void FieldTypeScope() + public void ReturnRefFieldByRef_02() { var source = -@"#pragma warning disable 169 -ref struct R1 { } -ref struct R2 +@"ref struct R { - scoped R1 F1; - ref scoped R1 F2; - scoped ref int F3; + public ref readonly T F; + public R(ref T t) { F = ref t; } +} +class Program +{ + static ref readonly T F1(scoped ref T t) + { + R r1 = new R(ref t); + return ref r1.F; // 1 + } + static ref readonly T F2(scoped ref T t) + { + R r2; + r2 = new R(ref t); // 2 + return ref r2.F; + } }"; - - var comp = CreateCompilation(source, parseOptions: TestOptions.Regular10); - comp.VerifyDiagnostics( - // (5,15): error CS0106: The modifier 'scoped' is not valid for this item - // scoped R1 F1; - Diagnostic(ErrorCode.ERR_BadMemberFlag, "F1").WithArguments("scoped").WithLocation(5, 15), - // (6,5): error CS8652: The feature 'ref fields' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. - // ref scoped R1 F2; - Diagnostic(ErrorCode.ERR_FeatureInPreview, "ref scoped R1").WithArguments("ref fields").WithLocation(6, 5), - // (6,5): error CS9050: A ref field cannot refer to a ref struct. - // ref scoped R1 F2; - Diagnostic(ErrorCode.ERR_RefFieldCannotReferToRefStruct, "ref scoped R1").WithLocation(6, 5), - // (6,9): error CS0106: The modifier 'scoped' is not valid for this item - // ref scoped R1 F2; - Diagnostic(ErrorCode.ERR_BadMemberFlag, "scoped").WithArguments("scoped").WithLocation(6, 9), - // (7,12): error CS8652: The feature 'ref fields' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. - // scoped ref int F3; - Diagnostic(ErrorCode.ERR_FeatureInPreview, "ref int").WithArguments("ref fields").WithLocation(7, 12), - // (7,20): error CS0106: The modifier 'scoped' is not valid for this item - // scoped ref int F3; - Diagnostic(ErrorCode.ERR_BadMemberFlag, "F3").WithArguments("scoped").WithLocation(7, 20)); - - comp = CreateCompilation(source); + var comp = CreateCompilation(source, runtimeFeature: RuntimeFlag.ByRefFields); comp.VerifyDiagnostics( - // (5,15): error CS0106: The modifier 'scoped' is not valid for this item - // scoped R1 F1; - Diagnostic(ErrorCode.ERR_BadMemberFlag, "F1").WithArguments("scoped").WithLocation(5, 15), - // (6,5): error CS9050: A ref field cannot refer to a ref struct. - // ref scoped R1 F2; - Diagnostic(ErrorCode.ERR_RefFieldCannotReferToRefStruct, "ref scoped R1").WithLocation(6, 5), - // (6,9): error CS0106: The modifier 'scoped' is not valid for this item - // ref scoped R1 F2; - Diagnostic(ErrorCode.ERR_BadMemberFlag, "scoped").WithArguments("scoped").WithLocation(6, 9), - // (7,20): error CS0106: The modifier 'scoped' is not valid for this item - // scoped ref int F3; - Diagnostic(ErrorCode.ERR_BadMemberFlag, "F3").WithArguments("scoped").WithLocation(7, 20)); + // (11,20): error CS8352: Cannot use variable 'r1' in this context because it may expose referenced variables outside of their declaration scope + // return ref r1.F; // 1 + Diagnostic(ErrorCode.ERR_EscapeVariable, "r1.F").WithArguments("r1").WithLocation(11, 20), + // (16,14): error CS8347: Cannot use a result of 'R.R(ref T)' in this context because it may expose variables referenced by parameter 't' outside of their declaration scope + // r2 = new R(ref t); // 2 + Diagnostic(ErrorCode.ERR_EscapeCall, "new R(ref t)").WithArguments("R.R(ref T)", "t").WithLocation(16, 14), + // (16,27): error CS8166: Cannot return a parameter by reference 't' because it is not a ref parameter + // r2 = new R(ref t); // 2 + Diagnostic(ErrorCode.ERR_RefReturnParameter, "t").WithArguments("t").WithLocation(16, 27)); } - [Theory] - [InlineData(LanguageVersion.CSharp10)] - [InlineData(LanguageVersionFacts.CSharpNext)] - public void PropertyTypeScope(LanguageVersion langVersion) + [Fact] + public void ReturnRefFieldByRef_03() { var source = -@"ref struct R1 { } -ref struct R2 +@"ref struct R { - scoped R1 P1 { get; } - scoped R1 P2 { get; init; } - scoped R1 P3 { set { } } - ref scoped R1 P4 => throw null; - scoped ref int P5 => throw null; + public ref readonly T F; + public R(in T t) { F = ref t; } +} +class Program +{ + static ref readonly T F1(scoped in T t) + { + R r1 = new R(t); + return ref r1.F; // 1 + } + static ref readonly T F2(scoped in T t) + { + R r2 = new R(in t); + return ref r2.F; // 2 + } }"; - var comp = CreateCompilation(new[] { source, IsExternalInitTypeDefinition }, parseOptions: TestOptions.Regular.WithLanguageVersion(langVersion)); + var comp = CreateCompilation(source, runtimeFeature: RuntimeFlag.ByRefFields); comp.VerifyDiagnostics( - // (4,15): error CS0106: The modifier 'scoped' is not valid for this item - // scoped R1 P1 { get; } - Diagnostic(ErrorCode.ERR_BadMemberFlag, "P1").WithArguments("scoped").WithLocation(4, 15), - // (5,15): error CS0106: The modifier 'scoped' is not valid for this item - // scoped R1 P2 { get; init; } - Diagnostic(ErrorCode.ERR_BadMemberFlag, "P2").WithArguments("scoped").WithLocation(5, 15), - // (6,15): error CS0106: The modifier 'scoped' is not valid for this item - // scoped R1 P3 { set { } } - Diagnostic(ErrorCode.ERR_BadMemberFlag, "P3").WithArguments("scoped").WithLocation(6, 15), - // (7,9): error CS0106: The modifier 'scoped' is not valid for this item - // ref scoped R1 P4 => throw null; - Diagnostic(ErrorCode.ERR_BadMemberFlag, "scoped").WithArguments("scoped").WithLocation(7, 9), - // (8,20): error CS0106: The modifier 'scoped' is not valid for this item - // scoped ref int P5 => throw null; - Diagnostic(ErrorCode.ERR_BadMemberFlag, "P5").WithArguments("scoped").WithLocation(8, 20)); - verify(comp); - - static void verify(CSharpCompilation comp) - { - verifyValueParameter(comp.GetMember("R2.P2"), "R1 value", RefKind.None, DeclarationScope.Unscoped); - verifyValueParameter(comp.GetMember("R2.P3"), "R1 value", RefKind.None, DeclarationScope.Unscoped); - } - - static void verifyValueParameter(PropertySymbol property, string expectedDisplayString, RefKind expectedRefKind, DeclarationScope expectedScope) - { - Assert.Equal(expectedRefKind, property.RefKind); - VerifyParameterSymbol(property.SetMethod.Parameters[0], expectedDisplayString, expectedRefKind, expectedScope); - } + // (11,20): error CS8352: Cannot use variable 'r1' in this context because it may expose referenced variables outside of their declaration scope + // return ref r1.F; // 1 + Diagnostic(ErrorCode.ERR_EscapeVariable, "r1.F").WithArguments("r1").WithLocation(11, 20), + // (16,20): error CS8352: Cannot use variable 'r2' in this context because it may expose referenced variables outside of their declaration scope + // return ref r2.F; // 2 + Diagnostic(ErrorCode.ERR_EscapeVariable, "r2.F").WithArguments("r2").WithLocation(16, 20)); } [Fact] - public void SubstitutedParameter() + public void ReturnRefStructFieldByValue_01() { var source = -@"ref struct R { } -class A +@"ref struct R { - public static void F(scoped R x, scoped in T y) { } + public ref T F; + public R(ref T t) { F = ref t; } } -class B : A +class Program { + static R F1(ref T t) => new R(ref t); + static R F2(out T t, T tValue) { t = tValue; return new R(ref t); } // 1 + static R F3(scoped ref T t) => new R(ref t); // 2 + static R F4(scoped out T t, T tValue) { t = tValue; return new R(ref t); } // 3 }"; - var comp = CreateCompilation(source); - comp.VerifyEmitDiagnostics(); - - var method = (MethodSymbol)comp.GetMember("B").BaseTypeNoUseSiteDiagnostics.GetMember("F"); - VerifyParameterSymbol(method.Parameters[0], "scoped R x", RefKind.None, DeclarationScope.ValueScoped); - VerifyParameterSymbol(method.Parameters[1], "scoped in System.Int32 y", RefKind.In, DeclarationScope.RefScoped); + var comp = CreateCompilation(source, runtimeFeature: RuntimeFlag.ByRefFields); + comp.VerifyDiagnostics( + // (9,63): error CS8347: Cannot use a result of 'R.R(ref T)' in this context because it may expose variables referenced by parameter 't' outside of their declaration scope + // static R F2(out T t, T tValue) { t = tValue; return new R(ref t); } // 1 + Diagnostic(ErrorCode.ERR_EscapeCall, "new R(ref t)").WithArguments("R.R(ref T)", "t").WithLocation(9, 63), + // (9,76): error CS8166: Cannot return a parameter by reference 't' because it is not a ref parameter + // static R F2(out T t, T tValue) { t = tValue; return new R(ref t); } // 1 + Diagnostic(ErrorCode.ERR_RefReturnParameter, "t").WithArguments("t").WithLocation(9, 76), + // (10,42): error CS8347: Cannot use a result of 'R.R(ref T)' in this context because it may expose variables referenced by parameter 't' outside of their declaration scope + // static R F3(scoped ref T t) => new R(ref t); // 2 + Diagnostic(ErrorCode.ERR_EscapeCall, "new R(ref t)").WithArguments("R.R(ref T)", "t").WithLocation(10, 42), + // (10,55): error CS8166: Cannot return a parameter by reference 't' because it is not a ref parameter + // static R F3(scoped ref T t) => new R(ref t); // 2 + Diagnostic(ErrorCode.ERR_RefReturnParameter, "t").WithArguments("t").WithLocation(10, 55), + // (11,70): error CS8347: Cannot use a result of 'R.R(ref T)' in this context because it may expose variables referenced by parameter 't' outside of their declaration scope + // static R F4(scoped out T t, T tValue) { t = tValue; return new R(ref t); } // 3 + Diagnostic(ErrorCode.ERR_EscapeCall, "new R(ref t)").WithArguments("R.R(ref T)", "t").WithLocation(11, 70), + // (11,83): error CS8166: Cannot return a parameter by reference 't' because it is not a ref parameter + // static R F4(scoped out T t, T tValue) { t = tValue; return new R(ref t); } // 3 + Diagnostic(ErrorCode.ERR_RefReturnParameter, "t").WithArguments("t").WithLocation(11, 83)); } [Fact] - public void RetargetingParameter() + public void ReturnRefStructFieldByValue_02() { - var sourceA = -@"public ref struct R { } -public class A + var source = +@"ref struct R0 { - public static void F(scoped R x, scoped in int y) { } + public ref T F0; + public R0(ref T t) { F0 = ref t; } } -"; - var comp = CreateCompilation(sourceA, targetFramework: TargetFramework.Mscorlib40); - var refA = comp.ToMetadataReference(); - - var sourceB = -@"class B +ref struct R1 { - static void Main() - { - A.F(default, 0); - } + public R0 F1; + public R1(ref T t) { F1 = new R0(ref t); } +} +class Program +{ + static R0 F0(R1 r0) => r0.F1; + static R0 F1(scoped R1 r1) => r1.F1; // 1 + static R0 F2(ref R1 r2) => r2.F1; + static R0 F3(scoped ref R1 r3) => r3.F1; }"; - comp = CreateCompilation(sourceB, new[] { refA }, targetFramework: TargetFramework.Mscorlib45); - comp.VerifyEmitDiagnostics(); - CompileAndVerify(comp); - - var tree = comp.SyntaxTrees[0]; - var model = comp.GetSemanticModel(tree); - var expr = tree.GetRoot().DescendantNodes().OfType().Single().Expression; - var method = model.GetSymbolInfo(expr).Symbol.GetSymbol(); - - VerifyParameterSymbol(method.Parameters[0], "scoped R x", RefKind.None, DeclarationScope.ValueScoped); - VerifyParameterSymbol(method.Parameters[1], "scoped in System.Int32 y", RefKind.In, DeclarationScope.RefScoped); - } - - private static readonly SymbolDisplayFormat displayFormatWithScoped = SymbolDisplayFormat.TestFormat. - WithCompilerInternalOptions(SymbolDisplayCompilerInternalOptions.IncludeScoped). - AddLocalOptions(SymbolDisplayLocalOptions.IncludeRef); - - private static void VerifyParameterSymbol(ParameterSymbol parameter, string expectedDisplayString, RefKind expectedRefKind, DeclarationScope expectedScope) - { - Assert.Equal(expectedRefKind, parameter.RefKind); - Assert.Equal(expectedScope, parameter.Scope); - Assert.Equal(expectedDisplayString, parameter.ToDisplayString(displayFormatWithScoped)); - - var attribute = parameter.GetAttributes().FirstOrDefault(a => a.GetTargetAttributeSignatureIndex(parameter, AttributeDescription.LifetimeAnnotationAttribute) != -1); - Assert.Null(attribute); - - VerifyParameterSymbol(parameter.GetPublicSymbol(), expectedDisplayString, expectedRefKind, expectedScope); - } - - private static void VerifyParameterSymbol(IParameterSymbol parameter, string expectedDisplayString, RefKind expectedRefKind, DeclarationScope expectedScope) - { - Assert.Equal(expectedRefKind, parameter.RefKind); - // https://github.com/dotnet/roslyn/issues/61647: Use public API. - //Assert.Equal(expectedScope == DeclarationScope.RefScoped, parameter.IsRefScoped); - //Assert.Equal(expectedScope == DeclarationScope.ValueScoped, parameter.IsValueScoped); - Assert.Equal(expectedDisplayString, parameter.ToDisplayString(displayFormatWithScoped)); + var comp = CreateCompilation(source, runtimeFeature: RuntimeFlag.ByRefFields); + comp.VerifyDiagnostics( + // (14,44): error CS8352: Cannot use variable 'R1' in this context because it may expose referenced variables outside of their declaration scope + // static R0 F1(scoped R1 r1) => r1.F1; // 1 + Diagnostic(ErrorCode.ERR_EscapeVariable, "r1.F1").WithArguments("R1").WithLocation(14, 44)); } [Fact] - public void LocalScope_01() + public void ReturnRefStructFieldByRef() { var source = -@"#pragma warning disable 219 -ref struct R { } -class Program +@"ref struct R0 { - static void F(ref R r) - { - scoped R r1 = default; - scoped ref R r2 = ref r; - ref scoped R r3 = ref r; - scoped ref scoped R r4 = ref r; - scoped ref readonly R r5 = ref r; - ref readonly scoped R r6 = ref r; - scoped ref readonly scoped R r7 = ref r; - } -}"; - var comp = CreateCompilation(source, parseOptions: TestOptions.Regular10); - comp.VerifyEmitDiagnostics( - // (7,9): error CS8652: The feature 'ref fields' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. - // scoped R r1 = default; - Diagnostic(ErrorCode.ERR_FeatureInPreview, "scoped").WithArguments("ref fields").WithLocation(7, 9), - // (8,9): error CS8652: The feature 'ref fields' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. - // scoped ref R r2 = ref r; - Diagnostic(ErrorCode.ERR_FeatureInPreview, "scoped").WithArguments("ref fields").WithLocation(8, 9), - // (9,13): error CS8652: The feature 'ref fields' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. - // ref scoped R r3 = ref r; - Diagnostic(ErrorCode.ERR_FeatureInPreview, "scoped").WithArguments("ref fields").WithLocation(9, 13), - // (10,9): error CS8652: The feature 'ref fields' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. - // scoped ref scoped R r4 = ref r; - Diagnostic(ErrorCode.ERR_FeatureInPreview, "scoped").WithArguments("ref fields").WithLocation(10, 9), - // (10,20): error CS8652: The feature 'ref fields' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. - // scoped ref scoped R r4 = ref r; - Diagnostic(ErrorCode.ERR_FeatureInPreview, "scoped").WithArguments("ref fields").WithLocation(10, 20), - // (11,9): error CS8652: The feature 'ref fields' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. - // scoped ref readonly R r5 = ref r; - Diagnostic(ErrorCode.ERR_FeatureInPreview, "scoped").WithArguments("ref fields").WithLocation(11, 9), - // (12,22): error CS8652: The feature 'ref fields' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. - // ref readonly scoped R r6 = ref r; - Diagnostic(ErrorCode.ERR_FeatureInPreview, "scoped").WithArguments("ref fields").WithLocation(12, 22), - // (13,9): error CS8652: The feature 'ref fields' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. - // scoped ref readonly scoped R r7 = ref r; - Diagnostic(ErrorCode.ERR_FeatureInPreview, "scoped").WithArguments("ref fields").WithLocation(13, 9), - // (13,29): error CS8652: The feature 'ref fields' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. - // scoped ref readonly scoped R r7 = ref r; - Diagnostic(ErrorCode.ERR_FeatureInPreview, "scoped").WithArguments("ref fields").WithLocation(13, 29)); - verify(comp, useUpdatedEscapeRules: false); - - comp = CreateCompilation(source); - comp.VerifyEmitDiagnostics(); - verify(comp, useUpdatedEscapeRules: true); - - static void verify(CSharpCompilation comp, bool useUpdatedEscapeRules) - { - var tree = comp.SyntaxTrees[0]; - var model = comp.GetSemanticModel(tree); - var decls = tree.GetRoot().DescendantNodes().OfType().ToArray(); - var locals = decls.Select(d => model.GetDeclaredSymbol(d).GetSymbol()).ToArray(); + public ref T F0; + public R0(ref T t) { F0 = ref t; } +} +ref struct R1 +{ + public R0 F1; + public R1(ref T t) { F1 = new R0(ref t); } +} +class Program +{ + static ref R0 F0(R1 r0) => ref r0.F1; // 1 + static ref R0 F1(scoped R1 r1) => ref r1.F1; // 2 + static ref R0 F2(ref R1 r2) => ref r2.F1; + static ref R0 F3(scoped ref R1 r3) => ref r3.F1; // 3 +}"; + var comp = CreateCompilation(source, runtimeFeature: RuntimeFlag.ByRefFields); + comp.VerifyDiagnostics( + // (13,45): error CS8167: Cannot return by reference a member of parameter 'r0' because it is not a ref or out parameter + // static ref R0 F0(R1 r0) => ref r0.F1; // 1 + Diagnostic(ErrorCode.ERR_RefReturnParameter2, "r0").WithArguments("r0").WithLocation(13, 45), + // (14,52): error CS8167: Cannot return by reference a member of parameter 'r1' because it is not a ref or out parameter + // static ref R0 F1(scoped R1 r1) => ref r1.F1; // 2 + Diagnostic(ErrorCode.ERR_RefReturnParameter2, "r1").WithArguments("r1").WithLocation(14, 52), + // (15,49): error CS8167: Cannot return by reference a member of parameter 'r2' because it is not a ref or out parameter + // static ref R0 F2(ref R1 r2) => ref r2.F1; + Diagnostic(ErrorCode.ERR_RefReturnParameter2, "r2").WithArguments("r2").WithLocation(15, 49), + // (16,56): error CS8167: Cannot return by reference a member of parameter 'r3' because it is not a ref or out parameter + // static ref R0 F3(scoped ref R1 r3) => ref r3.F1; // 3 + Diagnostic(ErrorCode.ERR_RefReturnParameter2, "r3").WithArguments("r3").WithLocation(16, 56)); - VerifyLocalSymbol(locals[0], "scoped R r1", RefKind.None, DeclarationScope.ValueScoped); - VerifyLocalSymbol(locals[1], "scoped ref R r2", RefKind.Ref, DeclarationScope.RefScoped); - VerifyLocalSymbol(locals[2], "ref scoped R r3", RefKind.Ref, DeclarationScope.ValueScoped); - VerifyLocalSymbol(locals[3], "ref scoped R r4", RefKind.Ref, DeclarationScope.ValueScoped); - VerifyLocalSymbol(locals[4], "scoped ref readonly R r5", RefKind.RefReadOnly, DeclarationScope.RefScoped); - VerifyLocalSymbol(locals[5], "ref readonly scoped R r6", RefKind.RefReadOnly, DeclarationScope.ValueScoped); - VerifyLocalSymbol(locals[6], "ref readonly scoped R r7", RefKind.RefReadOnly, DeclarationScope.ValueScoped); - } + // https://github.com/dotnet/roslyn/issues/62780: Test additional cases with [UnscopedRef]. } [Fact] - public void LocalScope_02() + public void ReturnRefFieldFromCaller() { var source = -@"ref struct R { } +@"ref struct R +{ + public ref T F; + public R(ref T t) { F = ref t; } +} class Program { - static void Main() + static ref T F0(R r0) { - scoped scoped R x = default; - ref scoped scoped R y = ref x; - scoped scoped ref R z = ref x; + return ref r0.F; + } + static ref T F1() + { + return ref F0(new R()); // ok, returns null + } + static ref T F2() + { + T t = default; + return ref F0(new R(ref t)); // error } }"; - var comp = CreateCompilation(source); - // Duplicate scoped modifiers result are parse errors rather than binding errors. + var comp = CreateCompilation(source, runtimeFeature: RuntimeFlag.ByRefFields); comp.VerifyDiagnostics( - // (6,16): error CS1031: Type expected - // scoped scoped R x = default; - Diagnostic(ErrorCode.ERR_TypeExpected, "scoped").WithLocation(6, 16), - // (7,20): error CS0118: 'scoped' is a variable but is used like a type - // ref scoped scoped R y = ref x; - Diagnostic(ErrorCode.ERR_BadSKknown, "scoped").WithArguments("scoped", "variable", "type").WithLocation(7, 20), - // (7,27): error CS8174: A declaration of a by-reference variable must have an initializer - // ref scoped scoped R y = ref x; - Diagnostic(ErrorCode.ERR_ByReferenceVariableMustBeInitialized, "R").WithLocation(7, 27), - // (7,27): warning CS0168: The variable 'R' is declared but never used - // ref scoped scoped R y = ref x; - Diagnostic(ErrorCode.WRN_UnreferencedVar, "R").WithArguments("R").WithLocation(7, 27), - // (7,29): error CS1002: ; expected - // ref scoped scoped R y = ref x; - Diagnostic(ErrorCode.ERR_SemicolonExpected, "y").WithLocation(7, 29), - // (7,29): error CS0103: The name 'y' does not exist in the current context - // ref scoped scoped R y = ref x; - Diagnostic(ErrorCode.ERR_NameNotInContext, "y").WithArguments("y").WithLocation(7, 29), - // (8,9): error CS0118: 'scoped' is a variable but is used like a type - // scoped scoped ref R z = ref x; - Diagnostic(ErrorCode.ERR_BadSKknown, "scoped").WithArguments("scoped", "variable", "type").WithLocation(8, 9), - // (8,16): warning CS0168: The variable 'scoped' is declared but never used - // scoped scoped ref R z = ref x; - Diagnostic(ErrorCode.WRN_UnreferencedVar, "scoped").WithArguments("scoped").WithLocation(8, 16), - // (8,23): error CS1002: ; expected - // scoped scoped ref R z = ref x; - Diagnostic(ErrorCode.ERR_SemicolonExpected, "ref").WithLocation(8, 23)); + // (19,20): error CS8347: Cannot use a result of 'Program.F0(R)' in this context because it may expose variables referenced by parameter 'r0' outside of their declaration scope + // return ref F0(new R(ref t)); // error + Diagnostic(ErrorCode.ERR_EscapeCall, "F0(new R(ref t))").WithArguments("Program.F0(R)", "r0").WithLocation(19, 20), + // (19,23): error CS8347: Cannot use a result of 'R.R(ref T)' in this context because it may expose variables referenced by parameter 't' outside of their declaration scope + // return ref F0(new R(ref t)); // error + Diagnostic(ErrorCode.ERR_EscapeCall, "new R(ref t)").WithArguments("R.R(ref T)", "t").WithLocation(19, 23), + // (19,36): error CS8168: Cannot return local 't' by reference because it is not a ref local + // return ref F0(new R(ref t)); // error + Diagnostic(ErrorCode.ERR_RefReturnLocal, "t").WithArguments("t").WithLocation(19, 36)); } [Fact] - public void LocalScope_03() + public void PropertyReturnValue_01() { var source = -@"scoped scoped R x = default; -ref scoped scoped R y = ref x; -scoped scoped ref R z = ref x; -ref struct R { } -"; - var comp = CreateCompilation(source); - // Duplicate scoped modifiers result are parse errors rather than binding errors. +@"ref struct R +{ + private ref int _i; + public R(ref int i) { _i = ref i; } +} +class C +{ + R this[R x, R y] => x; + R F1(R x1, R y1) + { + return this[x1, y1]; + } + R F2(R x2) + { + int i2 = 0; + return this[x2, new R(ref i2)]; // 1 + } + static R F3(C c, R x3, R y3) + { + return c[x3, y3]; + } + static R F4(C c, R y4) + { + int i4 = 0; + return c[new R(ref i4), y4]; // 2 + } +}"; + var comp = CreateCompilation(source, runtimeFeature: RuntimeFlag.ByRefFields); comp.VerifyDiagnostics( - // (1,8): error CS1031: Type expected - // scoped scoped R x = default; - Diagnostic(ErrorCode.ERR_TypeExpected, "scoped").WithLocation(1, 8), - // (1,17): warning CS0219: The variable 'x' is assigned but its value is never used - // scoped scoped R x = default; - Diagnostic(ErrorCode.WRN_UnreferencedVarAssg, "x").WithArguments("x").WithLocation(1, 17), - // (2,12): error CS0118: 'scoped' is a variable but is used like a type - // ref scoped scoped R y = ref x; - Diagnostic(ErrorCode.ERR_BadSKknown, "scoped").WithArguments("scoped", "variable", "type").WithLocation(2, 12), - // (2,19): error CS8174: A declaration of a by-reference variable must have an initializer - // ref scoped scoped R y = ref x; - Diagnostic(ErrorCode.ERR_ByReferenceVariableMustBeInitialized, "R").WithLocation(2, 19), - // (2,19): warning CS0168: The variable 'R' is declared but never used - // ref scoped scoped R y = ref x; - Diagnostic(ErrorCode.WRN_UnreferencedVar, "R").WithArguments("R").WithLocation(2, 19), - // (2,21): error CS1003: Syntax error, ',' expected - // ref scoped scoped R y = ref x; - Diagnostic(ErrorCode.ERR_SyntaxError, "y").WithArguments(",").WithLocation(2, 21), - // (3,1): error CS0118: 'scoped' is a variable but is used like a type - // scoped scoped ref R z = ref x; - Diagnostic(ErrorCode.ERR_BadSKknown, "scoped").WithArguments("scoped", "variable", "type").WithLocation(3, 1), - // (3,8): warning CS0168: The variable 'scoped' is declared but never used - // scoped scoped ref R z = ref x; - Diagnostic(ErrorCode.WRN_UnreferencedVar, "scoped").WithArguments("scoped").WithLocation(3, 8), - // (3,15): error CS1003: Syntax error, ',' expected - // scoped scoped ref R z = ref x; - Diagnostic(ErrorCode.ERR_SyntaxError, "ref").WithArguments(",").WithLocation(3, 15)); + // (16,16): error CS8347: Cannot use a result of 'C.this[R, R]' in this context because it may expose variables referenced by parameter 'y' outside of their declaration scope + // return this[x2, new R(ref i2)]; // 1 + Diagnostic(ErrorCode.ERR_EscapeCall, "this[x2, new R(ref i2)]").WithArguments("C.this[R, R]", "y").WithLocation(16, 16), + // (16,25): error CS8347: Cannot use a result of 'R.R(ref int)' in this context because it may expose variables referenced by parameter 'i' outside of their declaration scope + // return this[x2, new R(ref i2)]; // 1 + Diagnostic(ErrorCode.ERR_EscapeCall, "new R(ref i2)").WithArguments("R.R(ref int)", "i").WithLocation(16, 25), + // (16,35): error CS8168: Cannot return local 'i2' by reference because it is not a ref local + // return this[x2, new R(ref i2)]; // 1 + Diagnostic(ErrorCode.ERR_RefReturnLocal, "i2").WithArguments("i2").WithLocation(16, 35), + // (25,16): error CS8347: Cannot use a result of 'C.this[R, R]' in this context because it may expose variables referenced by parameter 'x' outside of their declaration scope + // return c[new R(ref i4), y4]; // 2 + Diagnostic(ErrorCode.ERR_EscapeCall, "c[new R(ref i4), y4]").WithArguments("C.this[R, R]", "x").WithLocation(25, 16), + // (25,18): error CS8347: Cannot use a result of 'R.R(ref int)' in this context because it may expose variables referenced by parameter 'i' outside of their declaration scope + // return c[new R(ref i4), y4]; // 2 + Diagnostic(ErrorCode.ERR_EscapeCall, "new R(ref i4)").WithArguments("R.R(ref int)", "i").WithLocation(25, 18), + // (25,28): error CS8168: Cannot return local 'i4' by reference because it is not a ref local + // return c[new R(ref i4), y4]; // 2 + Diagnostic(ErrorCode.ERR_RefReturnLocal, "i4").WithArguments("i4").WithLocation(25, 28)); } [Fact] - public void LocalScope_04() - { - var source = -@"scoped s1 = default; -ref scoped s2 = ref s1; -scoped scoped s3 = default; -scoped ref scoped s4 = ref s1; -ref struct scoped { } -"; - var comp = CreateCompilation(source, parseOptions: TestOptions.Regular10); - comp.VerifyEmitDiagnostics( - // (3,1): error CS8652: The feature 'ref fields' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. - // scoped scoped s3 = default; - Diagnostic(ErrorCode.ERR_FeatureInPreview, "scoped").WithArguments("ref fields").WithLocation(3, 1), - // (3,15): warning CS0219: The variable 's3' is assigned but its value is never used - // scoped scoped s3 = default; - Diagnostic(ErrorCode.WRN_UnreferencedVarAssg, "s3").WithArguments("s3").WithLocation(3, 15), - // (4,1): error CS8652: The feature 'ref fields' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. - // scoped ref scoped s4 = ref s1; - Diagnostic(ErrorCode.ERR_FeatureInPreview, "scoped").WithArguments("ref fields").WithLocation(4, 1), - // (5,12): warning CS8981: The type name 'scoped' only contains lower-cased ascii characters. Such names may become reserved for the language. - // ref struct scoped { } - Diagnostic(ErrorCode.WRN_LowerCaseTypeName, "scoped").WithArguments("scoped").WithLocation(5, 12)); - verify(comp); - - comp = CreateCompilation(source); - comp.VerifyDiagnostics( - // (3,15): warning CS0219: The variable 's3' is assigned but its value is never used - // scoped scoped s3 = default; - Diagnostic(ErrorCode.WRN_UnreferencedVarAssg, "s3").WithArguments("s3").WithLocation(3, 15), - // (5,12): warning CS8981: The type name 'scoped' only contains lower-cased ascii characters. Such names may become reserved for the language. - // ref struct scoped { } - Diagnostic(ErrorCode.WRN_LowerCaseTypeName, "scoped").WithArguments("scoped").WithLocation(5, 12)); - verify(comp); - - static void verify(CSharpCompilation comp) - { - var tree = comp.SyntaxTrees[0]; - var model = comp.GetSemanticModel(tree); - var decls = tree.GetRoot().DescendantNodes().OfType().ToArray(); - var locals = decls.Select(d => model.GetDeclaredSymbol(d).GetSymbol()).ToArray(); - - VerifyLocalSymbol(locals[0], "scoped s1", RefKind.None, DeclarationScope.Unscoped); - VerifyLocalSymbol(locals[1], "ref scoped s2", RefKind.Ref, DeclarationScope.Unscoped); - VerifyLocalSymbol(locals[2], "scoped scoped s3", RefKind.None, DeclarationScope.ValueScoped); - VerifyLocalSymbol(locals[3], "scoped ref scoped s4", RefKind.Ref, DeclarationScope.RefScoped); - } - } - - [Theory] - [InlineData(LanguageVersion.CSharp10)] - [InlineData(LanguageVersionFacts.CSharpNext)] - public void LocalScope_05(LanguageVersion langVersion) + public void PropertyReturnValue_02() { var source = -@"bool scoped; -scoped = true; -"; - var comp = CreateCompilation(source, parseOptions: TestOptions.Regular.WithLanguageVersion(langVersion)); +@"ref struct R +{ + private ref readonly int _i; + public R(in int i) { _i = ref i; } +} +class C +{ + R this[in int x, in int y] => new R(x); + R F1(in int x1, in int y1) + { + return this[x1, y1]; + } + R F2(in int x2) + { + int y2 = 0; + return this[x2, y2]; // 1 + } + static R F3(C c, in int x3, in int y3) + { + return c[x3, y3]; + } + static R F4(C c, in int y4) + { + int x4 = 0; + return c[x4, y4]; // 2 + } +}"; + var comp = CreateCompilation(source, runtimeFeature: RuntimeFlag.ByRefFields); comp.VerifyDiagnostics( - // (1,6): warning CS0219: The variable 'scoped' is assigned but its value is never used - // bool scoped; - Diagnostic(ErrorCode.WRN_UnreferencedVarAssg, "scoped").WithArguments("scoped").WithLocation(1, 6)); - - var tree = comp.SyntaxTrees[0]; - var model = comp.GetSemanticModel(tree); - var decls = tree.GetRoot().DescendantNodes().OfType().ToArray(); - var locals = decls.Select(d => model.GetDeclaredSymbol(d).GetSymbol()).ToArray(); - - VerifyLocalSymbol(locals[0], "System.Boolean scoped", RefKind.None, DeclarationScope.Unscoped); + // (16,16): error CS8347: Cannot use a result of 'C.this[in int, in int]' in this context because it may expose variables referenced by parameter 'y' outside of their declaration scope + // return this[x2, y2]; // 1 + Diagnostic(ErrorCode.ERR_EscapeCall, "this[x2, y2]").WithArguments("C.this[in int, in int]", "y").WithLocation(16, 16), + // (16,25): error CS8168: Cannot return local 'y2' by reference because it is not a ref local + // return this[x2, y2]; // 1 + Diagnostic(ErrorCode.ERR_RefReturnLocal, "y2").WithArguments("y2").WithLocation(16, 25), + // (25,16): error CS8347: Cannot use a result of 'C.this[in int, in int]' in this context because it may expose variables referenced by parameter 'x' outside of their declaration scope + // return c[x4, y4]; // 2 + Diagnostic(ErrorCode.ERR_EscapeCall, "c[x4, y4]").WithArguments("C.this[in int, in int]", "x").WithLocation(25, 16), + // (25,18): error CS8168: Cannot return local 'x4' by reference because it is not a ref local + // return c[x4, y4]; // 2 + Diagnostic(ErrorCode.ERR_RefReturnLocal, "x4").WithArguments("x4").WithLocation(25, 18)); } [Fact] - public void LocalScope_06() + public void PropertyReturnValue_03() { var source = -@"ref struct R { } -class Program +@"ref struct R { - static void M(R r0) + public ref int _i; + public R(ref int i) { _i = ref i; } +} +class C +{ + ref int this[R x, R y] => ref x._i; + ref int F1(R x1, R y1) { - scoped var r1 = new R(); - ref scoped var r2 = ref r1; - scoped ref var r3 = ref r0; - scoped ref scoped var r4 = ref r0; + return ref this[x1, y1]; + } + ref int F2(R x2) + { + int i2 = 0; + return ref this[x2, new R(ref i2)]; // 1 + } + static ref int F3(C c, R x3, R y3) + { + return ref c[x3, y3]; + } + static ref int F4(C c, R y4) + { + int i4 = 0; + return ref c[new R(ref i4), y4]; // 2 } }"; - var comp = CreateCompilation(source); - comp.VerifyDiagnostics(); - - var tree = comp.SyntaxTrees[0]; - var model = comp.GetSemanticModel(tree); - var decls = tree.GetRoot().DescendantNodes().OfType().ToArray(); - var locals = decls.Select(d => model.GetDeclaredSymbol(d).GetSymbol()).ToArray(); - - VerifyLocalSymbol(locals[0], "scoped R r1", RefKind.None, DeclarationScope.ValueScoped); - VerifyLocalSymbol(locals[1], "ref scoped R r2", RefKind.Ref, DeclarationScope.ValueScoped); - VerifyLocalSymbol(locals[2], "scoped ref R r3", RefKind.Ref, DeclarationScope.RefScoped); - VerifyLocalSymbol(locals[3], "ref scoped R r4", RefKind.Ref, DeclarationScope.ValueScoped); + var comp = CreateCompilation(source, runtimeFeature: RuntimeFlag.ByRefFields); + comp.VerifyDiagnostics( + // (16,20): error CS8347: Cannot use a result of 'C.this[R, R]' in this context because it may expose variables referenced by parameter 'y' outside of their declaration scope + // return ref this[x2, new R(ref i2)]; // 1 + Diagnostic(ErrorCode.ERR_EscapeCall, "this[x2, new R(ref i2)]").WithArguments("C.this[R, R]", "y").WithLocation(16, 20), + // (16,29): error CS8347: Cannot use a result of 'R.R(ref int)' in this context because it may expose variables referenced by parameter 'i' outside of their declaration scope + // return ref this[x2, new R(ref i2)]; // 1 + Diagnostic(ErrorCode.ERR_EscapeCall, "new R(ref i2)").WithArguments("R.R(ref int)", "i").WithLocation(16, 29), + // (16,39): error CS8168: Cannot return local 'i2' by reference because it is not a ref local + // return ref this[x2, new R(ref i2)]; // 1 + Diagnostic(ErrorCode.ERR_RefReturnLocal, "i2").WithArguments("i2").WithLocation(16, 39), + // (25,20): error CS8347: Cannot use a result of 'C.this[R, R]' in this context because it may expose variables referenced by parameter 'x' outside of their declaration scope + // return ref c[new R(ref i4), y4]; // 2 + Diagnostic(ErrorCode.ERR_EscapeCall, "c[new R(ref i4), y4]").WithArguments("C.this[R, R]", "x").WithLocation(25, 20), + // (25,22): error CS8347: Cannot use a result of 'R.R(ref int)' in this context because it may expose variables referenced by parameter 'i' outside of their declaration scope + // return ref c[new R(ref i4), y4]; // 2 + Diagnostic(ErrorCode.ERR_EscapeCall, "new R(ref i4)").WithArguments("R.R(ref int)", "i").WithLocation(25, 22), + // (25,32): error CS8168: Cannot return local 'i4' by reference because it is not a ref local + // return ref c[new R(ref i4), y4]; // 2 + Diagnostic(ErrorCode.ERR_RefReturnLocal, "i4").WithArguments("i4").WithLocation(25, 32)); } [Fact] - public void LocalScopeAndInitializer_01() + public void PropertyReturnValue_04() { var source = -@"ref struct R { } -class Program +@"class C { - static void Values(R r1, scoped R r2) + ref readonly int this[in int x, in int y] => ref x; + ref readonly int F1(in int x1, in int y1) { - R r11 = r1; - R r12 = r2; - scoped R r21 = r1; - scoped R r22 = r2; + return ref this[x1, y1]; } - static void Refs(ref R r1, scoped ref R r2, ref scoped R r3) + ref readonly int F2(in int x2) { - ref R r31 = ref r1; - ref R r32 = ref r2; - ref R r33 = ref r3; - scoped ref R r41 = ref r1; - scoped ref R r42 = ref r2; - scoped ref R r43 = ref r3; - ref scoped R r51 = ref r1; - ref scoped R r52 = ref r2; - ref scoped R r53 = ref r3; + int y2 = 0; + return ref this[x2, y2]; // 1 } -}"; - var comp = CreateCompilation(source); - comp.VerifyEmitDiagnostics( - // (18,32): error CS8352: Cannot use variable 'ref R' in this context because it may expose referenced variables outside of their declaration scope - // scoped ref R r43 = ref r3; - Diagnostic(ErrorCode.ERR_EscapeVariable, "r3").WithArguments("ref R").WithLocation(18, 32)); - - var tree = comp.SyntaxTrees[0]; - var model = comp.GetSemanticModel(tree); - var decls = tree.GetRoot().DescendantNodes().OfType().ToArray(); - var locals = decls.Select(d => model.GetDeclaredSymbol(d).GetSymbol()).ToArray(); - - VerifyLocalSymbol(locals[0], "R r11", RefKind.None, DeclarationScope.Unscoped); - VerifyLocalSymbol(locals[1], "R r12", RefKind.None, DeclarationScope.Unscoped); - VerifyLocalSymbol(locals[2], "scoped R r21", RefKind.None, DeclarationScope.ValueScoped); - VerifyLocalSymbol(locals[3], "scoped R r22", RefKind.None, DeclarationScope.ValueScoped); - - VerifyLocalSymbol(locals[4], "ref R r31", RefKind.Ref, DeclarationScope.Unscoped); - VerifyLocalSymbol(locals[5], "ref R r32", RefKind.Ref, DeclarationScope.Unscoped); - VerifyLocalSymbol(locals[6], "ref R r33", RefKind.Ref, DeclarationScope.Unscoped); - VerifyLocalSymbol(locals[7], "scoped ref R r41", RefKind.Ref, DeclarationScope.RefScoped); - VerifyLocalSymbol(locals[8], "scoped ref R r42", RefKind.Ref, DeclarationScope.RefScoped); - VerifyLocalSymbol(locals[9], "scoped ref R r43", RefKind.Ref, DeclarationScope.RefScoped); - VerifyLocalSymbol(locals[10], "ref scoped R r51", RefKind.Ref, DeclarationScope.ValueScoped); - VerifyLocalSymbol(locals[11], "ref scoped R r52", RefKind.Ref, DeclarationScope.ValueScoped); - VerifyLocalSymbol(locals[12], "ref scoped R r53", RefKind.Ref, DeclarationScope.ValueScoped); - } - - [Fact] - public void LocalScopeAndInitializer_02() - { - var source = -@"ref struct R { } -class Program -{ - static R Refs(ref scoped R r3) + static ref readonly int F3(C c, in int x3, in int y3) + { + return ref c[x3, y3]; + } + static ref readonly int F4(C c, in int y4) { - scoped ref R r43 = ref r3; - return r43; + int x4 = 0; + return ref c[x4, y4]; // 2 } }"; var comp = CreateCompilation(source); - comp.VerifyEmitDiagnostics( - // (6,32): error CS8352: Cannot use variable 'ref R' in this context because it may expose referenced variables outside of their declaration scope - // scoped ref R r43 = ref r3; - Diagnostic(ErrorCode.ERR_EscapeVariable, "r3").WithArguments("ref R").WithLocation(6, 32)); - } - - private static void VerifyLocalSymbol(LocalSymbol local, string expectedDisplayString, RefKind expectedRefKind, DeclarationScope expectedScope) - { - Assert.Equal(expectedRefKind, local.RefKind); - Assert.Equal(expectedScope, local.Scope); - Assert.Equal(expectedDisplayString, local.ToDisplayString(displayFormatWithScoped)); - - VerifyLocalSymbol(local.GetPublicSymbol(), expectedDisplayString, expectedRefKind, expectedScope); - } - - private static void VerifyLocalSymbol(ILocalSymbol local, string expectedDisplayString, RefKind expectedRefKind, DeclarationScope expectedScope) - { - Assert.Equal(expectedRefKind, local.RefKind); - // https://github.com/dotnet/roslyn/issues/61647: Use public API. - //Assert.Equal(expectedScope == DeclarationScope.RefScoped, local.IsRefScoped); - //Assert.Equal(expectedScope == DeclarationScope.ValueScoped, local.IsValueScoped); - Assert.Equal(expectedDisplayString, local.ToDisplayString(displayFormatWithScoped)); + comp.VerifyDiagnostics( + // (11,20): error CS8347: Cannot use a result of 'C.this[in int, in int]' in this context because it may expose variables referenced by parameter 'y' outside of their declaration scope + // return ref this[x2, y2]; // 1 + Diagnostic(ErrorCode.ERR_EscapeCall, "this[x2, y2]").WithArguments("C.this[in int, in int]", "y").WithLocation(11, 20), + // (11,29): error CS8168: Cannot return local 'y2' by reference because it is not a ref local + // return ref this[x2, y2]; // 1 + Diagnostic(ErrorCode.ERR_RefReturnLocal, "y2").WithArguments("y2").WithLocation(11, 29), + // (20,20): error CS8347: Cannot use a result of 'C.this[in int, in int]' in this context because it may expose variables referenced by parameter 'x' outside of their declaration scope + // return ref c[x4, y4]; // 2 + Diagnostic(ErrorCode.ERR_EscapeCall, "c[x4, y4]").WithArguments("C.this[in int, in int]", "x").WithLocation(20, 20), + // (20,22): error CS8168: Cannot return local 'x4' by reference because it is not a ref local + // return ref c[x4, y4]; // 2 + Diagnostic(ErrorCode.ERR_RefReturnLocal, "x4").WithArguments("x4").WithLocation(20, 22)); } - [ConditionalFact(typeof(WindowsDesktopOnly), Reason = ConditionalSkipReason.NoPiaNeedsDesktop)] - public void ParameterScope_EmbeddedMethod() + [Fact] + public void RefStructLocal_FromLocal_01() { - var sourceA = -@"using System.Runtime.InteropServices; -[assembly: ImportedFromTypeLib(""_.dll"")] -[assembly: Guid(""DB204C34-AE89-49C6-9174-09F72E7F7F10"")] -[ComImport()] -[Guid(""933FEEE7-2728-4F87-A802-953F3CF1B1E9"")] -public interface I -{ - void M(scoped ref int i); -} -"; - var comp = CreateCompilation(sourceA); - var refA = comp.EmitToImageReference(embedInteropTypes: true); - - var sourceB = -@"class C : I + var source = +@"ref struct R { - public void M(scoped ref int i) { } + public ref T F; + public R(ref T t) { F = ref t; } } class Program { - static void Main() + static R Create() => new R(); + static R Create(ref T t) => new R(ref t); + static void F(T t) { } + static T F1() + { + T t = default; + R r1 = new R(ref t); + F(r1.F); + return r1.F; + } + static T F2() + { + T t = default; + scoped R r2 = new R(ref t); + F(r2.F); + return r2.F; + } + static T F3() + { + T t = default; + R r3 = new R(); + r3.F = ref t; + F(r3.F); + return r3.F; + } + static T F4() + { + T t = default; + scoped R r4 = new R(); + r4.F = ref t; + F(r4.F); + return r4.F; + } + static T F5() + { + T t = default; + R r5 = Create(ref t); + F(r5.F); + return r5.F; + } + static T F6() + { + T t = default; + scoped R r6 = Create(ref t); + F(r6.F); + return r6.F; + } + static T F7() + { + T t = default; + R r7 = Create(); + r7.F = ref t; + F(r7.F); + return r7.F; + } + static T F8() { + T t = default; + scoped R r8 = Create(); + r8.F = ref t; + F(r8.F); + return r8.F; } }"; - CompileAndVerify(sourceB, references: new[] { refA }, - symbolValidator: module => - { - var method = module.GlobalNamespace.GetMember("I.M"); - // Attribute is not included for the parameter from the embedded method. - VerifyParameterSymbol(method.Parameters[0], "ref System.Int32 i", RefKind.Ref, DeclarationScope.Unscoped); - }); + var comp = CreateCompilation(source, runtimeFeature: RuntimeFlag.ByRefFields); + comp.VerifyEmitDiagnostics( + // (29,9): error CS8374: Cannot ref-assign 't' to 'F' because 't' has a narrower escape scope than 'F'. + // r3.F = ref t; + Diagnostic(ErrorCode.ERR_RefAssignNarrower, "r3.F = ref t").WithArguments("F", "t").WithLocation(29, 9), + // (59,9): error CS8374: Cannot ref-assign 't' to 'F' because 't' has a narrower escape scope than 'F'. + // r7.F = ref t; + Diagnostic(ErrorCode.ERR_RefAssignNarrower, "r7.F = ref t").WithArguments("F", "t").WithLocation(59, 9)); } [Fact] - public void Conversions_01() + public void RefStructLocal_FromParameter_01() { var source = -@"ref struct R { } -class Program +@"ref struct R { - static R Implicit1(scoped R r) => r; - static R Implicit2(ref R r) => r; - static R Implicit3(ref scoped R r) => r; - static R Implicit4(scoped ref R r) => r; - static R Explicit1(scoped R r) => (R)r; - static R Explicit2(ref R r) => (R)r; - static R Explicit3(ref scoped R r) => (R)r; - static R Explicit4(scoped ref R r) => (R)r; -}"; - var comp = CreateCompilation(source); - comp.VerifyDiagnostics( - // (4,39): error CS8352: Cannot use variable 'R' in this context because it may expose referenced variables outside of their declaration scope - // static R Implicit1(scoped R r) => r; - Diagnostic(ErrorCode.ERR_EscapeVariable, "r").WithArguments("R").WithLocation(4, 39), - // (6,43): error CS8352: Cannot use variable 'ref R' in this context because it may expose referenced variables outside of their declaration scope - // static R Implicit3(ref scoped R r) => r; - Diagnostic(ErrorCode.ERR_EscapeVariable, "r").WithArguments("ref R").WithLocation(6, 43), - // (8,39): error CS8352: Cannot use variable 'R' in this context because it may expose referenced variables outside of their declaration scope - // static R Explicit1(scoped R r) => (R)r; - Diagnostic(ErrorCode.ERR_EscapeVariable, "(R)r").WithArguments("R").WithLocation(8, 39), - // (10,43): error CS8352: Cannot use variable 'ref R' in this context because it may expose referenced variables outside of their declaration scope - // static R Explicit3(ref scoped R r) => (R)r; - Diagnostic(ErrorCode.ERR_EscapeVariable, "(R)r").WithArguments("ref R").WithLocation(10, 43)); - } - - [Fact] - public void DelegateConversions_01() - { - var source = -@"ref struct R { } -delegate R D1(R x, R y); -delegate R D2(R x, scoped R y); -delegate ref R D3(ref R x, ref R y); -delegate ref R D4(ref R x, ref scoped R y); -delegate ref R D5(ref R x, scoped ref R y); + public ref T F; + public R(ref T t) { F = ref t; } +} class Program { - static void Implicit() + static R Create() => new R(); + static R Create(ref T t) => new R(ref t); + static void F(T t) { } + static T F1(T t) { - D1 d1 = (R x, scoped R y) => x; - D2 d2 = (R x, R y) => x; - D3 d3 = (ref R x, ref scoped R y) => ref x; - D4 d4 = (ref R x, scoped ref R y) => ref x; - D5 d5 = (ref R x, ref R y) => ref x; + R r1 = new R(ref t); + F(r1.F); + return r1.F; + } + static T F2(T t) + { + scoped R r2 = new R(ref t); + F(r2.F); + return r2.F; + } + static T F3(T t) + { + R r3 = new R(); + r3.F = ref t; + F(r3.F); + return r3.F; + } + static T F4(T t) + { + scoped R r4 = new R(); + r4.F = ref t; + F(r4.F); + return r4.F; + } + static T F5(T t) + { + R r5 = Create(ref t); + F(r5.F); + return r5.F; + } + static T F6(T t) + { + scoped R r6 = Create(ref t); + F(r6.F); + return r6.F; } - static void Explicit() + static T F7(T t) { - var d1 = (D1)((R x, scoped R y) => x); - var d2 = (D2)((R x, R y) => x); - var d3 = (D3)((ref R x, ref scoped R y) => ref x); - var d4 = (D4)((ref R x, scoped ref R y) => ref x); - var d5 = (D5)((ref R x, ref R y) => ref x); + R r7 = Create(); + r7.F = ref t; + F(r7.F); + return r7.F; } - static void New() + static T F8(T t) { - var d1 = new D1((R x, scoped R y) => x); - var d2 = new D2((R x, R y) => x); - var d3 = new D3((ref R x, ref scoped R y) => ref x); - var d4 = new D4((ref R x, scoped ref R y) => ref x); - var d5 = new D5((ref R x, ref R y) => ref x); + scoped R r8 = Create(); + r8.F = ref t; + F(r8.F); + return r8.F; } }"; - var comp = CreateCompilation(source); - comp.VerifyDiagnostics( - // (11,17): error CS8986: The 'scoped' modifier of parameter 'y' doesn't match target 'D1'. - // D1 d1 = (R x, scoped R y) => x; - Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfTarget, "(R x, scoped R y) => x").WithArguments("y", "D1").WithLocation(11, 17), - // (12,17): error CS8986: The 'scoped' modifier of parameter 'y' doesn't match target 'D2'. - // D2 d2 = (R x, R y) => x; - Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfTarget, "(R x, R y) => x").WithArguments("y", "D2").WithLocation(12, 17), - // (13,17): error CS8986: The 'scoped' modifier of parameter 'y' doesn't match target 'D3'. - // D3 d3 = (ref R x, ref scoped R y) => ref x; - Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfTarget, "(ref R x, ref scoped R y) => ref x").WithArguments("y", "D3").WithLocation(13, 17), - // (14,17): error CS8986: The 'scoped' modifier of parameter 'y' doesn't match target 'D4'. - // D4 d4 = (ref R x, scoped ref R y) => ref x; - Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfTarget, "(ref R x, scoped ref R y) => ref x").WithArguments("y", "D4").WithLocation(14, 17), - // (15,17): error CS8986: The 'scoped' modifier of parameter 'y' doesn't match target 'D5'. - // D5 d5 = (ref R x, ref R y) => ref x; - Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfTarget, "(ref R x, ref R y) => ref x").WithArguments("y", "D5").WithLocation(15, 17), - // (19,18): error CS8986: The 'scoped' modifier of parameter 'y' doesn't match target 'D1'. - // var d1 = (D1)((R x, scoped R y) => x); - Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfTarget, "(D1)((R x, scoped R y) => x)").WithArguments("y", "D1").WithLocation(19, 18), - // (20,18): error CS8986: The 'scoped' modifier of parameter 'y' doesn't match target 'D2'. - // var d2 = (D2)((R x, R y) => x); - Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfTarget, "(D2)((R x, R y) => x)").WithArguments("y", "D2").WithLocation(20, 18), - // (21,18): error CS8986: The 'scoped' modifier of parameter 'y' doesn't match target 'D3'. - // var d3 = (D3)((ref R x, ref scoped R y) => ref x); - Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfTarget, "(D3)((ref R x, ref scoped R y) => ref x)").WithArguments("y", "D3").WithLocation(21, 18), - // (22,18): error CS8986: The 'scoped' modifier of parameter 'y' doesn't match target 'D4'. - // var d4 = (D4)((ref R x, scoped ref R y) => ref x); - Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfTarget, "(D4)((ref R x, scoped ref R y) => ref x)").WithArguments("y", "D4").WithLocation(22, 18), - // (23,18): error CS8986: The 'scoped' modifier of parameter 'y' doesn't match target 'D5'. - // var d5 = (D5)((ref R x, ref R y) => ref x); - Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfTarget, "(D5)((ref R x, ref R y) => ref x)").WithArguments("y", "D5").WithLocation(23, 18), - // (27,25): error CS8986: The 'scoped' modifier of parameter 'y' doesn't match target 'D1'. - // var d1 = new D1((R x, scoped R y) => x); - Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfTarget, "(R x, scoped R y) => x").WithArguments("y", "D1").WithLocation(27, 25), - // (28,25): error CS8986: The 'scoped' modifier of parameter 'y' doesn't match target 'D2'. - // var d2 = new D2((R x, R y) => x); - Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfTarget, "(R x, R y) => x").WithArguments("y", "D2").WithLocation(28, 25), - // (29,25): error CS8986: The 'scoped' modifier of parameter 'y' doesn't match target 'D3'. - // var d3 = new D3((ref R x, ref scoped R y) => ref x); - Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfTarget, "(ref R x, ref scoped R y) => ref x").WithArguments("y", "D3").WithLocation(29, 25), - // (30,25): error CS8986: The 'scoped' modifier of parameter 'y' doesn't match target 'D4'. - // var d4 = new D4((ref R x, scoped ref R y) => ref x); - Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfTarget, "(ref R x, scoped ref R y) => ref x").WithArguments("y", "D4").WithLocation(30, 25), - // (31,25): error CS8986: The 'scoped' modifier of parameter 'y' doesn't match target 'D5'. - // var d5 = new D5((ref R x, ref R y) => ref x); - Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfTarget, "(ref R x, ref R y) => ref x").WithArguments("y", "D5").WithLocation(31, 25)); + var comp = CreateCompilation(source, runtimeFeature: RuntimeFlag.ByRefFields); + comp.VerifyEmitDiagnostics( + // (26,9): error CS8374: Cannot ref-assign 't' to 'F' because 't' has a narrower escape scope than 'F'. + // r3.F = ref t; + Diagnostic(ErrorCode.ERR_RefAssignNarrower, "r3.F = ref t").WithArguments("F", "t").WithLocation(26, 9), + // (52,9): error CS8374: Cannot ref-assign 't' to 'F' because 't' has a narrower escape scope than 'F'. + // r7.F = ref t; + Diagnostic(ErrorCode.ERR_RefAssignNarrower, "r7.F = ref t").WithArguments("F", "t").WithLocation(52, 9)); } [Fact] - public void DelegateConversions_02() + public void RefStructLocal_FromLocal_02() { var source = -@"ref struct R { } -delegate R D1(R x, R y); -delegate R D2(R x, scoped R y); -delegate ref R D3(ref R x, ref R y); -delegate ref R D4(ref R x, ref scoped R y); -delegate ref R D5(ref R x, scoped ref R y); +@"ref struct R +{ + public ref T F; + public R(ref T t) { F = ref t; } +} class Program { - static R M1(R x, R y) => x; - static R M2(R x, scoped R y) => x; - static ref R M3(ref R x, ref R y) => ref x; - static ref R M4(ref R x, ref scoped R y) => ref x; - static ref R M5(ref R x, scoped ref R y) => ref x; - static void Implicit() + static R Create() => new R(); + static R Create(ref T t) => new R(ref t); + static void F(R r) { } + static R F1() { - D1 dA = M2; - D2 d2 = M1; - D3 d3 = M4; - D4 d4 = M5; - D5 d5 = M3; + T t = default; + R r1 = new R(ref t); + F(r1); + return r1; } - static void Explicit() + static R F2() { - var d1 = (D1)M2; - var d2 = (D2)M1; - var d3 = (D3)M4; - var d4 = (D4)M5; - var d5 = (D5)M3; + T t = default; + scoped R r2 = new R(ref t); + F(r2); + return r2; } - static void New() + static R F3() { - var d1 = new D1(M2); - var d2 = new D2(M1); - var d3 = new D3(M4); - var d4 = new D4(M5); - var d5 = new D5(M3); + T t = default; + R r3 = new R(); + r3.F = ref t; + F(r3); + return r3; } -}"; - var comp = CreateCompilation(source); - comp.VerifyDiagnostics( - // (16,17): error CS8986: The 'scoped' modifier of parameter 'y' doesn't match target 'D1'. - // D1 dA = M2; - Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfTarget, "M2").WithArguments("y", "D1").WithLocation(16, 17), - // (17,17): error CS8986: The 'scoped' modifier of parameter 'y' doesn't match target 'D2'. - // D2 d2 = M1; - Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfTarget, "M1").WithArguments("y", "D2").WithLocation(17, 17), - // (18,17): error CS8986: The 'scoped' modifier of parameter 'y' doesn't match target 'D3'. - // D3 d3 = M4; - Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfTarget, "M4").WithArguments("y", "D3").WithLocation(18, 17), - // (19,17): error CS8986: The 'scoped' modifier of parameter 'y' doesn't match target 'D4'. - // D4 d4 = M5; - Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfTarget, "M5").WithArguments("y", "D4").WithLocation(19, 17), - // (20,17): error CS8986: The 'scoped' modifier of parameter 'y' doesn't match target 'D5'. - // D5 d5 = M3; - Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfTarget, "M3").WithArguments("y", "D5").WithLocation(20, 17), - // (24,18): error CS8986: The 'scoped' modifier of parameter 'y' doesn't match target 'D1'. - // var d1 = (D1)M2; - Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfTarget, "(D1)M2").WithArguments("y", "D1").WithLocation(24, 18), - // (25,18): error CS8986: The 'scoped' modifier of parameter 'y' doesn't match target 'D2'. - // var d2 = (D2)M1; - Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfTarget, "(D2)M1").WithArguments("y", "D2").WithLocation(25, 18), - // (26,18): error CS8986: The 'scoped' modifier of parameter 'y' doesn't match target 'D3'. - // var d3 = (D3)M4; - Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfTarget, "(D3)M4").WithArguments("y", "D3").WithLocation(26, 18), - // (27,18): error CS8986: The 'scoped' modifier of parameter 'y' doesn't match target 'D4'. - // var d4 = (D4)M5; - Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfTarget, "(D4)M5").WithArguments("y", "D4").WithLocation(27, 18), - // (28,18): error CS8986: The 'scoped' modifier of parameter 'y' doesn't match target 'D5'. - // var d5 = (D5)M3; - Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfTarget, "(D5)M3").WithArguments("y", "D5").WithLocation(28, 18), - // (32,25): error CS8986: The 'scoped' modifier of parameter 'y' doesn't match target 'D1'. - // var d1 = new D1(M2); - Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfTarget, "M2").WithArguments("y", "D1").WithLocation(32, 25), - // (33,25): error CS8986: The 'scoped' modifier of parameter 'y' doesn't match target 'D2'. - // var d2 = new D2(M1); - Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfTarget, "M1").WithArguments("y", "D2").WithLocation(33, 25), - // (34,25): error CS8986: The 'scoped' modifier of parameter 'y' doesn't match target 'D3'. - // var d3 = new D3(M4); - Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfTarget, "M4").WithArguments("y", "D3").WithLocation(34, 25), - // (35,25): error CS8986: The 'scoped' modifier of parameter 'y' doesn't match target 'D4'. - // var d4 = new D4(M5); - Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfTarget, "M5").WithArguments("y", "D4").WithLocation(35, 25), - // (36,25): error CS8986: The 'scoped' modifier of parameter 'y' doesn't match target 'D5'. - // var d5 = new D5(M3); - Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfTarget, "M3").WithArguments("y", "D5").WithLocation(36, 25)); - } - - [Fact] - public void DelegateConversions_03() - { - var source = -@"delegate ref int D1(ref int x, ref int y); -delegate ref int D2(scoped ref int x, ref int y); -delegate D1 D1R(); -delegate D2 D2R(); -class Program -{ - static void Implicit() + static R F4() { - D1R d1 = () => (scoped ref int x, ref int y) => ref y; - D2R d2 = () => (ref int x, ref int y) => ref x; + T t = default; + scoped R r4 = new R(); + r4.F = ref t; + F(r4); + return r4; } - static void Explicit() + static R F5() { - var d1 = (D1R)(() => (scoped ref int x, ref int y) => ref y); - var d2 = (D2R)(() => (ref int x, ref int y) => ref x); + T t = default; + R r5 = Create(ref t); + F(r5); + return r5; } - static void New() + static R F6() { - var d1 = new D1R(() => (scoped ref int x, ref int y) => ref y); - var d2 = new D2R(() => (ref int x, ref int y) => ref x); + T t = default; + scoped R r6 = Create(ref t); + F(r6); + return r6; + } + static R F7() + { + T t = default; + R r7 = Create(); + r7.F = ref t; + F(r7); + return r7; + } + static R F8() + { + T t = default; + scoped R r8 = Create(); + r8.F = ref t; + F(r8); + return r8; } }"; - var comp = CreateCompilation(source); - comp.VerifyDiagnostics( - // (9,24): error CS8986: The 'scoped' modifier of parameter 'x' doesn't match target 'D1'. - // D1R d1 = () => (scoped ref int x, ref int y) => ref y; - Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfTarget, "(scoped ref int x, ref int y) => ref y").WithArguments("x", "D1").WithLocation(9, 24), - // (10,24): error CS8986: The 'scoped' modifier of parameter 'x' doesn't match target 'D2'. - // D2R d2 = () => (ref int x, ref int y) => ref x; - Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfTarget, "(ref int x, ref int y) => ref x").WithArguments("x", "D2").WithLocation(10, 24), - // (14,30): error CS8986: The 'scoped' modifier of parameter 'x' doesn't match target 'D1'. - // var d1 = (D1R)(() => (scoped ref int x, ref int y) => ref y); - Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfTarget, "(scoped ref int x, ref int y) => ref y").WithArguments("x", "D1").WithLocation(14, 30), - // (15,30): error CS8986: The 'scoped' modifier of parameter 'x' doesn't match target 'D2'. - // var d2 = (D2R)(() => (ref int x, ref int y) => ref x); - Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfTarget, "(ref int x, ref int y) => ref x").WithArguments("x", "D2").WithLocation(15, 30), - // (19,32): error CS8986: The 'scoped' modifier of parameter 'x' doesn't match target 'D1'. - // var d1 = new D1R(() => (scoped ref int x, ref int y) => ref y); - Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfTarget, "(scoped ref int x, ref int y) => ref y").WithArguments("x", "D1").WithLocation(19, 32), - // (20,32): error CS8986: The 'scoped' modifier of parameter 'x' doesn't match target 'D2'. - // var d2 = new D2R(() => (ref int x, ref int y) => ref x); - Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfTarget, "(ref int x, ref int y) => ref x").WithArguments("x", "D2").WithLocation(20, 32)); + var comp = CreateCompilation(source, runtimeFeature: RuntimeFlag.ByRefFields); + comp.VerifyEmitDiagnostics( + // (16,16): error CS8352: Cannot use variable 'r1' in this context because it may expose referenced variables outside of their declaration scope + // return r1; + Diagnostic(ErrorCode.ERR_EscapeVariable, "r1").WithArguments("r1").WithLocation(16, 16), + // (23,16): error CS8352: Cannot use variable 'r2' in this context because it may expose referenced variables outside of their declaration scope + // return r2; + Diagnostic(ErrorCode.ERR_EscapeVariable, "r2").WithArguments("r2").WithLocation(23, 16), + // (29,9): error CS8374: Cannot ref-assign 't' to 'F' because 't' has a narrower escape scope than 'F'. + // r3.F = ref t; + Diagnostic(ErrorCode.ERR_RefAssignNarrower, "r3.F = ref t").WithArguments("F", "t").WithLocation(29, 9), + // (39,16): error CS8352: Cannot use variable 'r4' in this context because it may expose referenced variables outside of their declaration scope + // return r4; + Diagnostic(ErrorCode.ERR_EscapeVariable, "r4").WithArguments("r4").WithLocation(39, 16), + // (46,16): error CS8352: Cannot use variable 'r5' in this context because it may expose referenced variables outside of their declaration scope + // return r5; + Diagnostic(ErrorCode.ERR_EscapeVariable, "r5").WithArguments("r5").WithLocation(46, 16), + // (53,16): error CS8352: Cannot use variable 'r6' in this context because it may expose referenced variables outside of their declaration scope + // return r6; + Diagnostic(ErrorCode.ERR_EscapeVariable, "r6").WithArguments("r6").WithLocation(53, 16), + // (59,9): error CS8374: Cannot ref-assign 't' to 'F' because 't' has a narrower escape scope than 'F'. + // r7.F = ref t; + Diagnostic(ErrorCode.ERR_RefAssignNarrower, "r7.F = ref t").WithArguments("F", "t").WithLocation(59, 9), + // (69,16): error CS8352: Cannot use variable 'r8' in this context because it may expose referenced variables outside of their declaration scope + // return r8; + Diagnostic(ErrorCode.ERR_EscapeVariable, "r8").WithArguments("r8").WithLocation(69, 16)); } [Fact] - public void DelegateConversions_04() + public void RefStructLocal_FromParameter_02() { var source = -@"delegate ref int D1(ref int x, ref int y); -delegate ref int D2(scoped ref int x, ref int y); -delegate D1 D1R(); -delegate D2 D2R(); +@"ref struct R +{ + public ref T F; + public R(ref T t) { F = ref t; } +} class Program { - static ref int M1(ref int x, ref int y) => ref x; - static ref int M2(scoped ref int x, ref int y) => ref y; - static void Implicit() + static R Create() => new R(); + static R Create(ref T t) => new R(ref t); + static void F(R r) { } + static R F1(T t) { - D1R d1 = () => M2; - D2R d2 = () => M1; + R r1 = new R(ref t); + F(r1); + return r1; } - static void Explicit() + static R F2(T t) { - var d1 = (D1R)M2; - var d2 = (D2R)M1; + scoped R r2 = new R(ref t); + F(r2); + return r2; + } + static R F3(T t) + { + R r3 = new R(); + r3.F = ref t; + F(r3); + return r3; + } + static R F4(T t) + { + scoped R r4 = new R(); + r4.F = ref t; + F(r4); + return r4; + } + static R F5(T t) + { + R r5 = Create(ref t); + F(r5); + return r5; + } + static R F6(T t) + { + scoped R r6 = Create(ref t); + F(r6); + return r6; + } + static R F7(T t) + { + R r7 = Create(); + r7.F = ref t; + F(r7); + return r7; } - static void New() + static R F8(T t) { - var d1 = new D1R(M2); - var d2 = new D2R(M1); + scoped R r8 = Create(); + r8.F = ref t; + F(r8); + return r8; } }"; - var comp = CreateCompilation(source); - comp.VerifyDiagnostics( - // (11,24): error CS8986: The 'scoped' modifier of parameter 'x' doesn't match target 'D1'. - // D1R d1 = () => M2; - Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfTarget, "M2").WithArguments("x", "D1").WithLocation(11, 24), - // (12,24): error CS8986: The 'scoped' modifier of parameter 'x' doesn't match target 'D2'. - // D2R d2 = () => M1; - Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfTarget, "M1").WithArguments("x", "D2").WithLocation(12, 24), - // (16,18): error CS0123: No overload for 'M2' matches delegate 'D1R' - // var d1 = (D1R)M2; - Diagnostic(ErrorCode.ERR_MethDelegateMismatch, "(D1R)M2").WithArguments("M2", "D1R").WithLocation(16, 18), - // (17,18): error CS0123: No overload for 'M1' matches delegate 'D2R' - // var d2 = (D2R)M1; - Diagnostic(ErrorCode.ERR_MethDelegateMismatch, "(D2R)M1").WithArguments("M1", "D2R").WithLocation(17, 18), - // (21,18): error CS0123: No overload for 'M2' matches delegate 'D1R' - // var d1 = new D1R(M2); - Diagnostic(ErrorCode.ERR_MethDelegateMismatch, "new D1R(M2)").WithArguments("M2", "D1R").WithLocation(21, 18), - // (22,18): error CS0123: No overload for 'M1' matches delegate 'D2R' - // var d2 = new D2R(M1); - Diagnostic(ErrorCode.ERR_MethDelegateMismatch, "new D2R(M1)").WithArguments("M1", "D2R").WithLocation(22, 18)); + var comp = CreateCompilation(source, runtimeFeature: RuntimeFlag.ByRefFields); + comp.VerifyEmitDiagnostics( + // (15,16): error CS8352: Cannot use variable 'r1' in this context because it may expose referenced variables outside of their declaration scope + // return r1; + Diagnostic(ErrorCode.ERR_EscapeVariable, "r1").WithArguments("r1").WithLocation(15, 16), + // (21,16): error CS8352: Cannot use variable 'r2' in this context because it may expose referenced variables outside of their declaration scope + // return r2; + Diagnostic(ErrorCode.ERR_EscapeVariable, "r2").WithArguments("r2").WithLocation(21, 16), + // (26,9): error CS8374: Cannot ref-assign 't' to 'F' because 't' has a narrower escape scope than 'F'. + // r3.F = ref t; + Diagnostic(ErrorCode.ERR_RefAssignNarrower, "r3.F = ref t").WithArguments("F", "t").WithLocation(26, 9), + // (35,16): error CS8352: Cannot use variable 'r4' in this context because it may expose referenced variables outside of their declaration scope + // return r4; + Diagnostic(ErrorCode.ERR_EscapeVariable, "r4").WithArguments("r4").WithLocation(35, 16), + // (41,16): error CS8352: Cannot use variable 'r5' in this context because it may expose referenced variables outside of their declaration scope + // return r5; + Diagnostic(ErrorCode.ERR_EscapeVariable, "r5").WithArguments("r5").WithLocation(41, 16), + // (47,16): error CS8352: Cannot use variable 'r6' in this context because it may expose referenced variables outside of their declaration scope + // return r6; + Diagnostic(ErrorCode.ERR_EscapeVariable, "r6").WithArguments("r6").WithLocation(47, 16), + // (52,9): error CS8374: Cannot ref-assign 't' to 'F' because 't' has a narrower escape scope than 'F'. + // r7.F = ref t; + Diagnostic(ErrorCode.ERR_RefAssignNarrower, "r7.F = ref t").WithArguments("F", "t").WithLocation(52, 9), + // (61,16): error CS8352: Cannot use variable 'r8' in this context because it may expose referenced variables outside of their declaration scope + // return r8; + Diagnostic(ErrorCode.ERR_EscapeVariable, "r8").WithArguments("r8").WithLocation(61, 16)); } [Fact] - public void DelegateConversions_05() + public void LocalFromRvalueInvocation() { var source = -@"ref struct R { } -delegate R D1(R x, R y); -delegate R D2(R x, scoped R y); -delegate ref R D3(ref R x, ref R y); -delegate ref R D4(ref R x, ref scoped R y); -delegate ref R D5(ref R x, scoped ref R y); +@"ref struct R { } class Program { - static void Implicit() + static R Create(scoped ref T t) { - D1 d1 = delegate(R x, scoped R y) { return x; }; - D2 d2 = delegate(R x, R y) { return x; }; - D3 d3 = delegate(ref R x, ref scoped R y) { return ref x; }; - D4 d4 = delegate(ref R x, scoped ref R y) { return ref x; }; - D5 d5 = delegate(ref R x, ref R y) { return ref x; }; + return default; } - static void Explicit() + static R CreateReadonly(scoped in T t) { - var d1 = (D1)(delegate(R x, scoped R y) { return x; }); - var d2 = (D2)(delegate(R x, R y) { return x; }); - var d3 = (D3)(delegate(ref R x, ref scoped R y) { return ref x; }); - var d4 = (D4)(delegate(ref R x, scoped ref R y) { return ref x; }); - var d5 = (D5)(delegate(ref R x, ref R y) { return ref x; }); + return default; } - static void New() + static void F0(string s0) { - var d1 = new D1(delegate(R x, scoped R y) { return x; }); - var d2 = new D2(delegate(R x, R y) { return x; }); - var d3 = new D3(delegate(ref R x, ref scoped R y) { return ref x; }); - var d4 = new D4(delegate(ref R x, scoped ref R y) { return ref x; }); - var d5 = new D5(delegate(ref R x, ref R y) { return ref x; }); + R r0; + r0 = Create(ref s0); } -}"; - var comp = CreateCompilation(source); - comp.VerifyDiagnostics( - // (11,17): error CS8986: The 'scoped' modifier of parameter 'y' doesn't match target 'D1'. - // D1 d1 = delegate(R x, scoped R y) { return x; }; - Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfTarget, "delegate(R x, scoped R y) { return x; }").WithArguments("y", "D1").WithLocation(11, 17), - // (12,17): error CS8986: The 'scoped' modifier of parameter 'y' doesn't match target 'D2'. - // D2 d2 = delegate(R x, R y) { return x; }; - Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfTarget, "delegate(R x, R y) { return x; }").WithArguments("y", "D2").WithLocation(12, 17), - // (13,17): error CS8986: The 'scoped' modifier of parameter 'y' doesn't match target 'D3'. - // D3 d3 = delegate(ref R x, ref scoped R y) { return ref x; }; - Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfTarget, "delegate(ref R x, ref scoped R y) { return ref x; }").WithArguments("y", "D3").WithLocation(13, 17), - // (14,17): error CS8986: The 'scoped' modifier of parameter 'y' doesn't match target 'D4'. - // D4 d4 = delegate(ref R x, scoped ref R y) { return ref x; }; - Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfTarget, "delegate(ref R x, scoped ref R y) { return ref x; }").WithArguments("y", "D4").WithLocation(14, 17), - // (15,17): error CS8986: The 'scoped' modifier of parameter 'y' doesn't match target 'D5'. - // D5 d5 = delegate(ref R x, ref R y) { return ref x; }; - Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfTarget, "delegate(ref R x, ref R y) { return ref x; }").WithArguments("y", "D5").WithLocation(15, 17), - // (19,18): error CS8986: The 'scoped' modifier of parameter 'y' doesn't match target 'D1'. - // var d1 = (D1)(delegate(R x, scoped R y) { return x; }); - Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfTarget, "(D1)(delegate(R x, scoped R y) { return x; })").WithArguments("y", "D1").WithLocation(19, 18), - // (20,18): error CS8986: The 'scoped' modifier of parameter 'y' doesn't match target 'D2'. - // var d2 = (D2)(delegate(R x, R y) { return x; }); - Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfTarget, "(D2)(delegate(R x, R y) { return x; })").WithArguments("y", "D2").WithLocation(20, 18), - // (21,18): error CS8986: The 'scoped' modifier of parameter 'y' doesn't match target 'D3'. - // var d3 = (D3)(delegate(ref R x, ref scoped R y) { return ref x; }); - Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfTarget, "(D3)(delegate(ref R x, ref scoped R y) { return ref x; })").WithArguments("y", "D3").WithLocation(21, 18), - // (22,18): error CS8986: The 'scoped' modifier of parameter 'y' doesn't match target 'D4'. - // var d4 = (D4)(delegate(ref R x, scoped ref R y) { return ref x; }); - Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfTarget, "(D4)(delegate(ref R x, scoped ref R y) { return ref x; })").WithArguments("y", "D4").WithLocation(22, 18), - // (23,18): error CS8986: The 'scoped' modifier of parameter 'y' doesn't match target 'D5'. - // var d5 = (D5)(delegate(ref R x, ref R y) { return ref x; }); - Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfTarget, "(D5)(delegate(ref R x, ref R y) { return ref x; })").WithArguments("y", "D5").WithLocation(23, 18), - // (27,25): error CS8986: The 'scoped' modifier of parameter 'y' doesn't match target 'D1'. - // var d1 = new D1(delegate(R x, scoped R y) { return x; }); - Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfTarget, "delegate(R x, scoped R y) { return x; }").WithArguments("y", "D1").WithLocation(27, 25), - // (28,25): error CS8986: The 'scoped' modifier of parameter 'y' doesn't match target 'D2'. - // var d2 = new D2(delegate(R x, R y) { return x; }); - Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfTarget, "delegate(R x, R y) { return x; }").WithArguments("y", "D2").WithLocation(28, 25), - // (29,25): error CS8986: The 'scoped' modifier of parameter 'y' doesn't match target 'D3'. - // var d3 = new D3(delegate(ref R x, ref scoped R y) { return ref x; }); - Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfTarget, "delegate(ref R x, ref scoped R y) { return ref x; }").WithArguments("y", "D3").WithLocation(29, 25), - // (30,25): error CS8986: The 'scoped' modifier of parameter 'y' doesn't match target 'D4'. - // var d4 = new D4(delegate(ref R x, scoped ref R y) { return ref x; }); - Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfTarget, "delegate(ref R x, scoped ref R y) { return ref x; }").WithArguments("y", "D4").WithLocation(30, 25), - // (31,25): error CS8986: The 'scoped' modifier of parameter 'y' doesn't match target 'D5'. - // var d5 = new D5(delegate(ref R x, ref R y) { return ref x; }); - Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfTarget, "delegate(ref R x, ref R y) { return ref x; }").WithArguments("y", "D5").WithLocation(31, 25)); - } - - [Fact] - public void DelegateConversions_06() - { - var source = -@"using System.Linq.Expressions; -ref struct R { } -delegate R D1(R x, R y); -delegate R D2(R x, scoped R y); -delegate ref int D3(ref int x, ref int y); -delegate ref int D4(ref int x, scoped ref int y); -class Program -{ - static void Implicit() + static void F1(ref string s1) { - Expression e1 = (R x, scoped R y) => x; - Expression e2 = (R x, R y) => x; - Expression e3 = (ref int x, scoped ref int y) => ref x; - Expression e4 = (ref int x, ref int y) => ref x; + R r1; + r1 = Create(ref s1); } - static void Explicit() + static void F2(out string s2) { - var e1 = (Expression)((R x, scoped R y) => x); - var e2 = (Expression)((R x, R y) => x); - var e3 = (Expression)((ref int x, scoped ref int y) => ref x); - var e4 = (Expression)((ref int x, ref int y) => ref x); + s2 = null; + R r2; + r2 = Create(ref s2); } -}"; - var comp = CreateCompilation(source); - comp.VerifyDiagnostics( - // (11,29): error CS8986: The 'scoped' modifier of parameter 'y' doesn't match target 'Expression'. - // Expression e1 = (R x, scoped R y) => x; - Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfTarget, "(R x, scoped R y) => x").WithArguments("y", "System.Linq.Expressions.Expression").WithLocation(11, 29), - // (11,32): error CS8640: Expression tree cannot contain value of ref struct or restricted type 'R'. - // Expression e1 = (R x, scoped R y) => x; - Diagnostic(ErrorCode.ERR_ExpressionTreeCantContainRefStruct, "x").WithArguments("R").WithLocation(11, 32), - // (11,44): error CS8640: Expression tree cannot contain value of ref struct or restricted type 'R'. - // Expression e1 = (R x, scoped R y) => x; - Diagnostic(ErrorCode.ERR_ExpressionTreeCantContainRefStruct, "y").WithArguments("R").WithLocation(11, 44), - // (11,50): error CS8640: Expression tree cannot contain value of ref struct or restricted type 'R'. - // Expression e1 = (R x, scoped R y) => x; - Diagnostic(ErrorCode.ERR_ExpressionTreeCantContainRefStruct, "x").WithArguments("R").WithLocation(11, 50), - // (12,29): error CS8986: The 'scoped' modifier of parameter 'y' doesn't match target 'Expression'. - // Expression e2 = (R x, R y) => x; - Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfTarget, "(R x, R y) => x").WithArguments("y", "System.Linq.Expressions.Expression").WithLocation(12, 29), - // (12,32): error CS8640: Expression tree cannot contain value of ref struct or restricted type 'R'. - // Expression e2 = (R x, R y) => x; - Diagnostic(ErrorCode.ERR_ExpressionTreeCantContainRefStruct, "x").WithArguments("R").WithLocation(12, 32), - // (12,37): error CS8640: Expression tree cannot contain value of ref struct or restricted type 'R'. - // Expression e2 = (R x, R y) => x; - Diagnostic(ErrorCode.ERR_ExpressionTreeCantContainRefStruct, "y").WithArguments("R").WithLocation(12, 37), - // (12,43): error CS8640: Expression tree cannot contain value of ref struct or restricted type 'R'. - // Expression e2 = (R x, R y) => x; - Diagnostic(ErrorCode.ERR_ExpressionTreeCantContainRefStruct, "x").WithArguments("R").WithLocation(12, 43), - // (13,29): error CS8986: The 'scoped' modifier of parameter 'y' doesn't match target 'Expression'. - // Expression e3 = (ref int x, scoped ref int y) => ref x; - Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfTarget, "(ref int x, scoped ref int y) => ref x").WithArguments("y", "System.Linq.Expressions.Expression").WithLocation(13, 29), - // (13,29): error CS8155: Lambda expressions that return by reference cannot be converted to expression trees - // Expression e3 = (ref int x, scoped ref int y) => ref x; - Diagnostic(ErrorCode.ERR_BadRefReturnExpressionTree, "(ref int x, scoped ref int y) => ref x").WithLocation(13, 29), - // (13,38): error CS1951: An expression tree lambda may not contain a ref, in or out parameter - // Expression e3 = (ref int x, scoped ref int y) => ref x; - Diagnostic(ErrorCode.ERR_ByRefParameterInExpressionTree, "x").WithLocation(13, 38), - // (13,56): error CS1951: An expression tree lambda may not contain a ref, in or out parameter - // Expression e3 = (ref int x, scoped ref int y) => ref x; - Diagnostic(ErrorCode.ERR_ByRefParameterInExpressionTree, "y").WithLocation(13, 56), - // (14,29): error CS8986: The 'scoped' modifier of parameter 'y' doesn't match target 'Expression'. - // Expression e4 = (ref int x, ref int y) => ref x; - Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfTarget, "(ref int x, ref int y) => ref x").WithArguments("y", "System.Linq.Expressions.Expression").WithLocation(14, 29), - // (14,29): error CS8155: Lambda expressions that return by reference cannot be converted to expression trees - // Expression e4 = (ref int x, ref int y) => ref x; - Diagnostic(ErrorCode.ERR_BadRefReturnExpressionTree, "(ref int x, ref int y) => ref x").WithLocation(14, 29), - // (14,38): error CS1951: An expression tree lambda may not contain a ref, in or out parameter - // Expression e4 = (ref int x, ref int y) => ref x; - Diagnostic(ErrorCode.ERR_ByRefParameterInExpressionTree, "x").WithLocation(14, 38), - // (14,49): error CS1951: An expression tree lambda may not contain a ref, in or out parameter - // Expression e4 = (ref int x, ref int y) => ref x; - Diagnostic(ErrorCode.ERR_ByRefParameterInExpressionTree, "y").WithLocation(14, 49), - // (18,18): error CS8986: The 'scoped' modifier of parameter 'y' doesn't match target 'Expression'. - // var e1 = (Expression)((R x, scoped R y) => x); - Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfTarget, "(Expression)((R x, scoped R y) => x)").WithArguments("y", "System.Linq.Expressions.Expression").WithLocation(18, 18), - // (18,38): error CS8640: Expression tree cannot contain value of ref struct or restricted type 'R'. - // var e1 = (Expression)((R x, scoped R y) => x); - Diagnostic(ErrorCode.ERR_ExpressionTreeCantContainRefStruct, "x").WithArguments("R").WithLocation(18, 38), - // (18,50): error CS8640: Expression tree cannot contain value of ref struct or restricted type 'R'. - // var e1 = (Expression)((R x, scoped R y) => x); - Diagnostic(ErrorCode.ERR_ExpressionTreeCantContainRefStruct, "y").WithArguments("R").WithLocation(18, 50), - // (18,56): error CS8640: Expression tree cannot contain value of ref struct or restricted type 'R'. - // var e1 = (Expression)((R x, scoped R y) => x); - Diagnostic(ErrorCode.ERR_ExpressionTreeCantContainRefStruct, "x").WithArguments("R").WithLocation(18, 56), - // (19,18): error CS8986: The 'scoped' modifier of parameter 'y' doesn't match target 'Expression'. - // var e2 = (Expression)((R x, R y) => x); - Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfTarget, "(Expression)((R x, R y) => x)").WithArguments("y", "System.Linq.Expressions.Expression").WithLocation(19, 18), - // (19,38): error CS8640: Expression tree cannot contain value of ref struct or restricted type 'R'. - // var e2 = (Expression)((R x, R y) => x); - Diagnostic(ErrorCode.ERR_ExpressionTreeCantContainRefStruct, "x").WithArguments("R").WithLocation(19, 38), - // (19,43): error CS8640: Expression tree cannot contain value of ref struct or restricted type 'R'. - // var e2 = (Expression)((R x, R y) => x); - Diagnostic(ErrorCode.ERR_ExpressionTreeCantContainRefStruct, "y").WithArguments("R").WithLocation(19, 43), - // (19,49): error CS8640: Expression tree cannot contain value of ref struct or restricted type 'R'. - // var e2 = (Expression)((R x, R y) => x); - Diagnostic(ErrorCode.ERR_ExpressionTreeCantContainRefStruct, "x").WithArguments("R").WithLocation(19, 49), - // (20,18): error CS8986: The 'scoped' modifier of parameter 'y' doesn't match target 'Expression'. - // var e3 = (Expression)((ref int x, scoped ref int y) => ref x); - Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfTarget, "(Expression)((ref int x, scoped ref int y) => ref x)").WithArguments("y", "System.Linq.Expressions.Expression").WithLocation(20, 18), - // (20,35): error CS8155: Lambda expressions that return by reference cannot be converted to expression trees - // var e3 = (Expression)((ref int x, scoped ref int y) => ref x); - Diagnostic(ErrorCode.ERR_BadRefReturnExpressionTree, "(ref int x, scoped ref int y) => ref x").WithLocation(20, 35), - // (20,44): error CS1951: An expression tree lambda may not contain a ref, in or out parameter - // var e3 = (Expression)((ref int x, scoped ref int y) => ref x); - Diagnostic(ErrorCode.ERR_ByRefParameterInExpressionTree, "x").WithLocation(20, 44), - // (20,62): error CS1951: An expression tree lambda may not contain a ref, in or out parameter - // var e3 = (Expression)((ref int x, scoped ref int y) => ref x); - Diagnostic(ErrorCode.ERR_ByRefParameterInExpressionTree, "y").WithLocation(20, 62), - // (21,18): error CS8986: The 'scoped' modifier of parameter 'y' doesn't match target 'Expression'. - // var e4 = (Expression)((ref int x, ref int y) => ref x); - Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfTarget, "(Expression)((ref int x, ref int y) => ref x)").WithArguments("y", "System.Linq.Expressions.Expression").WithLocation(21, 18), - // (21,35): error CS8155: Lambda expressions that return by reference cannot be converted to expression trees - // var e4 = (Expression)((ref int x, ref int y) => ref x); - Diagnostic(ErrorCode.ERR_BadRefReturnExpressionTree, "(ref int x, ref int y) => ref x").WithLocation(21, 35), - // (21,44): error CS1951: An expression tree lambda may not contain a ref, in or out parameter - // var e4 = (Expression)((ref int x, ref int y) => ref x); - Diagnostic(ErrorCode.ERR_ByRefParameterInExpressionTree, "x").WithLocation(21, 44), - // (21,55): error CS1951: An expression tree lambda may not contain a ref, in or out parameter - // var e4 = (Expression)((ref int x, ref int y) => ref x); - Diagnostic(ErrorCode.ERR_ByRefParameterInExpressionTree, "y").WithLocation(21, 55)); - } - - [Fact] - public void DelegateConversions_Out() - { - var source = -@"ref struct R { } -delegate void D1(out int x, scoped out int y); -delegate void D2(out scoped R x, scoped out scoped R y); -class Program -{ - static void Implicit() + static void F3(in string s3) { - D1 d1 = (scoped out int x, out int y) => { x = 0; y = 0; }; - D2 d2 = (scoped out scoped R x, out scoped R y) => { x = default; y = default; }; + R r3; + r3 = CreateReadonly(in s3); } - static void Explicit() + static void F4(scoped ref string s4) { - var d1 = (D1)((scoped out int x, out int y) => { x = 0; y = 0; }); - var d2 = (D2)((scoped out scoped R x, out scoped R y) => { x = default; y = default; }); + R r4; + r4 = Create(ref s4); } - static void New() + static void F5(scoped out string s5) { - var d1 = new D1((scoped out int x, out int y) => { x = 0; y = 0; }); - var d2 = new D2((scoped out scoped R x, out scoped R y) => { x = default; y = default; }); + s5 = null; + R r5; + r5 = Create(ref s5); + } + static void F6(scoped in string s6) + { + R r6; + r6 = CreateReadonly(in s6); } }"; var comp = CreateCompilation(source); @@ -8478,3239 +11835,4064 @@ static void New() } [Fact] - public void FunctionPointerConversions() + public void This_FromLocal() { var source = -@"ref struct R { } -unsafe class Program +@"ref struct R { - static R F1(R x, scoped R y) => x; - static ref R F2(ref R x, ref scoped R y) => ref x; - static ref readonly int F3(in int x, scoped in int y) => ref x; - static void Implicit() + static R Create() => new R(); + static R Create(ref T t) => new R(ref t); + static void M(R r) { } + private ref T F; + public R(ref T t) { F = ref t; } + public R(sbyte unused) { - delegate* d1 = &F1; - delegate* d2 = &F2; - delegate* d3 = &F3; + T t1 = default; + this = new R(ref t1); + M(this); } - static void Explicit() + public R(short unused) { - var d1 = (delegate*)&F1; - var d2 = (delegate*)&F2; - var d3 = (delegate*)&F3; + T t2 = default; + this = new R(); + this.F = ref t2; + M(this); } -}"; - var comp = CreateCompilation(source, options: TestOptions.UnsafeReleaseDll); - comp.VerifyDiagnostics( - // (9,33): error CS8986: The 'scoped' modifier of parameter 'y' doesn't match target 'delegate*'. - // delegate* d1 = &F1; - Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfTarget, "&F1").WithArguments("y", "delegate*").WithLocation(9, 33), - // (10,45): error CS8986: The 'scoped' modifier of parameter 'y' doesn't match target 'delegate*'. - // delegate* d2 = &F2; - Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfTarget, "&F2").WithArguments("y", "delegate*").WithLocation(10, 45), - // (11,58): error CS8986: The 'scoped' modifier of parameter 'y' doesn't match target 'delegate*'. - // delegate* d3 = &F3; - Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfTarget, "&F3").WithArguments("y", "delegate*").WithLocation(11, 58), - // (15,18): error CS8986: The 'scoped' modifier of parameter 'y' doesn't match target 'delegate*'. - // var d1 = (delegate*)&F1; - Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfTarget, "(delegate*)&F1").WithArguments("y", "delegate*").WithLocation(15, 18), - // (16,18): error CS8986: The 'scoped' modifier of parameter 'y' doesn't match target 'delegate*'. - // var d2 = (delegate*)&F2; - Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfTarget, "(delegate*)&F2").WithArguments("y", "delegate*").WithLocation(16, 18), - // (17,18): error CS8986: The 'scoped' modifier of parameter 'y' doesn't match target 'delegate*'. - // var d3 = (delegate*)&F3; - Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfTarget, "(delegate*)&F3").WithArguments("y", "delegate*").WithLocation(17, 18)); - } - - [Fact] - public void FunctionPointerConversions_Out() - { - var source = -@"unsafe class Program -{ - static void F(out int x, scoped out int y) { x = 0; y = 0; } - static void Implicit() + public R(int unused) { - delegate* d = &F; + T t3 = default; + this = Create(ref t3); + M(this); } - static void Explicit() + public R(long unused) { - var d = (delegate*)&F; + T t4 = default; + this = Create(); + this.F = ref t4; + M(this); } }"; - var comp = CreateCompilation(source, options: TestOptions.UnsafeReleaseDll); - comp.VerifyDiagnostics(); - } - - [Fact] - public void DuplicateMethodSignatures() - { - var source = -@"ref struct R { } -class C -{ - static void M1(R r) { } - void M2(scoped R r) { } - static void M3(ref scoped R r) { } - void M4(scoped ref R r) { } - object this[R r] => null; - static void M1(scoped R r) { } // 1 - void M2(R r) { } // 2 - static void M3(scoped ref R r) { } // 3 - void M4(ref scoped R r) { } // 4 - object this[scoped R r] => null; // 5 -}"; - var comp = CreateCompilation(source); - comp.VerifyEmitDiagnostics( - // (9,17): error CS0111: Type 'C' already defines a member called 'M1' with the same parameter types - // static void M1(scoped R r) { } // 1 - Diagnostic(ErrorCode.ERR_MemberAlreadyExists, "M1").WithArguments("M1", "C").WithLocation(9, 17), - // (10,10): error CS0111: Type 'C' already defines a member called 'M2' with the same parameter types - // void M2(R r) { } // 2 - Diagnostic(ErrorCode.ERR_MemberAlreadyExists, "M2").WithArguments("M2", "C").WithLocation(10, 10), - // (11,17): error CS0111: Type 'C' already defines a member called 'M3' with the same parameter types - // static void M3(scoped ref R r) { } // 3 - Diagnostic(ErrorCode.ERR_MemberAlreadyExists, "M3").WithArguments("M3", "C").WithLocation(11, 17), - // (12,10): error CS0111: Type 'C' already defines a member called 'M4' with the same parameter types - // void M4(ref scoped R r) { } // 4 - Diagnostic(ErrorCode.ERR_MemberAlreadyExists, "M4").WithArguments("M4", "C").WithLocation(12, 10), - // (13,12): error CS0111: Type 'C' already defines a member called 'this' with the same parameter types - // object this[scoped R r] => null; // 5 - Diagnostic(ErrorCode.ERR_MemberAlreadyExists, "this").WithArguments("this", "C").WithLocation(13, 12)); - } - - [Fact] - public void Overloads() - { - var source = -@"ref struct R { } -class C -{ - static void M1(R r) { } - static void M2(scoped R r) { } - static void M3(ref R r) { } - static void M4(ref scoped R r) { } - static void M5(scoped ref R r) { } - static void M1(scoped R r) { } // 1 - static void M2(R r) { } // 2 - static void M3(ref scoped R r) { } // 3 - static void M4(scoped ref R r) { } // 4 - static void M5(ref R r) { } // 5 -}"; - var comp = CreateCompilation(source); + var comp = CreateCompilation(source, runtimeFeature: RuntimeFlag.ByRefFields); comp.VerifyEmitDiagnostics( - // (9,17): error CS0111: Type 'C' already defines a member called 'M1' with the same parameter types - // static void M1(scoped R r) { } // 1 - Diagnostic(ErrorCode.ERR_MemberAlreadyExists, "M1").WithArguments("M1", "C").WithLocation(9, 17), - // (10,17): error CS0111: Type 'C' already defines a member called 'M2' with the same parameter types - // static void M2(R r) { } // 2 - Diagnostic(ErrorCode.ERR_MemberAlreadyExists, "M2").WithArguments("M2", "C").WithLocation(10, 17), - // (11,17): error CS0111: Type 'C' already defines a member called 'M3' with the same parameter types - // static void M3(ref scoped R r) { } // 3 - Diagnostic(ErrorCode.ERR_MemberAlreadyExists, "M3").WithArguments("M3", "C").WithLocation(11, 17), - // (12,17): error CS0111: Type 'C' already defines a member called 'M4' with the same parameter types - // static void M4(scoped ref R r) { } // 4 - Diagnostic(ErrorCode.ERR_MemberAlreadyExists, "M4").WithArguments("M4", "C").WithLocation(12, 17), - // (13,17): error CS0111: Type 'C' already defines a member called 'M5' with the same parameter types - // static void M5(ref R r) { } // 5 - Diagnostic(ErrorCode.ERR_MemberAlreadyExists, "M5").WithArguments("M5", "C").WithLocation(13, 17)); - } - - [Fact] - public void PartialMethods() - { - var sourceA = -@"ref struct R { } -partial class C -{ - static partial void M1(R r); - static partial void M2(scoped R r); - static partial void M3(ref R r); - static partial void M4(ref scoped R r); - static partial void M5(scoped ref R r); -}"; - var sourceB1 = -@"partial class C -{ - static partial void M1(R r) { } - static partial void M2(scoped R r) { } - static partial void M3(ref R r) { } - static partial void M4(ref scoped R r) { } - static partial void M5(scoped ref R r) { } -}"; - var sourceB2 = -@"partial class C -{ - static partial void M1(scoped R r) { } // 1 - static partial void M2(R r) { } // 2 - static partial void M3(ref scoped R r) { } // 3 - static partial void M4(scoped ref R r) { } // 4 - static partial void M5(ref R r) { } // 5 -}"; - var comp = CreateCompilation(new[] { sourceA, sourceB1 }); - comp.VerifyEmitDiagnostics(); - - var expectedDiagnostics = new[] - { - // (3,25): error CS8988: The 'scoped' modifier of parameter 'r' doesn't match partial method declaration. - // static partial void M1(scoped R r) { } // 1 - Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfPartial, "M1").WithArguments("r").WithLocation(3, 25), - // (4,25): error CS8988: The 'scoped' modifier of parameter 'r' doesn't match partial method declaration. - // static partial void M2(R r) { } // 2 - Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfPartial, "M2").WithArguments("r").WithLocation(4, 25), - // (5,25): error CS8988: The 'scoped' modifier of parameter 'r' doesn't match partial method declaration. - // static partial void M3(ref scoped R r) { } // 3 - Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfPartial, "M3").WithArguments("r").WithLocation(5, 25), - // (6,25): error CS8988: The 'scoped' modifier of parameter 'r' doesn't match partial method declaration. - // static partial void M4(scoped ref R r) { } // 4 - Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfPartial, "M4").WithArguments("r").WithLocation(6, 25), - // (7,25): error CS8988: The 'scoped' modifier of parameter 'r' doesn't match partial method declaration. - // static partial void M5(ref R r) { } // 5 - Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfPartial, "M5").WithArguments("r").WithLocation(7, 25) - }; - - comp = CreateCompilation(new[] { sourceA, sourceB2 }); - comp.VerifyEmitDiagnostics(expectedDiagnostics); - - comp = CreateCompilation(new[] { sourceB2, sourceA }); - comp.VerifyEmitDiagnostics(expectedDiagnostics); + // (11,16): error CS8347: Cannot use a result of 'R.R(ref T)' in this context because it may expose variables referenced by parameter 't' outside of their declaration scope + // this = new R(ref t1); + Diagnostic(ErrorCode.ERR_EscapeCall, "new R(ref t1)").WithArguments("R.R(ref T)", "t").WithLocation(11, 16), + // (11,29): error CS8168: Cannot return local 't1' by reference because it is not a ref local + // this = new R(ref t1); + Diagnostic(ErrorCode.ERR_RefReturnLocal, "t1").WithArguments("t1").WithLocation(11, 29), + // (18,9): error CS8374: Cannot ref-assign 't2' to 'F' because 't2' has a narrower escape scope than 'F'. + // this.F = ref t2; + Diagnostic(ErrorCode.ERR_RefAssignNarrower, "this.F = ref t2").WithArguments("F", "t2").WithLocation(18, 9), + // (24,16): error CS8347: Cannot use a result of 'R.Create(ref T)' in this context because it may expose variables referenced by parameter 't' outside of their declaration scope + // this = Create(ref t3); + Diagnostic(ErrorCode.ERR_EscapeCall, "Create(ref t3)").WithArguments("R.Create(ref T)", "t").WithLocation(24, 16), + // (24,27): error CS8168: Cannot return local 't3' by reference because it is not a ref local + // this = Create(ref t3); + Diagnostic(ErrorCode.ERR_RefReturnLocal, "t3").WithArguments("t3").WithLocation(24, 27), + // (31,9): error CS8374: Cannot ref-assign 't4' to 'F' because 't4' has a narrower escape scope than 'F'. + // this.F = ref t4; + Diagnostic(ErrorCode.ERR_RefAssignNarrower, "this.F = ref t4").WithArguments("F", "t4").WithLocation(31, 9)); } [Fact] - public void PartialMethods_Out() + public void This_FromParameter() { var source = -@"ref struct R { } -partial class C -{ - private partial void F1(out int i); - private partial void F2(scoped out int i); - private partial void F3(out scoped R r); - private partial void F4(scoped out scoped R r); - private partial void F1(scoped out int i) { i = 0; } - private partial void F2(out int i) { i = 0; } - private partial void F3(scoped out scoped R r) { r = default; } - private partial void F4(out scoped R r) { r = default; } -}"; - var comp = CreateCompilation(source); - comp.VerifyEmitDiagnostics(); - } - - [CombinatorialData] - [Theory] - public void Hiding(bool useCompilationReference) - { - var sourceA = -@"public ref struct R { } -public class A -{ - public void M1(R r) { } - public void M2(scoped R r) { } - public void M3(ref scoped R r) { } - public void M4(scoped ref R r) { } - public object this[R r] { get { return null; } set { } } - public object this[int x, scoped R y] => null; -}"; - var comp = CreateCompilation(sourceA); - comp.VerifyEmitDiagnostics(); - var refA = AsReference(comp, useCompilationReference); - - var sourceB = -@"class B1 : A -{ - public new void M1(scoped R r) { } - public new void M2(R r) { } - public new void M3(scoped ref R r) { } - public new void M4(ref scoped R r) { } - public new object this[scoped R r] { get { return null; } set { } } - public new object this[int x, R y] => null; -} -class B2 : A +@"ref struct R { - public void M1(scoped R r) { } // 1 - public void M2(R r) { } // 2 - public void M3(scoped ref R r) { } // 3 - public void M4(ref scoped R r) { } // 4 - public object this[scoped R r] { get { return null; } set { } } // 5 - public object this[int x, R y] => null; // 6 + static R Create() => new R(); + static R Create(ref T t) => new R(ref t); + static void M(R r) { } + private ref T F; + R(ref T t) { F = ref t; } + R(sbyte unused, T t1) + { + this = new R(ref t1); + M(this); + } + R(short unused, T t2) + { + this = new R(); + this.F = ref t2; + M(this); + } + R(int unused, T t3) + { + this = Create(ref t3); + M(this); + } + R(long unused, T t4) + { + this = Create(); + this.F = ref t4; + M(this); + } }"; - comp = CreateCompilation(sourceB, references: new[] { refA }); + var comp = CreateCompilation(source, runtimeFeature: RuntimeFlag.ByRefFields); comp.VerifyEmitDiagnostics( - // (12,17): warning CS0108: 'B2.M1(R)' hides inherited member 'A.M1(R)'. Use the new keyword if hiding was intended. - // public void M1(scoped R r) { } // 1 - Diagnostic(ErrorCode.WRN_NewRequired, "M1").WithArguments("B2.M1(R)", "A.M1(R)").WithLocation(12, 17), - // (13,17): warning CS0108: 'B2.M2(R)' hides inherited member 'A.M2(R)'. Use the new keyword if hiding was intended. - // public void M2(R r) { } // 2 - Diagnostic(ErrorCode.WRN_NewRequired, "M2").WithArguments("B2.M2(R)", "A.M2(R)").WithLocation(13, 17), - // (14,17): warning CS0108: 'B2.M3(ref R)' hides inherited member 'A.M3(ref R)'. Use the new keyword if hiding was intended. - // public void M3(scoped ref R r) { } // 3 - Diagnostic(ErrorCode.WRN_NewRequired, "M3").WithArguments("B2.M3(ref R)", "A.M3(ref R)").WithLocation(14, 17), - // (15,17): warning CS0108: 'B2.M4(ref R)' hides inherited member 'A.M4(ref R)'. Use the new keyword if hiding was intended. - // public void M4(ref scoped R r) { } // 4 - Diagnostic(ErrorCode.WRN_NewRequired, "M4").WithArguments("B2.M4(ref R)", "A.M4(ref R)").WithLocation(15, 17), - // (16,19): warning CS0108: 'B2.this[R]' hides inherited member 'A.this[R]'. Use the new keyword if hiding was intended. - // public object this[scoped R r] { get { return null; } set { } } // 5 - Diagnostic(ErrorCode.WRN_NewRequired, "this").WithArguments("B2.this[R]", "A.this[R]").WithLocation(16, 19), - // (17,19): warning CS0108: 'B2.this[int, R]' hides inherited member 'A.this[int, R]'. Use the new keyword if hiding was intended. - // public object this[int x, R y] => null; // 6 - Diagnostic(ErrorCode.WRN_NewRequired, "this").WithArguments("B2.this[int, R]", "A.this[int, R]").WithLocation(17, 19)); + // (10,16): error CS8347: Cannot use a result of 'R.R(ref T)' in this context because it may expose variables referenced by parameter 't' outside of their declaration scope + // this = new R(ref t1); + Diagnostic(ErrorCode.ERR_EscapeCall, "new R(ref t1)").WithArguments("R.R(ref T)", "t").WithLocation(10, 16), + // (10,29): error CS8166: Cannot return a parameter by reference 't1' because it is not a ref parameter + // this = new R(ref t1); + Diagnostic(ErrorCode.ERR_RefReturnParameter, "t1").WithArguments("t1").WithLocation(10, 29), + // (16,9): error CS8374: Cannot ref-assign 't2' to 'F' because 't2' has a narrower escape scope than 'F'. + // this.F = ref t2; + Diagnostic(ErrorCode.ERR_RefAssignNarrower, "this.F = ref t2").WithArguments("F", "t2").WithLocation(16, 9), + // (21,16): error CS8347: Cannot use a result of 'R.Create(ref T)' in this context because it may expose variables referenced by parameter 't' outside of their declaration scope + // this = Create(ref t3); + Diagnostic(ErrorCode.ERR_EscapeCall, "Create(ref t3)").WithArguments("R.Create(ref T)", "t").WithLocation(21, 16), + // (21,27): error CS8166: Cannot return a parameter by reference 't3' because it is not a ref parameter + // this = Create(ref t3); + Diagnostic(ErrorCode.ERR_RefReturnParameter, "t3").WithArguments("t3").WithLocation(21, 27), + // (27,9): error CS8374: Cannot ref-assign 't4' to 'F' because 't4' has a narrower escape scope than 'F'. + // this.F = ref t4; + Diagnostic(ErrorCode.ERR_RefAssignNarrower, "this.F = ref t4").WithArguments("F", "t4").WithLocation(27, 9)); } - [CombinatorialData] - [Theory] - public void Overrides(bool useCompilationReference) + [Fact] + public void This_FromRefParameter() { - var sourceA = -@"public ref struct R { } -public abstract class A -{ - public abstract R F1(R r); - public abstract R F2(scoped R r); - public abstract R F3(ref scoped R r); - public abstract R F4(scoped ref R r); - public abstract object this[R r] { get; set; } - public abstract object this[int x, scoped R y] { get; } -}"; - var comp = CreateCompilation(sourceA); - comp.VerifyEmitDiagnostics(); - var refA = AsReference(comp, useCompilationReference); - - var sourceB = -@"class B1 : A -{ - public override R F1(R r) => default; - public override R F2(scoped R r) => default; - public override R F3(ref scoped R r) => default; - public override R F4(scoped ref R r) => default; - public override object this[R r] { get { return null; } set { } } - public override object this[int x, scoped R y] => null; -} -class B2 : A + var source = +@"ref struct R { - public override R F1(scoped R r) => default; // 1 - public override R F2(R r) => default; // 2 - public override R F3(scoped ref R r) => default; // 3 - public override R F4(ref scoped R r) => default; // 4 - public override object this[scoped R r] { get { return null; } set { } } // 5 - public override object this[int x, R y] => null; // 6 + static void M(R r) { } + private ref T F; + R(ref T t) { F = ref t; } + R(sbyte unused, ref T t1) + { + this = new R(ref t1); + M(this); + } + R(short unused, scoped ref T t2) + { + this = new R(ref t2); + M(this); + } }"; - comp = CreateCompilation(sourceB, references: new[] { refA }); + var comp = CreateCompilation(source, runtimeFeature: RuntimeFlag.ByRefFields); comp.VerifyEmitDiagnostics( - // (12,31): error CS8987: The 'scoped' modifier of parameter 'r' doesn't match overridden or implemented member. - // public override R F1(scoped R r) => default; // 1 - Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfOverrideOrImplementation, "F1").WithArguments("r").WithLocation(12, 31), - // (13,31): error CS8987: The 'scoped' modifier of parameter 'r' doesn't match overridden or implemented member. - // public override R F2(R r) => default; // 2 - Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfOverrideOrImplementation, "F2").WithArguments("r").WithLocation(13, 31), - // (14,31): error CS8987: The 'scoped' modifier of parameter 'r' doesn't match overridden or implemented member. - // public override R F3(scoped ref R r) => default; // 3 - Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfOverrideOrImplementation, "F3").WithArguments("r").WithLocation(14, 31), - // (15,31): error CS8987: The 'scoped' modifier of parameter 'r' doesn't match overridden or implemented member. - // public override R F4(ref scoped R r) => default; // 4 - Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfOverrideOrImplementation, "F4").WithArguments("r").WithLocation(15, 31), - // (16,76): error CS8987: The 'scoped' modifier of parameter 'r' doesn't match overridden or implemented member. - // public override object this[scoped R r] { get { return null; } set { } } // 5 - Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfOverrideOrImplementation, "set").WithArguments("r").WithLocation(16, 76), - // (17,56): error CS8987: The 'scoped' modifier of parameter 'y' doesn't match overridden or implemented member. - // public override object this[int x, R y] => null; // 6 - Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfOverrideOrImplementation, "null").WithArguments("y").WithLocation(17, 56)); + // (13,16): error CS8347: Cannot use a result of 'R.R(ref T)' in this context because it may expose variables referenced by parameter 't' outside of their declaration scope + // this = new R(ref t2); + Diagnostic(ErrorCode.ERR_EscapeCall, "new R(ref t2)").WithArguments("R.R(ref T)", "t").WithLocation(13, 16), + // (13,29): error CS8166: Cannot return a parameter by reference 't2' because it is not a ref parameter + // this = new R(ref t2); + Diagnostic(ErrorCode.ERR_RefReturnParameter, "t2").WithArguments("t2").WithLocation(13, 29)); } - [CombinatorialData] - [Theory] - public void InterfaceImplementations(bool useCompilationReference) + [Fact] + public void This_FromRefStructParameter() { - var sourceA = -@"public ref struct R { } -public interface I + var source = +@"ref struct R { - R F1(R r); - R F2(scoped R r); - R F3(ref scoped R r); - R F4(scoped ref R r); - object this[R r] { get; set; } - object this[int x, scoped R y] { get; } + static void M(R r) { } + private ref T F; + R(sbyte unused, ref R r1) + { + this = r1; + M(this); + } + R(short unused, scoped ref R r2) + { + this = r2; + M(this); + } }"; - var comp = CreateCompilation(sourceA); - comp.VerifyEmitDiagnostics(); - var refA = AsReference(comp, useCompilationReference); + var comp = CreateCompilation(source, runtimeFeature: RuntimeFlag.ByRefFields); + comp.VerifyEmitDiagnostics( + // (4,19): warning CS0169: The field 'R.F' is never used + // private ref T F; + Diagnostic(ErrorCode.WRN_UnreferencedField, "F").WithArguments("R.F").WithLocation(4, 19)); + } - var sourceB1 = -@"class C1 : I + [WorkItem(63140, "https://github.com/dotnet/roslyn/issues/63140")] + [Fact] + public void Scoped_Cycle() + { + var source = +@"interface I { - public R F1(R r) => default; - public R F2(scoped R r) => default; - public R F3(ref scoped R r) => default; - public R F4(scoped ref R r) => default; - public object this[R r] { get { return null; } set { } } - public object this[int x, scoped R y] => null; + void M(T s); } -class C2 : I + +class C : I { - public R F1(scoped R r) => default; // 1 - public R F2(R r) => default; // 2 - public R F3(scoped ref R r) => default; // 3 - public R F4(ref scoped R r) => default; // 4 - public object this[scoped R r] { get { return null; } set { } } // 5 - public object this[int x, R y] => null; // 6 + void I.M(scoped T? s) {} }"; - comp = CreateCompilation(sourceB1, references: new[] { refA }); - comp.VerifyEmitDiagnostics( - // (12,22): error CS8987: The 'scoped' modifier of parameter 'r' doesn't match overridden or implemented member. - // public R F1(scoped R r) => default; // 1 - Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfOverrideOrImplementation, "F1").WithArguments("r").WithLocation(12, 22), - // (13,22): error CS8987: The 'scoped' modifier of parameter 'r' doesn't match overridden or implemented member. - // public R F2(R r) => default; // 2 - Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfOverrideOrImplementation, "F2").WithArguments("r").WithLocation(13, 22), - // (14,22): error CS8987: The 'scoped' modifier of parameter 'r' doesn't match overridden or implemented member. - // public R F3(scoped ref R r) => default; // 3 - Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfOverrideOrImplementation, "F3").WithArguments("r").WithLocation(14, 22), - // (15,22): error CS8987: The 'scoped' modifier of parameter 'r' doesn't match overridden or implemented member. - // public R F4(ref scoped R r) => default; // 4 - Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfOverrideOrImplementation, "F4").WithArguments("r").WithLocation(15, 22), - // (16,67): error CS8987: The 'scoped' modifier of parameter 'r' doesn't match overridden or implemented member. - // public object this[scoped R r] { get { return null; } set { } } // 5 - Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfOverrideOrImplementation, "set").WithArguments("r").WithLocation(16, 67), - // (17,47): error CS8987: The 'scoped' modifier of parameter 'y' doesn't match overridden or implemented member. - // public object this[int x, R y] => null; // 6 - Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfOverrideOrImplementation, "null").WithArguments("y").WithLocation(17, 47)); + var comp = CreateCompilation(source); + comp.VerifyDiagnostics( + // (6,11): error CS0535: 'C' does not implement interface member 'I.M(T)' + // class C : I + Diagnostic(ErrorCode.ERR_UnimplementedInterfaceMember, "I").WithArguments("C", "I.M(T)").WithLocation(6, 11), + // (8,12): error CS0539: 'C.M(T?)' in explicit interface declaration is not found among members of the interface that can be implemented + // void I.M(scoped T? s) {} + Diagnostic(ErrorCode.ERR_InterfaceMemberNotFound, "M").WithArguments("C.M(T?)").WithLocation(8, 12), + // (8,17): error CS9048: The 'scoped' modifier can be used for refs and ref struct values only. + // void I.M(scoped T? s) {} + Diagnostic(ErrorCode.ERR_ScopedRefAndRefStructOnly, "scoped T? s").WithLocation(8, 17), + // (8,25): warning CS8632: The annotation for nullable reference types should only be used in code within a '#nullable' annotations context. + // void I.M(scoped T? s) {} + Diagnostic(ErrorCode.WRN_MissingNonNullTypesContextForAnnotation, "?").WithLocation(8, 25), + // (8,27): 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 'Nullable' + // void I.M(scoped T? s) {} + Diagnostic(ErrorCode.ERR_ValConstraintNotSatisfied, "s").WithArguments("System.Nullable", "T", "T").WithLocation(8, 27)); + } - var sourceB2 = -@"class C3 : I + [Fact] + public void NestedScope() + { + var source = +@"ref struct R { - R I.F1(R r) => default; - R I.F2(scoped R r) => default; - R I.F3(ref scoped R r) => default; - R I.F4(scoped ref R r) => default; - object I.this[R r] { get { return null; } set { } } - object I.this[int x, scoped R y] => null; + public ref T F; } -class C4 : I +class Program { - R I.F1(scoped R r) => default; // 1 - R I.F2(R r) => default; // 2 - R I.F3(scoped ref R r) => default; // 3 - R I.F4(ref scoped R r) => default; // 4 - object I.this[scoped R r] { get { return null; } set { } } // 5 - object I.this[int x, R y] => null; // 6 + static T F() + { + scoped R r; + { + T t = default; + r.F = ref t; + } + return r.F; + } }"; - comp = CreateCompilation(sourceB2, references: new[] { refA }); + var comp = CreateCompilation(source, runtimeFeature: RuntimeFlag.ByRefFields); comp.VerifyEmitDiagnostics( - // (12,25): error CS8987: The 'scoped' modifier of parameter 'r' doesn't match overridden or implemented member. - // R I.F1(scoped R r) => default; // 1 - Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfOverrideOrImplementation, "F1").WithArguments("r").WithLocation(12, 25), - // (13,25): error CS8987: The 'scoped' modifier of parameter 'r' doesn't match overridden or implemented member. - // R I.F2(R r) => default; // 2 - Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfOverrideOrImplementation, "F2").WithArguments("r").WithLocation(13, 25), - // (14,25): error CS8987: The 'scoped' modifier of parameter 'r' doesn't match overridden or implemented member. - // R I.F3(scoped ref R r) => default; // 3 - Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfOverrideOrImplementation, "F3").WithArguments("r").WithLocation(14, 25), - // (15,25): error CS8987: The 'scoped' modifier of parameter 'r' doesn't match overridden or implemented member. - // R I.F4(ref scoped R r) => default; // 4 - Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfOverrideOrImplementation, "F4").WithArguments("r").WithLocation(15, 25), - // (16,70): error CS8987: The 'scoped' modifier of parameter 'r' doesn't match overridden or implemented member. - // object I.this[scoped R r] { get { return null; } set { } } // 5 - Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfOverrideOrImplementation, "set").WithArguments("r").WithLocation(16, 70), - // (17,50): error CS8987: The 'scoped' modifier of parameter 'y' doesn't match overridden or implemented member. - // object I.this[int x, R y] => null; // 6 - Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfOverrideOrImplementation, "null").WithArguments("y").WithLocation(17, 50)); + // (12,13): error CS8374: Cannot ref-assign 't' to 'F' because 't' has a narrower escape scope than 'F'. + // r.F = ref t; + Diagnostic(ErrorCode.ERR_RefAssignNarrower, "r.F = ref t").WithArguments("F", "t").WithLocation(12, 13)); } - [CombinatorialData] [Theory] - public void OverridesAndInterfaceImplementations_Out_01(bool useCompilationReference) + [InlineData(LanguageVersion.CSharp10)] + [InlineData(LanguageVersion.CSharp11)] + public void InstanceMethodWithOutVar_01(LanguageVersion languageVersion) { - var sourceA = -@"public abstract class A -{ - public abstract void F1(out T t); -} -public interface I -{ - void F2(out T t); -}"; - var comp = CreateCompilation(sourceA, parseOptions: TestOptions.Regular10); - comp.VerifyEmitDiagnostics(); - var refA = AsReference(comp, useCompilationReference); - - var sourceB = -@"class B1 : A, I + var source = +@"using System; +ref struct R { - public override void F1(scoped out int i) { i = 0; } - public void F2(scoped out int i) { i = 0; } + public R(Span s) { } + public void F(out R r) { r = default; } } -class B2 : I +class Program { - void I.F2(scoped out string s) { s = null; } + static void F(out R r) + { + Span s1 = stackalloc int[10]; + R r1 = new R(s1); + r1.F(out r); + } }"; - comp = CreateCompilation(sourceB, references: new[] { refA }); - comp.VerifyEmitDiagnostics(); + var comp = CreateCompilationWithSpanAndMemoryExtensions(source, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion)); + comp.VerifyDiagnostics( + // (13,9): error CS8352: Cannot use variable 'r1' in this context because it may expose referenced variables outside of their declaration scope + // r1.F(out r); + Diagnostic(ErrorCode.ERR_EscapeVariable, "r1").WithArguments("r1").WithLocation(13, 9)); } [Fact] - public void OverridesAndInterfaceImplementations_Out_02() + public void InstanceMethodWithOutVar_02() { var source = -@"ref struct R { } -abstract class A +@"ref struct R { - public abstract void F1(out int i); - public abstract void F2(scoped out int i); - public abstract void F3(out scoped R r); - public abstract void F4(scoped out scoped R r); + public ref int _i; + public R(ref int i) { _i = ref i; } + public void F(out R r) { r = new R(ref _i); } } -class B : A +class Program { - public override void F1(scoped out int i) { i = 0; } - public override void F2(out int i) { i = 0; } - public override void F3(scoped out scoped R r) { r = default; } - public override void F4(out scoped R r) { r = default; } + static void F(out R r) + { + int i = 0; + R r1 = new R(ref i); + r1.F(out r); + } }"; - var comp = CreateCompilation(source); - comp.VerifyEmitDiagnostics(); + var comp = CreateCompilation(source, runtimeFeature: RuntimeFlag.ByRefFields); + comp.VerifyDiagnostics( + // (13,9): error CS8352: Cannot use variable 'r1' in this context because it may expose referenced variables outside of their declaration scope + // r1.F(out r); + Diagnostic(ErrorCode.ERR_EscapeVariable, "r1").WithArguments("r1").WithLocation(13, 9)); } - [Fact] - public void OverridesAndInterfaceImplementations_Out_03() + [Theory] + [InlineData(LanguageVersion.CSharp10)] + [InlineData(LanguageVersion.CSharp11)] + public void InstanceMethodWithOutVar_03(LanguageVersion languageVersion) { var source = -@"ref struct R { } -interface I -{ - void F1(out int i); - void F2(scoped out int i); - void F3(out scoped R r); - void F4(scoped out scoped R r); -} -class C1 : I +@"using System; +ref struct R { - public void F1(out int i) { i = 0; } - public void F2(scoped out int i) { i = 0; } - public void F3(scoped out scoped R r) { r = default; } - public void F4(out scoped R r) { r = default; } + public void F(out Span s) { s = default; } } -class C2 : I +class Program { - void I.F1(out int i) { i = 0; } - void I.F2(scoped out int i) { i = 0; } - void I.F3(scoped out scoped R r) { r = default; } - void I.F4(out scoped R r) { r = default; } + static void Main() + { + Span s = stackalloc int[10]; + R r = new R(); + r.F(out s); + } }"; - var comp = CreateCompilation(source); - comp.VerifyEmitDiagnostics(); + var comp = CreateCompilationWithSpanAndMemoryExtensions(source, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion)); + comp.VerifyDiagnostics( + // (12,9): error CS8350: This combination of arguments to 'R.F(out Span)' is disallowed because it may expose variables referenced by parameter 's' outside of their declaration scope + // r.F(out s); + Diagnostic(ErrorCode.ERR_CallArgMixing, "r.F(out s)").WithArguments("R.F(out System.Span)", "s").WithLocation(12, 9), + // (12,17): error CS8352: Cannot use variable 's' in this context because it may expose referenced variables outside of their declaration scope + // r.F(out s); + Diagnostic(ErrorCode.ERR_EscapeVariable, "s").WithArguments("s").WithLocation(12, 17)); } + [WorkItem(63016, "https://github.com/dotnet/roslyn/issues/63016")] [Fact] - public void Overrides_Example() + public void RefToLocalFromInstanceMethod_01() { var source = @"ref struct R { - public ref int F; - public R(ref int i) { F = ref i; } -} -abstract class A -{ - public abstract R F1(scoped R r); - public abstract R F2(R r); -} -class B : A -{ - public override R F1(R r) => r; - public override R F2(scoped R r) => default; -} -class Program + private ref int _i; + public void M1() + { + int i = 42; + M2(ref i); + } + private void M2(ref int i) + { + _i = ref i; + } +}"; + var comp = CreateCompilation(source, runtimeFeature: RuntimeFlag.ByRefFields); + comp.VerifyDiagnostics( + // (7,9): error CS8350: This combination of arguments to 'R.M2(ref int)' is disallowed because it may expose variables referenced by parameter 'i' outside of their declaration scope + // M2(ref i); + Diagnostic(ErrorCode.ERR_CallArgMixing, "M2(ref i)").WithArguments("R.M2(ref int)", "i").WithLocation(7, 9), + // (7,16): error CS8168: Cannot return local 'i' by reference because it is not a ref local + // M2(ref i); + Diagnostic(ErrorCode.ERR_RefReturnLocal, "i").WithArguments("i").WithLocation(7, 16)); + } + + [WorkItem(63016, "https://github.com/dotnet/roslyn/issues/63016")] + [Fact] + public void RefToLocalFromInstanceMethod_02() + { + var sourceA = +@"namespace System { - static R F1(A a) + public ref struct Span { - int i = 0; - return a.F1(new R(ref i)); + unsafe public Span(void* ptr, int length) { } + public ref T this[int index] => throw null; + public static implicit operator Span(T[] a) => throw null; } - static R F2(B b) +}"; + var sourceB = +@"using System; +ref struct S +{ + private ref int _i; + public S(ref int i) { - int i = 0; - return b.F2(new R(ref i)); // unsafe + Span s = stackalloc int[100]; + M2(ref s[0]); } - static void Main() + private void M2(ref int i) { - R r1 = F1(new B()); // unsafe - R r2 = F2(new B()); + _i = ref i; } }"; - var comp = CreateCompilation(source); - comp.VerifyEmitDiagnostics( - // (13,23): error CS8987: The 'scoped' modifier of parameter 'r' doesn't match overridden or implemented member. - // public override R F1(R r) => r; - Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfOverrideOrImplementation, "F1").WithArguments("r").WithLocation(13, 23), - // (14,23): error CS8987: The 'scoped' modifier of parameter 'r' doesn't match overridden or implemented member. - // public override R F2(scoped R r) => default; - Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfOverrideOrImplementation, "F2").WithArguments("r").WithLocation(14, 23)); + var comp = CreateCompilation(new[] { sourceA, sourceB }, options: TestOptions.UnsafeReleaseDll, runtimeFeature: RuntimeFlag.ByRefFields); + comp.VerifyDiagnostics( + // (8,9): error CS8350: This combination of arguments to 'S.M2(ref int)' is disallowed because it may expose variables referenced by parameter 'i' outside of their declaration scope + // M2(ref s[0]); + Diagnostic(ErrorCode.ERR_CallArgMixing, "M2(ref s[0])").WithArguments("S.M2(ref int)", "i").WithLocation(8, 9), + // (8,16): error CS8352: Cannot use variable 's' in this context because it may expose referenced variables outside of their declaration scope + // M2(ref s[0]); + Diagnostic(ErrorCode.ERR_EscapeVariable, "s").WithArguments("s").WithLocation(8, 16)); } [Fact] - public void Delegates_Example() + public void RefStructProperty_01() { var source = -@"ref struct R +@"ref struct R { - public ref int F; - public R(ref int i) { F = ref i; } + public R(ref T t) { } } -delegate R D1(scoped R x); -delegate R D2(R x); -class Program +class C { - static R F1(D1 d1) - { - int i = 0; - return d1(new R(ref i)); - } - static R F2(D2 d2) + R this[R r] => default; + static R F1(C c) { - int i = 0; - return d2(new R(ref i)); + int i = 1; + var r1 = new R(ref i); + return c[r1]; // 1 } - static void Main() + static R F2(C c) { - R r1 = F1((R x) => x); // unsafe - R r2 = F2((scoped R x) => default); + var r2 = new R(); + return c[r2]; } }"; - var comp = CreateCompilation(source); - comp.VerifyEmitDiagnostics( - // (18,16): error CS8347: Cannot use a result of 'D2.Invoke(R)' in this context because it may expose variables referenced by parameter 'x' outside of their declaration scope - // return d2(new R(ref i)); - Diagnostic(ErrorCode.ERR_EscapeCall, "d2(new R(ref i))").WithArguments("D2.Invoke(R)", "x").WithLocation(18, 16), - // (18,19): error CS8347: Cannot use a result of 'R.R(ref int)' in this context because it may expose variables referenced by parameter 'i' outside of their declaration scope - // return d2(new R(ref i)); - Diagnostic(ErrorCode.ERR_EscapeCall, "new R(ref i)").WithArguments("R.R(ref int)", "i").WithLocation(18, 19), - // (18,29): error CS8168: Cannot return local 'i' by reference because it is not a ref local - // return d2(new R(ref i)); - Diagnostic(ErrorCode.ERR_RefReturnLocal, "i").WithArguments("i").WithLocation(18, 29), - // (22,19): error CS8989: The 'scoped' modifier of parameter 'x' doesn't match target 'D1'. - // R r1 = F1((R x) => x); // unsafe - Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfTarget, "(R x) => x").WithArguments("x", "D1").WithLocation(22, 19), - // (23,19): error CS8989: The 'scoped' modifier of parameter 'x' doesn't match target 'D2'. - // R r2 = F2((scoped R x) => default); - Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfTarget, "(scoped R x) => default").WithArguments("x", "D2").WithLocation(23, 19)); + + var comp = CreateCompilation(source, parseOptions: TestOptions.Regular10); + comp.VerifyDiagnostics(); + + comp = CreateCompilation(source); + comp.VerifyDiagnostics( + // (12,16): error CS8347: Cannot use a result of 'C.this[R]' in this context because it may expose variables referenced by parameter 'r' outside of their declaration scope + // return c[r1]; // 1 + Diagnostic(ErrorCode.ERR_EscapeCall, "c[r1]").WithArguments("C.this[R]", "r").WithLocation(12, 16), + // (12,18): error CS8352: Cannot use variable 'r1' in this context because it may expose referenced variables outside of their declaration scope + // return c[r1]; // 1 + Diagnostic(ErrorCode.ERR_EscapeVariable, "r1").WithArguments("r1").WithLocation(12, 18)); } [Fact] - public void BestCommonType_01() + public void RefStructProperty_02() { var source = -@"ref struct R { } -class Program +@"ref struct R { - static R F1(bool b, R x, scoped R y) => b ? x : y; - static R F2(bool b, R x, scoped R y) => b ? y : x; +} +class C +{ + R this[in int i] => default; + static R F1(C c) + { + int i1 = 1; + return c[i1]; // 1 + } + static R F2(C c) + { + return c[2]; // 2 + } + static R F2(C c, in int i3) + { + return c[i3]; + } }"; - var comp = CreateCompilation(source); + + var comp = CreateCompilation(source, parseOptions: TestOptions.Regular10); + comp.VerifyDiagnostics(); + + comp = CreateCompilation(source); comp.VerifyDiagnostics( - // (4,53): error CS8352: Cannot use variable 'R' in this context because it may expose referenced variables outside of their declaration scope - // static R F1(bool b, R x, scoped R y) => b ? x : y; - Diagnostic(ErrorCode.ERR_EscapeVariable, "y").WithArguments("R").WithLocation(4, 53), - // (5,49): error CS8352: Cannot use variable 'R' in this context because it may expose referenced variables outside of their declaration scope - // static R F2(bool b, R x, scoped R y) => b ? y : x; - Diagnostic(ErrorCode.ERR_EscapeVariable, "y").WithArguments("R").WithLocation(5, 49)); + // (10,16): error CS8347: Cannot use a result of 'C.this[in int]' in this context because it may expose variables referenced by parameter 'i' outside of their declaration scope + // return c[i1]; // 1 + Diagnostic(ErrorCode.ERR_EscapeCall, "c[i1]").WithArguments("C.this[in int]", "i").WithLocation(10, 16), + // (10,18): error CS8168: Cannot return local 'i1' by reference because it is not a ref local + // return c[i1]; // 1 + Diagnostic(ErrorCode.ERR_RefReturnLocal, "i1").WithArguments("i1").WithLocation(10, 18), + // (14,16): error CS8347: Cannot use a result of 'C.this[in int]' in this context because it may expose variables referenced by parameter 'i' outside of their declaration scope + // return c[2]; // 2 + Diagnostic(ErrorCode.ERR_EscapeCall, "c[2]").WithArguments("C.this[in int]", "i").WithLocation(14, 16), + // (14,18): error CS8156: An expression cannot be used in this context because it may not be passed or returned by reference + // return c[2]; // 2 + Diagnostic(ErrorCode.ERR_RefReturnLvalueExpected, "2").WithLocation(14, 18)); } - [Fact] - public void BestCommonType_02() + [Theory] + [InlineData(LanguageVersion.CSharp10)] + [InlineData(LanguageVersion.CSharp11)] + public void ReturnThis_01(LanguageVersion languageVersion) { var source = -@"ref struct R { } -class Program +@"ref struct R { - static ref R F1(bool b, ref R x, ref scoped R y) => ref b ? ref x : ref y; - static ref R F2(bool b, ref R x, ref scoped R y) => ref b ? ref y : ref x; + R F1() => this; + ref R F2() => ref this; + ref readonly R F3() => ref this; }"; - var comp = CreateCompilation(source); + var comp = CreateCompilation(source, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion)); comp.VerifyDiagnostics( - // (4,61): error CS8351: Branches of a ref conditional operator cannot refer to variables with incompatible declaration scopes - // static ref R F1(bool b, ref R x, ref scoped R y) => ref b ? ref x : ref y; - Diagnostic(ErrorCode.ERR_MismatchedRefEscapeInTernary, "b ? ref x : ref y").WithLocation(4, 61), - // (4,77): error CS8352: Cannot use variable 'ref R' in this context because it may expose referenced variables outside of their declaration scope - // static ref R F1(bool b, ref R x, ref scoped R y) => ref b ? ref x : ref y; - Diagnostic(ErrorCode.ERR_EscapeVariable, "y").WithArguments("ref R").WithLocation(4, 77), - // (5,61): error CS8351: Branches of a ref conditional operator cannot refer to variables with incompatible declaration scopes - // static ref R F2(bool b, ref R x, ref scoped R y) => ref b ? ref y : ref x; - Diagnostic(ErrorCode.ERR_MismatchedRefEscapeInTernary, "b ? ref y : ref x").WithLocation(5, 61), - // (5,69): error CS8352: Cannot use variable 'ref R' in this context because it may expose referenced variables outside of their declaration scope - // static ref R F2(bool b, ref R x, ref scoped R y) => ref b ? ref y : ref x; - Diagnostic(ErrorCode.ERR_EscapeVariable, "y").WithArguments("ref R").WithLocation(5, 69)); + // (4,23): error CS8170: Struct members cannot return 'this' or other instance members by reference + // ref R F2() => ref this; + Diagnostic(ErrorCode.ERR_RefReturnStructThis, "this").WithLocation(4, 23), + // (5,32): error CS8170: Struct members cannot return 'this' or other instance members by reference + // ref readonly R F3() => ref this; + Diagnostic(ErrorCode.ERR_RefReturnStructThis, "this").WithLocation(5, 32)); } - [Fact] - public void BestCommonType_03() + [Theory] + [InlineData(LanguageVersion.CSharp10)] + [InlineData(LanguageVersion.CSharp11)] + public void ReturnThis_02(LanguageVersion languageVersion) { var source = -@"class Program +@"readonly ref struct R { - static ref int F1(bool b, scoped ref int x, ref int y) => ref b ? ref x : ref y; - static ref int F2(bool b, scoped ref int x, ref int y) => ref b ? ref y : ref x; + R F1() => this; + ref R F2() => ref this; + ref readonly R F3() => ref this; }"; - var comp = CreateCompilation(source); + var comp = CreateCompilation(source, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion)); comp.VerifyDiagnostics( - // (3,75): error CS8166: Cannot return a parameter by reference 'x' because it is not a ref parameter - // static ref int F1(bool b, scoped ref int x, ref int y) => ref b ? ref x : ref y; - Diagnostic(ErrorCode.ERR_RefReturnParameter, "x").WithArguments("x").WithLocation(3, 75), - // (4,83): error CS8166: Cannot return a parameter by reference 'x' because it is not a ref parameter - // static ref int F2(bool b, scoped ref int x, ref int y) => ref b ? ref y : ref x; - Diagnostic(ErrorCode.ERR_RefReturnParameter, "x").WithArguments("x").WithLocation(4, 83)); + // (4,23): error CS8354: Cannot return 'this' by reference. + // ref R F2() => ref this; + Diagnostic(ErrorCode.ERR_RefReturnThis, "this").WithLocation(4, 23), + // (5,32): error CS8170: Struct members cannot return 'this' or other instance members by reference + // ref readonly R F3() => ref this; + Diagnostic(ErrorCode.ERR_RefReturnStructThis, "this").WithLocation(5, 32)); } [Fact] - public void BestCommonType_04() + public void RefInitializer_LangVer() { - var source = -@"ref struct R { } -class Program + var source = @" +int x = 42; +var r = new R() { field = ref x }; + +ref struct R { - static void Main() - { - var f1 = new[] { (R r) => { }, (scoped R r) => { } }[0]; // 1 - var f2 = new[] { (scoped R r) => { }, (scoped R r) => { } }[0]; - var f3 = new[] { (ref R r) => { }, (scoped ref R r) => { } }[0]; // 2 - var f4 = new[] { (scoped ref R r) => { }, (scoped ref R r) => { } }[0]; - var f5 = new[] { (scoped in R r) => { }, (in scoped R r) => { } }[0]; // 3 - var f6 = new[] { (in scoped R r) => { }, (in scoped R r) => { } }[0]; - var f7 = new[] { (out scoped R r) => { r = default; }, (out R r) => { r = default; } }[0]; // 4 - var f8 = new[] { (out scoped R r) => { r = default; }, (out scoped R r) => { r = default; } }[0]; - } -}"; - var comp = CreateCompilation(source); + public ref int field; +} +"; + var comp = CreateCompilation(source, parseOptions: TestOptions.Regular10, runtimeFeature: RuntimeFlag.ByRefFields); comp.VerifyDiagnostics( - // (6,18): error CS0826: No best type found for implicitly-typed array - // var f1 = new[] { (R r) => { }, (scoped R r) => { } }[0]; // 1 - Diagnostic(ErrorCode.ERR_ImplicitlyTypedArrayNoBestType, "new[] { (R r) => { }, (scoped R r) => { } }").WithLocation(6, 18), - // (8,18): error CS0826: No best type found for implicitly-typed array - // var f3 = new[] { (ref R r) => { }, (scoped ref R r) => { } }[0]; // 2 - Diagnostic(ErrorCode.ERR_ImplicitlyTypedArrayNoBestType, "new[] { (ref R r) => { }, (scoped ref R r) => { } }").WithLocation(8, 18), - // (10,18): error CS0826: No best type found for implicitly-typed array - // var f5 = new[] { (scoped in R r) => { }, (in scoped R r) => { } }[0]; // 3 - Diagnostic(ErrorCode.ERR_ImplicitlyTypedArrayNoBestType, "new[] { (scoped in R r) => { }, (in scoped R r) => { } }").WithLocation(10, 18), - // (12,18): error CS0826: No best type found for implicitly-typed array - // var f7 = new[] { (out scoped R r) => { r = default; }, (out R r) => { r = default; } }[0]; // 4 - Diagnostic(ErrorCode.ERR_ImplicitlyTypedArrayNoBestType, "new[] { (out scoped R r) => { r = default; }, (out R r) => { r = default; } }").WithLocation(12, 18)); + // (7,12): error CS8936: Feature 'ref fields' is not available in C# 10.0. Please use language version 11.0 or greater. + // public ref int field; + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "ref int").WithArguments("ref fields", "11.0").WithLocation(7, 12) + ); + + comp = CreateCompilation(source, parseOptions: TestOptions.Regular11, runtimeFeature: RuntimeFlag.ByRefFields); + comp.VerifyDiagnostics(); } [Fact] - public void InferredDelegateTypes_01() + public void RefInitializer_LangVer_FromMetadata() { - var source = -@"ref struct R { } -class Program + var lib_cs = @" +public ref struct R { - static void F1(R x1, scoped R y1) + public ref int field; +} +"; + var source = @" +int x = 42; +var r1 = new R() { field = ref x }; // 1 +var r2 = new R() { field = x }; // 2 + +R r3 = default; +_ = r3 with { field = ref x }; // 3 +"; + var lib = CreateCompilation(lib_cs, parseOptions: TestOptions.Regular11, runtimeFeature: RuntimeFlag.ByRefFields); + + var comp = CreateCompilation(source, references: new[] { lib.EmitToImageReference() }, parseOptions: TestOptions.Regular10, runtimeFeature: RuntimeFlag.ByRefFields); + comp.VerifyDiagnostics( + // (3,20): error CS8936: Feature 'ref fields' is not available in C# 10.0. Please use language version 11.0 or greater. + // var r1 = new R() { field = ref x }; // 1 + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "field").WithArguments("ref fields", "11.0").WithLocation(3, 20), + // (4,20): error CS8936: Feature 'ref fields' is not available in C# 10.0. Please use language version 11.0 or greater. + // var r2 = new R() { field = x }; // 2 + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "field").WithArguments("ref fields", "11.0").WithLocation(4, 20), + // (7,15): error CS8936: Feature 'ref fields' is not available in C# 10.0. Please use language version 11.0 or greater. + // _ = r3 with { field = ref x }; // 3 + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "field").WithArguments("ref fields", "11.0").WithLocation(7, 15) + ); + + comp = CreateCompilation(source, references: new[] { lib.EmitToImageReference() }, parseOptions: TestOptions.Regular10); + comp.VerifyDiagnostics( + // (3,20): error CS8936: Feature 'ref fields' is not available in C# 10.0. Please use language version 11.0 or greater. + // var r1 = new R() { field = ref x }; // 1 + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "field").WithArguments("ref fields", "11.0").WithLocation(3, 20), + // (3,20): error CS9061: Target runtime doesn't support ref fields. + // var r1 = new R() { field = ref x }; // 1 + Diagnostic(ErrorCode.ERR_RuntimeDoesNotSupportRefFields, "field").WithLocation(3, 20), + // (4,20): error CS8936: Feature 'ref fields' is not available in C# 10.0. Please use language version 11.0 or greater. + // var r2 = new R() { field = x }; // 2 + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "field").WithArguments("ref fields", "11.0").WithLocation(4, 20), + // (4,20): error CS9061: Target runtime doesn't support ref fields. + // var r2 = new R() { field = x }; // 2 + Diagnostic(ErrorCode.ERR_RuntimeDoesNotSupportRefFields, "field").WithLocation(4, 20), + // (7,15): error CS8936: Feature 'ref fields' is not available in C# 10.0. Please use language version 11.0 or greater. + // _ = r3 with { field = ref x }; // 3 + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "field").WithArguments("ref fields", "11.0").WithLocation(7, 15), + // (7,15): error CS9061: Target runtime doesn't support ref fields. + // _ = r3 with { field = ref x }; // 3 + Diagnostic(ErrorCode.ERR_RuntimeDoesNotSupportRefFields, "field").WithLocation(7, 15) + ); + } + + [Fact] + public void RefInitializer() + { + var source = @" +public class C +{ + public static void Main() { - var f = (R x, scoped R y) => x; - R z; - z = f(x1, y1); - z = f(y1, x1); // 1 + int x = 42; + var r = new R() { field = ref x }; + System.Console.Write(r.ToString()); } - static void F2(ref R x2, ref scoped R y2) +} + +ref struct R +{ + public ref int field; + public override string ToString() { - var f = (ref R x, ref scoped R y) => ref x; - R z; - z = f(ref x2, ref y2); - z = f(ref y2, ref x2); // 2 + return field.ToString(); } - static void F3(ref int x3, scoped ref int y3) +} +"; + var comp = CreateCompilation(source, options: TestOptions.ReleaseExe, runtimeFeature: RuntimeFlag.ByRefFields); + comp.VerifyDiagnostics(); + var verifier = CompileAndVerify(comp, verify: Verification.Skipped, expectedOutput: IncludeExpectedOutput("42")); + verifier.VerifyIL("C.Main", +""" +{ + // Code size 41 (0x29) + .maxstack 2 + .locals init (int V_0, //x + R V_1, //r + R V_2) + IL_0000: ldc.i4.s 42 + IL_0002: stloc.0 + IL_0003: ldloca.s V_2 + IL_0005: initobj "R" + IL_000b: ldloca.s V_2 + IL_000d: ldloca.s V_0 + IL_000f: stfld "ref int R.field" + IL_0014: ldloc.2 + IL_0015: stloc.1 + IL_0016: ldloca.s V_1 + IL_0018: constrained. "R" + IL_001e: callvirt "string object.ToString()" + IL_0023: call "void System.Console.Write(string)" + IL_0028: ret +} +"""); + } + + [Fact] + public void RefInitializer_RHSMustBeDefinitelyAssigned() + { + // The right operand must be definitely assigned at the point of the ref assignment. + var source = @" +int x; +var r = new R() { field = ref x }; + +ref struct R +{ + public ref int field; + public override string ToString() { - var f = (ref int x, scoped ref int y) => ref x; - int z; - z = f(ref x3, ref y3); - z = f(ref y3, ref x3); + return field.ToString(); } -}"; - var comp = CreateCompilation(source); +} +"; + var comp = CreateCompilation(source, runtimeFeature: RuntimeFlag.ByRefFields); comp.VerifyDiagnostics( - // (9,13): error CS8347: Cannot use a result of '.Invoke(R, R)' in this context because it may expose variables referenced by parameter '0' outside of their declaration scope - // z = f(y1, x1); // 1 - Diagnostic(ErrorCode.ERR_EscapeCall, "f(y1, x1)").WithArguments(".Invoke(R, R)", "0").WithLocation(9, 13), - // (9,15): error CS8352: Cannot use variable 'R' in this context because it may expose referenced variables outside of their declaration scope - // z = f(y1, x1); // 1 - Diagnostic(ErrorCode.ERR_EscapeVariable, "y1").WithArguments("R").WithLocation(9, 15), - // (16,13): error CS8347: Cannot use a result of '.Invoke(ref R, ref R)' in this context because it may expose variables referenced by parameter '0' outside of their declaration scope - // z = f(ref y2, ref x2); // 2 - Diagnostic(ErrorCode.ERR_EscapeCall, "f(ref y2, ref x2)").WithArguments(".Invoke(ref R, ref R)", "0").WithLocation(16, 13), - // (16,19): error CS8166: Cannot return a parameter by reference 'y2' because it is not a ref parameter - // z = f(ref y2, ref x2); // 2 - Diagnostic(ErrorCode.ERR_RefReturnParameter, "y2").WithArguments("y2").WithLocation(16, 19)); + // (3,31): error CS0165: Use of unassigned local variable 'x' + // var r = new R() { field = ref x }; + Diagnostic(ErrorCode.ERR_UseDefViolation, "x").WithArguments("x").WithLocation(3, 31) + ); + } - var tree = comp.SyntaxTrees[0]; - var model = comp.GetSemanticModel(tree); - var decls = tree.GetRoot().DescendantNodes().OfType().Where(v => v.Identifier.Text == "f").ToArray(); - var delegateInvokeMethods = decls.Select(d => ((ILocalSymbol)model.GetDeclaredSymbol(d)).Type.GetSymbol().DelegateInvokeMethod).ToArray(); + [Fact] + public void RefInitializer_RHSTypeMustMatch() + { + // The right operand must be an expression that yields an lvalue designating a value of the same type as the left operand. + var source = @" +object x = null; +var r = new R() { field = ref x }; - VerifyParameterSymbol(delegateInvokeMethods[0].Parameters[1], "scoped R", RefKind.None, DeclarationScope.ValueScoped); - VerifyParameterSymbol(delegateInvokeMethods[1].Parameters[1], "ref scoped R", RefKind.Ref, DeclarationScope.ValueScoped); - VerifyParameterSymbol(delegateInvokeMethods[2].Parameters[1], "scoped ref System.Int32", RefKind.Ref, DeclarationScope.RefScoped); +ref struct R +{ + public ref int field; + public override string ToString() + { + return field.ToString(); + } +} +"; + var comp = CreateCompilation(source, runtimeFeature: RuntimeFlag.ByRefFields); + comp.VerifyDiagnostics( + // (3,31): error CS8173: The expression must be of type 'int' because it is being assigned by reference + // var r = new R() { field = ref x }; + Diagnostic(ErrorCode.ERR_RefAssignmentMustHaveIdentityConversion, "x").WithArguments("int").WithLocation(3, 31) + ); } [Fact] - public void InferredDelegateTypes_02() + public void RefInitializer_RHSTypeMustMatch_ImplicitConversionExists() { - var source = -@"ref struct R { } -static class E1 + // The right operand must be an expression that yields an lvalue designating a value of the same type as the left operand. + var source = @" +S1 x = default; +var r = new R() { field = ref x }; + +struct S1 { } +struct S2 { - public static void F1(this object o, R r) { } - public static void F2(this object o, ref R r) { } - public static void F3(this object o, scoped in R r) { } - public static void F4(this object o, out scoped R r) { } + public static implicit operator S2(S1 s1) => throw null; } -static class E2 +ref struct R { - public static void F1(this object o, scoped R r) { } - public static void F2(this object o, scoped ref R r) { } - public static void F3(this object o, in scoped R r) { } - public static void F4(this object o, out R r) { } + public ref S2 field; + public override string ToString() + { + return field.ToString(); + } } -class Program +"; + var comp = CreateCompilation(source, runtimeFeature: RuntimeFlag.ByRefFields); + comp.VerifyDiagnostics( + // (3,31): error CS8173: The expression must be of type 'S2' because it is being assigned by reference + // var r = new R() { field = ref x }; + Diagnostic(ErrorCode.ERR_RefAssignmentMustHaveIdentityConversion, "x").WithArguments("S2").WithLocation(3, 31) + ); + } + + [Fact] + public void RefInitializer_StaticRefField() + { + var source = @" +int x = 0; +var r = new R() { field = ref x }; + +ref struct R { - static void Main() + public static ref int field; + public override string ToString() { - object o = new object(); - var d1 = o.F1; - var d2 = o.F2; - var d3 = o.F3; - var d4 = o.F4; + return field.ToString(); } -}"; - var comp = CreateCompilation(source); +} +"; + var comp = CreateCompilation(source, runtimeFeature: RuntimeFlag.ByRefFields); comp.VerifyDiagnostics( - // (21,18): error CS0121: The call is ambiguous between the following methods or properties: 'E1.F1(object, R)' and 'E2.F1(object, R)' - // var d1 = o.F1; - Diagnostic(ErrorCode.ERR_AmbigCall, "o.F1").WithArguments("E1.F1(object, R)", "E2.F1(object, R)").WithLocation(21, 18), - // (22,18): error CS0121: The call is ambiguous between the following methods or properties: 'E1.F2(object, ref R)' and 'E2.F2(object, ref R)' - // var d2 = o.F2; - Diagnostic(ErrorCode.ERR_AmbigCall, "o.F2").WithArguments("E1.F2(object, ref R)", "E2.F2(object, ref R)").WithLocation(22, 18), - // (23,18): error CS0121: The call is ambiguous between the following methods or properties: 'E1.F3(object, in R)' and 'E2.F3(object, in R)' - // var d3 = o.F3; - Diagnostic(ErrorCode.ERR_AmbigCall, "o.F3").WithArguments("E1.F3(object, in R)", "E2.F3(object, in R)").WithLocation(23, 18), - // (24,18): error CS0121: The call is ambiguous between the following methods or properties: 'E1.F4(object, out R)' and 'E2.F4(object, out R)' - // var d4 = o.F4; - Diagnostic(ErrorCode.ERR_AmbigCall, "o.F4").WithArguments("E1.F4(object, out R)", "E2.F4(object, out R)").WithLocation(24, 18)); + // (3,19): error CS1914: Static field or property 'R.field' cannot be assigned in an object initializer + // var r = new R() { field = ref x }; + Diagnostic(ErrorCode.ERR_StaticMemberInObjectInitializer, "field").WithArguments("R.field").WithLocation(3, 19), + // (7,27): error CS0106: The modifier 'static' is not valid for this item + // public static ref int field; + Diagnostic(ErrorCode.ERR_BadMemberFlag, "field").WithArguments("static").WithLocation(7, 27) + ); } [Fact] - public void ScopedRefAndRefStructOnly_01() + public void RefInitializer_VarInvocationReserved() { - var source = -@"struct S { } -class Program + var source = @" +var r = new R() { field = ref var() }; + +ref struct R { - static void F1(scoped S s) { } - static void F2(ref scoped S s) { } - static void F3(scoped ref S s) { } - static void F4(scoped ref scoped S s) { } - static void F5(ref scoped int i) { } - static void F6(in scoped int i) { } - static void F7(out scoped int i) { i = 0; } -}"; - var comp = CreateCompilation(source); + public ref int field; +} +"; + var comp = CreateCompilation(source, runtimeFeature: RuntimeFlag.ByRefFields); comp.VerifyDiagnostics( - // (4,20): error CS9048: The 'scoped' modifier can be used for refs and ref struct values only. - // static void F1(scoped S s) { } - Diagnostic(ErrorCode.ERR_ScopedRefAndRefStructOnly, "scoped S s").WithLocation(4, 20), - // (5,20): error CS9048: The 'scoped' modifier can be used for refs and ref struct values only. - // static void F2(ref scoped S s) { } - Diagnostic(ErrorCode.ERR_ScopedRefAndRefStructOnly, "ref scoped S s").WithLocation(5, 20), - // (7,20): error CS9048: The 'scoped' modifier can be used for refs and ref struct values only. - // static void F4(scoped ref scoped S s) { } - Diagnostic(ErrorCode.ERR_ScopedRefAndRefStructOnly, "scoped ref scoped S s").WithLocation(7, 20), - // (8,20): error CS9048: The 'scoped' modifier can be used for refs and ref struct values only. - // static void F5(ref scoped int i) { } - Diagnostic(ErrorCode.ERR_ScopedRefAndRefStructOnly, "ref scoped int i").WithLocation(8, 20), - // (9,20): error CS9048: The 'scoped' modifier can be used for refs and ref struct values only. - // static void F6(in scoped int i) { } - Diagnostic(ErrorCode.ERR_ScopedRefAndRefStructOnly, "in scoped int i").WithLocation(9, 20), - // (10,20): error CS9048: The 'scoped' modifier can be used for refs and ref struct values only. - // static void F7(out scoped int i) { i = 0; } - Diagnostic(ErrorCode.ERR_ScopedRefAndRefStructOnly, "out scoped int i").WithLocation(10, 20)); + // (2,31): error CS8199: The syntax 'var (...)' as an lvalue is reserved. + // var r = new R() { field = ref var() }; + Diagnostic(ErrorCode.ERR_VarInvocationLvalueReserved, "var()").WithLocation(2, 31), + // (2,31): error CS0103: The name 'var' does not exist in the current context + // var r = new R() { field = ref var() }; + Diagnostic(ErrorCode.ERR_NameNotInContext, "var").WithArguments("var").WithLocation(2, 31) + ); } [Fact] - public void ScopedRefAndRefStructOnly_02() + public void RefInitializer_ReadonlyRefField() { - var source = -@"struct S { } -interface I + var source = @" +int x = 42; +var r = new R() { field = ref x }; + +ref struct R { - void F1(scoped T t); - void F2(scoped T t) where T : class; - void F3(scoped T t) where T : struct; - void F4(scoped T t) where T : unmanaged; -}"; - var comp = CreateCompilation(source); + public readonly ref int field; +} +"; + var comp = CreateCompilation(source, runtimeFeature: RuntimeFlag.ByRefFields); comp.VerifyDiagnostics( - // (4,16): error CS9048: The 'scoped' modifier can be used for refs and ref struct values only. - // void F1(scoped T t); - Diagnostic(ErrorCode.ERR_ScopedRefAndRefStructOnly, "scoped T t").WithLocation(4, 16), - // (5,16): error CS9048: The 'scoped' modifier can be used for refs and ref struct values only. - // void F2(scoped T t) where T : class; - Diagnostic(ErrorCode.ERR_ScopedRefAndRefStructOnly, "scoped T t").WithLocation(5, 16), - // (6,16): error CS9048: The 'scoped' modifier can be used for refs and ref struct values only. - // void F3(scoped T t) where T : struct; - Diagnostic(ErrorCode.ERR_ScopedRefAndRefStructOnly, "scoped T t").WithLocation(6, 16), - // (7,16): error CS9048: The 'scoped' modifier can be used for refs and ref struct values only. - // void F4(scoped T t) where T : unmanaged; - Diagnostic(ErrorCode.ERR_ScopedRefAndRefStructOnly, "scoped T t").WithLocation(7, 16)); + // (3,19): error CS0191: A readonly field cannot be assigned to (except in a constructor or init-only setter of the type in which the field is defined or a variable initializer) + // var r = new R() { field = ref x }; + Diagnostic(ErrorCode.ERR_AssgReadonly, "field").WithLocation(3, 19) + ); } [Fact] - public void ScopedRefAndRefStructOnly_03() + public void RefInitializer_RefReadonlyField() { - var source = -@"enum E { } -class Program + var source = @" +int x = 42; +var r = new R() { field = ref x }; + +ref struct R { - static void Main() - { - var f = (scoped ref E x, scoped E y) => { }; -#pragma warning disable 8321 - static void L(scoped ref E x, scoped E y) { } - } -}"; - var comp = CreateCompilation(source); - comp.VerifyDiagnostics( - // (6,43): error CS9048: The 'scoped' modifier can be used for refs and ref struct values only. - // var f = (scoped ref E x, scoped E y) => { }; - Diagnostic(ErrorCode.ERR_ScopedRefAndRefStructOnly, "y").WithLocation(6, 43), - // (8,39): error CS9048: The 'scoped' modifier can be used for refs and ref struct values only. - // static void L(scoped ref E x, scoped E y) { } - Diagnostic(ErrorCode.ERR_ScopedRefAndRefStructOnly, "scoped E y").WithLocation(8, 39)); + public ref readonly int field; +} +"; + var comp = CreateCompilation(source, runtimeFeature: RuntimeFlag.ByRefFields); + comp.VerifyDiagnostics(); } [Fact] - public void ScopedRefAndRefStructOnly_04() + public void RefInitializer_RefReadonlyValue_Field() { - var source = -@"delegate void D(scoped C c); + // If the left operand is a writeable ref (i.e. it designates anything other than a `ref readonly` local or `in` parameter), then the right operand must be a writeable lvalue. + var source = @" class C { - static unsafe void Main() + ref readonly int Value() => throw null; + + void M() { - delegate* d = default; + var r = new R() { field = ref Value() }; } -}"; - var comp = CreateCompilation(source, options: TestOptions.UnsafeReleaseExe); - comp.VerifyDiagnostics( - // (1,17): error CS9048: The 'scoped' modifier can be used for refs and ref struct values only. - // delegate void D(scoped C c); - Diagnostic(ErrorCode.ERR_ScopedRefAndRefStructOnly, "scoped C c").WithLocation(1, 17), - // (6,19): error CS8755: 'scoped' cannot be used as a modifier on a function pointer parameter. - // delegate* d = default; - Diagnostic(ErrorCode.ERR_BadFuncPointerParamModifier, "scoped").WithArguments("scoped").WithLocation(6, 19)); - } +} - [Theory] - [InlineData("ref ")] - [InlineData("ref readonly")] - public void ScopedRefAndRefStructOnly_05(string refModifier) - { - var source = -$@"struct S {{ }} -class Program -{{ - static void F(S s) - {{ - {refModifier} scoped S s1 = ref s; - scoped {refModifier} S s2 = ref s; - scoped {refModifier} scoped S s3 = ref s; - }} -}}"; - var comp = CreateCompilation(source); +ref struct R +{ + public ref int field; +} +"; + // Confusing error message + // Tracked by https://github.com/dotnet/roslyn/issues/62756 + var comp = CreateCompilation(source, runtimeFeature: RuntimeFlag.ByRefFields); comp.VerifyDiagnostics( - // (6,29): error CS9048: The 'scoped' modifier can be used for refs and ref struct values only. - // ref readonly scoped S s1 = ref s; - Diagnostic(ErrorCode.ERR_ScopedRefAndRefStructOnly, "S").WithLocation(6, 29), - // (8,36): error CS9048: The 'scoped' modifier can be used for refs and ref struct values only. - // scoped ref readonly scoped S s3 = ref s; - Diagnostic(ErrorCode.ERR_ScopedRefAndRefStructOnly, "S").WithLocation(8, 36)); + // (8,39): error CS8331: Cannot assign to method 'C.Value()' because it is a readonly variable + // var r = new R() { field = ref Value() }; + Diagnostic(ErrorCode.ERR_AssignReadonlyNotField, "Value()").WithArguments("method", "C.Value()").WithLocation(8, 39) + ); } [Fact] - public void ScopedRefAndRefStructOnly_06() + public void RefInitializer_AssignInParameter() { - var source = -@"ref struct R { } -struct S { } -class Program + var source = @" +class C { - static void Main() + static void F(in int i) { - scoped var x1 = new R(); - ref scoped var x2 = ref x1; - scoped ref var x3 = ref x1; - scoped ref scoped var x4 = ref x1; - scoped var y1 = new S(); // 1 - ref scoped var y2 = ref y1; // 2 - scoped ref var y3 = ref y1; - scoped ref scoped var y4 = ref y1; // 3 + _ = new R1 { _f = ref i }; + _ = new R2 { _f = ref i }; // 1 } -}"; - var comp = CreateCompilation(source); +} + +ref struct R1 +{ + public ref readonly int _f; +} + +ref struct R2 +{ + public ref int _f; +} +"; + // Diagnostic is missing parameter name + // Tracked by https://github.com/dotnet/roslyn/issues/62096 + var comp = CreateCompilation(source, runtimeFeature: RuntimeFlag.ByRefFields); comp.VerifyDiagnostics( - // (9,33): error CS8352: Cannot use variable 'x1' in this context because it may expose referenced variables outside of their declaration scope - // scoped ref var x3 = ref x1; - Diagnostic(ErrorCode.ERR_EscapeVariable, "x1").WithArguments("x1").WithLocation(9, 33), - // (11,16): error CS8986: The 'scoped' modifier can be used for refs and ref struct values only. - // scoped var y1 = new S(); // 1 - Diagnostic(ErrorCode.ERR_ScopedRefAndRefStructOnly, "var").WithLocation(11, 16), - // (12,20): error CS9048: The 'scoped' modifier can be used for refs and ref struct values only. - // ref scoped var y2 = ref y1; // 2 - Diagnostic(ErrorCode.ERR_ScopedRefAndRefStructOnly, "var").WithLocation(12, 20), - // (14,27): error CS9048: The 'scoped' modifier can be used for refs and ref struct values only. - // scoped ref scoped var y4 = ref y1; // 3 - Diagnostic(ErrorCode.ERR_ScopedRefAndRefStructOnly, "var").WithLocation(14, 27)); + // (7,31): error CS8331: Cannot assign to variable 'in int' because it is a readonly variable + // _ = new R2 { _f = ref i }; // 1 + Diagnostic(ErrorCode.ERR_AssignReadonlyNotField, "i").WithArguments("variable", "in int").WithLocation(7, 31) + ); } [Fact] - public void ScopedRefAndRefStructOnly_07() + public void RefInitializer_RefReadonlyValue_GetOnlyProperty() { - var source = -@"ref struct R { } -class Program + var source = @" +class C { - static void F1(scoped Unknown x, scoped R y) + ref readonly int Value() => throw null; + + void M() { - var f = (ref scoped Unknown u) => { }; - scoped R z = y; - scoped var v = F2(); + var r = new R() { Property = ref Value() }; } -}"; +} + +ref struct R +{ + public ref int Property { get => throw null; } +} +"; var comp = CreateCompilation(source); comp.VerifyDiagnostics( - // (4,27): error CS0246: The type or namespace name 'Unknown' could not be found (are you missing a using directive or an assembly reference?) - // static void F1(scoped Unknown x, scoped R y) - Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "Unknown").WithArguments("Unknown").WithLocation(4, 27), - // (4,47): error CS0246: The type or namespace name 'Unknown' could not be found (are you missing a using directive or an assembly reference?) - // static void F1(scoped Unknown x, scoped R y) - Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "Unknown").WithArguments("Unknown").WithLocation(4, 47), - // (6,29): error CS0246: The type or namespace name 'Unknown' could not be found (are you missing a using directive or an assembly reference?) - // var f = (ref scoped Unknown u) => { }; - Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "Unknown").WithArguments("Unknown").WithLocation(6, 29), - // (7,18): error CS0246: The type or namespace name 'Unknown' could not be found (are you missing a using directive or an assembly reference?) - // scoped R z = y; - Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "Unknown").WithArguments("Unknown").WithLocation(7, 18), - // (8,24): error CS0103: The name 'F2' does not exist in the current context - // scoped var v = F2(); - Diagnostic(ErrorCode.ERR_NameNotInContext, "F2").WithArguments("F2").WithLocation(8, 24)); + // (8,27): error CS8373: The left-hand side of a ref assignment must be a ref variable. + // var r = new R() { Property = ref Value() }; + Diagnostic(ErrorCode.ERR_RefLocalOrParamExpected, "Property").WithLocation(8, 27) + ); } [Fact] - public void Local_SequencePoints() + public void RefInitializer_RefReadonlyValue_Property() { - var source = -@"using System; -ref struct R -{ - public ref T F; - public R(ref T t) { F = ref t; } -} -class Program + var source = @" +class C { - static void Main() + ref readonly int Value() => throw null; + + void M() { - int x = 1; - scoped R y = new R(ref x); - ref scoped R z = ref y; - z.F = 2; - Console.WriteLine(x); + var r = new R() { Property = ref Value() }; } -}"; - var verifier = CompileAndVerify(source, options: TestOptions.DebugExe, verify: Verification.Skipped); - verifier.VerifyIL("Program.Main", - source: source, - sequencePoints: "Program.Main", - expectedIL: -@"{ - // Code size 30 (0x1e) - .maxstack 2 - .locals init (int V_0, //x - R V_1, //y - R& V_2) //z - // sequence point: { - IL_0000: nop - // sequence point: int x = 1; - IL_0001: ldc.i4.1 - IL_0002: stloc.0 - // sequence point: scoped R y = new R(ref x); - IL_0003: ldloca.s V_0 - IL_0005: newobj ""R..ctor(ref int)"" - IL_000a: stloc.1 - // sequence point: ref scoped R z = ref y; - IL_000b: ldloca.s V_1 - IL_000d: stloc.2 - // sequence point: z.F = 2; - IL_000e: ldloc.2 - IL_000f: ldfld ""ref int R.F"" - IL_0014: ldc.i4.2 - IL_0015: stind.i4 - // sequence point: Console.WriteLine(x); - IL_0016: ldloc.0 - IL_0017: call ""void System.Console.WriteLine(int)"" - IL_001c: nop - // sequence point: } - IL_001d: ret -}"); +} + +ref struct R +{ + public ref int Property { get => throw null; set => throw null; } +} +"; + var comp = CreateCompilation(source); + comp.VerifyDiagnostics( + // (8,27): error CS8373: The left-hand side of a ref assignment must be a ref variable. + // var r = new R() { Property = ref Value() }; + Diagnostic(ErrorCode.ERR_RefLocalOrParamExpected, "Property").WithLocation(8, 27), + // (14,50): error CS8147: Properties which return by reference cannot have set accessors + // public ref int Property { get => throw null; set => throw null; } + Diagnostic(ErrorCode.ERR_RefPropertyCannotHaveSetAccessor, "set").WithLocation(14, 50) + ); } [Fact] - public void SafeToEscape_01() + public void RefInitializer_RefReadonlyValue_Indexer() { - var source = -@"ref struct R { } -class Program + var source = @" +var r = new R() { [0] = ref Value() }; // 1 + +R r2 = default; +r2[0] = ref Value(); // 2 + +ref readonly int Value() => throw null; + +ref struct R { - static R F0(R r0) => r0; - static R F1(scoped R r1) => r1; // 1 - static R F2(ref R r2) => r2; - static R F3(scoped ref R r3) => r3; - static R F4(ref scoped R r4) => r4; // 2 - static R F5(scoped ref scoped R r5) => r5; // 3 -}"; + public ref int this[int i] { get => throw null; } +} +"; var comp = CreateCompilation(source); comp.VerifyDiagnostics( - // (5,43): error CS8352: Cannot use variable 'R' in this context because it may expose referenced variables outside of their declaration scope - // static R F1(scoped R r1) => r1; // 1 - Diagnostic(ErrorCode.ERR_EscapeVariable, "r1").WithArguments("R").WithLocation(5, 43), - // (8,47): error CS8352: Cannot use variable 'ref R' in this context because it may expose referenced variables outside of their declaration scope - // static R F4(ref scoped R r4) => r4; // 2 - Diagnostic(ErrorCode.ERR_EscapeVariable, "r4").WithArguments("ref R").WithLocation(8, 47), - // (9,54): error CS8352: Cannot use variable 'ref R' in this context because it may expose referenced variables outside of their declaration scope - // static R F5(scoped ref scoped R r5) => r5; // 3 - Diagnostic(ErrorCode.ERR_EscapeVariable, "r5").WithArguments("ref R").WithLocation(9, 54)); + // (2,19): error CS8373: The left-hand side of a ref assignment must be a ref variable. + // var r = new R() { [0] = ref Value() }; // 1 + Diagnostic(ErrorCode.ERR_RefLocalOrParamExpected, "[0]").WithLocation(2, 19), + // (5,1): error CS8373: The left-hand side of a ref assignment must be a ref variable. + // r2[0] = ref Value(); // 2 + Diagnostic(ErrorCode.ERR_RefLocalOrParamExpected, "r2[0]").WithLocation(5, 1) + ); } [Fact] - public void RefSafeToEscape_01() + public void RefInitializer_Indexer() { - var source = -@"ref struct R { } -class Program + var source = @" +var r = new R() { [0] = ref Value() }; // 1 + +R r2 = default; +r2[0] = ref Value(); // 2 + +ref int Value() => throw null; + +ref struct R { - static ref R F0(R r0) => ref r0; // 1 - static ref R F1(scoped R r1) => ref r1; // 2 - static ref R F2(ref R r2) => ref r2; - static ref R F3(scoped ref R r3) => ref r3; // 3 - static ref R F4(ref scoped R r4) => ref r4; // 4 - static ref R F5(scoped ref scoped R r5) => ref r5; // 5 -}"; + public ref int this[int i] { get => throw null; } +} +"; var comp = CreateCompilation(source); comp.VerifyDiagnostics( - // (4,44): error CS8166: Cannot return a parameter by reference 'r0' because it is not a ref parameter - // static ref R F0(R r0) => ref r0; // 1 - Diagnostic(ErrorCode.ERR_RefReturnParameter, "r0").WithArguments("r0").WithLocation(4, 44), - // (5,51): error CS8166: Cannot return a parameter by reference 'r1' because it is not a ref parameter - // static ref R F1(scoped R r1) => ref r1; // 2 - Diagnostic(ErrorCode.ERR_RefReturnParameter, "r1").WithArguments("r1").WithLocation(5, 51), - // (7,55): error CS8166: Cannot return a parameter by reference 'r3' because it is not a ref parameter - // static ref R F3(scoped ref R r3) => ref r3; // 3 - Diagnostic(ErrorCode.ERR_RefReturnParameter, "r3").WithArguments("r3").WithLocation(7, 55), - // (8,55): error CS8166: Cannot return a parameter by reference 'r4' because it is not a ref parameter - // static ref R F4(ref scoped R r4) => ref r4; // 4 - Diagnostic(ErrorCode.ERR_RefReturnParameter, "r4").WithArguments("r4").WithLocation(8, 55), - // (9,62): error CS8166: Cannot return a parameter by reference 'r5' because it is not a ref parameter - // static ref R F5(scoped ref scoped R r5) => ref r5; // 5 - Diagnostic(ErrorCode.ERR_RefReturnParameter, "r5").WithArguments("r5").WithLocation(9, 62)); + // (2,19): error CS8373: The left-hand side of a ref assignment must be a ref variable. + // var r = new R() { [0] = ref Value() }; // 1 + Diagnostic(ErrorCode.ERR_RefLocalOrParamExpected, "[0]").WithLocation(2, 19), + // (5,1): error CS8373: The left-hand side of a ref assignment must be a ref variable. + // r2[0] = ref Value(); // 2 + Diagnostic(ErrorCode.ERR_RefLocalOrParamExpected, "r2[0]").WithLocation(5, 1) + ); } [Fact] - public void SafeToEscape_02() + public void RefInitializer_ValueMustReferToLocation() { - var source = -@"ref struct R { } -class Program + var source = @" +class C { - static R F0(R r0) - { - R l0 = r0; - return l0; - } - static R F1(scoped R r1) - { - R l1 = r1; - return l1; // 1 - } - static R F2(ref R r2) + int Value() => throw null; + + void M() { - R l2 = r2; - return l2; + var r = new R() { field = ref Value() }; } - static R F3(scoped ref R r3) +} + +ref struct R +{ + public ref int field; +} +"; + var comp = CreateCompilation(source, runtimeFeature: RuntimeFlag.ByRefFields); + comp.VerifyDiagnostics( + // (8,39): error CS1510: A ref or out value must be an assignable variable + // var r = new R() { field = ref Value() }; + Diagnostic(ErrorCode.ERR_RefLvalueExpected, "Value()").WithLocation(8, 39) + ); + } + + [Fact] + public void RefInitializer_RefReadonlyField_RefReadonlyValue() + { + var source = @" +class C +{ + ref readonly int Value() => throw null; + + void M() { - R l3 = r3; - return l3; + var r = new R() { field = ref Value() }; } - static R F4(ref scoped R r4) +} + +ref struct R +{ + public ref readonly int field; +} +"; + var comp = CreateCompilation(source, runtimeFeature: RuntimeFlag.ByRefFields); + comp.VerifyDiagnostics(); + } + + [Fact] + public void RefInitializer_OnInterface_Field() + { + var source = @" +class C +{ + void M() where T : I, new() { - R l4 = r4; - return l4; // 2 + int x = 42; + var t = new T() { field = ref x }; } - static R F5(scoped ref scoped R r5) +} +interface I +{ + public ref int field; +} +"; + var comp = CreateCompilation(source, runtimeFeature: RuntimeFlag.ByRefFields); + comp.VerifyDiagnostics( + // (12,20): error CS0525: Interfaces cannot contain instance fields + // public ref int field; + Diagnostic(ErrorCode.ERR_InterfacesCantContainFields, "field").WithLocation(12, 20), + // (12,20): error CS9059: A ref field can only be declared in a ref struct. + // public ref int field; + Diagnostic(ErrorCode.ERR_RefFieldInNonRefStruct, "field").WithLocation(12, 20) + ); + } + + [Fact] + public void RefInitializer_OnInterface_Property() + { + var source = @" +class C +{ + void M() where T : I, new() { - R l5 = r5; - return l5; // 3 + int x = 42; + var t = new T() { Property = ref x }; } -}"; +} + +interface I +{ + public ref int Property { get; } +} +"; var comp = CreateCompilation(source); comp.VerifyDiagnostics( - // (12,16): error CS8352: Cannot use variable 'l1' in this context because it may expose referenced variables outside of their declaration scope - // return l1; // 1 - Diagnostic(ErrorCode.ERR_EscapeVariable, "l1").WithArguments("l1").WithLocation(12, 16), - // (27,16): error CS8352: Cannot use variable 'l4' in this context because it may expose referenced variables outside of their declaration scope - // return l4; // 2 - Diagnostic(ErrorCode.ERR_EscapeVariable, "l4").WithArguments("l4").WithLocation(27, 16), - // (32,16): error CS8352: Cannot use variable 'l5' in this context because it may expose referenced variables outside of their declaration scope - // return l5; // 3 - Diagnostic(ErrorCode.ERR_EscapeVariable, "l5").WithArguments("l5").WithLocation(32, 16)); + // (7,27): error CS8373: The left-hand side of a ref assignment must be a ref variable. + // var t = new T() { Property = ref x }; + Diagnostic(ErrorCode.ERR_RefLocalOrParamExpected, "Property").WithLocation(7, 27) + ); } [Fact] - public void RefSafeToEscape_02() + public void RefInitializer_Collection() { - var source = -@"ref struct R { } -class Program + var source = @" +using System.Collections; + +int x = 42; +int y = 43; +var r = new R() { ref x, ref y }; + +struct R : IEnumerable { - static ref R F0(R r0) - { - R l0 = r0; - return ref l0; // 1 - } - static ref R F1(scoped R r1) - { - R l1 = r1; - return ref l1; // 2 - } - static ref R F2(ref R r2) - { - R l2 = r2; - return ref l2; // 3 - } - static ref R F3(scoped ref R r3) - { - R l3 = r3; - return ref l3; // 4 - } - static ref R F4(ref scoped R r4) - { - R l4 = r4; - return ref l4; // 5 - } - static ref R F5(scoped ref scoped R r5) - { - R l5 = r5; - return ref l5; // 6 - } -}"; + public void Add(ref int x) => throw null; + public IEnumerator GetEnumerator() => throw null; +} +"; var comp = CreateCompilation(source); comp.VerifyDiagnostics( - // (7,20): error CS8168: Cannot return local 'l0' by reference because it is not a ref local - // return ref l0; // 1 - Diagnostic(ErrorCode.ERR_RefReturnLocal, "l0").WithArguments("l0").WithLocation(7, 20), - // (12,20): error CS8168: Cannot return local 'l1' by reference because it is not a ref local - // return ref l1; // 2 - Diagnostic(ErrorCode.ERR_RefReturnLocal, "l1").WithArguments("l1").WithLocation(12, 20), - // (17,20): error CS8168: Cannot return local 'l2' by reference because it is not a ref local - // return ref l2; // 3 - Diagnostic(ErrorCode.ERR_RefReturnLocal, "l2").WithArguments("l2").WithLocation(17, 20), - // (22,20): error CS8168: Cannot return local 'l3' by reference because it is not a ref local - // return ref l3; // 4 - Diagnostic(ErrorCode.ERR_RefReturnLocal, "l3").WithArguments("l3").WithLocation(22, 20), - // (27,20): error CS8168: Cannot return local 'l4' by reference because it is not a ref local - // return ref l4; // 5 - Diagnostic(ErrorCode.ERR_RefReturnLocal, "l4").WithArguments("l4").WithLocation(27, 20), - // (32,20): error CS8168: Cannot return local 'l5' by reference because it is not a ref local - // return ref l5; // 6 - Diagnostic(ErrorCode.ERR_RefReturnLocal, "l5").WithArguments("l5").WithLocation(32, 20)); + // (4,5): warning CS0219: The variable 'x' is assigned but its value is never used + // int x = 42; + Diagnostic(ErrorCode.WRN_UnreferencedVarAssg, "x").WithArguments("x").WithLocation(4, 5), + // (5,5): warning CS0219: The variable 'y' is assigned but its value is never used + // int y = 43; + Diagnostic(ErrorCode.WRN_UnreferencedVarAssg, "y").WithArguments("y").WithLocation(5, 5), + // (6,19): error CS1073: Unexpected token 'ref' + // var r = new R() { ref x, ref y }; + Diagnostic(ErrorCode.ERR_UnexpectedToken, "ref").WithArguments("ref").WithLocation(6, 19), + // (6,26): error CS1073: Unexpected token 'ref' + // var r = new R() { ref x, ref y }; + Diagnostic(ErrorCode.ERR_UnexpectedToken, "ref").WithArguments("ref").WithLocation(6, 26) + ); } [Fact] - public void SafeToEscape_03() + public void RefInitializer_OnNonRefField() { - var source = -@"ref struct R { } -class Program + var source = @" +int x = 42; +var r = new R() { field = ref x }; // 1 + +R r2 = default; +r2.field = ref x; // 2 + +ref struct R { - static R F0(R r0) - { - scoped R l0 = r0; - return l0; // 1 - } - static R F1(scoped R r1) - { - scoped R l1 = r1; - return l1; // 2 - } - static R F2(ref R r2) - { - scoped R l2 = r2; - return l2; // 3 - } - static R F3(scoped ref R r3) - { - scoped R l3 = r3; - return l3; // 4 - } - static R F4(ref scoped R r4) - { - scoped R l4 = r4; - return l4; // 5 - } - static R F5(scoped ref scoped R r5) - { - scoped R l5 = r5; - return l5; // 6 - } -}"; + public int field; +} +"; var comp = CreateCompilation(source); comp.VerifyDiagnostics( - // (7,16): error CS8352: Cannot use variable 'l0' in this context because it may expose referenced variables outside of their declaration scope - // return l0; // 1 - Diagnostic(ErrorCode.ERR_EscapeVariable, "l0").WithArguments("l0").WithLocation(7, 16), - // (12,16): error CS8352: Cannot use variable 'l1' in this context because it may expose referenced variables outside of their declaration scope - // return l1; // 2 - Diagnostic(ErrorCode.ERR_EscapeVariable, "l1").WithArguments("l1").WithLocation(12, 16), - // (17,16): error CS8352: Cannot use variable 'l2' in this context because it may expose referenced variables outside of their declaration scope - // return l2; // 3 - Diagnostic(ErrorCode.ERR_EscapeVariable, "l2").WithArguments("l2").WithLocation(17, 16), - // (22,16): error CS8352: Cannot use variable 'l3' in this context because it may expose referenced variables outside of their declaration scope - // return l3; // 4 - Diagnostic(ErrorCode.ERR_EscapeVariable, "l3").WithArguments("l3").WithLocation(22, 16), - // (27,16): error CS8352: Cannot use variable 'l4' in this context because it may expose referenced variables outside of their declaration scope - // return l4; // 5 - Diagnostic(ErrorCode.ERR_EscapeVariable, "l4").WithArguments("l4").WithLocation(27, 16), - // (32,16): error CS8352: Cannot use variable 'l5' in this context because it may expose referenced variables outside of their declaration scope - // return l5; // 6 - Diagnostic(ErrorCode.ERR_EscapeVariable, "l5").WithArguments("l5").WithLocation(32, 16)); + // (3,19): error CS8373: The left-hand side of a ref assignment must be a ref variable. + // var r = new R() { field = ref x }; // 1 + Diagnostic(ErrorCode.ERR_RefLocalOrParamExpected, "field").WithLocation(3, 19), + // (6,1): error CS8373: The left-hand side of a ref assignment must be a ref variable. + // r2.field = ref x; // 2 + Diagnostic(ErrorCode.ERR_RefLocalOrParamExpected, "r2.field").WithLocation(6, 1) + ); } [Fact] - public void RefSafeToEscape_03() + public void RefInitializer_OnNonRefProperty() { - var source = -@"ref struct R { } -class Program + var source = @" +int x = 42; +var r = new R() { Property = ref x }; // 1 + +R r2 = default; +r2.Property = ref x; // 2 + +ref struct R { - static ref R F0(R r0) - { - scoped R l0 = r0; - return ref l0; // 1 - } - static ref R F1(scoped R r1) - { - scoped R l1 = r1; - return ref l1; // 2 - } - static ref R F2(ref R r2) - { - scoped R l2 = r2; - return ref l2; // 3 - } - static ref R F3(scoped ref R r3) - { - scoped R l3 = r3; - return ref l3; // 4 - } - static ref R F4(ref scoped R r4) - { - scoped R l4 = r4; - return ref l4; // 5 - } - static ref R F5(scoped ref scoped R r5) - { - scoped R l5 = r5; - return ref l5; // 6 - } -}"; + public int Property { get; set; } +} +"; var comp = CreateCompilation(source); comp.VerifyDiagnostics( - // (7,20): error CS8168: Cannot return local 'l0' by reference because it is not a ref local - // return ref l0; // 1 - Diagnostic(ErrorCode.ERR_RefReturnLocal, "l0").WithArguments("l0").WithLocation(7, 20), - // (12,20): error CS8168: Cannot return local 'l1' by reference because it is not a ref local - // return ref l1; // 2 - Diagnostic(ErrorCode.ERR_RefReturnLocal, "l1").WithArguments("l1").WithLocation(12, 20), - // (17,20): error CS8168: Cannot return local 'l2' by reference because it is not a ref local - // return ref l2; // 3 - Diagnostic(ErrorCode.ERR_RefReturnLocal, "l2").WithArguments("l2").WithLocation(17, 20), - // (22,20): error CS8168: Cannot return local 'l3' by reference because it is not a ref local - // return ref l3; // 4 - Diagnostic(ErrorCode.ERR_RefReturnLocal, "l3").WithArguments("l3").WithLocation(22, 20), - // (27,20): error CS8168: Cannot return local 'l4' by reference because it is not a ref local - // return ref l4; // 5 - Diagnostic(ErrorCode.ERR_RefReturnLocal, "l4").WithArguments("l4").WithLocation(27, 20), - // (32,20): error CS8168: Cannot return local 'l5' by reference because it is not a ref local - // return ref l5; // 6 - Diagnostic(ErrorCode.ERR_RefReturnLocal, "l5").WithArguments("l5").WithLocation(32, 20)); + // (3,19): error CS8373: The left-hand side of a ref assignment must be a ref variable. + // var r = new R() { Property = ref x }; // 1 + Diagnostic(ErrorCode.ERR_RefLocalOrParamExpected, "Property").WithLocation(3, 19), + // (6,1): error CS8373: The left-hand side of a ref assignment must be a ref variable. + // r2.Property = ref x; // 2 + Diagnostic(ErrorCode.ERR_RefLocalOrParamExpected, "r2.Property").WithLocation(6, 1) + ); + } + + [Fact] + public void RefInitializer_OnNonRefIndexer() + { + var source = @" +int x = 42; +var r = new R() { [0] = ref x }; // 1 + +R r2 = default; +r2[0] = ref x; // 2 + +ref struct R +{ + public int this[int i] { get => throw null; set => throw null; } +} +"; + var comp = CreateCompilation(source); + comp.VerifyDiagnostics( + // (3,19): error CS8373: The left-hand side of a ref assignment must be a ref variable. + // var r = new R() { [0] = ref x }; // 1 + Diagnostic(ErrorCode.ERR_RefLocalOrParamExpected, "[0]").WithLocation(3, 19), + // (6,1): error CS8373: The left-hand side of a ref assignment must be a ref variable. + // r2[0] = ref x; // 2 + Diagnostic(ErrorCode.ERR_RefLocalOrParamExpected, "r2[0]").WithLocation(6, 1) + ); } [Fact] - public void SafeToEscape_04() + public void RefInitializer_OnArray() { - var source = -@"ref struct R { } -class Program + var source = @" +public ref struct C { - static R F0(R r0) - { - ref R l0 = ref r0; - return l0; - } - static R F1(scoped R r1) + C M() { - ref R l1 = ref r1; - return l1; // 1 - } - static R F2(ref R r2) - { - ref R l2 = ref r2; - return l2; - } - static R F3(scoped ref R r3) - { - ref R l3 = ref r3; - return l3; - } - static R F4(ref scoped R r4) - { - ref R l4 = ref r4; - return l4; // 2 + int x = 0; + var c = new C { array = { [0] = ref x } }; // 1 + return c; } - static R F5(scoped ref scoped R r5) + + void M2() { - ref R l5 = ref r5; - return l5; // 3 + int x = 0; + C c2 = new C(); + c2.array[0] = ref x; // 2 } -}"; + + public int[] array; +} +"; var comp = CreateCompilation(source); comp.VerifyDiagnostics( - // (12,16): error CS8352: Cannot use variable 'l1' in this context because it may expose referenced variables outside of their declaration scope - // return l1; // 1 - Diagnostic(ErrorCode.ERR_EscapeVariable, "l1").WithArguments("l1").WithLocation(12, 16), - // (27,16): error CS8352: Cannot use variable 'l4' in this context because it may expose referenced variables outside of their declaration scope - // return l4; // 2 - Diagnostic(ErrorCode.ERR_EscapeVariable, "l4").WithArguments("l4").WithLocation(27, 16), - // (32,16): error CS8352: Cannot use variable 'l5' in this context because it may expose referenced variables outside of their declaration scope - // return l5; // 3 - Diagnostic(ErrorCode.ERR_EscapeVariable, "l5").WithArguments("l5").WithLocation(32, 16)); + // (7,35): error CS8373: The left-hand side of a ref assignment must be a ref variable. + // var c = new C { array = { [0] = ref x } }; // 1 + Diagnostic(ErrorCode.ERR_RefLocalOrParamExpected, "[0]").WithLocation(7, 35), + // (15,9): error CS8373: The left-hand side of a ref assignment must be a ref variable. + // c2.array[0] = ref x; // 2 + Diagnostic(ErrorCode.ERR_RefLocalOrParamExpected, "c2.array[0]").WithLocation(15, 9) + ); } [Fact] - public void RefSafeToEscape_04() + public void RefInitializer_OnPointer() { - var source = -@"ref struct R { } -class Program + var source = @" +public unsafe class C { - static ref R F0(R r0) - { - ref R l0 = ref r0; - return ref l0; // 1 - } - static ref R F1(scoped R r1) - { - ref R l1 = ref r1; - return ref l1; // 2 - } - static ref R F2(ref R r2) - { - ref R l2 = ref r2; - return ref l2; - } - static ref R F3(scoped ref R r3) - { - ref R l3 = ref r3; - return ref l3; // 3 - } - static ref R F4(ref scoped R r4) + public int* pointer; + + C M() { - ref R l4 = ref r4; - return ref l4; // 4 + int x = 0; + var c = new C { pointer = { [0] = ref x } }; // 1 + return c; } - static ref R F5(scoped ref scoped R r5) + + void M2() { - ref R l5 = ref r5; - return ref l5; // 5 + int x = 0; + C c2 = new C(); + c2.pointer[0] = ref x; // 2 } -}"; +} +"; + var comp = CreateCompilation(source, options: TestOptions.UnsafeDebugDll); + comp.VerifyDiagnostics( + // (9,37): error CS8373: The left-hand side of a ref assignment must be a ref variable. + // var c = new C { pointer = { [0] = ref x } }; // 1 + Diagnostic(ErrorCode.ERR_RefLocalOrParamExpected, "[0]").WithLocation(9, 37), + // (17,9): error CS8373: The left-hand side of a ref assignment must be a ref variable. + // c2.pointer[0] = ref x; // 2 + Diagnostic(ErrorCode.ERR_RefLocalOrParamExpected, "c2.pointer[0]").WithLocation(17, 9) + ); + } + + [Fact] + public void RefInitializer_OnEvent() + { + var source = @" +int x = 42; +var r = new C { a = ref x }; // 1 + +C c = default; +c.a = ref x; // 2 + +class C +{ + public event System.Action a; +} +"; var comp = CreateCompilation(source); comp.VerifyDiagnostics( - // (7,20): error CS8157: Cannot return 'l0' by reference because it was initialized to a value that cannot be returned by reference - // return ref l0; // 1 - Diagnostic(ErrorCode.ERR_RefReturnNonreturnableLocal, "l0").WithArguments("l0").WithLocation(7, 20), - // (12,20): error CS8157: Cannot return 'l1' by reference because it was initialized to a value that cannot be returned by reference - // return ref l1; // 2 - Diagnostic(ErrorCode.ERR_RefReturnNonreturnableLocal, "l1").WithArguments("l1").WithLocation(12, 20), - // (22,20): error CS8157: Cannot return 'l3' by reference because it was initialized to a value that cannot be returned by reference - // return ref l3; // 3 - Diagnostic(ErrorCode.ERR_RefReturnNonreturnableLocal, "l3").WithArguments("l3").WithLocation(22, 20), - // (27,20): error CS8157: Cannot return 'l4' by reference because it was initialized to a value that cannot be returned by reference - // return ref l4; // 4 - Diagnostic(ErrorCode.ERR_RefReturnNonreturnableLocal, "l4").WithArguments("l4").WithLocation(27, 20), - // (32,20): error CS8157: Cannot return 'l5' by reference because it was initialized to a value that cannot be returned by reference - // return ref l5; // 5 - Diagnostic(ErrorCode.ERR_RefReturnNonreturnableLocal, "l5").WithArguments("l5").WithLocation(32, 20)); + // (3,17): error CS0070: The event 'C.a' can only appear on the left hand side of += or -= (except when used from within the type 'C') + // var r = new C { a = ref x }; // 1 + Diagnostic(ErrorCode.ERR_BadEventUsage, "a").WithArguments("C.a", "C").WithLocation(3, 17), + // (6,3): error CS0070: The event 'C.a' can only appear on the left hand side of += or -= (except when used from within the type 'C') + // c.a = ref x; // 2 + Diagnostic(ErrorCode.ERR_BadEventUsage, "a").WithArguments("C.a", "C").WithLocation(6, 3) + ); } [Fact] - public void SafeToEscape_05() + public void RefInitializer_OnEvent_ThisMemberAccess() { - var source = -@"ref struct R { } -class Program + var source = @" +int x = 42; +var r1 = new C { this.a = ref x }; // 1 + +class C { - static R F0(R r0) - { - scoped ref R l0 = ref r0; - return l0; - } - static R F1(scoped R r1) - { - scoped ref R l1 = ref r1; // 1 - return l1; - } - static R F2(ref R r2) - { - scoped ref R l2 = ref r2; - return l2; - } - static R F3(scoped ref R r3) - { - scoped ref R l3 = ref r3; - return l3; - } - static R F4(ref scoped R r4) - { - scoped ref R l4 = ref r4; // 2 - return l4; - } - static R F5(scoped ref scoped R r5) - { - scoped ref R l5 = ref r5; // 3 - return l5; - } -}"; + public event System.Action a; +} +"; var comp = CreateCompilation(source); comp.VerifyDiagnostics( - // (11,36): error CS8352: Cannot use variable 'R' in this context because it may expose referenced variables outside of their declaration scope - // scoped ref R l1 = ref r1; // 1 - Diagnostic(ErrorCode.ERR_EscapeVariable, "r1").WithArguments("R").WithLocation(11, 36), - // (26,36): error CS8352: Cannot use variable 'ref R' in this context because it may expose referenced variables outside of their declaration scope - // scoped ref R l4 = ref r4; // 2 - Diagnostic(ErrorCode.ERR_EscapeVariable, "r4").WithArguments("ref R").WithLocation(26, 36), - // (31,36): error CS8352: Cannot use variable 'ref R' in this context because it may expose referenced variables outside of their declaration scope - // scoped ref R l5 = ref r5; // 3 - Diagnostic(ErrorCode.ERR_EscapeVariable, "r5").WithArguments("ref R").WithLocation(31, 36)); + // (3,16): error CS1922: Cannot initialize type 'C' with a collection initializer because it does not implement 'System.Collections.IEnumerable' + // var r1 = new C { this.a = ref x }; // 1 + Diagnostic(ErrorCode.ERR_CollectionInitRequiresIEnumerable, "{ this.a = ref x }").WithArguments("C").WithLocation(3, 16), + // (3,18): error CS0747: Invalid initializer member declarator + // var r1 = new C { this.a = ref x }; // 1 + Diagnostic(ErrorCode.ERR_InvalidInitializerElementInitializer, "this.a = ref x").WithLocation(3, 18), + // (3,18): error CS0026: Keyword 'this' is not valid in a static property, static method, or static field initializer + // var r1 = new C { this.a = ref x }; // 1 + Diagnostic(ErrorCode.ERR_ThisInStaticMeth, "this").WithLocation(3, 18), + // (7,32): warning CS0067: The event 'C.a' is never used + // public event System.Action a; + Diagnostic(ErrorCode.WRN_UnreferencedEvent, "a").WithArguments("C.a").WithLocation(7, 32) + ); } [Fact] - public void RefSafeToEscape_05() + public void RefInitializer_OnMethodGroup() { - var source = -@"ref struct R { } -class Program + var source = @" +int x = 42; +var r = new C { F = ref x }; // 1 + +C c = default; +c.F = ref x; // 2 + +class C { - static ref R F0(R r0) - { - scoped ref R l0 = ref r0; - return ref l0; // 1 - } - static ref R F1(scoped R r1) - { - scoped ref R l1 = ref r1; // 2 - return ref l1; // 3 - } - static ref R F2(ref R r2) - { - scoped ref R l2 = ref r2; - return ref l2; // 4 - } - static ref R F3(scoped ref R r3) + public void F() { } +} +"; + var comp = CreateCompilation(source); + comp.VerifyDiagnostics( + // (3,17): error CS1913: Member 'F' cannot be initialized. It is not a field or property. + // var r = new C { F = ref x }; // 1 + Diagnostic(ErrorCode.ERR_MemberCannotBeInitialized, "F").WithArguments("F").WithLocation(3, 17), + // (6,1): error CS1656: Cannot assign to 'F' because it is a 'method group' + // c.F = ref x; // 2 + Diagnostic(ErrorCode.ERR_AssgReadonlyLocalCause, "c.F").WithArguments("F", "method group").WithLocation(6, 1) + ); + } + + [Fact] + public void RefInitializer_Nested() + { + var source = @" +class C +{ + static void Main() { - scoped ref R l3 = ref r3; - return ref l3; // 5 + int x = 42; + var r = new Container { item = { field = ref x } }; + System.Console.Write(r.item.field); } - static ref R F4(ref scoped R r4) +} +ref struct Container +{ + public Item item; +} +ref struct Item +{ + public ref int field; +} +"; + var comp = CreateCompilation(source, options: TestOptions.ReleaseExe, runtimeFeature: RuntimeFlag.ByRefFields); + comp.VerifyDiagnostics(); + var verifier = CompileAndVerify(comp, verify: Verification.Skipped, expectedOutput: IncludeExpectedOutput("42")); + verifier.VerifyIL("C.Main", @" +{ + // Code size 43 (0x2b) + .maxstack 2 + .locals init (int V_0, //x + Container V_1) + IL_0000: ldc.i4.s 42 + IL_0002: stloc.0 + IL_0003: ldloca.s V_1 + IL_0005: initobj ""Container"" + IL_000b: ldloca.s V_1 + IL_000d: ldflda ""Item Container.item"" + IL_0012: ldloca.s V_0 + IL_0014: stfld ""ref int Item.field"" + IL_0019: ldloc.1 + IL_001a: ldfld ""Item Container.item"" + IL_001f: ldfld ""ref int Item.field"" + IL_0024: ldind.i4 + IL_0025: call ""void System.Console.Write(int)"" + IL_002a: ret +} +"); + } + + [Fact] + public void RefInitializer_Nullability() + { + var source = @" +#nullable enable + +S x1 = default; +S x2 = default; + +_ = new R { field = ref x1 }; +_ = new R { field = ref x2 }; // 1 +_ = new R { field = ref x1 }; // 2 +_ = new R { field = ref x2 }; + +_ = new R() with { field = ref x1 }; +_ = new R() with { field = ref x2 }; // 3 +_ = new R() with { field = ref x1 }; // 4 +_ = new R() with { field = ref x2 }; + +struct S { } +ref struct R +{ + public ref S field; +} +"; + var comp = CreateCompilation(source, options: TestOptions.ReleaseExe, runtimeFeature: RuntimeFlag.ByRefFields); + comp.VerifyDiagnostics( + // (8,33): warning CS8619: Nullability of reference types in value of type 'S' doesn't match target type 'S'. + // _ = new R { field = ref x2 }; // 1 + Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "x2").WithArguments("S", "S").WithLocation(8, 33), + // (9,34): warning CS8619: Nullability of reference types in value of type 'S' doesn't match target type 'S'. + // _ = new R { field = ref x1 }; // 2 + Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "x1").WithArguments("S", "S").WithLocation(9, 34), + // (13,40): warning CS8619: Nullability of reference types in value of type 'S' doesn't match target type 'S'. + // _ = new R() with { field = ref x2 }; // 3 + Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "x2").WithArguments("S", "S").WithLocation(13, 40), + // (14,41): warning CS8619: Nullability of reference types in value of type 'S' doesn't match target type 'S'. + // _ = new R() with { field = ref x1 }; // 4 + Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "x1").WithArguments("S", "S").WithLocation(14, 41) + ); + } + + [Fact] + public void RefInitializer_RefOnNestedInitializer() + { + var source = @" +int x = 42; +var r = new R { field = ref { item = 42 } }; // 1 + +struct S +{ + public int item; +} +ref struct R +{ + public ref S field; +} +"; + var comp = CreateCompilation(source, options: TestOptions.ReleaseExe, runtimeFeature: RuntimeFlag.ByRefFields); + comp.VerifyDiagnostics( + // (2,5): warning CS0219: The variable 'x' is assigned but its value is never used + // int x = 42; + Diagnostic(ErrorCode.WRN_UnreferencedVarAssg, "x").WithArguments("x").WithLocation(2, 5), + // (3,29): error CS1525: Invalid expression term '{' + // var r = new R { field = ref { item = 42 } }; // 1 + Diagnostic(ErrorCode.ERR_InvalidExprTerm, "{").WithArguments("{").WithLocation(3, 29), + // (3,29): error CS1003: Syntax error, ',' expected + // var r = new R { field = ref { item = 42 } }; // 1 + Diagnostic(ErrorCode.ERR_SyntaxError, "{").WithArguments(",").WithLocation(3, 29), + // (3,29): error CS0747: Invalid initializer member declarator + // var r = new R { field = ref { item = 42 } }; // 1 + Diagnostic(ErrorCode.ERR_InvalidInitializerElementInitializer, "{ item = 42 }").WithLocation(3, 29), + // (3,31): error CS0103: The name 'item' does not exist in the current context + // var r = new R { field = ref { item = 42 } }; // 1 + Diagnostic(ErrorCode.ERR_NameNotInContext, "item").WithArguments("item").WithLocation(3, 31) + ); + } + + [Fact] + public void RefInitializer_FieldOnDynamic() + { + var source = @" +int x = 42; +var r = new S { D = { field = ref x } }; // 1 + +S s = default; +s.D.field = ref x; // 2 + +struct S +{ + public dynamic D; +} +"; + var comp = CreateCompilation(source); + comp.VerifyDiagnostics( + // (3,23): error CS8373: The left-hand side of a ref assignment must be a ref variable. + // var r = new S { D = { field = ref x } }; // 1 + Diagnostic(ErrorCode.ERR_RefLocalOrParamExpected, "field").WithLocation(3, 23), + // (6,1): error CS8373: The left-hand side of a ref assignment must be a ref variable. + // s.D.field = ref x; // 2 + Diagnostic(ErrorCode.ERR_RefLocalOrParamExpected, "s.D.field").WithLocation(6, 1) + ); + } + + [Fact] + public void RefInitializer_DynamicField() + { + var source = @" +int i = 42; +var r = new R { F = ref i }; // 1 + +ref struct R +{ + public ref T F; +} +"; + var comp = CreateCompilation(source, runtimeFeature: RuntimeFlag.ByRefFields); + comp.VerifyDiagnostics( + // (3,34): error CS8173: The expression must be of type 'dynamic' because it is being assigned by reference + // var r = new R { F = ref i }; // 1 + Diagnostic(ErrorCode.ERR_RefAssignmentMustHaveIdentityConversion, "i").WithArguments("dynamic").WithLocation(3, 34) + ); + } + + [Fact] + public void RefInitializer_DynamicField_DynamicValue() + { + var source = @" +public class C +{ + public static void Main() { - scoped ref R l4 = ref r4; // 6 - return ref l4; // 7 + dynamic i = 42; + var r = new R { F = ref i }; + System.Console.Write(r.F); + + var r2 = new R(ref i); + System.Console.Write(r2.F); } - static ref R F5(scoped ref scoped R r5) +} + +ref struct R +{ + public R(ref T f) { F = ref f; } + public ref T F; +} +"; + var references = TargetFrameworkUtil.GetReferences(TargetFramework.NetCoreAppAndCSharp, additionalReferences: null); + // Note: we use skipExtraValidation so that nobody pulls + // on the compilation or its references before we set the RuntimeSupportsByRefFields flag. + var comp = CreateEmptyCompilation(source, references: CopyWithoutSharingCachedSymbols(references), options: TestOptions.DebugExe, skipExtraValidation: true); + comp.Assembly.RuntimeSupportsByRefFields = true; + var verifier = CompileAndVerify(comp, verify: Verification.Skipped, expectedOutput: IncludeExpectedOutput("4242")); + verifier.VerifyIL("C.Main", """ +{ + // Code size 257 (0x101) + .maxstack 9 + .locals init (object V_0, //i + R V_1, //r + R V_2, //r2 + R V_3) + IL_0000: nop + IL_0001: ldc.i4.s 42 + IL_0003: box "int" + IL_0008: stloc.0 + IL_0009: ldloca.s V_3 + IL_000b: initobj "R" + IL_0011: ldloca.s V_3 + IL_0013: ldloca.s V_0 + IL_0015: stfld "ref dynamic R.F" + IL_001a: ldloc.3 + IL_001b: stloc.1 + IL_001c: ldsfld "System.Runtime.CompilerServices.CallSite> C.<>o__0.<>p__0" + IL_0021: brfalse.s IL_0025 + IL_0023: br.s IL_0064 + IL_0025: ldc.i4 0x100 + IL_002a: ldstr "Write" + IL_002f: ldnull + IL_0030: ldtoken "C" + IL_0035: call "System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)" + IL_003a: ldc.i4.2 + IL_003b: newarr "Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo" + IL_0040: dup + IL_0041: ldc.i4.0 + IL_0042: ldc.i4.s 33 + IL_0044: ldnull + IL_0045: call "Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo.Create(Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfoFlags, string)" + IL_004a: stelem.ref + IL_004b: dup + IL_004c: ldc.i4.1 + IL_004d: ldc.i4.0 + IL_004e: ldnull + IL_004f: call "Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo.Create(Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfoFlags, string)" + IL_0054: stelem.ref + IL_0055: call "System.Runtime.CompilerServices.CallSiteBinder Microsoft.CSharp.RuntimeBinder.Binder.InvokeMember(Microsoft.CSharp.RuntimeBinder.CSharpBinderFlags, string, System.Collections.Generic.IEnumerable, System.Type, System.Collections.Generic.IEnumerable)" + IL_005a: call "System.Runtime.CompilerServices.CallSite> System.Runtime.CompilerServices.CallSite>.Create(System.Runtime.CompilerServices.CallSiteBinder)" + IL_005f: stsfld "System.Runtime.CompilerServices.CallSite> C.<>o__0.<>p__0" + IL_0064: ldsfld "System.Runtime.CompilerServices.CallSite> C.<>o__0.<>p__0" + IL_0069: ldfld "System.Action System.Runtime.CompilerServices.CallSite>.Target" + IL_006e: ldsfld "System.Runtime.CompilerServices.CallSite> C.<>o__0.<>p__0" + IL_0073: ldtoken "System.Console" + IL_0078: call "System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)" + IL_007d: ldloc.1 + IL_007e: ldfld "ref dynamic R.F" + IL_0083: ldind.ref + IL_0084: callvirt "void System.Action.Invoke(System.Runtime.CompilerServices.CallSite, System.Type, dynamic)" + IL_0089: nop + IL_008a: ldloca.s V_0 + IL_008c: newobj "R..ctor(ref dynamic)" + IL_0091: stloc.2 + IL_0092: ldsfld "System.Runtime.CompilerServices.CallSite> C.<>o__0.<>p__1" + IL_0097: brfalse.s IL_009b + IL_0099: br.s IL_00da + IL_009b: ldc.i4 0x100 + IL_00a0: ldstr "Write" + IL_00a5: ldnull + IL_00a6: ldtoken "C" + IL_00ab: call "System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)" + IL_00b0: ldc.i4.2 + IL_00b1: newarr "Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo" + IL_00b6: dup + IL_00b7: ldc.i4.0 + IL_00b8: ldc.i4.s 33 + IL_00ba: ldnull + IL_00bb: call "Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo.Create(Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfoFlags, string)" + IL_00c0: stelem.ref + IL_00c1: dup + IL_00c2: ldc.i4.1 + IL_00c3: ldc.i4.0 + IL_00c4: ldnull + IL_00c5: call "Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo.Create(Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfoFlags, string)" + IL_00ca: stelem.ref + IL_00cb: call "System.Runtime.CompilerServices.CallSiteBinder Microsoft.CSharp.RuntimeBinder.Binder.InvokeMember(Microsoft.CSharp.RuntimeBinder.CSharpBinderFlags, string, System.Collections.Generic.IEnumerable, System.Type, System.Collections.Generic.IEnumerable)" + IL_00d0: call "System.Runtime.CompilerServices.CallSite> System.Runtime.CompilerServices.CallSite>.Create(System.Runtime.CompilerServices.CallSiteBinder)" + IL_00d5: stsfld "System.Runtime.CompilerServices.CallSite> C.<>o__0.<>p__1" + IL_00da: ldsfld "System.Runtime.CompilerServices.CallSite> C.<>o__0.<>p__1" + IL_00df: ldfld "System.Action System.Runtime.CompilerServices.CallSite>.Target" + IL_00e4: ldsfld "System.Runtime.CompilerServices.CallSite> C.<>o__0.<>p__1" + IL_00e9: ldtoken "System.Console" + IL_00ee: call "System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)" + IL_00f3: ldloc.2 + IL_00f4: ldfld "ref dynamic R.F" + IL_00f9: ldind.ref + IL_00fa: callvirt "void System.Action.Invoke(System.Runtime.CompilerServices.CallSite, System.Type, dynamic)" + IL_00ff: nop + IL_0100: ret +} +"""); + } + + [Fact] + public void RefInitializer_SubstitutedObjectField() + { + var source = @" +public class C +{ + public static void Main() { - scoped ref R l5 = ref r5; // 8 - return ref l5; // 9 + object i = 42; + var r = new R { F = ref i }; + System.Console.Write(r.F); + + var r2 = new R(ref i); + System.Console.Write(r2.F); } -}"; +} + +ref struct R +{ + public R(ref T f) { F = ref f; } + public ref T F; +} +"; + var comp = CreateCompilation(source, options: TestOptions.DebugExe, runtimeFeature: RuntimeFlag.ByRefFields); + comp.VerifyDiagnostics(); + comp = CreateCompilation(source, options: TestOptions.ReleaseExe, runtimeFeature: RuntimeFlag.ByRefFields); + var verifier = CompileAndVerify(comp, verify: Verification.Skipped, expectedOutput: IncludeExpectedOutput("4242")); + verifier.VerifyIL("C.Main", """ +{ + // Code size 56 (0x38) + .maxstack 2 + .locals init (object V_0, //i + R V_1) + IL_0000: ldc.i4.s 42 + IL_0002: box "int" + IL_0007: stloc.0 + IL_0008: ldloca.s V_1 + IL_000a: initobj "R" + IL_0010: ldloca.s V_1 + IL_0012: ldloca.s V_0 + IL_0014: stfld "ref object R.F" + IL_0019: ldloc.1 + IL_001a: ldfld "ref object R.F" + IL_001f: ldind.ref + IL_0020: call "void System.Console.Write(object)" + IL_0025: ldloca.s V_0 + IL_0027: newobj "R..ctor(ref object)" + IL_002c: ldfld "ref object R.F" + IL_0031: ldind.ref + IL_0032: call "void System.Console.Write(object)" + IL_0037: ret +} +"""); + } + + [Fact] + public void RefInitializer_DynamicInstance() + { + var source = @" +int x = 42; +var r = new dynamic { field = ref x }; // 1 + +dynamic r2 = null; +r2.field = ref x; // 2 +"; var comp = CreateCompilation(source); comp.VerifyDiagnostics( - // (7,20): error CS8157: Cannot return 'l0' by reference because it was initialized to a value that cannot be returned by reference - // return ref l0; // 1 - Diagnostic(ErrorCode.ERR_RefReturnNonreturnableLocal, "l0").WithArguments("l0").WithLocation(7, 20), - // (11,36): error CS8352: Cannot use variable 'R' in this context because it may expose referenced variables outside of their declaration scope - // scoped ref R l1 = ref r1; // 2 - Diagnostic(ErrorCode.ERR_EscapeVariable, "r1").WithArguments("R").WithLocation(11, 36), - // (12,20): error CS8157: Cannot return 'l1' by reference because it was initialized to a value that cannot be returned by reference - // return ref l1; // 3 - Diagnostic(ErrorCode.ERR_RefReturnNonreturnableLocal, "l1").WithArguments("l1").WithLocation(12, 20), - // (17,20): error CS8157: Cannot return 'l2' by reference because it was initialized to a value that cannot be returned by reference - // return ref l2; // 4 - Diagnostic(ErrorCode.ERR_RefReturnNonreturnableLocal, "l2").WithArguments("l2").WithLocation(17, 20), - // (22,20): error CS8157: Cannot return 'l3' by reference because it was initialized to a value that cannot be returned by reference - // return ref l3; // 5 - Diagnostic(ErrorCode.ERR_RefReturnNonreturnableLocal, "l3").WithArguments("l3").WithLocation(22, 20), - // (26,36): error CS8352: Cannot use variable 'ref R' in this context because it may expose referenced variables outside of their declaration scope - // scoped ref R l4 = ref r4; // 6 - Diagnostic(ErrorCode.ERR_EscapeVariable, "r4").WithArguments("ref R").WithLocation(26, 36), - // (27,20): error CS8157: Cannot return 'l4' by reference because it was initialized to a value that cannot be returned by reference - // return ref l4; // 7 - Diagnostic(ErrorCode.ERR_RefReturnNonreturnableLocal, "l4").WithArguments("l4").WithLocation(27, 20), - // (31,36): error CS8352: Cannot use variable 'ref R' in this context because it may expose referenced variables outside of their declaration scope - // scoped ref R l5 = ref r5; // 8 - Diagnostic(ErrorCode.ERR_EscapeVariable, "r5").WithArguments("ref R").WithLocation(31, 36), - // (32,20): error CS8157: Cannot return 'l5' by reference because it was initialized to a value that cannot be returned by reference - // return ref l5; // 9 - Diagnostic(ErrorCode.ERR_RefReturnNonreturnableLocal, "l5").WithArguments("l5").WithLocation(32, 20)); + // (3,13): error CS8386: Invalid object creation + // var r = new dynamic { field = ref x }; // 1 + Diagnostic(ErrorCode.ERR_InvalidObjectCreation, "dynamic").WithLocation(3, 13), + // (3,23): error CS8373: The left-hand side of a ref assignment must be a ref variable. + // var r = new dynamic { field = ref x }; // 1 + Diagnostic(ErrorCode.ERR_RefLocalOrParamExpected, "field").WithLocation(3, 23), + // (6,1): error CS8373: The left-hand side of a ref assignment must be a ref variable. + // r2.field = ref x; // 2 + Diagnostic(ErrorCode.ERR_RefLocalOrParamExpected, "r2.field").WithLocation(6, 1) + ); } [Fact] - public void SafeToEscape_06() + public void RefInitializer_DynamicIndexer() { - var source = -@"ref struct R { } -class Program + var source = @" +int x = 42; +var r = new S { D = { [0] = ref x } }; // 1 + +S s = default; +s.D[0] = ref x; // 2 + +struct S { - static R F0(R r0) - { - ref scoped R l0 = ref r0; - return l0; // 1 - } - static R F1(scoped R r1) - { - ref scoped R l1 = ref r1; - return l1; // 2 - } - static R F2(ref R r2) - { - ref scoped R l2 = ref r2; - return l2; // 3 - } - static R F3(scoped ref R r3) - { - ref scoped R l3 = ref r3; - return l3; // 4 - } - static R F4(ref scoped R r4) - { - ref scoped R l4 = ref r4; - return l4; // 5 - } - static R F5(scoped ref scoped R r5) - { - ref scoped R l5 = ref r5; - return l5; // 6 - } -}"; + public dynamic D; +} +ref struct R +{ +} +"; var comp = CreateCompilation(source); comp.VerifyDiagnostics( - // (7,16): error CS8352: Cannot use variable 'l0' in this context because it may expose referenced variables outside of their declaration scope - // return l0; // 1 - Diagnostic(ErrorCode.ERR_EscapeVariable, "l0").WithArguments("l0").WithLocation(7, 16), - // (12,16): error CS8352: Cannot use variable 'l1' in this context because it may expose referenced variables outside of their declaration scope - // return l1; // 2 - Diagnostic(ErrorCode.ERR_EscapeVariable, "l1").WithArguments("l1").WithLocation(12, 16), - // (17,16): error CS8352: Cannot use variable 'l2' in this context because it may expose referenced variables outside of their declaration scope - // return l2; // 3 - Diagnostic(ErrorCode.ERR_EscapeVariable, "l2").WithArguments("l2").WithLocation(17, 16), - // (22,16): error CS8352: Cannot use variable 'l3' in this context because it may expose referenced variables outside of their declaration scope - // return l3; // 4 - Diagnostic(ErrorCode.ERR_EscapeVariable, "l3").WithArguments("l3").WithLocation(22, 16), - // (27,16): error CS8352: Cannot use variable 'l4' in this context because it may expose referenced variables outside of their declaration scope - // return l4; // 5 - Diagnostic(ErrorCode.ERR_EscapeVariable, "l4").WithArguments("l4").WithLocation(27, 16), - // (32,16): error CS8352: Cannot use variable 'l5' in this context because it may expose referenced variables outside of their declaration scope - // return l5; // 6 - Diagnostic(ErrorCode.ERR_EscapeVariable, "l5").WithArguments("l5").WithLocation(32, 16)); + // (3,23): error CS8373: The left-hand side of a ref assignment must be a ref variable. + // var r = new S { D = { [0] = ref x } }; // 1 + Diagnostic(ErrorCode.ERR_RefLocalOrParamExpected, "[0]").WithLocation(3, 23), + // (6,1): error CS8373: The left-hand side of a ref assignment must be a ref variable. + // s.D[0] = ref x; // 2 + Diagnostic(ErrorCode.ERR_RefLocalOrParamExpected, "s.D[0]").WithLocation(6, 1) + ); } [Fact] - public void RefSafeToEscape_06() + public void RefInitializer_DynamicIndexer_Nested() { - var source = -@"ref struct R { } -class Program + var source = @" +dynamic x = 1; +int i = 42; +var a = new A() { [y: x, x: x] = { X = ref i } }; // 1 + +A a2 = null; +a2[y: x, x: x].X = ref i; // 2 + +public class A { - static ref R F0(R r0) - { - ref scoped R l0 = ref r0; - return ref l0; // 1 - } - static ref R F1(scoped R r1) - { - ref scoped R l1 = ref r1; - return ref l1; // 2 - } - static ref R F2(ref R r2) - { - ref scoped R l2 = ref r2; - return ref l2; // 3 - } - static ref R F3(scoped ref R r3) - { - ref scoped R l3 = ref r3; - return ref l3; // 4 - } - static ref R F4(ref scoped R r4) - { - ref scoped R l4 = ref r4; - return ref l4; // 5 - } - static ref R F5(scoped ref scoped R r5) - { - ref scoped R l5 = ref r5; - return ref l5; // 6 - } -}"; + public dynamic this[int x, int y] { get => throw null; } +} +"; var comp = CreateCompilation(source); comp.VerifyDiagnostics( - // (7,20): error CS8157: Cannot return 'l0' by reference because it was initialized to a value that cannot be returned by reference - // return ref l0; // 1 - Diagnostic(ErrorCode.ERR_RefReturnNonreturnableLocal, "l0").WithArguments("l0").WithLocation(7, 20), - // (12,20): error CS8157: Cannot return 'l1' by reference because it was initialized to a value that cannot be returned by reference - // return ref l1; // 2 - Diagnostic(ErrorCode.ERR_RefReturnNonreturnableLocal, "l1").WithArguments("l1").WithLocation(12, 20), - // (17,20): error CS8157: Cannot return 'l2' by reference because it was initialized to a value that cannot be returned by reference - // return ref l2; // 3 - Diagnostic(ErrorCode.ERR_RefReturnNonreturnableLocal, "l2").WithArguments("l2").WithLocation(17, 20), - // (22,20): error CS8157: Cannot return 'l3' by reference because it was initialized to a value that cannot be returned by reference - // return ref l3; // 4 - Diagnostic(ErrorCode.ERR_RefReturnNonreturnableLocal, "l3").WithArguments("l3").WithLocation(22, 20), - // (27,20): error CS8157: Cannot return 'l4' by reference because it was initialized to a value that cannot be returned by reference - // return ref l4; // 5 - Diagnostic(ErrorCode.ERR_RefReturnNonreturnableLocal, "l4").WithArguments("l4").WithLocation(27, 20), - // (32,20): error CS8157: Cannot return 'l5' by reference because it was initialized to a value that cannot be returned by reference - // return ref l5; // 6 - Diagnostic(ErrorCode.ERR_RefReturnNonreturnableLocal, "l5").WithArguments("l5").WithLocation(32, 20)); + // (4,36): error CS8373: The left-hand side of a ref assignment must be a ref variable. + // var a = new A() { [y: x, x: x] = { X = ref i } }; // 1 + Diagnostic(ErrorCode.ERR_RefLocalOrParamExpected, "X").WithLocation(4, 36), + // (7,1): error CS8373: The left-hand side of a ref assignment must be a ref variable. + // a2[y: x, x: x].X = ref i; // 2 + Diagnostic(ErrorCode.ERR_RefLocalOrParamExpected, "a2[y: x, x: x].X").WithLocation(7, 1) + ); } [Fact] - public void SafeToEscape_07() + public void RefInitializer_Escape() { - var source = -@"ref struct R { } -class Program + var source = @" +public class C { - static R F0(R r0) + public static R M1() { - scoped ref scoped R l0 = ref r0; - return l0; // 1 - } - static R F1(scoped R r1) - { - scoped ref scoped R l1 = ref r1; - return l1; // 2 + int x = 42; + var r = new R { field = ref x }; + return r; // 1 } - static R F2(ref R r2) + public static R M2(ref int x) { - scoped ref scoped R l2 = ref r2; - return l2; // 3 + var r = new R { field = ref x }; + return r; } - static R F3(scoped ref R r3) + public static R M3() { - scoped ref scoped R l3 = ref r3; - return l3; // 4 + R r = default; + { + int x = 42; + r = new R { field = ref x }; // 2 + } + return r; } - static R F4(ref scoped R r4) + public static R M4() { - scoped ref scoped R l4 = ref r4; - return l4; // 5 + R r = default; + int x = 42; + { + r = new R { field = ref x }; // 3 + } + return r; } - static R F5(scoped ref scoped R r5) + public static void M5(ref R r) { - scoped ref scoped R l5 = ref r5; - return l5; // 6 + int x = 42; + r = new R { field = ref x }; // 4 } -}"; - var comp = CreateCompilation(source); - comp.VerifyDiagnostics( - // (7,16): error CS8352: Cannot use variable 'l0' in this context because it may expose referenced variables outside of their declaration scope - // return l0; // 1 - Diagnostic(ErrorCode.ERR_EscapeVariable, "l0").WithArguments("l0").WithLocation(7, 16), - // (12,16): error CS8352: Cannot use variable 'l1' in this context because it may expose referenced variables outside of their declaration scope - // return l1; // 2 - Diagnostic(ErrorCode.ERR_EscapeVariable, "l1").WithArguments("l1").WithLocation(12, 16), - // (17,16): error CS8352: Cannot use variable 'l2' in this context because it may expose referenced variables outside of their declaration scope - // return l2; // 3 - Diagnostic(ErrorCode.ERR_EscapeVariable, "l2").WithArguments("l2").WithLocation(17, 16), - // (22,16): error CS8352: Cannot use variable 'l3' in this context because it may expose referenced variables outside of their declaration scope - // return l3; // 4 - Diagnostic(ErrorCode.ERR_EscapeVariable, "l3").WithArguments("l3").WithLocation(22, 16), - // (27,16): error CS8352: Cannot use variable 'l4' in this context because it may expose referenced variables outside of their declaration scope - // return l4; // 5 - Diagnostic(ErrorCode.ERR_EscapeVariable, "l4").WithArguments("l4").WithLocation(27, 16), - // (32,16): error CS8352: Cannot use variable 'l5' in this context because it may expose referenced variables outside of their declaration scope - // return l5; // 6 - Diagnostic(ErrorCode.ERR_EscapeVariable, "l5").WithArguments("l5").WithLocation(32, 16)); - } +} - [Fact] - public void RefSafeToEscape_07() - { - var source = -@"ref struct R { } -class Program +public ref struct R { - static ref R F0(R r0) - { - scoped ref scoped R l0 = ref r0; - return ref l0; // 1 - } - static ref R F1(scoped R r1) + public ref int field; +} +"; + var comp = CreateCompilation(source, runtimeFeature: RuntimeFlag.ByRefFields); + comp.VerifyDiagnostics( + // (8,16): error CS8352: Cannot use variable 'r' in this context because it may expose referenced variables outside of their declaration scope + // return r; // 1 + Diagnostic(ErrorCode.ERR_EscapeVariable, "r").WithArguments("r").WithLocation(8, 16), + // (20,25): error CS8168: Cannot return local 'x' by reference because it is not a ref local + // r = new R { field = ref x }; // 2 + Diagnostic(ErrorCode.ERR_RefReturnLocal, "field = ref x").WithArguments("x").WithLocation(20, 25), + // (29,25): error CS8168: Cannot return local 'x' by reference because it is not a ref local + // r = new R { field = ref x }; // 3 + Diagnostic(ErrorCode.ERR_RefReturnLocal, "field = ref x").WithArguments("x").WithLocation(29, 25), + // (36,21): error CS8168: Cannot return local 'x' by reference because it is not a ref local + // r = new R { field = ref x }; // 4 + Diagnostic(ErrorCode.ERR_RefReturnLocal, "field = ref x").WithArguments("x").WithLocation(36, 21) + ); + + // Initializer values behave like constructor parameters for purpose of escape analysis + source = @" +public class C +{ + public static R M1() { - scoped ref scoped R l1 = ref r1; - return ref l1; // 2 + int x = 42; + var r = new R(ref x); + return r; // 1 } - static ref R F2(ref R r2) + public static R M2(ref int x) { - scoped ref scoped R l2 = ref r2; - return ref l2; // 3 + var r = new R(ref x); + return r; } - static ref R F3(scoped ref R r3) + public static R M3() { - scoped ref scoped R l3 = ref r3; - return ref l3; // 4 + R r = default; + { + int x = 42; + r = new R(ref x); // 2 + } + return r; } - static ref R F4(ref scoped R r4) + public static R M4() { - scoped ref scoped R l4 = ref r4; - return ref l4; // 5 + R r = default; + int x = 42; + { + r = new R(ref x); // 3 + } + return r; } - static ref R F5(scoped ref scoped R r5) + public static void M5(ref R r) { - scoped ref scoped R l5 = ref r5; - return ref l5; // 6 + int x = 42; + r = new R(ref x); // 4 } -}"; - var comp = CreateCompilation(source); - comp.VerifyDiagnostics( - // (7,20): error CS8157: Cannot return 'l0' by reference because it was initialized to a value that cannot be returned by reference - // return ref l0; // 1 - Diagnostic(ErrorCode.ERR_RefReturnNonreturnableLocal, "l0").WithArguments("l0").WithLocation(7, 20), - // (12,20): error CS8157: Cannot return 'l1' by reference because it was initialized to a value that cannot be returned by reference - // return ref l1; // 2 - Diagnostic(ErrorCode.ERR_RefReturnNonreturnableLocal, "l1").WithArguments("l1").WithLocation(12, 20), - // (17,20): error CS8157: Cannot return 'l2' by reference because it was initialized to a value that cannot be returned by reference - // return ref l2; // 3 - Diagnostic(ErrorCode.ERR_RefReturnNonreturnableLocal, "l2").WithArguments("l2").WithLocation(17, 20), - // (22,20): error CS8157: Cannot return 'l3' by reference because it was initialized to a value that cannot be returned by reference - // return ref l3; // 4 - Diagnostic(ErrorCode.ERR_RefReturnNonreturnableLocal, "l3").WithArguments("l3").WithLocation(22, 20), - // (27,20): error CS8157: Cannot return 'l4' by reference because it was initialized to a value that cannot be returned by reference - // return ref l4; // 5 - Diagnostic(ErrorCode.ERR_RefReturnNonreturnableLocal, "l4").WithArguments("l4").WithLocation(27, 20), - // (32,20): error CS8157: Cannot return 'l5' by reference because it was initialized to a value that cannot be returned by reference - // return ref l5; // 6 - Diagnostic(ErrorCode.ERR_RefReturnNonreturnableLocal, "l5").WithArguments("l5").WithLocation(32, 20)); - } +} - [Fact] - public void ReturnValueField_01() - { - var source = -@"ref struct R +public ref struct R { - public T F; - public T GetValue() => F; - public ref T GetRef() => ref F; // 1 - public ref readonly T GetRefReadonly() => ref F; // 2 -}"; - var comp = CreateCompilation(source); + public ref int field; + public R(ref int i) { } +} +"; + comp = CreateCompilation(source, runtimeFeature: RuntimeFlag.ByRefFields); comp.VerifyDiagnostics( - // (5,34): error CS8170: Struct members cannot return 'this' or other instance members by reference - // public ref T GetRef() => ref F; // 1 - Diagnostic(ErrorCode.ERR_RefReturnStructThis, "F").WithLocation(5, 34), - // (6,51): error CS8170: Struct members cannot return 'this' or other instance members by reference - // public ref readonly T GetRefReadonly() => ref F; // 2 - Diagnostic(ErrorCode.ERR_RefReturnStructThis, "F").WithLocation(6, 51)); - } - - [Fact] - public void ReturnValueField_02() - { - var source = -@"struct S + // (8,16): error CS8352: Cannot use variable 'r' in this context because it may expose referenced variables outside of their declaration scope + // return r; // 1 + Diagnostic(ErrorCode.ERR_EscapeVariable, "r").WithArguments("r").WithLocation(8, 16), + // (20,17): error CS8347: Cannot use a result of 'R.R(ref int)' in this context because it may expose variables referenced by parameter 'i' outside of their declaration scope + // r = new R(ref x); // 2 + Diagnostic(ErrorCode.ERR_EscapeCall, "new R(ref x)").WithArguments("R.R(ref int)", "i").WithLocation(20, 17), + // (20,27): error CS8168: Cannot return local 'x' by reference because it is not a ref local + // r = new R(ref x); // 2 + Diagnostic(ErrorCode.ERR_RefReturnLocal, "x").WithArguments("x").WithLocation(20, 27), + // (29,17): error CS8347: Cannot use a result of 'R.R(ref int)' in this context because it may expose variables referenced by parameter 'i' outside of their declaration scope + // r = new R(ref x); // 3 + Diagnostic(ErrorCode.ERR_EscapeCall, "new R(ref x)").WithArguments("R.R(ref int)", "i").WithLocation(29, 17), + // (29,27): error CS8168: Cannot return local 'x' by reference because it is not a ref local + // r = new R(ref x); // 3 + Diagnostic(ErrorCode.ERR_RefReturnLocal, "x").WithArguments("x").WithLocation(29, 27), + // (36,13): error CS8347: Cannot use a result of 'R.R(ref int)' in this context because it may expose variables referenced by parameter 'i' outside of their declaration scope + // r = new R(ref x); // 4 + Diagnostic(ErrorCode.ERR_EscapeCall, "new R(ref x)").WithArguments("R.R(ref int)", "i").WithLocation(36, 13), + // (36,23): error CS8168: Cannot return local 'x' by reference because it is not a ref local + // r = new R(ref x); // 4 + Diagnostic(ErrorCode.ERR_RefReturnLocal, "x").WithArguments("x").WithLocation(36, 23) + ); + } + + [Fact] + public void RefInitializer_Escape_Nested() + { + var source = @" +class C { - public T F; - public T GetValue() => F; - public ref T GetRef() => ref F; // 1 - public ref readonly T GetRefReadonly() => ref F; // 2 -}"; - var comp = CreateCompilation(source); - comp.VerifyDiagnostics( - // (5,34): error CS8170: Struct members cannot return 'this' or other instance members by reference - // public ref T GetRef() => ref F; // 1 - Diagnostic(ErrorCode.ERR_RefReturnStructThis, "F").WithLocation(5, 34), - // (6,51): error CS8170: Struct members cannot return 'this' or other instance members by reference - // public ref readonly T GetRefReadonly() => ref F; // 2 - Diagnostic(ErrorCode.ERR_RefReturnStructThis, "F").WithLocation(6, 51)); - } - - [Fact] - public void ReturnRefField() + public static Container M3() + { + Container r = default; { - var source = -@"ref struct R -{ - public ref T F; - public T GetValue() => F; - public ref T GetRef() => ref F; - public ref readonly T GetRefReadonly() => ref F; -}"; - var comp = CreateCompilation(source); - comp.VerifyDiagnostics(); + int x = 42; + var r = new Container { item = { field = ref x } }; // 1 } - - [Fact] - public void ReturnRefReadonlyField() + return r; + } + public static Container M4() + { + Container r = default; + int x = 42; { - var source = -@"ref struct R + r = new Container { item = { field = ref x } }; // 2 + } + return r; + } + public static void M5(ref Container r) + { + int x = 42; + r = new Container { item = { field = ref x } }; // 3 + } + public static Container M6() + { + int x = 42; + var r = new Container { item = { field = ref x } }; + return r; // 4 + } + } +ref struct Container { - public ref readonly T F; - public T GetValue() => F; - public ref T GetRef() => ref F; // 1 - public ref readonly T GetRefReadonly() => ref F; -}"; - var comp = CreateCompilation(source); + public Item item; +} +ref struct Item +{ + public ref int field; +} +"; + var comp = CreateCompilation(source, runtimeFeature: RuntimeFlag.ByRefFields); comp.VerifyDiagnostics( - // (5,34): error CS8333: Cannot return field 'R.F' by writable reference because it is a readonly variable - // public ref T GetRef() => ref F; // 1 - Diagnostic(ErrorCode.ERR_RefReturnReadonlyNotField, "F").WithArguments("field", "R.F").WithLocation(5, 34)); + // (9,17): error CS0136: A local or parameter named 'r' cannot be declared in this scope because that name is used in an enclosing local scope to define a local or parameter + // var r = new Container { item = { field = ref x } }; // 1 + Diagnostic(ErrorCode.ERR_LocalIllegallyOverrides, "r").WithArguments("r").WithLocation(9, 17), + // (18,42): error CS8168: Cannot return local 'x' by reference because it is not a ref local + // r = new Container { item = { field = ref x } }; // 2 + Diagnostic(ErrorCode.ERR_RefReturnLocal, "field = ref x").WithArguments("x").WithLocation(18, 42), + // (25,38): error CS8168: Cannot return local 'x' by reference because it is not a ref local + // r = new Container { item = { field = ref x } }; // 3 + Diagnostic(ErrorCode.ERR_RefReturnLocal, "field = ref x").WithArguments("x").WithLocation(25, 38), + // (31,16): error CS8352: Cannot use variable 'r' in this context because it may expose referenced variables outside of their declaration scope + // return r; // 4 + Diagnostic(ErrorCode.ERR_EscapeVariable, "r").WithArguments("r").WithLocation(31, 16) + ); } [Fact] - public void ReturnValueFieldByValue() + public void RefWith() { - var source = -@"#pragma warning disable 649 -ref struct R + var source = @" +public class C { - public T F; + public static void Main() + { + int x = 42; + var r = new R() with { field = ref x }; + System.Console.Write(r.ToString()); + } } -class Program + +ref struct R { - static T F0(R r0) => r0.F; - static T F1(scoped R r1) => r1.F; - static T F2(ref R r2) => r2.F; - static T F3(scoped ref R r3) => r3.F; - static T F4(ref scoped R r4) => r4.F; - static T F5(scoped ref scoped R r5) => r5.F; -}"; - var comp = CreateCompilation(source); + public ref int field; + public override string ToString() + { + return field.ToString(); + } +} +"; + var comp = CreateCompilation(source, options: TestOptions.ReleaseExe, runtimeFeature: RuntimeFlag.ByRefFields); comp.VerifyDiagnostics(); + var verifier = CompileAndVerify(comp, verify: Verification.Skipped, expectedOutput: IncludeExpectedOutput("42")); + verifier.VerifyIL("C.Main", +""" +{ + // Code size 41 (0x29) + .maxstack 2 + .locals init (int V_0, //x + R V_1, //r + R V_2) + IL_0000: ldc.i4.s 42 + IL_0002: stloc.0 + IL_0003: ldloca.s V_2 + IL_0005: initobj "R" + IL_000b: ldloca.s V_2 + IL_000d: ldloca.s V_0 + IL_000f: stfld "ref int R.field" + IL_0014: ldloc.2 + IL_0015: stloc.1 + IL_0016: ldloca.s V_1 + IL_0018: constrained. "R" + IL_001e: callvirt "string object.ToString()" + IL_0023: call "void System.Console.Write(string)" + IL_0028: ret +} +"""); } [Fact] - public void ReturnValueFieldByRef() + public void RefWith_Escape() { - var source = -@"ref struct R -{ - public T F; -} -class Program + var source = @" +public class C { - static ref T F0(R r0) => ref r0.F; // 1 - static ref T F1(scoped R r1) => ref r1.F; // 2 - static ref T F2(ref R r2) => ref r2.F; - static ref T F3(scoped ref R r3) => ref r3.F; // 3 - static ref T F4(ref scoped R r4) => ref r4.F; // 4 - static ref T F5(scoped ref scoped R r5) => ref r5.F; // 5 -}"; - var comp = CreateCompilation(source); - comp.VerifyDiagnostics( - // (7,40): error CS8167: Cannot return by reference a member of parameter 'r0' because it is not a ref or out parameter - // static ref T F0(R r0) => ref r0.F; // 1 - Diagnostic(ErrorCode.ERR_RefReturnParameter2, "r0").WithArguments("r0").WithLocation(7, 40), - // (8,47): error CS8167: Cannot return by reference a member of parameter 'r1' because it is not a ref or out parameter - // static ref T F1(scoped R r1) => ref r1.F; // 2 - Diagnostic(ErrorCode.ERR_RefReturnParameter2, "r1").WithArguments("r1").WithLocation(8, 47), - // (10,51): error CS8167: Cannot return by reference a member of parameter 'r3' because it is not a ref or out parameter - // static ref T F3(scoped ref R r3) => ref r3.F; // 3 - Diagnostic(ErrorCode.ERR_RefReturnParameter2, "r3").WithArguments("r3").WithLocation(10, 51), - // (11,51): error CS8167: Cannot return by reference a member of parameter 'r4' because it is not a ref or out parameter - // static ref T F4(ref scoped R r4) => ref r4.F; // 4 - Diagnostic(ErrorCode.ERR_RefReturnParameter2, "r4").WithArguments("r4").WithLocation(11, 51), - // (12,58): error CS8167: Cannot return by reference a member of parameter 'r5' because it is not a ref or out parameter - // static ref T F5(scoped ref scoped R r5) => ref r5.F; // 5 - Diagnostic(ErrorCode.ERR_RefReturnParameter2, "r5").WithArguments("r5").WithLocation(12, 58)); + public static R M1() + { + int x = 42; + var r = new R() with { field = ref x }; + return r; // 1 + } + public static R M2(ref int x) + { + var r = new R() with { field = ref x }; + return r; + } + public static R M3() + { + R r = default; + { + int x = 42; + r = new R() with { field = ref x }; // 2 } - - [Theory] - [InlineData("ref ")] - [InlineData("ref readonly")] - public void ReturnRefFieldByValue(string refOrRefReadonly) + return r; + } + public static R M4() + { + R r = default; + int x = 42; { - var source = -$@"ref struct R -{{ - public {refOrRefReadonly} T F; - public R(ref T t) {{ F = ref t; }} -}} -class Program -{{ - static T F0(R r) => r.F; - static T F1(ref R r) => r.F; - static T F2(out R r) {{ r = default; return r.F; }} - static T F3(in R r) => r.F; - static T F4(scoped R r) => r.F; - static T F5(scoped ref R r) => r.F; - static T F6(scoped out R r) {{ r = default; return r.F; }} - static T F7(scoped in R r) => r.F; - static T F8(ref scoped R r) => r.F; - static T F9(out scoped R r) {{ r = default; return r.F; }} - static T FA(in scoped R r) => r.F; - static T FB(scoped ref scoped R r) => r.F; - static T FC(scoped out scoped R r) {{ r = default; return r.F; }} - static T FD(scoped in scoped R r) => r.F; -}}"; - var comp = CreateCompilation(source); - comp.VerifyDiagnostics(); + r = new R() with { field = ref x }; // 3 } + return r; + } + public static void M5(ref R r) + { + int x = 42; + r = new R() with { field = ref x }; // 4 + } +} - [Theory] - [InlineData("ref ")] - [InlineData("ref readonly")] - public void ReturnRefFieldByRef_01(string refOrRefReadonly) - { - var source = -$@"ref struct R -{{ - public {refOrRefReadonly} T F; - public R(ref T t) {{ F = ref t; }} -}} -class Program -{{ - static {refOrRefReadonly} T F0(R r) => ref r.F; - static {refOrRefReadonly} T F1(ref R r) => ref r.F; - static {refOrRefReadonly} T F2(out R r) {{ r = default; return ref r.F; }} - static {refOrRefReadonly} T F3(in R r) => ref r.F; - static {refOrRefReadonly} T F4(scoped R r) => ref r.F; // 1 - static {refOrRefReadonly} T F5(scoped ref R r) => ref r.F; - static {refOrRefReadonly} T F6(scoped out R r) {{ r = default; return ref r.F; }} - static {refOrRefReadonly} T F7(scoped in R r) => ref r.F; - static {refOrRefReadonly} T F8(ref scoped R r) => ref r.F; // 2 - static {refOrRefReadonly} T F9(out scoped R r) {{ r = default; return ref r.F; }} // 3 - static {refOrRefReadonly} T FA(in scoped R r) => ref r.F; // 4 - static {refOrRefReadonly} T FB(scoped ref scoped R r) => ref r.F; // 5 - static {refOrRefReadonly} T FC(scoped out scoped R r) {{ r = default; return ref r.F; }} // 6 - static {refOrRefReadonly} T FD(scoped in scoped R r) => ref r.F; // 7 -}}"; - var comp = CreateCompilation(source); +public ref struct R +{ + public ref int field; +} +"; + var comp = CreateCompilation(source, runtimeFeature: RuntimeFlag.ByRefFields); comp.VerifyDiagnostics( - // (12,55): error CS8352: Cannot use variable 'R' in this context because it may expose referenced variables outside of their declaration scope - // static ref T F4(scoped R r) => ref r.F; // 1 - Diagnostic(ErrorCode.ERR_EscapeVariable, "r.F").WithArguments("R").WithLocation(12, 55), - // (16,59): error CS8352: Cannot use variable 'ref R' in this context because it may expose referenced variables outside of their declaration scope - // static ref T F8(ref scoped R r) => ref r.F; // 2 - Diagnostic(ErrorCode.ERR_EscapeVariable, "r.F").WithArguments("ref R").WithLocation(16, 59), - // (17,78): error CS8352: Cannot use variable 'out R' in this context because it may expose referenced variables outside of their declaration scope - // static ref T F9(out scoped R r) { r = default; return ref r.F; } // 3 - Diagnostic(ErrorCode.ERR_EscapeVariable, "r.F").WithArguments("out R").WithLocation(17, 78), - // (18,58): error CS8352: Cannot use variable 'in R' in this context because it may expose referenced variables outside of their declaration scope - // static ref T FA(in scoped R r) => ref r.F; // 4 - Diagnostic(ErrorCode.ERR_EscapeVariable, "r.F").WithArguments("in R").WithLocation(18, 58), - // (19,66): error CS8352: Cannot use variable 'ref R' in this context because it may expose referenced variables outside of their declaration scope - // static ref T FB(scoped ref scoped R r) => ref r.F; // 5 - Diagnostic(ErrorCode.ERR_EscapeVariable, "r.F").WithArguments("ref R").WithLocation(19, 66), - // (20,85): error CS8352: Cannot use variable 'out R' in this context because it may expose referenced variables outside of their declaration scope - // static ref T FC(scoped out scoped R r) { r = default; return ref r.F; } // 6 - Diagnostic(ErrorCode.ERR_EscapeVariable, "r.F").WithArguments("out R").WithLocation(20, 85), - // (21,65): error CS8352: Cannot use variable 'in R' in this context because it may expose referenced variables outside of their declaration scope - // static ref T FD(scoped in scoped R r) => ref r.F; // 7 - Diagnostic(ErrorCode.ERR_EscapeVariable, "r.F").WithArguments("in R").WithLocation(21, 65)); + // (8,16): error CS8352: Cannot use variable 'r' in this context because it may expose referenced variables outside of their declaration scope + // return r; // 1 + Diagnostic(ErrorCode.ERR_EscapeVariable, "r").WithArguments("r").WithLocation(8, 16), + // (20,32): error CS8168: Cannot return local 'x' by reference because it is not a ref local + // r = new R() with { field = ref x }; // 2 + Diagnostic(ErrorCode.ERR_RefReturnLocal, "field = ref x").WithArguments("x").WithLocation(20, 32), + // (29,32): error CS8168: Cannot return local 'x' by reference because it is not a ref local + // r = new R() with { field = ref x }; // 3 + Diagnostic(ErrorCode.ERR_RefReturnLocal, "field = ref x").WithArguments("x").WithLocation(29, 32), + // (36,28): error CS8168: Cannot return local 'x' by reference because it is not a ref local + // r = new R() with { field = ref x }; // 4 + Diagnostic(ErrorCode.ERR_RefReturnLocal, "field = ref x").WithArguments("x").WithLocation(36, 28) + ); } [Fact] - public void ReturnRefFieldByRef_02() + public void RefScoped() { var source = -@"ref struct R +@"ref struct R { - public ref readonly T F; - public R(ref T t) { F = ref t; } -} -class Program + ref scoped R field; +}"; + var comp = CreateCompilation(source, runtimeFeature: RuntimeFlag.ByRefFields); + comp.VerifyDiagnostics( + // (3,5): error CS9050: A ref field cannot refer to a ref struct. + // ref scoped R field; + Diagnostic(ErrorCode.ERR_RefFieldCannotReferToRefStruct, "ref scoped R").WithLocation(3, 5), + // (3,9): error CS9061: Unexpected contextual keyword 'scoped'. Did you mean 'scoped ref' or '@scoped'? + // ref scoped R field; + Diagnostic(ErrorCode.ERR_MisplacedScoped, "scoped").WithLocation(3, 9), + // (3,18): error CS0523: Struct member 'R.field' of type 'R' causes a cycle in the struct layout + // ref scoped R field; + Diagnostic(ErrorCode.ERR_StructLayoutCycle, "field").WithArguments("R.field", "R").WithLocation(3, 18), + // (3,18): warning CS0169: The field 'R.field' is never used + // ref scoped R field; + Diagnostic(ErrorCode.WRN_UnreferencedField, "field").WithArguments("R.field").WithLocation(3, 18) + ); + + source = +@"ref struct R { - static ref readonly T F1(scoped ref T t) - { - R r1 = new R(ref t); - return ref r1.F; // 1 + ref scoped R Property { get => throw null; } +}"; + comp = CreateCompilation(source); + comp.VerifyDiagnostics( + // (3,9): error CS9061: Unexpected contextual keyword 'scoped'. Did you mean 'scoped ref' or '@scoped'? + // ref scoped R Property { get => throw null; } + Diagnostic(ErrorCode.ERR_MisplacedScoped, "scoped").WithLocation(3, 9) + ); + + source = +@"ref struct R +{ + void M(ref scoped R parameter) + { } - static ref readonly T F2(scoped ref T t) - { - R r2; - r2 = new R(ref t); // 2 - return ref r2.F; +}"; + comp = CreateCompilation(source); + comp.VerifyDiagnostics( + // (3,16): error CS8339: The parameter modifier 'scoped' cannot follow 'ref' + // void M(ref scoped R parameter) + Diagnostic(ErrorCode.ERR_BadParameterModifiersOrder, "scoped").WithArguments("scoped", "ref").WithLocation(3, 16) + ); + + source = +@"ref struct R +{ + void M(in scoped R parameter) + { } }"; - var comp = CreateCompilation(source); + comp = CreateCompilation(source); comp.VerifyDiagnostics( - // (11,20): error CS8352: Cannot use variable 'r1' in this context because it may expose referenced variables outside of their declaration scope - // return ref r1.F; // 1 - Diagnostic(ErrorCode.ERR_EscapeVariable, "r1.F").WithArguments("r1").WithLocation(11, 20), - // (16,14): error CS8347: Cannot use a result of 'R.R(ref T)' in this context because it may expose variables referenced by parameter 't' outside of their declaration scope - // r2 = new R(ref t); // 2 - Diagnostic(ErrorCode.ERR_EscapeCall, "new R(ref t)").WithArguments("R.R(ref T)", "t").WithLocation(16, 14), - // (16,27): error CS8166: Cannot return a parameter by reference 't' because it is not a ref parameter - // r2 = new R(ref t); // 2 - Diagnostic(ErrorCode.ERR_RefReturnParameter, "t").WithArguments("t").WithLocation(16, 27)); - } + // (3,15): error CS8339: The parameter modifier 'scoped' cannot follow 'in' + // void M(in scoped R parameter) + Diagnostic(ErrorCode.ERR_BadParameterModifiersOrder, "scoped").WithArguments("scoped", "in").WithLocation(3, 15) + ); - [Fact] - public void ReturnRefFieldByRef_03() - { - var source = -@"ref struct R + source = +@"ref struct R { - public ref readonly T F; - public R(in T t) { F = ref t; } -} -class Program + void M(out scoped R parameter) + { + } +}"; + comp = CreateCompilation(source); + comp.VerifyDiagnostics( + // (3,16): error CS8339: The parameter modifier 'scoped' cannot follow 'out' + // void M(out scoped R parameter) + Diagnostic(ErrorCode.ERR_BadParameterModifiersOrder, "scoped").WithArguments("scoped", "out").WithLocation(3, 16) + ); + + source = +@"ref struct R { - static ref readonly T F1(scoped in T t) - { - R r1 = new R(t); - return ref r1.F; // 1 + void M(ref scoped scoped R parameter) + { } - static ref readonly T F2(scoped in T t) - { - R r2 = new R(in t); - return ref r2.F; // 2 +}"; + comp = CreateCompilation(source); + comp.VerifyDiagnostics( + // (3,16): error CS8339: The parameter modifier 'scoped' cannot follow 'ref' + // void M(ref scoped scoped R parameter) + Diagnostic(ErrorCode.ERR_BadParameterModifiersOrder, "scoped").WithArguments("scoped", "ref").WithLocation(3, 16), + // (3,23): error CS8339: The parameter modifier 'scoped' cannot follow 'ref' + // void M(ref scoped scoped R parameter) + Diagnostic(ErrorCode.ERR_BadParameterModifiersOrder, "scoped").WithArguments("scoped", "ref").WithLocation(3, 23) + ); + + source = +@"ref struct R +{ + void M() + { + ref scoped R local; } }"; - var comp = CreateCompilation(source); + comp = CreateCompilation(source); comp.VerifyDiagnostics( - // (11,20): error CS8352: Cannot use variable 'r1' in this context because it may expose referenced variables outside of their declaration scope - // return ref r1.F; // 1 - Diagnostic(ErrorCode.ERR_EscapeVariable, "r1.F").WithArguments("r1").WithLocation(11, 20), - // (16,20): error CS8352: Cannot use variable 'r2' in this context because it may expose referenced variables outside of their declaration scope - // return ref r2.F; // 2 - Diagnostic(ErrorCode.ERR_EscapeVariable, "r2.F").WithArguments("r2").WithLocation(16, 20)); - } + // (5,13): error CS9061: Unexpected contextual keyword 'scoped'. Did you mean 'scoped ref' or '@scoped'? + // ref scoped R local; + Diagnostic(ErrorCode.ERR_MisplacedScoped, "scoped").WithLocation(5, 13), + // (5,22): error CS8174: A declaration of a by-reference variable must have an initializer + // ref scoped R local; + Diagnostic(ErrorCode.ERR_ByReferenceVariableMustBeInitialized, "local").WithLocation(5, 22), + // (5,22): warning CS0168: The variable 'local' is declared but never used + // ref scoped R local; + Diagnostic(ErrorCode.WRN_UnreferencedVar, "local").WithArguments("local").WithLocation(5, 22) + ); - [Fact] - public void ReturnRefStructFieldByValue_01() - { - var source = -@"ref struct R + source = +@"ref struct R { - public ref T F; - public R(ref T t) { F = ref t; } -} -class Program + void M() + { + scoped ref scoped R local; + } +}"; + comp = CreateCompilation(source); + comp.VerifyDiagnostics( + // (5,20): error CS9061: Unexpected contextual keyword 'scoped'. Did you mean 'scoped ref' or '@scoped'? + // scoped ref scoped R local; + Diagnostic(ErrorCode.ERR_MisplacedScoped, "scoped").WithLocation(5, 20), + // (5,29): error CS8174: A declaration of a by-reference variable must have an initializer + // scoped ref scoped R local; + Diagnostic(ErrorCode.ERR_ByReferenceVariableMustBeInitialized, "local").WithLocation(5, 29), + // (5,29): warning CS0168: The variable 'local' is declared but never used + // scoped ref scoped R local; + Diagnostic(ErrorCode.WRN_UnreferencedVar, "local").WithArguments("local").WithLocation(5, 29) + ); + + source = +@"ref struct R { - static R F1(ref T t) => new R(ref t); - static R F2(out T t, T tValue) { t = tValue; return new R(ref t); } // 1 - static R F3(scoped ref T t) => new R(ref t); // 2 - static R F4(scoped out T t, T tValue) { t = tValue; return new R(ref t); } // 3 + ref scoped R M() => throw null; }"; - var comp = CreateCompilation(source); + comp = CreateCompilation(source); + comp.VerifyDiagnostics( + // (3,9): error CS9061: Unexpected contextual keyword 'scoped'. Did you mean 'scoped ref' or '@scoped'? + // ref scoped R M() => throw null; + Diagnostic(ErrorCode.ERR_MisplacedScoped, "scoped").WithLocation(3, 9) + ); + + source = @" +delegate void M(ref scoped R parameter); +ref struct R { } +"; + comp = CreateCompilation(source); + comp.VerifyDiagnostics( + // (2,21): error CS8339: The parameter modifier 'scoped' cannot follow 'ref' + // delegate void M(ref scoped R parameter); + Diagnostic(ErrorCode.ERR_BadParameterModifiersOrder, "scoped").WithArguments("scoped", "ref").WithLocation(2, 21) + ); + + source = @" +ref struct R +{ + void M() + { + _ = void (ref scoped R parameter) => throw null; + } +} +"; + comp = CreateCompilation(source); + comp.VerifyDiagnostics( + // (6,9): error CS8183: Cannot infer the type of implicitly-typed discard. + // _ = void (ref scoped R parameter) => throw null; + Diagnostic(ErrorCode.ERR_DiscardTypeInferenceFailed, "_").WithLocation(6, 9), + // (6,23): error CS8339: The parameter modifier 'scoped' cannot follow 'ref' + // _ = void (ref scoped R parameter) => throw null; + Diagnostic(ErrorCode.ERR_BadParameterModifiersOrder, "scoped").WithArguments("scoped", "ref").WithLocation(6, 23) + ); + } + + [Theory, WorkItem(62931, "https://github.com/dotnet/roslyn/issues/62931")] + [InlineData("class")] + [InlineData("struct")] + [InlineData("interface")] + [InlineData("enum")] + [InlineData("record")] + public void ScopedReserved_Type(string typeKind) + { + var source = $$""" +{{typeKind}} scoped { } +"""; + var comp = CreateCompilation(source, parseOptions: TestOptions.Regular10); comp.VerifyDiagnostics( - // (9,63): error CS8347: Cannot use a result of 'R.R(ref T)' in this context because it may expose variables referenced by parameter 't' outside of their declaration scope - // static R F2(out T t, T tValue) { t = tValue; return new R(ref t); } // 1 - Diagnostic(ErrorCode.ERR_EscapeCall, "new R(ref t)").WithArguments("R.R(ref T)", "t").WithLocation(9, 63), - // (9,76): error CS8166: Cannot return a parameter by reference 't' because it is not a ref parameter - // static R F2(out T t, T tValue) { t = tValue; return new R(ref t); } // 1 - Diagnostic(ErrorCode.ERR_RefReturnParameter, "t").WithArguments("t").WithLocation(9, 76), - // (10,42): error CS8347: Cannot use a result of 'R.R(ref T)' in this context because it may expose variables referenced by parameter 't' outside of their declaration scope - // static R F3(scoped ref T t) => new R(ref t); // 2 - Diagnostic(ErrorCode.ERR_EscapeCall, "new R(ref t)").WithArguments("R.R(ref T)", "t").WithLocation(10, 42), - // (10,55): error CS8166: Cannot return a parameter by reference 't' because it is not a ref parameter - // static R F3(scoped ref T t) => new R(ref t); // 2 - Diagnostic(ErrorCode.ERR_RefReturnParameter, "t").WithArguments("t").WithLocation(10, 55), - // (11,70): error CS8347: Cannot use a result of 'R.R(ref T)' in this context because it may expose variables referenced by parameter 't' outside of their declaration scope - // static R F4(scoped out T t, T tValue) { t = tValue; return new R(ref t); } // 3 - Diagnostic(ErrorCode.ERR_EscapeCall, "new R(ref t)").WithArguments("R.R(ref T)", "t").WithLocation(11, 70), - // (11,83): error CS8166: Cannot return a parameter by reference 't' because it is not a ref parameter - // static R F4(scoped out T t, T tValue) { t = tValue; return new R(ref t); } // 3 - Diagnostic(ErrorCode.ERR_RefReturnParameter, "t").WithArguments("t").WithLocation(11, 83)); + // (1,8): warning CS8981: The type name 'scoped' only contains lower-cased ascii characters. Such names may become reserved for the language. + // struct scoped { } + Diagnostic(ErrorCode.WRN_LowerCaseTypeName, "scoped").WithArguments("scoped") + ); + + comp = CreateCompilation(source, parseOptions: TestOptions.Regular11); + comp.VerifyDiagnostics( + // (1,8): error CS9062: Types and aliases cannot be named 'scoped'. + // struct scoped { } + Diagnostic(ErrorCode.ERR_ScopedTypeNameDisallowed, "scoped") + ); } - [Fact] - public void ReturnRefStructFieldByValue_02() + [Fact, WorkItem(62931, "https://github.com/dotnet/roslyn/issues/62931")] + public void ScopedReserved_Type_Escaped() { - var source = -@"ref struct R0 + var source = """ +class @scoped { } +"""; + var comp = CreateCompilation(source, parseOptions: TestOptions.Regular10); + comp.VerifyDiagnostics(); + + comp = CreateCompilation(source, parseOptions: TestOptions.Regular11); + comp.VerifyDiagnostics(); + } + + [Fact, WorkItem(62931, "https://github.com/dotnet/roslyn/issues/62931")] + public void ScopedReserved_TypeParameter() + { + var source = """ +class C { } // 1 +class C2<@scoped> { } + +class D { - public ref T F0; - public R0(ref T t) { F0 = ref t; } + void M() + { + local(); + void local() { } // 2 + } + + void M2() + { + local(); + void local<@scoped>() { } + } } -ref struct R1 + +class D2 { - public R0 F1; - public R1(ref T t) { F1 = new R0(ref t); } + void M() { } // 3 + void M2<@scoped>() { } } -class Program -{ - static R0 F0(R1 r0) => r0.F1; - static R0 F1(scoped R1 r1) => r1.F1; // 1 - static R0 F2(ref R1 r2) => r2.F1; - static R0 F3(scoped ref R1 r3) => r3.F1; - static R0 F4(ref scoped R1 r4) => r4.F1; // 2 - static R0 F5(scoped ref scoped R1 r5) => r5.F1; // 3 -}"; - var comp = CreateCompilation(source); +"""; + var comp = CreateCompilation(source, parseOptions: TestOptions.Regular10); comp.VerifyDiagnostics( - // (14,44): error CS8352: Cannot use variable 'R1' in this context because it may expose referenced variables outside of their declaration scope - // static R0 F1(scoped R1 r1) => r1.F1; // 1 - Diagnostic(ErrorCode.ERR_EscapeVariable, "r1.F1").WithArguments("R1").WithLocation(14, 44), - // (17,48): error CS8352: Cannot use variable 'ref R1' in this context because it may expose referenced variables outside of their declaration scope - // static R0 F4(ref scoped R1 r4) => r4.F1; // 2 - Diagnostic(ErrorCode.ERR_EscapeVariable, "r4.F1").WithArguments("ref R1").WithLocation(17, 48), - // (18,55): error CS8352: Cannot use variable 'ref R1' in this context because it may expose referenced variables outside of their declaration scope - // static R0 F5(scoped ref scoped R1 r5) => r5.F1; // 3 - Diagnostic(ErrorCode.ERR_EscapeVariable, "r5.F1").WithArguments("ref R1").WithLocation(18, 55)); + // (1,9): warning CS8981: The type name 'scoped' only contains lower-cased ascii characters. Such names may become reserved for the language. + // class C { } // 1 + Diagnostic(ErrorCode.WRN_LowerCaseTypeName, "scoped").WithArguments("scoped").WithLocation(1, 9), + // (9,20): warning CS8981: The type name 'scoped' only contains lower-cased ascii characters. Such names may become reserved for the language. + // void local() { } // 2 + Diagnostic(ErrorCode.WRN_LowerCaseTypeName, "scoped").WithArguments("scoped").WithLocation(9, 20), + // (21,12): warning CS8981: The type name 'scoped' only contains lower-cased ascii characters. Such names may become reserved for the language. + // void M() { } // 3 + Diagnostic(ErrorCode.WRN_LowerCaseTypeName, "scoped").WithArguments("scoped").WithLocation(21, 12) + ); + + comp = CreateCompilation(source, parseOptions: TestOptions.Regular11); + comp.VerifyDiagnostics( + // (1,9): error CS9062: Types and aliases cannot be named 'scoped'. + // class C { } // 1 + Diagnostic(ErrorCode.ERR_ScopedTypeNameDisallowed, "scoped").WithLocation(1, 9), + // (9,20): error CS9062: Types and aliases cannot be named 'scoped'. + // void local() { } // 2 + Diagnostic(ErrorCode.ERR_ScopedTypeNameDisallowed, "scoped").WithLocation(9, 20), + // (21,12): error CS9062: Types and aliases cannot be named 'scoped'. + // void M() { } // 3 + Diagnostic(ErrorCode.ERR_ScopedTypeNameDisallowed, "scoped").WithLocation(21, 12) + ); + } + + [Fact, WorkItem(62931, "https://github.com/dotnet/roslyn/issues/62931")] + public void ScopedReserved_Alias() + { + var source = """ +using scoped = System.Int32; +"""; + var comp = CreateCompilation(source, parseOptions: TestOptions.Regular10); + comp.VerifyDiagnostics( + // (1,1): hidden CS8019: Unnecessary using directive. + // using scoped = System.Int32; + Diagnostic(ErrorCode.HDN_UnusedUsingDirective, "using scoped = System.Int32;").WithLocation(1, 1), + // (1,7): warning CS8981: The type name 'scoped' only contains lower-cased ascii characters. Such names may become reserved for the language. + // using scoped = System.Int32; + Diagnostic(ErrorCode.WRN_LowerCaseTypeName, "scoped").WithArguments("scoped").WithLocation(1, 7) + ); + + comp = CreateCompilation(source, parseOptions: TestOptions.Regular11); + comp.VerifyDiagnostics( + // (1,1): hidden CS8019: Unnecessary using directive. + // using scoped = System.Int32; + Diagnostic(ErrorCode.HDN_UnusedUsingDirective, "using scoped = System.Int32;").WithLocation(1, 1), + // (1,7): error CS9062: Types and aliases cannot be named 'scoped'. + // using scoped = System.Int32; + Diagnostic(ErrorCode.ERR_ScopedTypeNameDisallowed, "scoped").WithLocation(1, 7) + ); } - [Fact] - public void ReturnRefStructFieldByRef() + [Fact, WorkItem(62931, "https://github.com/dotnet/roslyn/issues/62931")] + public void ScopedReserved_Alias_Escaped() { - var source = -@"ref struct R0 -{ - public ref T F0; - public R0(ref T t) { F0 = ref t; } -} -ref struct R1 -{ - public R0 F1; - public R1(ref T t) { F1 = new R0(ref t); } -} -class Program -{ - static ref R0 F0(R1 r0) => ref r0.F1; // 1 - static ref R0 F1(scoped R1 r1) => ref r1.F1; // 2 - static ref R0 F2(ref R1 r2) => ref r2.F1; - static ref R0 F3(scoped ref R1 r3) => ref r3.F1; // 3 - static ref R0 F4(ref scoped R1 r4) => ref r4.F1; // 4 - static ref R0 F5(scoped ref scoped R1 r5) => ref r5.F1; // 5 -}"; - var comp = CreateCompilation(source); + var source = """ +using @scoped = System.Int32; +"""; + var comp = CreateCompilation(source, parseOptions: TestOptions.Regular10); comp.VerifyDiagnostics( - // (13,45): error CS8167: Cannot return by reference a member of parameter 'r0' because it is not a ref or out parameter - // static ref R0 F0(R1 r0) => ref r0.F1; // 1 - Diagnostic(ErrorCode.ERR_RefReturnParameter2, "r0").WithArguments("r0").WithLocation(13, 45), - // (14,52): error CS8167: Cannot return by reference a member of parameter 'r1' because it is not a ref or out parameter - // static ref R0 F1(scoped R1 r1) => ref r1.F1; // 2 - Diagnostic(ErrorCode.ERR_RefReturnParameter2, "r1").WithArguments("r1").WithLocation(14, 52), - // (16,56): error CS8167: Cannot return by reference a member of parameter 'r3' because it is not a ref or out parameter - // static ref R0 F3(scoped ref R1 r3) => ref r3.F1; // 3 - Diagnostic(ErrorCode.ERR_RefReturnParameter2, "r3").WithArguments("r3").WithLocation(16, 56), - // (17,56): error CS8167: Cannot return by reference a member of parameter 'r4' because it is not a ref or out parameter - // static ref R0 F4(ref scoped R1 r4) => ref r4.F1; // 4 - Diagnostic(ErrorCode.ERR_RefReturnParameter2, "r4").WithArguments("r4").WithLocation(17, 56), - // (18,63): error CS8167: Cannot return by reference a member of parameter 'r5' because it is not a ref or out parameter - // static ref R0 F5(scoped ref scoped R1 r5) => ref r5.F1; // 5 - Diagnostic(ErrorCode.ERR_RefReturnParameter2, "r5").WithArguments("r5").WithLocation(18, 63)); + // (1,1): hidden CS8019: Unnecessary using directive. + // using @scoped = System.Int32; + Diagnostic(ErrorCode.HDN_UnusedUsingDirective, "using @scoped = System.Int32;").WithLocation(1, 1) + ); + + comp = CreateCompilation(source, parseOptions: TestOptions.Regular11); + comp.VerifyDiagnostics( + // (1,1): hidden CS8019: Unnecessary using directive. + // using @scoped = System.Int32; + Diagnostic(ErrorCode.HDN_UnusedUsingDirective, "using @scoped = System.Int32;").WithLocation(1, 1) + ); } - [Fact] - public void ReturnRefFieldFromCaller() + [Theory] + [InlineData("struct")] + [InlineData("ref struct")] + public void UnscopedRefAttribute_Method_01(string type) { var source = -@"ref struct R -{ - public ref T F; - public R(ref T t) { F = ref t; } -} -class Program -{ - static ref T F0(R r0) - { - return ref r0.F; - } - static ref T F1() - { - return ref F0(new R()); // ok, returns null - } - static ref T F2() - { - T t = default; - return ref F0(new R(ref t)); // error - } -}"; - var comp = CreateCompilation(source); +$@"using System.Diagnostics.CodeAnalysis; +{type} S1 +{{ + private int _field; + public ref int GetField1() => ref _field; // 1 + [UnscopedRef] public ref int GetField2() => ref _field; +}}"; + var comp = CreateCompilation(new[] { source, UnscopedRefAttributeDefinition }); comp.VerifyDiagnostics( - // (19,20): error CS8347: Cannot use a result of 'Program.F0(R)' in this context because it may expose variables referenced by parameter 'r0' outside of their declaration scope - // return ref F0(new R(ref t)); // error - Diagnostic(ErrorCode.ERR_EscapeCall, "F0(new R(ref t))").WithArguments("Program.F0(R)", "r0").WithLocation(19, 20), - // (19,23): error CS8347: Cannot use a result of 'R.R(ref T)' in this context because it may expose variables referenced by parameter 't' outside of their declaration scope - // return ref F0(new R(ref t)); // error - Diagnostic(ErrorCode.ERR_EscapeCall, "new R(ref t)").WithArguments("R.R(ref T)", "t").WithLocation(19, 23), - // (19,36): error CS8168: Cannot return local 't' by reference because it is not a ref local - // return ref F0(new R(ref t)); // error - Diagnostic(ErrorCode.ERR_RefReturnLocal, "t").WithArguments("t").WithLocation(19, 36)); + // (5,39): error CS8170: Struct members cannot return 'this' or other instance members by reference + // public ref int GetField1() => ref _field; // 1 + Diagnostic(ErrorCode.ERR_RefReturnStructThis, "_field").WithLocation(5, 39)); } - [Fact] - public void PropertyReturnValue_01() + [Theory] + [InlineData("struct")] + [InlineData("ref struct")] + public void UnscopedRefAttribute_Method_02(string type) { var source = -@"ref struct R +$@"using System.Diagnostics.CodeAnalysis; +{type} S +{{ + ref S F1() + {{ + ref S s1 = ref this; + return ref s1; + }} + [UnscopedRef] ref S F2() + {{ + ref S s2 = ref this; + return ref s2; + }} +}}"; + var comp = CreateCompilation(new[] { source, UnscopedRefAttributeDefinition }); + comp.VerifyDiagnostics( + // (7,20): error CS8157: Cannot return 's1' by reference because it was initialized to a value that cannot be returned by reference + // return ref s1; + Diagnostic(ErrorCode.ERR_RefReturnNonreturnableLocal, "s1").WithArguments("s1").WithLocation(7, 20)); + } + + [CombinatorialData] + [Theory] + public void UnscopedRefAttribute_Method_03(bool useCompilationReference) + { + var sourceA = +@"using System.Diagnostics.CodeAnalysis; +public struct S { - private ref int _i; - public R(ref int i) { _i = ref i; } -} -class C + private T _t; + public ref T F1() => throw null; + [UnscopedRef] public ref T F2() => ref _t; +}"; + var comp = CreateCompilation(new[] { sourceA, UnscopedRefAttributeDefinition }); + comp.VerifyEmitDiagnostics(); + var refA = AsReference(comp, useCompilationReference); + + var sourceB = +@"class Program { - R this[R x, R y] => x; - R F1(R x1, R y1) - { - return this[x1, y1]; - } - R F2(R x2) - { - int i2 = 0; - return this[x2, new R(ref i2)]; // 1 - } - static R F3(C c, R x3, R y3) + static ref int F1() { - return c[x3, y3]; + var s = new S(); + return ref s.F1(); } - static R F4(C c, R y4) + static ref int F2() { - int i4 = 0; - return c[new R(ref i4), y4]; // 2 + var s = new S(); + return ref s.F2(); // 1 } }"; - var comp = CreateCompilation(source); - comp.VerifyDiagnostics( - // (16,16): error CS8347: Cannot use a result of 'C.this[R, R]' in this context because it may expose variables referenced by parameter 'y' outside of their declaration scope - // return this[x2, new R(ref i2)]; // 1 - Diagnostic(ErrorCode.ERR_EscapeCall, "this[x2, new R(ref i2)]").WithArguments("C.this[R, R]", "y").WithLocation(16, 16), - // (16,25): error CS8347: Cannot use a result of 'R.R(ref int)' in this context because it may expose variables referenced by parameter 'i' outside of their declaration scope - // return this[x2, new R(ref i2)]; // 1 - Diagnostic(ErrorCode.ERR_EscapeCall, "new R(ref i2)").WithArguments("R.R(ref int)", "i").WithLocation(16, 25), - // (16,35): error CS8168: Cannot return local 'i2' by reference because it is not a ref local - // return this[x2, new R(ref i2)]; // 1 - Diagnostic(ErrorCode.ERR_RefReturnLocal, "i2").WithArguments("i2").WithLocation(16, 35), - // (25,16): error CS8347: Cannot use a result of 'C.this[R, R]' in this context because it may expose variables referenced by parameter 'x' outside of their declaration scope - // return c[new R(ref i4), y4]; // 2 - Diagnostic(ErrorCode.ERR_EscapeCall, "c[new R(ref i4), y4]").WithArguments("C.this[R, R]", "x").WithLocation(25, 16), - // (25,18): error CS8347: Cannot use a result of 'R.R(ref int)' in this context because it may expose variables referenced by parameter 'i' outside of their declaration scope - // return c[new R(ref i4), y4]; // 2 - Diagnostic(ErrorCode.ERR_EscapeCall, "new R(ref i4)").WithArguments("R.R(ref int)", "i").WithLocation(25, 18), - // (25,28): error CS8168: Cannot return local 'i4' by reference because it is not a ref local - // return c[new R(ref i4), y4]; // 2 - Diagnostic(ErrorCode.ERR_RefReturnLocal, "i4").WithArguments("i4").WithLocation(25, 28)); + comp = CreateCompilation(sourceB, references: new[] { refA }); + comp.VerifyEmitDiagnostics( + // (11,20): error CS8168: Cannot return local 's' by reference because it is not a ref local + // return ref s.F2(); // 1 + Diagnostic(ErrorCode.ERR_RefReturnLocal, "s").WithArguments("s").WithLocation(11, 20)); } [Fact] - public void PropertyReturnValue_02() + public void UnscopedRefAttribute_Property_01() { var source = -@"ref struct R -{ - private ref readonly int _i; - public R(in int i) { _i = ref i; } -} -class C +@"using System.Diagnostics.CodeAnalysis; +struct S1 { - R this[in int x, in int y] => new R(x); - R F1(in int x1, in int y1) - { - return this[x1, y1]; - } - R F2(in int x2) - { - int y2 = 0; - return this[x2, y2]; // 1 - } - static R F3(C c, in int x3, in int y3) - { - return c[x3, y3]; - } - static R F4(C c, in int y4) - { - int x4 = 0; - return c[x4, y4]; // 2 - } + private int _field; + public ref int Property1 => ref _field; // 1 + [UnscopedRef] public ref int Property2 => ref _field; }"; - var comp = CreateCompilation(source); + var comp = CreateCompilation(new[] { source, UnscopedRefAttributeDefinition }); comp.VerifyDiagnostics( - // (16,16): error CS8347: Cannot use a result of 'C.this[in int, in int]' in this context because it may expose variables referenced by parameter 'y' outside of their declaration scope - // return this[x2, y2]; // 1 - Diagnostic(ErrorCode.ERR_EscapeCall, "this[x2, y2]").WithArguments("C.this[in int, in int]", "y").WithLocation(16, 16), - // (16,25): error CS8168: Cannot return local 'y2' by reference because it is not a ref local - // return this[x2, y2]; // 1 - Diagnostic(ErrorCode.ERR_RefReturnLocal, "y2").WithArguments("y2").WithLocation(16, 25), - // (25,16): error CS8347: Cannot use a result of 'C.this[in int, in int]' in this context because it may expose variables referenced by parameter 'x' outside of their declaration scope - // return c[x4, y4]; // 2 - Diagnostic(ErrorCode.ERR_EscapeCall, "c[x4, y4]").WithArguments("C.this[in int, in int]", "x").WithLocation(25, 16), - // (25,18): error CS8168: Cannot return local 'x4' by reference because it is not a ref local - // return c[x4, y4]; // 2 - Diagnostic(ErrorCode.ERR_RefReturnLocal, "x4").WithArguments("x4").WithLocation(25, 18)); + // (5,37): error CS8170: Struct members cannot return 'this' or other instance members by reference + // public ref int Property1 => ref _field; // 1 + Diagnostic(ErrorCode.ERR_RefReturnStructThis, "_field").WithLocation(5, 37)); } - [Fact] - public void PropertyReturnValue_03() + [CombinatorialData] + [Theory] + public void UnscopedRefAttribute_Property_02(bool useCompilationReference) { - var source = -@"ref struct R + var sourceA = +@"using System.Diagnostics.CodeAnalysis; +public struct S { - public ref int _i; - public R(ref int i) { _i = ref i; } -} -class C + private T _t; + public ref T P1 => throw null; + [UnscopedRef] public ref T P2 => ref _t; +}"; + var comp = CreateCompilation(new[] { sourceA, UnscopedRefAttributeDefinition }); + comp.VerifyEmitDiagnostics(); + var refA = AsReference(comp, useCompilationReference); + + var sourceB = +@"class Program { - ref int this[R x, R y] => ref x._i; - ref int F1(R x1, R y1) + static ref int F1() { - return ref this[x1, y1]; + var s = new S(); + return ref s.P1; } - ref int F2(R x2) + static ref int F2() { - int i2 = 0; - return ref this[x2, new R(ref i2)]; // 1 + var s = new S(); + return ref s.P2; // 1 } - static ref int F3(C c, R x3, R y3) +}"; + comp = CreateCompilation(sourceB, references: new[] { refA }); + comp.VerifyEmitDiagnostics( + // (11,20): error CS8168: Cannot return local 's' by reference because it is not a ref local + // return ref s.P2; // 1 + Diagnostic(ErrorCode.ERR_RefReturnLocal, "s").WithArguments("s").WithLocation(11, 20)); + } + + [Fact] + public void UnscopedRefAttribute_Property_03() + { + var source = +@"using System.Diagnostics.CodeAnalysis; +struct S +{ + [UnscopedRef] object P1 { get; } + [UnscopedRef] object P2 { get; set; } + [UnscopedRef] object P3 { get; init; } // 1 + object P5 { - return ref c[x3, y3]; + [UnscopedRef] get; + [UnscopedRef] set; } - static ref int F4(C c, R y4) + object P6 { - int i4 = 0; - return ref c[new R(ref i4), y4]; // 2 + [UnscopedRef] get; + [UnscopedRef] init; // 2 } }"; - var comp = CreateCompilation(source); + var comp = CreateCompilation(new[] { source, UnscopedRefAttributeDefinition, IsExternalInitTypeDefinition }); comp.VerifyDiagnostics( - // (16,20): error CS8347: Cannot use a result of 'C.this[R, R]' in this context because it may expose variables referenced by parameter 'y' outside of their declaration scope - // return ref this[x2, new R(ref i2)]; // 1 - Diagnostic(ErrorCode.ERR_EscapeCall, "this[x2, new R(ref i2)]").WithArguments("C.this[R, R]", "y").WithLocation(16, 20), - // (16,29): error CS8347: Cannot use a result of 'R.R(ref int)' in this context because it may expose variables referenced by parameter 'i' outside of their declaration scope - // return ref this[x2, new R(ref i2)]; // 1 - Diagnostic(ErrorCode.ERR_EscapeCall, "new R(ref i2)").WithArguments("R.R(ref int)", "i").WithLocation(16, 29), - // (16,39): error CS8168: Cannot return local 'i2' by reference because it is not a ref local - // return ref this[x2, new R(ref i2)]; // 1 - Diagnostic(ErrorCode.ERR_RefReturnLocal, "i2").WithArguments("i2").WithLocation(16, 39), - // (25,20): error CS8347: Cannot use a result of 'C.this[R, R]' in this context because it may expose variables referenced by parameter 'x' outside of their declaration scope - // return ref c[new R(ref i4), y4]; // 2 - Diagnostic(ErrorCode.ERR_EscapeCall, "c[new R(ref i4), y4]").WithArguments("C.this[R, R]", "x").WithLocation(25, 20), - // (25,22): error CS8347: Cannot use a result of 'R.R(ref int)' in this context because it may expose variables referenced by parameter 'i' outside of their declaration scope - // return ref c[new R(ref i4), y4]; // 2 - Diagnostic(ErrorCode.ERR_EscapeCall, "new R(ref i4)").WithArguments("R.R(ref int)", "i").WithLocation(25, 22), - // (25,32): error CS8168: Cannot return local 'i4' by reference because it is not a ref local - // return ref c[new R(ref i4), y4]; // 2 - Diagnostic(ErrorCode.ERR_RefReturnLocal, "i4").WithArguments("i4").WithLocation(25, 32)); + // (6,6): error CS9063: UnscopedRefAttribute can only be applied to 'out' parameters, 'ref' and 'in' parameters that refer to 'ref struct' types, and instance methods and properties on 'struct' types other than constructors and 'init' accessors. + // [UnscopedRef] object P3 { get; init; } // 1 + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedTarget, "UnscopedRef").WithLocation(6, 6), + // (15,10): error CS9063: UnscopedRefAttribute can only be applied to 'out' parameters, 'ref' and 'in' parameters that refer to 'ref struct' types, and instance methods and properties on 'struct' types other than constructors and 'init' accessors. + // [UnscopedRef] init; // 2 + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedTarget, "UnscopedRef").WithLocation(15, 10)); + } + + [Theory] + [InlineData("struct")] + [InlineData("ref struct")] + public void UnscopedRefAttribute_Accessor_01(string type) + { + var source = +$@"using System.Diagnostics.CodeAnalysis; +{type} S +{{ + private T _t; + ref T P1 + {{ + get => ref _t; // 1 + }} + ref T P2 + {{ + [UnscopedRef] + get => ref _t; + }} +}}"; + var comp = CreateCompilation(new[] { source, UnscopedRefAttributeDefinition }); + comp.VerifyDiagnostics( + // (7,20): error CS8170: Struct members cannot return 'this' or other instance members by reference + // get => ref _t; // 1 + Diagnostic(ErrorCode.ERR_RefReturnStructThis, "_t").WithLocation(7, 20)); } [Fact] - public void PropertyReturnValue_04() + public void UnscopedRefAttribute_Accessor_02() { var source = -@"class C +@"using System.Diagnostics.CodeAnalysis; +ref struct R { - ref readonly int this[in int x, in int y] => ref x; - ref readonly int F1(in int x1, in int y1) - { - return ref this[x1, y1]; - } - ref readonly int F2(in int x2) - { - int y2 = 0; - return ref this[x2, y2]; // 1 - } - static ref readonly int F3(C c, in int x3, in int y3) + public ref T F; +} +struct A +{ + R this[int i] { - return ref c[x3, y3]; + get { return default; } + set { value.F = ref this; } // 1 } - static ref readonly int F4(C c, in int y4) +} +struct B +{ + R this[int i] { - int x4 = 0; - return ref c[x4, y4]; // 2 + get { return default; } + [UnscopedRef] + set { value.F = ref this; } } }"; - var comp = CreateCompilation(source); + var comp = CreateCompilation(new[] { source, UnscopedRefAttributeDefinition }, runtimeFeature: RuntimeFlag.ByRefFields); comp.VerifyDiagnostics( - // (11,20): error CS8347: Cannot use a result of 'C.this[in int, in int]' in this context because it may expose variables referenced by parameter 'y' outside of their declaration scope - // return ref this[x2, y2]; // 1 - Diagnostic(ErrorCode.ERR_EscapeCall, "this[x2, y2]").WithArguments("C.this[in int, in int]", "y").WithLocation(11, 20), - // (11,29): error CS8168: Cannot return local 'y2' by reference because it is not a ref local - // return ref this[x2, y2]; // 1 - Diagnostic(ErrorCode.ERR_RefReturnLocal, "y2").WithArguments("y2").WithLocation(11, 29), - // (20,20): error CS8347: Cannot use a result of 'C.this[in int, in int]' in this context because it may expose variables referenced by parameter 'x' outside of their declaration scope - // return ref c[x4, y4]; // 2 - Diagnostic(ErrorCode.ERR_EscapeCall, "c[x4, y4]").WithArguments("C.this[in int, in int]", "x").WithLocation(20, 20), - // (20,22): error CS8168: Cannot return local 'x4' by reference because it is not a ref local - // return ref c[x4, y4]; // 2 - Diagnostic(ErrorCode.ERR_RefReturnLocal, "x4").WithArguments("x4").WithLocation(20, 22)); + // (11,15): error CS8374: Cannot ref-assign 'this' to 'F' because 'this' has a narrower escape scope than 'F'. + // set { value.F = ref this; } // 1 + Diagnostic(ErrorCode.ERR_RefAssignNarrower, "value.F = ref this").WithArguments("F", "this").WithLocation(11, 15)); } [Fact] - public void RefStructLocal_FromLocal_01() + public void UnscopedRefAttribute_Accessor_03() { var source = -@"ref struct R +@"using System.Diagnostics.CodeAnalysis; +ref struct R { public ref T F; - public R(ref T t) { F = ref t; } } -class Program +struct A { - static R Create() => new R(); - static R Create(ref T t) => new R(ref t); - static void F(T t) { } - static T F1() - { - T t = default; - R r1 = new R(ref t); - F(r1.F); - return r1.F; - } - static T F2() - { - T t = default; - scoped R r2 = new R(ref t); - F(r2.F); - return r2.F; - } - static T F3() + R this[int i] { - T t = default; - R r3 = new R(); - r3.F = ref t; - F(r3.F); - return r3.F; + get { return default; } + init { value.F = ref this; } // 1 } - static T F4() +} +struct B +{ + R this[int i] { - T t = default; - scoped R r4 = new R(); - r4.F = ref t; - F(r4.F); - return r4.F; + get { return default; } + [UnscopedRef] + init { value.F = ref this; } // 2 } - static T F5() +}"; + var comp = CreateCompilation(new[] { source, UnscopedRefAttributeDefinition, IsExternalInitTypeDefinition }, runtimeFeature: RuntimeFlag.ByRefFields); + comp.VerifyDiagnostics( + // (11,16): error CS8374: Cannot ref-assign 'this' to 'F' because 'this' has a narrower escape scope than 'F'. + // init { value.F = ref this; } // 1 + Diagnostic(ErrorCode.ERR_RefAssignNarrower, "value.F = ref this").WithArguments("F", "this").WithLocation(11, 16), + // (19,10): error CS9063: UnscopedRefAttribute can only be applied to 'out' parameters, 'ref' and 'in' parameters that refer to 'ref struct' types, and instance methods and properties on 'struct' types other than constructors and 'init' accessors. + // [UnscopedRef] + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedTarget, "UnscopedRef").WithLocation(19, 10), + // (20,16): error CS8374: Cannot ref-assign 'this' to 'F' because 'this' has a narrower escape scope than 'F'. + // init { value.F = ref this; } // 2 + Diagnostic(ErrorCode.ERR_RefAssignNarrower, "value.F = ref this").WithArguments("F", "this").WithLocation(20, 16)); + } + + [Theory] + [CombinatorialData] + public void UnscopedRefAttribute_SubstitutedMembers(bool useCompilationReference) + { + var sourceA = +@"using System.Diagnostics.CodeAnalysis; +public ref struct R1 +{ + private T _t; + public R1(T t) { _t = t; } + public ref T Get() => ref this[0]; + public ref T this[int index] => throw null; +} +public ref struct R2 +{ + private T _t; + public R2(T t) { _t = t; } + [UnscopedRef] public ref T Get() => ref this[0]; + [UnscopedRef] public ref T this[int index] => ref _t; +}"; + var comp = CreateCompilation(new[] { sourceA, UnscopedRefAttributeDefinition }); + comp.VerifyEmitDiagnostics(); + + var refA = AsReference(comp, useCompilationReference); + + var sourceB = +@"class Program +{ + static ref int F1(bool b) { - T t = default; - R r5 = Create(ref t); - F(r5.F); - return r5.F; + R1 r1 = new R1(1); + if (b) return ref r1.Get(); + return ref r1[0]; } - static T F6() + static ref int F2(bool b) { - T t = default; - scoped R r6 = Create(ref t); - F(r6.F); - return r6.F; + R2 r2 = new R2(2); + if (b) return ref r2.Get(); // 1 + return ref r2[0]; // 2 } - static T F7() +}"; + comp = CreateCompilation(sourceB, references: new[] { refA }); + comp.VerifyDiagnostics( + // (12,27): error CS8168: Cannot return local 'r2' by reference because it is not a ref local + // if (b) return ref r2.Get(); // 1 + Diagnostic(ErrorCode.ERR_RefReturnLocal, "r2").WithArguments("r2").WithLocation(12, 27), + // (13,20): error CS8168: Cannot return local 'r2' by reference because it is not a ref local + // return ref r2[0]; // 2 + Diagnostic(ErrorCode.ERR_RefReturnLocal, "r2").WithArguments("r2").WithLocation(13, 20)); + + var tree = comp.SyntaxTrees[0]; + var model = comp.GetSemanticModel(tree); + var decls = tree.GetRoot().DescendantNodes().OfType().Where(v => v.Identifier.Text is "r1" or "r2").ToArray(); + var types = decls.Select(d => (NamedTypeSymbol)model.GetDeclaredSymbol(d).GetSymbol().Type).ToArray(); + + var type = types[0]; + Assert.Equal("R1", type.ToTestDisplayString()); + VerifyParameterSymbol(type.GetMethod("Get").ThisParameter, "ref R1 this", RefKind.Ref, DeclarationScope.RefScoped); + VerifyParameterSymbol(type.GetMethod("get_Item").ThisParameter, "ref R1 this", RefKind.Ref, DeclarationScope.RefScoped); + + type = types[1]; + Assert.Equal("R2", type.ToTestDisplayString()); + VerifyParameterSymbol(type.GetMethod("Get").ThisParameter, "ref R2 this", RefKind.Ref, DeclarationScope.Unscoped); + VerifyParameterSymbol(type.GetMethod("get_Item").ThisParameter, "ref R2 this", RefKind.Ref, DeclarationScope.Unscoped); + } + + [Fact] + public void UnscopedRefAttribute_RetargetingMembers() + { + var sourceA = +@"using System.Diagnostics.CodeAnalysis; +public ref struct R1 +{ + private readonly T _t; + public R1(T t) { _t = t; } + public ref readonly T Get() => ref this[0]; + public ref readonly T this[int index] => ref _t; // 1 +} +public ref struct R2 +{ + private readonly T _t; + public R2(T t) { _t = t; } + [UnscopedRef] public ref readonly T Get() => ref this[0]; + [UnscopedRef] public ref readonly T this[int index] => ref _t; +}"; + var comp = CreateCompilation(new[] { sourceA, UnscopedRefAttributeDefinition }, targetFramework: TargetFramework.Mscorlib40); + comp.VerifyDiagnostics( + // (7,50): error CS8170: Struct members cannot return 'this' or other instance members by reference + // public ref readonly T this[int index] => ref _t; // 1 + Diagnostic(ErrorCode.ERR_RefReturnStructThis, "_t").WithLocation(7, 50)); + + var refA = comp.ToMetadataReference(); + + var sourceB = +@"class Program +{ + static ref readonly int F1(bool b) { - T t = default; - R r7 = Create(); - r7.F = ref t; - F(r7.F); - return r7.F; + R1 r1 = new R1(1); + if (b) return ref r1.Get(); + return ref r1[0]; } - static T F8() + static ref readonly int F2(bool b) { - T t = default; - scoped R r8 = Create(); - r8.F = ref t; - F(r8.F); - return r8.F; + R2 r2 = new R2(2); + if (b) return ref r2.Get(); // 1 + return ref r2[0]; // 2 } }"; - var comp = CreateCompilation(source); + comp = CreateCompilation(sourceB, new[] { refA }, targetFramework: TargetFramework.Mscorlib45); comp.VerifyEmitDiagnostics( - // (29,9): error CS8374: Cannot ref-assign 't' to 'F' because 't' has a narrower escape scope than 'F'. - // r3.F = ref t; - Diagnostic(ErrorCode.ERR_RefAssignNarrower, "r3.F = ref t").WithArguments("F", "t").WithLocation(29, 9), - // (59,9): error CS8374: Cannot ref-assign 't' to 'F' because 't' has a narrower escape scope than 'F'. - // r7.F = ref t; - Diagnostic(ErrorCode.ERR_RefAssignNarrower, "r7.F = ref t").WithArguments("F", "t").WithLocation(59, 9)); + // (12,27): error CS8168: Cannot return local 'r2' by reference because it is not a ref local + // if (b) return ref r2.Get(); // 1 + Diagnostic(ErrorCode.ERR_RefReturnLocal, "r2").WithArguments("r2").WithLocation(12, 27), + // (13,20): error CS8168: Cannot return local 'r2' by reference because it is not a ref local + // return ref r2[0]; // 2 + Diagnostic(ErrorCode.ERR_RefReturnLocal, "r2").WithArguments("r2").WithLocation(13, 20)); + + var tree = comp.SyntaxTrees[0]; + var model = comp.GetSemanticModel(tree); + var decls = tree.GetRoot().DescendantNodes().OfType().Where(v => v.Identifier.Text is "r1" or "r2").ToArray(); + var types = decls.Select(d => (NamedTypeSymbol)model.GetDeclaredSymbol(d).GetSymbol().Type).ToArray(); + + var type = types[0]; + var underlyingType = (RetargetingNamedTypeSymbol)type.OriginalDefinition; + Assert.Equal("R1", type.ToTestDisplayString()); + VerifyParameterSymbol(type.GetMethod("Get").ThisParameter, "ref R1 this", RefKind.Ref, DeclarationScope.RefScoped); + VerifyParameterSymbol(type.GetMethod("get_Item").ThisParameter, "ref R1 this", RefKind.Ref, DeclarationScope.RefScoped); + + type = types[1]; + underlyingType = (RetargetingNamedTypeSymbol)type.OriginalDefinition; + Assert.Equal("R2", type.ToTestDisplayString()); + VerifyParameterSymbol(type.GetMethod("Get").ThisParameter, "ref R2 this", RefKind.Ref, DeclarationScope.Unscoped); + VerifyParameterSymbol(type.GetMethod("get_Item").ThisParameter, "ref R2 this", RefKind.Ref, DeclarationScope.Unscoped); } [Fact] - public void RefStructLocal_FromParameter_01() + public void UnscopedRefAttribute_Constructor() { var source = -@"ref struct R +@"using System.Diagnostics.CodeAnalysis; +ref struct R { public ref T F; - public R(ref T t) { F = ref t; } } -class Program +struct A { - static R Create() => new R(); - static R Create(ref T t) => new R(ref t); - static void F(T t) { } - static T F1(T t) - { - R r1 = new R(ref t); - F(r1.F); - return r1.F; - } - static T F2(T t) - { - scoped R r2 = new R(ref t); - F(r2.F); - return r2.F; - } - static T F3(T t) + A(R r) { - R r3 = new R(); - r3.F = ref t; - F(r3.F); - return r3.F; - } - static T F4(T t) - { - scoped R r4 = new R(); - r4.F = ref t; - F(r4.F); - return r4.F; - } - static T F5(T t) - { - R r5 = Create(ref t); - F(r5.F); - return r5.F; - } - static T F6(T t) - { - scoped R r6 = Create(ref t); - F(r6.F); - return r6.F; - } - static T F7(T t) - { - R r7 = Create(); - r7.F = ref t; - F(r7.F); - return r7.F; + r.F = ref this; // 1 } - static T F8(T t) +} +struct B +{ + [UnscopedRef] + B(R r) { - scoped R r8 = Create(); - r8.F = ref t; - F(r8.F); - return r8.F; + r.F = ref this; // 2 } }"; - var comp = CreateCompilation(source); - comp.VerifyEmitDiagnostics( - // (26,9): error CS8374: Cannot ref-assign 't' to 'F' because 't' has a narrower escape scope than 'F'. - // r3.F = ref t; - Diagnostic(ErrorCode.ERR_RefAssignNarrower, "r3.F = ref t").WithArguments("F", "t").WithLocation(26, 9), - // (52,9): error CS8374: Cannot ref-assign 't' to 'F' because 't' has a narrower escape scope than 'F'. - // r7.F = ref t; - Diagnostic(ErrorCode.ERR_RefAssignNarrower, "r7.F = ref t").WithArguments("F", "t").WithLocation(52, 9)); + var comp = CreateCompilation(new[] { source, UnscopedRefAttributeDefinition }, runtimeFeature: RuntimeFlag.ByRefFields); + comp.VerifyDiagnostics( + // (10,9): error CS8374: Cannot ref-assign 'this' to 'F' because 'this' has a narrower escape scope than 'F'. + // r.F = ref this; // 1 + Diagnostic(ErrorCode.ERR_RefAssignNarrower, "r.F = ref this").WithArguments("F", "this").WithLocation(10, 9), + // (15,6): error CS9063: UnscopedRefAttribute can only be applied to 'out' parameters, 'ref' and 'in' parameters that refer to 'ref struct' types, and instance methods and properties on 'struct' types other than constructors and 'init' accessors. + // [UnscopedRef] + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedTarget, "UnscopedRef").WithLocation(15, 6), + // (18,9): error CS8374: Cannot ref-assign 'this' to 'F' because 'this' has a narrower escape scope than 'F'. + // r.F = ref this; // 2 + Diagnostic(ErrorCode.ERR_RefAssignNarrower, "r.F = ref this").WithArguments("F", "this").WithLocation(18, 9)); } [Fact] - public void RefStructLocal_FromLocal_02() + public void UnscopedRefAttribute_StaticMembers() { var source = -@"ref struct R +@"using System.Diagnostics.CodeAnalysis; +struct S +{ + [UnscopedRef] static S() { } // 1 + [UnscopedRef] static object F() => null; // 2 + [UnscopedRef] static object P => null; // 3 +}"; + var comp = CreateCompilation(new[] { source, UnscopedRefAttributeDefinition }); + comp.VerifyDiagnostics( + // (4,6): error CS9063: UnscopedRefAttribute can only be applied to 'out' parameters, 'ref' and 'in' parameters that refer to 'ref struct' types, and instance methods and properties on 'struct' types other than constructors and 'init' accessors. + // [UnscopedRef] static S() { } // 1 + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedTarget, "UnscopedRef").WithLocation(4, 6), + // (5,6): error CS9063: UnscopedRefAttribute can only be applied to 'out' parameters, 'ref' and 'in' parameters that refer to 'ref struct' types, and instance methods and properties on 'struct' types other than constructors and 'init' accessors. + // [UnscopedRef] static object F() => null; // 2 + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedTarget, "UnscopedRef").WithLocation(5, 6), + // (6,6): error CS9063: UnscopedRefAttribute can only be applied to 'out' parameters, 'ref' and 'in' parameters that refer to 'ref struct' types, and instance methods and properties on 'struct' types other than constructors and 'init' accessors. + // [UnscopedRef] static object P => null; // 3 + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedTarget, "UnscopedRef").WithLocation(6, 6)); + } + + [Fact] + public void UnscopedRefAttribute_OtherTypes() + { + var source = +@"using System.Diagnostics.CodeAnalysis; +class C +{ + [UnscopedRef] object F1() => null; // 1 +} +record R +{ + [UnscopedRef] object F2() => null; // 2 +} +record struct S +{ + [UnscopedRef] object F3() => null; +}"; + var comp = CreateCompilation(new[] { source, UnscopedRefAttributeDefinition }); + comp.VerifyDiagnostics( + // (4,6): error CS9063: UnscopedRefAttribute can only be applied to 'out' parameters, 'ref' and 'in' parameters that refer to 'ref struct' types, and instance methods and properties on 'struct' types other than constructors and 'init' accessors. + // [UnscopedRef] object F1() => null; // 1 + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedTarget, "UnscopedRef").WithLocation(4, 6), + // (8,6): error CS9063: UnscopedRefAttribute can only be applied to 'out' parameters, 'ref' and 'in' parameters that refer to 'ref struct' types, and instance methods and properties on 'struct' types other than constructors and 'init' accessors. + // [UnscopedRef] object F2() => null; // 2 + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedTarget, "UnscopedRef").WithLocation(8, 6)); + } + + [WorkItem(62691, "https://github.com/dotnet/roslyn/issues/62691")] + [Fact] + public void UnscopedRefAttribute_RefRefStructParameter_01() + { + var source = +@"using System.Diagnostics.CodeAnalysis; +ref struct R { } +class Program +{ + static ref R ReturnRefStructRef(bool b, ref R x, [UnscopedRef] ref R y) + { + if (b) + return ref x; // 1 + else + return ref y; + } +}"; + var comp = CreateCompilation(new[] { source, UnscopedRefAttributeDefinition }); + comp.VerifyDiagnostics( + // (8,24): error CS8166: Cannot return a parameter by reference 'x' because it is not a ref parameter + // return ref x; // 1 + Diagnostic(ErrorCode.ERR_RefReturnParameter, "x").WithArguments("x").WithLocation(8, 24)); + + var parameters = comp.GetMember("Program.ReturnRefStructRef").Parameters; + VerifyParameterSymbol(parameters[1], "ref R x", RefKind.Ref, DeclarationScope.RefScoped); + VerifyParameterSymbol(parameters[2], "ref R y", RefKind.Ref, DeclarationScope.Unscoped); + } + + [CombinatorialData] + [Theory, WorkItem(63070, "https://github.com/dotnet/roslyn/issues/63070")] + public void UnscopedRefAttribute_RefRefStructParameter_02(bool useCompilationReference) + { + var sourceA = +@"using System.Diagnostics.CodeAnalysis; +public ref struct R { public ref T F; public R(ref T t) { F = ref t; } } -class Program +public class A { - static R Create() => new R(); - static R Create(ref T t) => new R(ref t); - static void F(R r) { } - static R F1() + public ref T F1A(ref R r1) { - T t = default; - R r1 = new R(ref t); - F(r1); - return r1; + return ref r1.F; } - static R F2() + public ref T F2A(scoped ref R r2) { - T t = default; - scoped R r2 = new R(ref t); - F(r2); - return r2; + return ref r2.F; } - static R F3() + public ref T F3A([UnscopedRef] ref R r3) { - T t = default; - R r3 = new R(); - r3.F = ref t; - F(r3); - return r3; + return ref r3.F; } - static R F4() +}"; + var comp = CreateCompilation(new[] { sourceA, UnscopedRefAttributeDefinition }, runtimeFeature: RuntimeFlag.ByRefFields); + comp.VerifyEmitDiagnostics(); + var refA = AsReference(comp, useCompilationReference); + + var sourceB1 = +@"class B1 : A +{ + ref int F1B() { - T t = default; - scoped R r4 = new R(); - r4.F = ref t; - F(r4); - return r4; + int i = 1; + var r = new R(ref i); + return ref F1A(ref r); // 1 } - static R F5() + ref int F2B() { - T t = default; - R r5 = Create(ref t); - F(r5); - return r5; + int i = 2; + var r = new R(ref i); + return ref F2A(ref r); // 2 } - static R F6() + ref int F3B() { - T t = default; - scoped R r6 = Create(ref t); - F(r6); - return r6; + int i = 3; + var r = new R(ref i); + return ref F3A(ref r); // 3 } - static R F7() +}"; + comp = CreateCompilation(sourceB1, references: new[] { refA }); + comp.VerifyEmitDiagnostics( + // (7,20): error CS8347: Cannot use a result of 'A.F1A(ref R)' in this context because it may expose variables referenced by parameter 'r1' outside of their declaration scope + // return ref F1A(ref r); // 1 + Diagnostic(ErrorCode.ERR_EscapeCall, "F1A(ref r)").WithArguments("A.F1A(ref R)", "r1").WithLocation(7, 20), + // (7,28): error CS8352: Cannot use variable 'r' in this context because it may expose referenced variables outside of their declaration scope + // return ref F1A(ref r); // 1 + Diagnostic(ErrorCode.ERR_EscapeVariable, "r").WithArguments("r").WithLocation(7, 28), + // (13,20): error CS8347: Cannot use a result of 'A.F2A(ref R)' in this context because it may expose variables referenced by parameter 'r2' outside of their declaration scope + // return ref F2A(ref r); // 2 + Diagnostic(ErrorCode.ERR_EscapeCall, "F2A(ref r)").WithArguments("A.F2A(ref R)", "r2").WithLocation(13, 20), + // (13,28): error CS8352: Cannot use variable 'r' in this context because it may expose referenced variables outside of their declaration scope + // return ref F2A(ref r); // 2 + Diagnostic(ErrorCode.ERR_EscapeVariable, "r").WithArguments("r").WithLocation(13, 28), + // (19,20): error CS8347: Cannot use a result of 'A.F3A(ref R)' in this context because it may expose variables referenced by parameter 'r3' outside of their declaration scope + // return ref F3A(ref r); // 3 + Diagnostic(ErrorCode.ERR_EscapeCall, "F3A(ref r)").WithArguments("A.F3A(ref R)", "r3").WithLocation(19, 20), + // (19,28): error CS8352: Cannot use variable 'r' in this context because it may expose referenced variables outside of their declaration scope + // return ref F3A(ref r); // 3 + Diagnostic(ErrorCode.ERR_EscapeVariable, "r").WithArguments("r").WithLocation(19, 28)); + + var baseType = comp.GetMember("B1").BaseTypeNoUseSiteDiagnostics; + VerifyParameterSymbol(baseType.GetMethod("F1A").Parameters[0], "ref R r1", RefKind.Ref, DeclarationScope.RefScoped); + VerifyParameterSymbol(baseType.GetMethod("F2A").Parameters[0], "ref R r2", RefKind.Ref, DeclarationScope.RefScoped); + VerifyParameterSymbol(baseType.GetMethod("F3A").Parameters[0], "ref R r3", RefKind.Ref, DeclarationScope.Unscoped); + + var sourceB2 = +@"class B2 : A +{ + ref int F1B(ref int i) { - T t = default; - R r7 = Create(); - r7.F = ref t; - F(r7); - return r7; + var r = new R(ref i); + return ref F1A(ref r); } - static R F8() + ref int F2B(ref int i) { - T t = default; - scoped R r8 = Create(); - r8.F = ref t; - F(r8); - return r8; + var r = new R(ref i); + return ref F2A(ref r); + } + ref int F3B(ref int i) + { + var r = new R(ref i); + return ref F3A(ref r); // 1 } }"; - var comp = CreateCompilation(source); + comp = CreateCompilation(sourceB2, references: new[] { refA }); comp.VerifyEmitDiagnostics( - // (16,16): error CS8352: Cannot use variable 'r1' in this context because it may expose referenced variables outside of their declaration scope - // return r1; - Diagnostic(ErrorCode.ERR_EscapeVariable, "r1").WithArguments("r1").WithLocation(16, 16), - // (23,16): error CS8352: Cannot use variable 'r2' in this context because it may expose referenced variables outside of their declaration scope - // return r2; - Diagnostic(ErrorCode.ERR_EscapeVariable, "r2").WithArguments("r2").WithLocation(23, 16), - // (29,9): error CS8374: Cannot ref-assign 't' to 'F' because 't' has a narrower escape scope than 'F'. - // r3.F = ref t; - Diagnostic(ErrorCode.ERR_RefAssignNarrower, "r3.F = ref t").WithArguments("F", "t").WithLocation(29, 9), - // (39,16): error CS8352: Cannot use variable 'r4' in this context because it may expose referenced variables outside of their declaration scope - // return r4; - Diagnostic(ErrorCode.ERR_EscapeVariable, "r4").WithArguments("r4").WithLocation(39, 16), - // (46,16): error CS8352: Cannot use variable 'r5' in this context because it may expose referenced variables outside of their declaration scope - // return r5; - Diagnostic(ErrorCode.ERR_EscapeVariable, "r5").WithArguments("r5").WithLocation(46, 16), - // (53,16): error CS8352: Cannot use variable 'r6' in this context because it may expose referenced variables outside of their declaration scope - // return r6; - Diagnostic(ErrorCode.ERR_EscapeVariable, "r6").WithArguments("r6").WithLocation(53, 16), - // (59,9): error CS8374: Cannot ref-assign 't' to 'F' because 't' has a narrower escape scope than 'F'. - // r7.F = ref t; - Diagnostic(ErrorCode.ERR_RefAssignNarrower, "r7.F = ref t").WithArguments("F", "t").WithLocation(59, 9), - // (69,16): error CS8352: Cannot use variable 'r8' in this context because it may expose referenced variables outside of their declaration scope - // return r8; - Diagnostic(ErrorCode.ERR_EscapeVariable, "r8").WithArguments("r8").WithLocation(69, 16)); + // (16,20): error CS8350: This combination of arguments to 'A.F3A(ref R)' is disallowed because it may expose variables referenced by parameter 'r3' outside of their declaration scope + // return ref F3A(ref r); // 1 + Diagnostic(ErrorCode.ERR_CallArgMixing, "F3A(ref r)").WithArguments("A.F3A(ref R)", "r3").WithLocation(16, 20), + // (16,28): error CS8168: Cannot return local 'r' by reference because it is not a ref local + // return ref F3A(ref r); // 2 + Diagnostic(ErrorCode.ERR_RefReturnLocal, "r").WithArguments("r").WithLocation(16, 28)); } - [Fact] - public void RefStructLocal_FromParameter_02() + [Fact, WorkItem(63057, "https://github.com/dotnet/roslyn/issues/63057")] + public void UnscopedScoped_Source() { - var source = -@"ref struct R + var sourceA = +@"using System.Diagnostics.CodeAnalysis; +public ref struct R { public ref T F; public R(ref T t) { F = ref t; } } -class Program +public class A { - static R Create() => new R(); - static R Create(ref T t) => new R(ref t); - static void F(R r) { } - static R F1(T t) + public ref T F1([UnscopedRef] scoped ref R r1) // 1 { - R r1 = new R(ref t); - F(r1); - return r1; + return ref r1.F; } - static R F2(T t) + public ref T F2([UnscopedRef] scoped out T t2) // 2 { - scoped R r2 = new R(ref t); - F(r2); - return r2; + t2 = default; + return ref t2; } - static R F3(T t) + public ref T F3([UnscopedRef] scoped in R t3) // 3 { - R r3 = new R(); - r3.F = ref t; - F(r3); - return r3; + throw null; } - static R F4(T t) + public ref T F4([UnscopedRef] scoped R t4) // 4 { - scoped R r4 = new R(); - r4.F = ref t; - F(r4); - return r4; + throw null; } - static R F5(T t) +}"; + var comp = CreateCompilation(new[] { sourceA, UnscopedRefAttributeDefinition }, runtimeFeature: RuntimeFlag.ByRefFields); + comp.VerifyEmitDiagnostics( + // (9,22): error CS9066: UnscopedRefAttribute cannot be applied to parameters that have a 'scoped' modifier. + // public ref T F1([UnscopedRef] scoped ref R r1) // 1 + Diagnostic(ErrorCode.ERR_UnscopedScoped, "UnscopedRef").WithLocation(9, 22), + // (13,22): error CS9066: UnscopedRefAttribute cannot be applied to parameters that have a 'scoped' modifier. + // public ref T F2([UnscopedRef] scoped out T t2) // 2 + Diagnostic(ErrorCode.ERR_UnscopedScoped, "UnscopedRef").WithLocation(13, 22), + // (18,22): error CS9066: UnscopedRefAttribute cannot be applied to parameters that have a 'scoped' modifier. + // public ref T F3([UnscopedRef] scoped in R t3) // 3 + Diagnostic(ErrorCode.ERR_UnscopedScoped, "UnscopedRef").WithLocation(18, 22), + // (22,22): error CS9063: UnscopedRefAttribute can only be applied to 'out' parameters, 'ref' and 'in' parameters that refer to 'ref struct' types, and instance methods and properties on 'struct' types other than constructors and 'init' accessors. + // public ref T F4([UnscopedRef] scoped R t4) // 4 + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedTarget, "UnscopedRef").WithLocation(22, 22)); + + var type = comp.GetMember("A"); + VerifyParameterSymbol(type.GetMethod("F1").Parameters[0], "ref R r1", RefKind.Ref, DeclarationScope.Unscoped); + VerifyParameterSymbol(type.GetMethod("F2").Parameters[0], "out T t2", RefKind.Out, DeclarationScope.Unscoped); + VerifyParameterSymbol(type.GetMethod("F3").Parameters[0], "in R t3", RefKind.In, DeclarationScope.Unscoped); + VerifyParameterSymbol(type.GetMethod("F4").Parameters[0], "R t4", RefKind.None, DeclarationScope.Unscoped); + } + + [Fact, WorkItem(63070, "https://github.com/dotnet/roslyn/issues/63070")] + public void UnscopedScoped_Metadata() + { + // Equivalent to: + // public class A + // { + // public ref T F4([UnscopedRef] scoped R t4) { throw null; } + // } + var ilSource = """ +.class public sequential ansi sealed beforefieldinit R`1 + extends [mscorlib]System.ValueType +{ + .method public hidebysig specialname rtspecialname instance void .ctor ( !T& t ) cil managed + { + IL_0000: ldnull + IL_0001: throw + } +} + +.class public auto ansi beforefieldinit A`1 + extends [mscorlib]System.Object +{ + // [UnscopedRef] scoped parameter + .method public hidebysig instance !T& F4A ( valuetype R`1& r4 ) cil managed + { + .param [1] + .custom instance void System.Runtime.CompilerServices.ScopedRefAttribute::.ctor() = ( 01 00 00 00 ) + .custom instance void System.Diagnostics.CodeAnalysis.UnscopedRefAttribute::.ctor() = ( 01 00 00 00 ) + IL_0000: ldnull + IL_0001: throw + } + .method public hidebysig specialname rtspecialname instance void .ctor () cil managed + { + IL_0000: ldnull + IL_0001: throw + } +} + +.class private auto ansi sealed beforefieldinit System.Runtime.CompilerServices.ScopedRefAttribute + extends [mscorlib]System.Attribute +{ + .method public hidebysig specialname rtspecialname instance void .ctor () cil managed + { + IL_0000: ldnull + IL_0001: throw + } +} + +.class public auto ansi sealed beforefieldinit System.Diagnostics.CodeAnalysis.UnscopedRefAttribute + extends [mscorlib]System.Attribute +{ + .method public hidebysig specialname rtspecialname + instance void .ctor () cil managed + { + IL_0000: ldnull + IL_0001: throw + } +} +"""; + var refA = CompileIL(ilSource); + + var sourceB = +@"class B : A +{ + ref int F4B() { - R r5 = Create(ref t); - F(r5); - return r5; + int i = 4; + var r = new R(ref i); + return ref F4A(ref r); // 1 } - static R F6(T t) +}"; + var comp = CreateCompilation(sourceB, references: new[] { refA }); + comp.VerifyEmitDiagnostics( + // (7,20): error CS0570: 'A.F4A(ref R)' is not supported by the language + // return ref F4A(ref r); // 1 + Diagnostic(ErrorCode.ERR_BindToBogus, "F4A").WithArguments("A.F4A(ref R)").WithLocation(7, 20)); + + var baseType = comp.GetMember("B").BaseTypeNoUseSiteDiagnostics; + VerifyParameterSymbol(baseType.GetMethod("F4A").Parameters[0], "ref R r4", RefKind.Ref, DeclarationScope.Unscoped); + } + + [Fact] + public void UnscopedRefAttribute_OutParameter_01() + { + var source = +@"using System.Diagnostics.CodeAnalysis; +class Program +{ + static ref int ReturnOut(bool b, out int x, [UnscopedRef] out int y) { - scoped R r6 = Create(ref t); - F(r6); - return r6; + x = 1; + y = 2; + if (b) + return ref x; // 1 + else + return ref y; } - static R F7(T t) +}"; + var comp = CreateCompilation(new[] { source, UnscopedRefAttributeDefinition }); + comp.VerifyDiagnostics( + // (9,24): error CS8166: Cannot return a parameter by reference 'x' because it is not a ref parameter + // return ref x; // 1 + Diagnostic(ErrorCode.ERR_RefReturnParameter, "x").WithArguments("x").WithLocation(9, 24)); + + var parameters = comp.GetMember("Program.ReturnOut").Parameters; + VerifyParameterSymbol(parameters[1], "out System.Int32 x", RefKind.Out, DeclarationScope.RefScoped); + VerifyParameterSymbol(parameters[2], "out System.Int32 y", RefKind.Out, DeclarationScope.Unscoped); + } + + [CombinatorialData] + [Theory] + public void UnscopedRefAttribute_OutParameter_02(bool useCompilationReference) + { + var sourceA = +@"using System.Diagnostics.CodeAnalysis; +public class A +{ + public ref T F1A(out T t1) { - R r7 = Create(); - r7.F = ref t; - F(r7); - return r7; + throw null; } - static R F8(T t) + public ref T F2A(scoped out T t2) { - scoped R r8 = Create(); - r8.F = ref t; - F(r8); - return r8; - } -}"; - var comp = CreateCompilation(source); - comp.VerifyEmitDiagnostics( - // (15,16): error CS8352: Cannot use variable 'r1' in this context because it may expose referenced variables outside of their declaration scope - // return r1; - Diagnostic(ErrorCode.ERR_EscapeVariable, "r1").WithArguments("r1").WithLocation(15, 16), - // (21,16): error CS8352: Cannot use variable 'r2' in this context because it may expose referenced variables outside of their declaration scope - // return r2; - Diagnostic(ErrorCode.ERR_EscapeVariable, "r2").WithArguments("r2").WithLocation(21, 16), - // (26,9): error CS8374: Cannot ref-assign 't' to 'F' because 't' has a narrower escape scope than 'F'. - // r3.F = ref t; - Diagnostic(ErrorCode.ERR_RefAssignNarrower, "r3.F = ref t").WithArguments("F", "t").WithLocation(26, 9), - // (35,16): error CS8352: Cannot use variable 'r4' in this context because it may expose referenced variables outside of their declaration scope - // return r4; - Diagnostic(ErrorCode.ERR_EscapeVariable, "r4").WithArguments("r4").WithLocation(35, 16), - // (41,16): error CS8352: Cannot use variable 'r5' in this context because it may expose referenced variables outside of their declaration scope - // return r5; - Diagnostic(ErrorCode.ERR_EscapeVariable, "r5").WithArguments("r5").WithLocation(41, 16), - // (47,16): error CS8352: Cannot use variable 'r6' in this context because it may expose referenced variables outside of their declaration scope - // return r6; - Diagnostic(ErrorCode.ERR_EscapeVariable, "r6").WithArguments("r6").WithLocation(47, 16), - // (52,9): error CS8374: Cannot ref-assign 't' to 'F' because 't' has a narrower escape scope than 'F'. - // r7.F = ref t; - Diagnostic(ErrorCode.ERR_RefAssignNarrower, "r7.F = ref t").WithArguments("F", "t").WithLocation(52, 9), - // (61,16): error CS8352: Cannot use variable 'r8' in this context because it may expose referenced variables outside of their declaration scope - // return r8; - Diagnostic(ErrorCode.ERR_EscapeVariable, "r8").WithArguments("r8").WithLocation(61, 16)); + throw null; + } + public ref T F3A([UnscopedRef] out T t3) + { + t3 = default; + return ref t3; + } +}"; + var comp = CreateCompilation(new[] { sourceA, UnscopedRefAttributeDefinition }); + comp.VerifyEmitDiagnostics(); + var refA = AsReference(comp, useCompilationReference); + + var sourceB = +@"class B : A +{ + ref int F1B() + { + int i = 1; + return ref F1A(out i); + } + ref int F2B() + { + int i = 2; + return ref F2A(out i); + } + ref int F3B() + { + int i = 3; + return ref F3A(out i); // 1 + } +}"; + comp = CreateCompilation(sourceB, references: new[] { refA }); + comp.VerifyEmitDiagnostics( + // (16,20): error CS8347: Cannot use a result of 'A.F3A(out int)' in this context because it may expose variables referenced by parameter 't3' outside of their declaration scope + // return ref F3A(out i); // 1 + Diagnostic(ErrorCode.ERR_EscapeCall, "F3A(out i)").WithArguments("A.F3A(out int)", "t3").WithLocation(16, 20), + // (16,28): error CS8168: Cannot return local 'i' by reference because it is not a ref local + // return ref F3A(out i); // 1 + Diagnostic(ErrorCode.ERR_RefReturnLocal, "i").WithArguments("i").WithLocation(16, 28)); + + var baseType = comp.GetMember("B").BaseTypeNoUseSiteDiagnostics; + VerifyParameterSymbol(baseType.GetMethod("F1A").Parameters[0], "out System.Int32 t1", RefKind.Out, DeclarationScope.RefScoped); + VerifyParameterSymbol(baseType.GetMethod("F2A").Parameters[0], "out System.Int32 t2", RefKind.Out, DeclarationScope.RefScoped); + VerifyParameterSymbol(baseType.GetMethod("F3A").Parameters[0], "out System.Int32 t3", RefKind.Out, DeclarationScope.Unscoped); } [Fact] - public void LocalFromRvalueInvocation() + public void UnscopedRefAttribute_RefParameter() { var source = -@"ref struct R { } -class Program +@"using System.Diagnostics.CodeAnalysis; +public class A { - static R Create(scoped ref T t) - { - return default; - } - static R CreateReadonly(scoped in T t) + public ref T F1A(ref T t1) => ref t1; + public ref T F2A(scoped ref T t2) => throw null; + public ref T F3A([UnscopedRef] ref T t3) => ref t3; + public ref T F4A([UnscopedRef] scoped ref T t4) => ref t4; +} +class B : A +{ + ref int F1B() { - return default; + int i = 1; + return ref F1A(ref i); // 1 } - static void F0(string s0) + ref int F2B() { - R r0; - r0 = Create(ref s0); + int i = 2; + return ref F2A(ref i); } - static void F1(ref string s1) + ref int F3B() { - R r1; - r1 = Create(ref s1); + int i = 3; + return ref F3A(ref i); // 2 } - static void F2(out string s2) + ref int F4B() { - s2 = null; - R r2; - r2 = Create(ref s2); + int i = 4; + return ref F4A(ref i); // 3 } - static void F3(in string s3) +}"; + var comp = CreateCompilation(new[] { source, UnscopedRefAttributeDefinition }); + comp.VerifyEmitDiagnostics( + // (6,23): error CS9063: UnscopedRefAttribute can only be applied to 'out' parameters, 'ref' and 'in' parameters that refer to 'ref struct' types, and instance methods and properties on 'struct' types other than constructors and 'init' accessors. + // public ref T F3A([UnscopedRef] ref T t3) => ref t3; + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedTarget, "UnscopedRef").WithLocation(6, 23), + // (7,23): error CS9063: UnscopedRefAttribute can only be applied to 'out' parameters, 'ref' and 'in' parameters that refer to 'ref struct' types, and instance methods and properties on 'struct' types other than constructors and 'init' accessors. + // public ref T F4A([UnscopedRef] scoped ref T t4) => ref t4; + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedTarget, "UnscopedRef").WithLocation(7, 23), + // (14,20): error CS8347: Cannot use a result of 'A.F1A(ref int)' in this context because it may expose variables referenced by parameter 't1' outside of their declaration scope + // return ref F1A(ref i); // 1 + Diagnostic(ErrorCode.ERR_EscapeCall, "F1A(ref i)").WithArguments("A.F1A(ref int)", "t1").WithLocation(14, 20), + // (14,28): error CS8168: Cannot return local 'i' by reference because it is not a ref local + // return ref F1A(ref i); // 1 + Diagnostic(ErrorCode.ERR_RefReturnLocal, "i").WithArguments("i").WithLocation(14, 28), + // (24,20): error CS8347: Cannot use a result of 'A.F3A(ref int)' in this context because it may expose variables referenced by parameter 't3' outside of their declaration scope + // return ref F3A(ref i); // 2 + Diagnostic(ErrorCode.ERR_EscapeCall, "F3A(ref i)").WithArguments("A.F3A(ref int)", "t3").WithLocation(24, 20), + // (24,28): error CS8168: Cannot return local 'i' by reference because it is not a ref local + // return ref F3A(ref i); // 2 + Diagnostic(ErrorCode.ERR_RefReturnLocal, "i").WithArguments("i").WithLocation(24, 28), + // (29,20): error CS8347: Cannot use a result of 'A.F4A(ref int)' in this context because it may expose variables referenced by parameter 't4' outside of their declaration scope + // return ref F4A(ref i); // 3 + Diagnostic(ErrorCode.ERR_EscapeCall, "F4A(ref i)").WithArguments("A.F4A(ref int)", "t4").WithLocation(29, 20), + // (29,28): error CS8168: Cannot return local 'i' by reference because it is not a ref local + // return ref F4A(ref i); // 3 + Diagnostic(ErrorCode.ERR_RefReturnLocal, "i").WithArguments("i").WithLocation(29, 28)); + + var baseType = comp.GetMember("B").BaseTypeNoUseSiteDiagnostics; + VerifyParameterSymbol(baseType.GetMethod("F1A").Parameters[0], "ref System.Int32 t1", RefKind.Ref, DeclarationScope.Unscoped); + VerifyParameterSymbol(baseType.GetMethod("F2A").Parameters[0], "scoped ref System.Int32 t2", RefKind.Ref, DeclarationScope.RefScoped); + VerifyParameterSymbol(baseType.GetMethod("F3A").Parameters[0], "ref System.Int32 t3", RefKind.Ref, DeclarationScope.Unscoped); + VerifyParameterSymbol(baseType.GetMethod("F4A").Parameters[0], "ref System.Int32 t4", RefKind.Ref, DeclarationScope.Unscoped); + } + + [Fact] + public void UnscopedRefAttribute_InParameter() + { + var source = +@"using System.Diagnostics.CodeAnalysis; +public class A +{ + public ref readonly T F1A(in T t1) => ref t1; + public ref readonly T F2A(scoped in T t2) => throw null; + public ref readonly T F3A([UnscopedRef] in T t3) => ref t3; + public ref readonly T F4A([UnscopedRef] scoped in T t4) => ref t4; +} +class B : A +{ + ref readonly int F1B() { - R r3; - r3 = CreateReadonly(in s3); + int i = 1; + return ref F1A(in i); // 1 } - static void F4(scoped ref string s4) + ref readonly int F2B() { - R r4; - r4 = Create(ref s4); + int i = 2; + return ref F2A(in i); } - static void F5(scoped out string s5) + ref readonly int F3B() { - s5 = null; - R r5; - r5 = Create(ref s5); + int i = 3; + return ref F3A(in i); // 2 } - static void F6(scoped in string s6) + ref readonly int F4B() { - R r6; - r6 = CreateReadonly(in s6); + int i = 4; + return ref F4A(in i); // 3 } }"; - var comp = CreateCompilation(source); - comp.VerifyDiagnostics(); - } - - [Fact] - public void This_FromLocal() - { - var source = -@"ref struct R + var comp = CreateCompilation(new[] { source, UnscopedRefAttributeDefinition }); + comp.VerifyEmitDiagnostics( + // (6,32): error CS9063: UnscopedRefAttribute can only be applied to 'out' parameters, 'ref' and 'in' parameters that refer to 'ref struct' types, and instance methods and properties on 'struct' types other than constructors and 'init' accessors. + // public ref readonly T F3A([UnscopedRef] in T t3) => ref t3; + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedTarget, "UnscopedRef").WithLocation(6, 32), + // (7,32): error CS9063: UnscopedRefAttribute can only be applied to 'out' parameters, 'ref' and 'in' parameters that refer to 'ref struct' types, and instance methods and properties on 'struct' types other than constructors and 'init' accessors. + // public ref readonly T F4A([UnscopedRef] scoped in T t4) => ref t4; + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedTarget, "UnscopedRef").WithLocation(7, 32), + // (14,20): error CS8347: Cannot use a result of 'A.F1A(in int)' in this context because it may expose variables referenced by parameter 't1' outside of their declaration scope + // return ref F1A(in i); // 1 + Diagnostic(ErrorCode.ERR_EscapeCall, "F1A(in i)").WithArguments("A.F1A(in int)", "t1").WithLocation(14, 20), + // (14,27): error CS8168: Cannot return local 'i' by reference because it is not a ref local + // return ref F1A(in i); // 1 + Diagnostic(ErrorCode.ERR_RefReturnLocal, "i").WithArguments("i").WithLocation(14, 27), + // (24,20): error CS8347: Cannot use a result of 'A.F3A(in int)' in this context because it may expose variables referenced by parameter 't3' outside of their declaration scope + // return ref F3A(in i); // 2 + Diagnostic(ErrorCode.ERR_EscapeCall, "F3A(in i)").WithArguments("A.F3A(in int)", "t3").WithLocation(24, 20), + // (24,27): error CS8168: Cannot return local 'i' by reference because it is not a ref local + // return ref F3A(in i); // 2 + Diagnostic(ErrorCode.ERR_RefReturnLocal, "i").WithArguments("i").WithLocation(24, 27), + // (29,20): error CS8347: Cannot use a result of 'A.F4A(in int)' in this context because it may expose variables referenced by parameter 't4' outside of their declaration scope + // return ref F4A(in i); // 3 + Diagnostic(ErrorCode.ERR_EscapeCall, "F4A(in i)").WithArguments("A.F4A(in int)", "t4").WithLocation(29, 20), + // (29,27): error CS8168: Cannot return local 'i' by reference because it is not a ref local + // return ref F4A(in i); // 3 + Diagnostic(ErrorCode.ERR_RefReturnLocal, "i").WithArguments("i").WithLocation(29, 27)); + + var baseType = comp.GetMember("B").BaseTypeNoUseSiteDiagnostics; + VerifyParameterSymbol(baseType.GetMethod("F1A").Parameters[0], "in System.Int32 t1", RefKind.In, DeclarationScope.Unscoped); + VerifyParameterSymbol(baseType.GetMethod("F2A").Parameters[0], "scoped in System.Int32 t2", RefKind.In, DeclarationScope.RefScoped); + VerifyParameterSymbol(baseType.GetMethod("F3A").Parameters[0], "in System.Int32 t3", RefKind.In, DeclarationScope.Unscoped); + VerifyParameterSymbol(baseType.GetMethod("F4A").Parameters[0], "in System.Int32 t4", RefKind.In, DeclarationScope.Unscoped); + } + + [Fact] + public void UnscopedRefAttribute_RefStructParameter_01() + { + var source = +@"using System.Diagnostics.CodeAnalysis; +public ref struct R { - static R Create() => new R(); - static R Create(ref T t) => new R(ref t); - static void M(R r) { } - private ref T F; + public ref T F; public R(ref T t) { F = ref t; } - public R(sbyte unused) +} +public class A +{ + public ref T F1A(R r1) { - T t1 = default; - this = new R(ref t1); - M(this); + return ref r1.F; } - public R(short unused) + public ref T F2A(scoped R r2) { - T t2 = default; - this = new R(); - this.F = ref t2; - M(this); + throw null; } - public R(int unused) + public ref T F3A([UnscopedRef] R r3) { - T t3 = default; - this = Create(ref t3); - M(this); + return ref r3.F; } - public R(long unused) + public ref T F4A([UnscopedRef] scoped R r4) { - T t4 = default; - this = Create(); - this.F = ref t4; - M(this); + return ref r4.F; } -}"; - var comp = CreateCompilation(source); - comp.VerifyEmitDiagnostics( - // (11,16): error CS8347: Cannot use a result of 'R.R(ref T)' in this context because it may expose variables referenced by parameter 't' outside of their declaration scope - // this = new R(ref t1); - Diagnostic(ErrorCode.ERR_EscapeCall, "new R(ref t1)").WithArguments("R.R(ref T)", "t").WithLocation(11, 16), - // (11,29): error CS8168: Cannot return local 't1' by reference because it is not a ref local - // this = new R(ref t1); - Diagnostic(ErrorCode.ERR_RefReturnLocal, "t1").WithArguments("t1").WithLocation(11, 29), - // (18,9): error CS8374: Cannot ref-assign 't2' to 'F' because 't2' has a narrower escape scope than 'F'. - // this.F = ref t2; - Diagnostic(ErrorCode.ERR_RefAssignNarrower, "this.F = ref t2").WithArguments("F", "t2").WithLocation(18, 9), - // (24,16): error CS8347: Cannot use a result of 'R.Create(ref T)' in this context because it may expose variables referenced by parameter 't' outside of their declaration scope - // this = Create(ref t3); - Diagnostic(ErrorCode.ERR_EscapeCall, "Create(ref t3)").WithArguments("R.Create(ref T)", "t").WithLocation(24, 16), - // (24,27): error CS8168: Cannot return local 't3' by reference because it is not a ref local - // this = Create(ref t3); - Diagnostic(ErrorCode.ERR_RefReturnLocal, "t3").WithArguments("t3").WithLocation(24, 27), - // (31,9): error CS8374: Cannot ref-assign 't4' to 'F' because 't4' has a narrower escape scope than 'F'. - // this.F = ref t4; - Diagnostic(ErrorCode.ERR_RefAssignNarrower, "this.F = ref t4").WithArguments("F", "t4").WithLocation(31, 9)); - } - - [Fact] - public void This_FromParameter() - { - var source = -@"ref struct R +} +class B : A { - static R Create() => new R(); - static R Create(ref T t) => new R(ref t); - static void M(R r) { } - private ref T F; - R(ref T t) { F = ref t; } - R(sbyte unused, T t1) + ref int F1B() { - this = new R(ref t1); - M(this); + int i = 1; + var r = new R(ref i); + return ref F1A(r); // 1 } - R(short unused, T t2) + ref int F2B() { - this = new R(); - this.F = ref t2; - M(this); + int i = 2; + var r = new R(ref i); + return ref F2A(r); } - R(int unused, T t3) + ref int F3B() { - this = Create(ref t3); - M(this); + int i = 3; + var r = new R(ref i); + return ref F3A(r); // 2 } - R(long unused, T t4) + ref int F4B() { - this = Create(); - this.F = ref t4; - M(this); + int i = 4; + var r = new R(ref i); + return ref F4A(r); // 3 } }"; - var comp = CreateCompilation(source); + var comp = CreateCompilation(new[] { source, UnscopedRefAttributeDefinition }, runtimeFeature: RuntimeFlag.ByRefFields); comp.VerifyEmitDiagnostics( - // (10,16): error CS8347: Cannot use a result of 'R.R(ref T)' in this context because it may expose variables referenced by parameter 't' outside of their declaration scope - // this = new R(ref t1); - Diagnostic(ErrorCode.ERR_EscapeCall, "new R(ref t1)").WithArguments("R.R(ref T)", "t").WithLocation(10, 16), - // (10,29): error CS8166: Cannot return a parameter by reference 't1' because it is not a ref parameter - // this = new R(ref t1); - Diagnostic(ErrorCode.ERR_RefReturnParameter, "t1").WithArguments("t1").WithLocation(10, 29), - // (16,9): error CS8374: Cannot ref-assign 't2' to 'F' because 't2' has a narrower escape scope than 'F'. - // this.F = ref t2; - Diagnostic(ErrorCode.ERR_RefAssignNarrower, "this.F = ref t2").WithArguments("F", "t2").WithLocation(16, 9), - // (21,16): error CS8347: Cannot use a result of 'R.Create(ref T)' in this context because it may expose variables referenced by parameter 't' outside of their declaration scope - // this = Create(ref t3); - Diagnostic(ErrorCode.ERR_EscapeCall, "Create(ref t3)").WithArguments("R.Create(ref T)", "t").WithLocation(21, 16), - // (21,27): error CS8166: Cannot return a parameter by reference 't3' because it is not a ref parameter - // this = Create(ref t3); - Diagnostic(ErrorCode.ERR_RefReturnParameter, "t3").WithArguments("t3").WithLocation(21, 27), - // (27,9): error CS8374: Cannot ref-assign 't4' to 'F' because 't4' has a narrower escape scope than 'F'. - // this.F = ref t4; - Diagnostic(ErrorCode.ERR_RefAssignNarrower, "this.F = ref t4").WithArguments("F", "t4").WithLocation(27, 9)); + // (17,23): error CS9063: UnscopedRefAttribute can only be applied to 'out' parameters, 'ref' and 'in' parameters that refer to 'ref struct' types, and instance methods and properties on 'struct' types other than constructors and 'init' accessors. + // public ref T F3A([UnscopedRef] R r3) + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedTarget, "UnscopedRef").WithLocation(17, 23), + // (21,23): error CS9063: UnscopedRefAttribute can only be applied to 'out' parameters, 'ref' and 'in' parameters that refer to 'ref struct' types, and instance methods and properties on 'struct' types other than constructors and 'init' accessors. + // public ref T F4A([UnscopedRef] scoped R r4) + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedTarget, "UnscopedRef").WithLocation(21, 23), + // (32,20): error CS8347: Cannot use a result of 'A.F1A(R)' in this context because it may expose variables referenced by parameter 'r1' outside of their declaration scope + // return ref F1A(r); // 1 + Diagnostic(ErrorCode.ERR_EscapeCall, "F1A(r)").WithArguments("A.F1A(R)", "r1").WithLocation(32, 20), + // (32,24): error CS8352: Cannot use variable 'r' in this context because it may expose referenced variables outside of their declaration scope + // return ref F1A(r); // 1 + Diagnostic(ErrorCode.ERR_EscapeVariable, "r").WithArguments("r").WithLocation(32, 24), + // (44,20): error CS8347: Cannot use a result of 'A.F3A(R)' in this context because it may expose variables referenced by parameter 'r3' outside of their declaration scope + // return ref F3A(r); // 2 + Diagnostic(ErrorCode.ERR_EscapeCall, "F3A(r)").WithArguments("A.F3A(R)", "r3").WithLocation(44, 20), + // (44,24): error CS8352: Cannot use variable 'r' in this context because it may expose referenced variables outside of their declaration scope + // return ref F3A(r); // 2 + Diagnostic(ErrorCode.ERR_EscapeVariable, "r").WithArguments("r").WithLocation(44, 24), + // (50,20): error CS8347: Cannot use a result of 'A.F4A(R)' in this context because it may expose variables referenced by parameter 'r4' outside of their declaration scope + // return ref F4A(r); // 3 + Diagnostic(ErrorCode.ERR_EscapeCall, "F4A(r)").WithArguments("A.F4A(R)", "r4").WithLocation(50, 20), + // (50,24): error CS8352: Cannot use variable 'r' in this context because it may expose referenced variables outside of their declaration scope + // return ref F4A(r); // 3 + Diagnostic(ErrorCode.ERR_EscapeVariable, "r").WithArguments("r").WithLocation(50, 24)); + + var baseType = comp.GetMember("B").BaseTypeNoUseSiteDiagnostics; + VerifyParameterSymbol(baseType.GetMethod("F1A").Parameters[0], "R r1", RefKind.None, DeclarationScope.Unscoped); + VerifyParameterSymbol(baseType.GetMethod("F2A").Parameters[0], "scoped R r2", RefKind.None, DeclarationScope.ValueScoped); + VerifyParameterSymbol(baseType.GetMethod("F3A").Parameters[0], "R r3", RefKind.None, DeclarationScope.Unscoped); + VerifyParameterSymbol(baseType.GetMethod("F4A").Parameters[0], "R r4", RefKind.None, DeclarationScope.Unscoped); + } + + [Fact] + public void UnscopedRefAttribute_RefStructParameter_02() + { + var source = +@"using System.Diagnostics.CodeAnalysis; +public ref struct R +{ + public ref T F; +} +class Program +{ + static void F1([UnscopedRef] R r1) { } + static void F2([UnscopedRef] ref R r2) { } + static void F3([UnscopedRef] in R r3) { } + static void F4([UnscopedRef] out R r4) { r4 = default; } +}"; + var comp = CreateCompilation(new[] { source, UnscopedRefAttributeDefinition }, runtimeFeature: RuntimeFlag.ByRefFields); + comp.VerifyEmitDiagnostics( + // (8,24): error CS9063: UnscopedRefAttribute can only be applied to 'out' parameters, 'ref' and 'in' parameters that refer to 'ref struct' types, and instance methods and properties on 'struct' types other than constructors and 'init' accessors. + // static void F1([UnscopedRef] R r1) { } + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedTarget, "UnscopedRef").WithLocation(8, 24)); + + VerifyParameterSymbol(comp.GetMember("Program.F1").Parameters[0], "R r1", RefKind.None, DeclarationScope.Unscoped); + VerifyParameterSymbol(comp.GetMember("Program.F2").Parameters[0], "ref R r2", RefKind.Ref, DeclarationScope.Unscoped); + VerifyParameterSymbol(comp.GetMember("Program.F3").Parameters[0], "in R r3", RefKind.In, DeclarationScope.Unscoped); + VerifyParameterSymbol(comp.GetMember("Program.F4").Parameters[0], "out R r4", RefKind.Out, DeclarationScope.Unscoped); + } + + [Fact] + public void UnscopedRefAttribute_Overrides_01() + { + var source = +@"using System.Diagnostics.CodeAnalysis; +abstract class A +{ + internal abstract void F1(out T t); + internal abstract void F2([UnscopedRef] out T t); +} +class B1 : A +{ + internal override void F1(out int i) { i = 0; } + internal override void F2([UnscopedRef] out int i) { i = 0; } +} +class B2 : A +{ + internal override void F1([UnscopedRef] out int i) { i = 0; } // 1 + internal override void F2(out int i) { i = 0; } // 2 +} +"; + var comp = CreateCompilation(new[] { source, UnscopedRefAttributeDefinition }); + // https://github.com/dotnet/roslyn/issues/62340: Should allow removing [UnscopedRef] rather than reporting error 2. + comp.VerifyDiagnostics( + // (14,28): error CS8987: The 'scoped' modifier of parameter 'i' doesn't match overridden or implemented member. + // internal override void F1([UnscopedRef] out int i) { i = 0; } // 1 + Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfOverrideOrImplementation, "F1").WithArguments("i").WithLocation(14, 28), + // (15,28): error CS8987: The 'scoped' modifier of parameter 'i' doesn't match overridden or implemented member. + // internal override void F2(out int i) { i = 0; } // 2 + Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfOverrideOrImplementation, "F2").WithArguments("i").WithLocation(15, 28)); + } + + [Fact] + public void UnscopedRefAttribute_Overrides_02() + { + var source = +@"using System.Diagnostics.CodeAnalysis; +abstract class A +{ + internal abstract void F1(ref T t); + internal abstract void F2([UnscopedRef] ref T t); +} +class B1 : A +{ + internal override void F1(ref int i) { } + internal override void F2([UnscopedRef] ref int i) { } +} +class B2 : A +{ + internal override void F1([UnscopedRef] ref int i) { } + internal override void F2(ref int i) { } +} +"; + var comp = CreateCompilation(new[] { source, UnscopedRefAttributeDefinition }); + comp.VerifyDiagnostics( + // (5,32): error CS9063: UnscopedRefAttribute can only be applied to 'out' parameters, 'ref' and 'in' parameters that refer to 'ref struct' types, and instance methods and properties on 'struct' types other than constructors and 'init' accessors. + // internal abstract void F2([UnscopedRef] ref T t); + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedTarget, "UnscopedRef").WithLocation(5, 32), + // (10,32): error CS9063: UnscopedRefAttribute can only be applied to 'out' parameters, 'ref' and 'in' parameters that refer to 'ref struct' types, and instance methods and properties on 'struct' types other than constructors and 'init' accessors. + // internal override void F2([UnscopedRef] ref int i) { } + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedTarget, "UnscopedRef").WithLocation(10, 32), + // (14,32): error CS9063: UnscopedRefAttribute can only be applied to 'out' parameters, 'ref' and 'in' parameters that refer to 'ref struct' types, and instance methods and properties on 'struct' types other than constructors and 'init' accessors. + // internal override void F1([UnscopedRef] ref int i) { } + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedTarget, "UnscopedRef").WithLocation(14, 32)); + } + + [Fact] + public void UnscopedRefAttribute_Overrides_03() + { + var source = +@"using System.Diagnostics.CodeAnalysis; +ref struct R +{ +} +abstract class A +{ + internal abstract void F1(ref R r); + internal abstract void F2([UnscopedRef] ref R r); +} +class B1 : A +{ + internal override void F1(ref R r) { } + internal override void F2([UnscopedRef] ref R r) { } +} +class B2 : A +{ + internal override void F1([UnscopedRef] ref R r) { } // 1 + internal override void F2(ref R r) { } // 2 +} +"; + var comp = CreateCompilation(new[] { source, UnscopedRefAttributeDefinition }); + comp.VerifyDiagnostics( + // (17,28): error CS8987: The 'scoped' modifier of parameter 'r' doesn't match overridden or implemented member. + // internal override void F1([UnscopedRef] ref R r) { } // 1 + Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfOverrideOrImplementation, "F1").WithArguments("r").WithLocation(17, 28), + // (18,28): error CS8987: The 'scoped' modifier of parameter 'r' doesn't match overridden or implemented member. + // internal override void F2(ref R r) { } // 2 + Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfOverrideOrImplementation, "F2").WithArguments("r").WithLocation(18, 28)); + } + + [Fact] + public void UnscopedRefAttribute_Implementations_01() + { + var source = +@"using System.Diagnostics.CodeAnalysis; +interface I +{ + void F1(out T t); + void F2([UnscopedRef] out T t); +} +class C1 : I +{ + public void F1(out int i) { i = 0; } + public void F2([UnscopedRef] out int i) { i = 0; } +} +class C2 : I +{ + public void F1([UnscopedRef] out int i) { i = 0; } // 1 + public void F2(out int i) { i = 0; } // 2 +} +class C3 : I +{ + void I.F1(out object o) { o = null; } + void I.F2([UnscopedRef] out object o) { o = null; } +} +class C4 : I +{ + void I.F1([UnscopedRef] out object o) { o = null; } // 3 + void I.F2(out object o) { o = null; } // 4 +} +"; + var comp = CreateCompilation(new[] { source, UnscopedRefAttributeDefinition }); + // https://github.com/dotnet/roslyn/issues/62340: Should allow removing [UnscopedRef] rather than reporting error 2 and 4. + comp.VerifyDiagnostics( + // (14,17): error CS8987: The 'scoped' modifier of parameter 'i' doesn't match overridden or implemented member. + // public void F1([UnscopedRef] out int i) { i = 0; } // 1 + Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfOverrideOrImplementation, "F1").WithArguments("i").WithLocation(14, 17), + // (15,17): error CS8987: The 'scoped' modifier of parameter 'i' doesn't match overridden or implemented member. + // public void F2(out int i) { i = 0; } // 2 + Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfOverrideOrImplementation, "F2").WithArguments("i").WithLocation(15, 17), + // (24,20): error CS8987: The 'scoped' modifier of parameter 'o' doesn't match overridden or implemented member. + // void I.F1([UnscopedRef] out object o) { o = null; } // 3 + Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfOverrideOrImplementation, "F1").WithArguments("o").WithLocation(24, 20), + // (25,20): error CS8987: The 'scoped' modifier of parameter 'o' doesn't match overridden or implemented member. + // void I.F2(out object o) { o = null; } // 4 + Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfOverrideOrImplementation, "F2").WithArguments("o").WithLocation(25, 20)); + } + + [Fact] + public void UnscopedRefAttribute_Implementations_02() + { + var source = +@"using System.Diagnostics.CodeAnalysis; +interface I +{ + void F1(ref T t); + void F2([UnscopedRef] ref T t); +} +class C1 : I +{ + public void F1(ref int i) { } + public void F2([UnscopedRef] ref int i) { } +} +class C2 : I +{ + public void F1([UnscopedRef] ref int i) { } + public void F2(ref int i) { } +} +class C3 : I +{ + void I.F1(ref object o) { } + void I.F2([UnscopedRef] ref object o) { } +} +class C4 : I +{ + void I.F1([UnscopedRef] ref object o) { } + void I.F2(ref object o) { } +} +"; + var comp = CreateCompilation(new[] { source, UnscopedRefAttributeDefinition }); + comp.VerifyDiagnostics( + // (5,14): error CS9063: UnscopedRefAttribute can only be applied to 'out' parameters, 'ref' and 'in' parameters that refer to 'ref struct' types, and instance methods and properties on 'struct' types other than constructors and 'init' accessors. + // void F2([UnscopedRef] ref T t); + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedTarget, "UnscopedRef").WithLocation(5, 14), + // (10,21): error CS9063: UnscopedRefAttribute can only be applied to 'out' parameters, 'ref' and 'in' parameters that refer to 'ref struct' types, and instance methods and properties on 'struct' types other than constructors and 'init' accessors. + // public void F2([UnscopedRef] ref int i) { } + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedTarget, "UnscopedRef").WithLocation(10, 21), + // (14,21): error CS9063: UnscopedRefAttribute can only be applied to 'out' parameters, 'ref' and 'in' parameters that refer to 'ref struct' types, and instance methods and properties on 'struct' types other than constructors and 'init' accessors. + // public void F1([UnscopedRef] ref int i) { } + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedTarget, "UnscopedRef").WithLocation(14, 21), + // (20,24): error CS9063: UnscopedRefAttribute can only be applied to 'out' parameters, 'ref' and 'in' parameters that refer to 'ref struct' types, and instance methods and properties on 'struct' types other than constructors and 'init' accessors. + // void I.F2([UnscopedRef] ref object o) { } + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedTarget, "UnscopedRef").WithLocation(20, 24), + // (24,24): error CS9063: UnscopedRefAttribute can only be applied to 'out' parameters, 'ref' and 'in' parameters that refer to 'ref struct' types, and instance methods and properties on 'struct' types other than constructors and 'init' accessors. + // void I.F1([UnscopedRef] ref object o) { } + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedTarget, "UnscopedRef").WithLocation(24, 24)); } [Fact] - public void This_FromRefParameter() + public void UnscopedRefAttribute_Implementations_03() { var source = -@"ref struct R +@"using System.Diagnostics.CodeAnalysis; +ref struct R { - static void M(R r) { } - private ref T F; - R(ref T t) { F = ref t; } - R(sbyte unused, ref T t1) - { - this = new R(ref t1); - M(this); - } - R(short unused, scoped ref T t2) - { - this = new R(ref t2); - M(this); - } -}"; - var comp = CreateCompilation(source); - comp.VerifyEmitDiagnostics( - // (13,16): error CS8347: Cannot use a result of 'R.R(ref T)' in this context because it may expose variables referenced by parameter 't' outside of their declaration scope - // this = new R(ref t2); - Diagnostic(ErrorCode.ERR_EscapeCall, "new R(ref t2)").WithArguments("R.R(ref T)", "t").WithLocation(13, 16), - // (13,29): error CS8166: Cannot return a parameter by reference 't2' because it is not a ref parameter - // this = new R(ref t2); - Diagnostic(ErrorCode.ERR_RefReturnParameter, "t2").WithArguments("t2").WithLocation(13, 29)); +} +interface I +{ + void F1(ref R r); + void F2([UnscopedRef] ref R r); +} +class C1 : I +{ + public void F1(ref R r) { } + public void F2([UnscopedRef] ref R r) { } +} +class C2 : I +{ + public void F1([UnscopedRef] ref R r) { } // 1 + public void F2(ref R r) { } // 2 +} +class C3 : I +{ + void I.F1(ref R r) { } + void I.F2([UnscopedRef] ref R r) { } +} +class C4 : I +{ + void I.F1([UnscopedRef] ref R r) { } // 3 + void I.F2(ref R r) { } // 4 +} +"; + var comp = CreateCompilation(new[] { source, UnscopedRefAttributeDefinition }); + comp.VerifyDiagnostics( + // (17,17): error CS8987: The 'scoped' modifier of parameter 'r' doesn't match overridden or implemented member. + // public void F1([UnscopedRef] ref R r) { } // 1 + Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfOverrideOrImplementation, "F1").WithArguments("r").WithLocation(17, 17), + // (18,17): error CS8987: The 'scoped' modifier of parameter 'r' doesn't match overridden or implemented member. + // public void F2(ref R r) { } // 2 + Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfOverrideOrImplementation, "F2").WithArguments("r").WithLocation(18, 17), + // (27,20): error CS8987: The 'scoped' modifier of parameter 'r' doesn't match overridden or implemented member. + // void I.F1([UnscopedRef] ref R r) { } // 3 + Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfOverrideOrImplementation, "F1").WithArguments("r").WithLocation(27, 20), + // (28,20): error CS8987: The 'scoped' modifier of parameter 'r' doesn't match overridden or implemented member. + // void I.F2(ref R r) { } // 4 + Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfOverrideOrImplementation, "F2").WithArguments("r").WithLocation(28, 20)); } [Fact] - public void This_FromRefStructParameter() + public void UnscopedRefAttribute_Delegates_01() { var source = -@"ref struct R +@"using System.Diagnostics.CodeAnalysis; +delegate void D1(out T t); +delegate void D2([UnscopedRef] out T t); +class Program { - static void M(R r) { } - private ref T F; - R(sbyte unused, ref R r1) - { - this = r1; - M(this); - } - R(short unused, scoped ref R r2) - { - this = r2; - M(this); - } - R(int unused, ref scoped R r3) - { - this = r3; - M(this); - } - R(long unused, scoped ref scoped R r4) + static void Main() { - this = r4; - M(this); + D1 d1; + d1 = (out int i1) => { i1 = 1; }; + d1 = ([UnscopedRef] out int i2) => { i2 = 2; }; // 1 + D2 d2; + d2 = (out object o1) => { o1 = 1; }; // 2 + d2 = ([UnscopedRef] out object o2) => { o2 = 2; }; } }"; - var comp = CreateCompilation(source); - comp.VerifyEmitDiagnostics( - // (4,19): warning CS0169: The field 'R.F' is never used - // private ref T F; - Diagnostic(ErrorCode.WRN_UnreferencedField, "F").WithArguments("R.F").WithLocation(4, 19), - // (17,16): error CS8352: Cannot use variable 'ref R' in this context because it may expose referenced variables outside of their declaration scope - // this = r3; - Diagnostic(ErrorCode.ERR_EscapeVariable, "r3").WithArguments("ref R").WithLocation(17, 16), - // (22,16): error CS8352: Cannot use variable 'ref R' in this context because it may expose referenced variables outside of their declaration scope - // this = r4; - Diagnostic(ErrorCode.ERR_EscapeVariable, "r4").WithArguments("ref R").WithLocation(22, 16)); + var comp = CreateCompilation(new[] { source, UnscopedRefAttributeDefinition }); + // https://github.com/dotnet/roslyn/issues/62340: Should allow removing [UnscopedRef] rather than reporting error 2. + comp.VerifyDiagnostics( + // (10,14): error CS8986: The 'scoped' modifier of parameter 'i2' doesn't match target 'D1'. + // d1 = ([UnscopedRef] out int i2) => { i2 = 2; }; // 1 + Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfTarget, "([UnscopedRef] out int i2) => { i2 = 2; }").WithArguments("i2", "D1").WithLocation(10, 14), + // (12,14): error CS8986: The 'scoped' modifier of parameter 'o1' doesn't match target 'D2'. + // d2 = (out object o1) => { o1 = 1; }; // 2 + Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfTarget, "(out object o1) => { o1 = 1; }").WithArguments("o1", "D2").WithLocation(12, 14)); + + var tree = comp.SyntaxTrees[0]; + var model = comp.GetSemanticModel(tree); + var lambdas = tree.GetRoot().DescendantNodes().OfType().Select(e => model.GetSymbolInfo(e).Symbol.GetSymbol()).ToArray(); + + VerifyParameterSymbol(lambdas[0].Parameters[0], "out System.Int32 i1", RefKind.Out, DeclarationScope.RefScoped); + VerifyParameterSymbol(lambdas[1].Parameters[0], "out System.Int32 i2", RefKind.Out, DeclarationScope.Unscoped); + VerifyParameterSymbol(lambdas[2].Parameters[0], "out System.Object o1", RefKind.Out, DeclarationScope.RefScoped); + VerifyParameterSymbol(lambdas[3].Parameters[0], "out System.Object o2", RefKind.Out, DeclarationScope.Unscoped); } [Fact] - public void NestedScope() + public void UnscopedRefAttribute_Delegates_02() { var source = -@"ref struct R -{ - public ref T F; -} +@"using System.Diagnostics.CodeAnalysis; +delegate void D1(ref T t); +delegate void D2([UnscopedRef] ref T t); class Program { - static T F() + static void Main() { - scoped R r; - { - T t = default; - r.F = ref t; - } - return r.F; + D1 d1; + d1 = (ref int i1) => { }; + d1 = ([UnscopedRef] ref int i2) => { }; + D2 d2; + d2 = (ref object o1) => { }; + d2 = ([UnscopedRef] ref object o2) => { }; } }"; - var comp = CreateCompilation(source); - comp.VerifyEmitDiagnostics( - // (12,13): error CS8374: Cannot ref-assign 't' to 'F' because 't' has a narrower escape scope than 'F'. - // r.F = ref t; - Diagnostic(ErrorCode.ERR_RefAssignNarrower, "r.F = ref t").WithArguments("F", "t").WithLocation(12, 13)); + var comp = CreateCompilation(new[] { source, UnscopedRefAttributeDefinition }); + comp.VerifyDiagnostics( + // (3,22): error CS9063: UnscopedRefAttribute can only be applied to 'out' parameters, 'ref' and 'in' parameters that refer to 'ref struct' types, and instance methods and properties on 'struct' types other than constructors and 'init' accessors. + // delegate void D2([UnscopedRef] ref T t); + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedTarget, "UnscopedRef").WithLocation(3, 22), + // (10,16): error CS9063: UnscopedRefAttribute can only be applied to 'out' parameters, 'ref' and 'in' parameters that refer to 'ref struct' types, and instance methods and properties on 'struct' types other than constructors and 'init' accessors. + // d1 = ([UnscopedRef] ref int i2) => { }; + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedTarget, "UnscopedRef").WithLocation(10, 16), + // (13,16): error CS9063: UnscopedRefAttribute can only be applied to 'out' parameters, 'ref' and 'in' parameters that refer to 'ref struct' types, and instance methods and properties on 'struct' types other than constructors and 'init' accessors. + // d2 = ([UnscopedRef] ref object o2) => { }; + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedTarget, "UnscopedRef").WithLocation(13, 16)); } - [Theory] - [InlineData(LanguageVersion.CSharp10)] - [InlineData(LanguageVersionFacts.CSharpNext)] - public void InstanceMethodWithOutVar_01(LanguageVersion languageVersion) + [Fact] + public void UnscopedRefAttribute_Delegates_03() { var source = -@"using System; -ref struct R -{ - public R(Span s) { } - public void F(out R r) { r = default; } -} +@"using System.Diagnostics.CodeAnalysis; +ref struct R { } +delegate void D1(ref R r); +delegate void D2([UnscopedRef] ref R r); class Program { - static void F(out R r) - { - Span s1 = stackalloc int[10]; - R r1 = new R(s1); - r1.F(out r); + static void Main() + { + D1 d1; + d1 = (ref R r1) => { }; + d1 = ([UnscopedRef] ref R r2) => { }; // 1 + D2 d2; + d2 = (ref R r1) => { }; // 2 + d2 = ([UnscopedRef] ref R r2) => { }; } }"; - var comp = CreateCompilationWithSpanAndMemoryExtensions(source, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion)); + var comp = CreateCompilation(new[] { source, UnscopedRefAttributeDefinition }); comp.VerifyDiagnostics( - // (13,9): error CS8352: Cannot use variable 'r1' in this context because it may expose referenced variables outside of their declaration scope - // r1.F(out r); - Diagnostic(ErrorCode.ERR_EscapeVariable, "r1").WithArguments("r1").WithLocation(13, 9)); + // (11,14): error CS8986: The 'scoped' modifier of parameter 'r2' doesn't match target 'D1'. + // d1 = ([UnscopedRef] ref R r2) => { }; // 1 + Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfTarget, "([UnscopedRef] ref R r2) => { }").WithArguments("r2", "D1").WithLocation(11, 14), + // (13,14): error CS8986: The 'scoped' modifier of parameter 'r1' doesn't match target 'D2'. + // d2 = (ref R r1) => { }; // 2 + Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfTarget, "(ref R r1) => { }").WithArguments("r1", "D2").WithLocation(13, 14)); } [Fact] - public void InstanceMethodWithOutVar_02() + public void UnscopedRefAttribute_Cycle() { var source = -@"ref struct R -{ - public ref int _i; - public R(ref int i) { _i = ref i; } - public void F(out R r) { r = new R(ref _i); } -} -class Program +@"namespace System.Diagnostics.CodeAnalysis { - static void F(out R r) - { - int i = 0; - R r1 = new R(ref i); - r1.F(out r); + public sealed class UnscopedRefAttribute : Attribute + { + public UnscopedRefAttribute([UnscopedRef] out int i) { i = 0; } } }"; var comp = CreateCompilation(source); comp.VerifyDiagnostics( - // (13,9): error CS8352: Cannot use variable 'r1' in this context because it may expose referenced variables outside of their declaration scope - // r1.F(out r); - Diagnostic(ErrorCode.ERR_EscapeVariable, "r1").WithArguments("r1").WithLocation(13, 9)); + // (5,38): error CS7036: There is no argument given that corresponds to the required formal parameter 'i' of 'UnscopedRefAttribute.UnscopedRefAttribute(out int)' + // public UnscopedRefAttribute([UnscopedRef] out int i) { i = 0; } + Diagnostic(ErrorCode.ERR_NoCorrespondingArgument, "UnscopedRef").WithArguments("i", "System.Diagnostics.CodeAnalysis.UnscopedRefAttribute.UnscopedRefAttribute(out int)").WithLocation(5, 38)); } - [Theory] - [InlineData(LanguageVersion.CSharp10)] - [InlineData(LanguageVersionFacts.CSharpNext)] - public void InstanceMethodWithOutVar_03(LanguageVersion languageVersion) + [Fact] + public void UnscopedRefAttribute_UnexpectedConstructorArgument() { - var source = -@"using System; -ref struct R + var sourceA = +@"namespace System.Diagnostics.CodeAnalysis { - public void F(out Span s) { s = default; } -} + public sealed class UnscopedRefAttribute : Attribute + { + public UnscopedRefAttribute(bool b) { } + } +}"; + var sourceB = +@"using System.Diagnostics.CodeAnalysis; class Program { - static void Main() + static ref int F1([UnscopedRef] out int i1) { - Span s = stackalloc int[10]; - R r = new R(); - r.F(out s); + i1 = 0; + return ref i1; + } + static ref int F2([UnscopedRef(true)] out int i2) + { + i2 = 0; + return ref i2; + } + static ref int F3() + { + int i3; + return ref F1(out i3); + } + static ref int F4() + { + int i4; + return ref F2(out i4); } }"; - var comp = CreateCompilationWithSpanAndMemoryExtensions(source, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion)); + var comp = CreateCompilation(new[] { sourceA, sourceB }); comp.VerifyDiagnostics( - // (12,9): error CS8350: This combination of arguments to 'R.F(out Span)' is disallowed because it may expose variables referenced by parameter 's' outside of their declaration scope - // r.F(out s); - Diagnostic(ErrorCode.ERR_CallArgMixing, "r.F(out s)").WithArguments("R.F(out System.Span)", "s").WithLocation(12, 9), - // (12,17): error CS8352: Cannot use variable 's' in this context because it may expose referenced variables outside of their declaration scope - // r.F(out s); - Diagnostic(ErrorCode.ERR_EscapeVariable, "s").WithArguments("s").WithLocation(12, 17)); + // (4,24): error CS7036: There is no argument given that corresponds to the required formal parameter 'b' of 'UnscopedRefAttribute.UnscopedRefAttribute(bool)' + // static ref int F1([UnscopedRef] out int i1) + Diagnostic(ErrorCode.ERR_NoCorrespondingArgument, "UnscopedRef").WithArguments("b", "System.Diagnostics.CodeAnalysis.UnscopedRefAttribute.UnscopedRefAttribute(bool)").WithLocation(4, 24), + // (12,20): error CS8166: Cannot return a parameter by reference 'i2' because it is not a ref parameter + // return ref i2; + Diagnostic(ErrorCode.ERR_RefReturnParameter, "i2").WithArguments("i2").WithLocation(12, 20), + // (17,20): error CS8347: Cannot use a result of 'Program.F1(out int)' in this context because it may expose variables referenced by parameter 'i1' outside of their declaration scope + // return ref F1(out i3); + Diagnostic(ErrorCode.ERR_EscapeCall, "F1(out i3)").WithArguments("Program.F1(out int)", "i1").WithLocation(17, 20), + // (17,27): error CS8168: Cannot return local 'i3' by reference because it is not a ref local + // return ref F1(out i3); + Diagnostic(ErrorCode.ERR_RefReturnLocal, "i3").WithArguments("i3").WithLocation(17, 27)); } - [Theory] - [InlineData(LanguageVersion.CSharp10)] - [InlineData(LanguageVersionFacts.CSharpNext)] - public void ReturnThis_01(LanguageVersion languageVersion) + [Fact] + public void UnscopedRefAttribute_InvalidConstructorArgument() { - var source = -@"ref struct R + var sourceA = +@"namespace System.Diagnostics.CodeAnalysis { - R F1() => this; - ref R F2() => ref this; - ref readonly R F3() => ref this; + public sealed class UnscopedRefAttribute : Attribute + { + public UnscopedRefAttribute(bool b) { } + } }"; - var comp = CreateCompilationWithSpanAndMemoryExtensions(source, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion)); + var sourceB = +@"using System.Diagnostics.CodeAnalysis; +class Program +{ + static bool F1() + { + return true; + } + static ref int F2([UnscopedRef(F1())] out int i) + { + i = 0; + return ref i; + } +}"; + var comp = CreateCompilation(new[] { sourceA, sourceB }); comp.VerifyDiagnostics( - // (4,23): error CS8170: Struct members cannot return 'this' or other instance members by reference - // ref R F2() => ref this; - Diagnostic(ErrorCode.ERR_RefReturnStructThis, "this").WithLocation(4, 23), - // (5,32): error CS8170: Struct members cannot return 'this' or other instance members by reference - // ref readonly R F3() => ref this; - Diagnostic(ErrorCode.ERR_RefReturnStructThis, "this").WithLocation(5, 32)); + // (8,36): error CS0182: An attribute argument must be a constant expression, typeof expression or array creation expression of an attribute parameter type + // static ref int F2([UnscopedRef(F1())] out int i) + Diagnostic(ErrorCode.ERR_BadAttributeArgument, "F1()").WithLocation(8, 36), + // (11,20): error CS8166: Cannot return a parameter by reference 'i' because it is not a ref parameter + // return ref i; + Diagnostic(ErrorCode.ERR_RefReturnParameter, "i").WithArguments("i").WithLocation(11, 20)); } - [Theory] - [InlineData(LanguageVersion.CSharp10)] - [InlineData(LanguageVersionFacts.CSharpNext)] - public void ReturnThis_02(LanguageVersion languageVersion) + [Fact] + public void UnscopedRefAttribute_ScopeRefAttribute() { - var source = -@"readonly ref struct R + var sourceA = +@".class private System.Diagnostics.CodeAnalysis.UnscopedRefAttribute extends [mscorlib]System.Attribute { - R F1() => this; - ref R F2() => ref this; - ref readonly R F3() => ref this; + .method public hidebysig specialname rtspecialname instance void .ctor() cil managed { ret } +} +.class private System.Runtime.CompilerServices.LifetimeAnnotationAttribute extends [mscorlib]System.Attribute +{ + .method public hidebysig specialname rtspecialname instance void .ctor(bool isRefScoped, bool isValueScoped) cil managed { ret } +} +.class public A +{ + .method public static int32& NoAttributes([out] int32& i) + { + ldnull + throw + } + .method public static int32& ScopedRefOnly([out] int32& i) + { + .param [1] + .custom instance void System.Runtime.CompilerServices.LifetimeAnnotationAttribute::.ctor(bool, bool) = ( 01 00 01 00 00 00 ) // LifetimeAnnotationAttribute(isRefScoped: true, isValueScoped: false) + ldnull + throw + } + .method public static int32& UnscopedRefOnly([out] int32& i) + { + .param [1] + .custom instance void System.Diagnostics.CodeAnalysis.UnscopedRefAttribute::.ctor() = ( 01 00 00 00 ) + ldnull + throw + } + .method public static int32& ScopedRefAndUnscopedRef([out] int32& i) + { + .param [1] + .custom instance void System.Diagnostics.CodeAnalysis.UnscopedRefAttribute::.ctor() = ( 01 00 00 00 ) + .param [1] + .custom instance void System.Runtime.CompilerServices.LifetimeAnnotationAttribute::.ctor(bool, bool) = ( 01 00 01 00 00 00 ) // LifetimeAnnotationAttribute(isRefScoped: true, isValueScoped: false) + ldnull + throw + } +} +"; + var refA = CompileIL(sourceA); + + var sourceB = +@"class Program +{ + static ref int F1() + { + int i; + return ref A.NoAttributes(out i); + } + static ref int F2() + { + int i; + return ref A.ScopedRefOnly(out i); + } + static ref int F3() + { + int i; + return ref A.UnscopedRefOnly(out i); // 1 + } + static ref int F4() + { + int i; + return ref A.ScopedRefAndUnscopedRef(out i); // 2 + } }"; - var comp = CreateCompilationWithSpanAndMemoryExtensions(source, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion)); - comp.VerifyDiagnostics( - // (4,23): error CS8354: Cannot return 'this' by reference. - // ref R F2() => ref this; - Diagnostic(ErrorCode.ERR_RefReturnThis, "this").WithLocation(4, 23), - // (5,32): error CS8170: Struct members cannot return 'this' or other instance members by reference - // ref readonly R F3() => ref this; - Diagnostic(ErrorCode.ERR_RefReturnStructThis, "this").WithLocation(5, 32)); + var comp = CreateCompilation(sourceB, new[] { refA }); + comp.VerifyEmitDiagnostics( + // (16,20): error CS8347: Cannot use a result of 'A.UnscopedRefOnly(out int)' in this context because it may expose variables referenced by parameter 'i' outside of their declaration scope + // return ref A.UnscopedRefOnly(out i); // 1 + Diagnostic(ErrorCode.ERR_EscapeCall, "A.UnscopedRefOnly(out i)").WithArguments("A.UnscopedRefOnly(out int)", "i").WithLocation(16, 20), + // (16,42): error CS8168: Cannot return local 'i' by reference because it is not a ref local + // return ref A.UnscopedRefOnly(out i); // 1 + Diagnostic(ErrorCode.ERR_RefReturnLocal, "i").WithArguments("i").WithLocation(16, 42), + // (21,20): error CS8347: Cannot use a result of 'A.ScopedRefAndUnscopedRef(out int)' in this context because it may expose variables referenced by parameter 'i' outside of their declaration scope + // return ref A.ScopedRefAndUnscopedRef(out i); // 2 + Diagnostic(ErrorCode.ERR_EscapeCall, "A.ScopedRefAndUnscopedRef(out i)").WithArguments("A.ScopedRefAndUnscopedRef(out int)", "i").WithLocation(21, 20), + // (21,50): error CS8168: Cannot return local 'i' by reference because it is not a ref local + // return ref A.ScopedRefAndUnscopedRef(out i); // 2 + Diagnostic(ErrorCode.ERR_RefReturnLocal, "i").WithArguments("i").WithLocation(21, 50)); + + var typeA = comp.GetMember("A"); + VerifyParameterSymbol(typeA.GetMethod("NoAttributes").Parameters[0], "out System.Int32 i", RefKind.Out, DeclarationScope.RefScoped); + VerifyParameterSymbol(typeA.GetMethod("ScopedRefOnly").Parameters[0], "out System.Int32 i", RefKind.Out, DeclarationScope.RefScoped); + VerifyParameterSymbol(typeA.GetMethod("UnscopedRefOnly").Parameters[0], "out System.Int32 i", RefKind.Out, DeclarationScope.Unscoped); + VerifyParameterSymbol(typeA.GetMethod("ScopedRefAndUnscopedRef").Parameters[0], "out System.Int32 i", RefKind.Out, DeclarationScope.Unscoped); } } } diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/RefLocalsAndReturnsTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/RefLocalsAndReturnsTests.cs index feafeb141960d..6d0c44b23625a 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/RefLocalsAndReturnsTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/RefLocalsAndReturnsTests.cs @@ -561,14 +561,16 @@ void M(ref int x, out int o) Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7_2, "ref _f").WithArguments("ref reassignment", "7.3").WithLocation(12, 13)); } - [Fact] - public void RefReassignSpanLifetime() + [Theory] + [InlineData(LanguageVersion.CSharp10)] + [InlineData(LanguageVersion.CSharp11)] + public void RefReassignSpanLifetime(LanguageVersion languageVersion) { - var comp = CreateCompilationWithMscorlibAndSpan(@" -using System; + string source = @"using System; +using System.Diagnostics.CodeAnalysis; class C { - void M(ref Span s) + void M([UnscopedRef] ref Span s) { Span s2 = new Span(new int[10]); s = ref s2; // Illegal, narrower escape scope @@ -578,7 +580,8 @@ void M(ref Span s) Span s3 = stackalloc int[10]; s = ref s3; // Illegal, narrower escape scope } -}"); +}"; + var comp = CreateCompilationWithMscorlibAndSpan(new[] { source, UnscopedRefAttributeDefinition }, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion)); comp.VerifyDiagnostics( // (8,9): error CS8374: Cannot ref-assign 's2' to 's' because 's2' has a narrower escape scope than 's'. // s = ref s2; // Illegal, narrower escape scope @@ -4293,7 +4296,7 @@ public void M(int value) [WorkItem(27772, "https://github.com/dotnet/roslyn/issues/27772")] public void RefReturnInvocationOfRefLikeTypeRefResult() { - CreateCompilationWithMscorlibAndSpan(@" + string source = @" class C { public ref long M(S receiver) @@ -4315,20 +4318,38 @@ public ref long M2(S receiver) ref struct S { public ref long M(ref long x) => ref x; -}").VerifyDiagnostics( +}"; + + var comp = CreateCompilationWithMscorlibAndSpan(source, parseOptions: TestOptions.Regular10); + comp.VerifyDiagnostics( // (8,20): error CS8157: Cannot return 'y' by reference because it was initialized to a value that cannot be returned by reference // return ref y; Diagnostic(ErrorCode.ERR_RefReturnNonreturnableLocal, "y").WithArguments("y").WithLocation(8, 20), // (16,24): error CS8157: Cannot return 'y' by reference because it was initialized to a value that cannot be returned by reference // return ref y; Diagnostic(ErrorCode.ERR_RefReturnNonreturnableLocal, "y").WithArguments("y").WithLocation(16, 24)); + + comp = CreateCompilationWithMscorlibAndSpan(source); + comp.VerifyDiagnostics( + // (7,26): error CS8350: This combination of arguments to 'S.M(ref long)' is disallowed because it may expose variables referenced by parameter 'x' outside of their declaration scope + // ref long y = ref receiver.M(ref x); + Diagnostic(ErrorCode.ERR_CallArgMixing, "receiver.M(ref x)").WithArguments("S.M(ref long)", "x").WithLocation(7, 26), + // (7,41): error CS8168: Cannot return local 'x' by reference because it is not a ref local + // ref long y = ref receiver.M(ref x); + Diagnostic(ErrorCode.ERR_RefReturnLocal, "x").WithArguments("x").WithLocation(7, 41), + // (15,30): error CS8350: This combination of arguments to 'S.M(ref long)' is disallowed because it may expose variables referenced by parameter 'x' outside of their declaration scope + // ref long y = ref receiver.M(ref x); + Diagnostic(ErrorCode.ERR_CallArgMixing, "receiver.M(ref x)").WithArguments("S.M(ref long)", "x").WithLocation(15, 30), + // (15,45): error CS8168: Cannot return local 'x' by reference because it is not a ref local + // ref long y = ref receiver.M(ref x); + Diagnostic(ErrorCode.ERR_RefReturnLocal, "x").WithArguments("x").WithLocation(15, 45)); } [Fact] [WorkItem(27772, "https://github.com/dotnet/roslyn/issues/27772")] public void RefReturnInvocationOfRefLikeTypeRefResult_Repro() { - CreateCompilationWithMscorlibAndSpan(@" + string source = @" using System; class C { @@ -4363,10 +4384,23 @@ static void M2(ref long q) ref struct S { public ref long M(ref long x) => ref x; -}").VerifyDiagnostics( +}"; + + var comp = CreateCompilationWithMscorlibAndSpan(source, parseOptions: TestOptions.Regular10); + comp.VerifyDiagnostics( // (19,18): error CS8157: Cannot return 'z' by reference because it was initialized to a value that cannot be returned by reference // return ref z; Diagnostic(ErrorCode.ERR_RefReturnNonreturnableLocal, "z").WithArguments("z").WithLocation(19, 18)); + + // Breaking change in C#11: Instance method on ref struct instance may capture unscoped ref or in arguments. + comp = CreateCompilationWithMscorlibAndSpan(source); + comp.VerifyDiagnostics( + // (18,23): error CS8350: This combination of arguments to 'S.M(ref long)' is disallowed because it may expose variables referenced by parameter 'x' outside of their declaration scope + // ref var z = ref receiver.M(ref y); + Diagnostic(ErrorCode.ERR_CallArgMixing, "receiver.M(ref y)").WithArguments("S.M(ref long)", "x").WithLocation(18, 23), + // (18,38): error CS8157: Cannot return 'y' by reference because it was initialized to a value that cannot be returned by reference + // ref var z = ref receiver.M(ref y); + Diagnostic(ErrorCode.ERR_RefReturnNonreturnableLocal, "y").WithArguments("y").WithLocation(18, 38)); } [Fact, WorkItem(49617, "https://github.com/dotnet/roslyn/issues/49617")] diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/SemanticErrorTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/SemanticErrorTests.cs index 095dadc92ae66..cb1a936eec44b 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/SemanticErrorTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/SemanticErrorTests.cs @@ -6466,9 +6466,9 @@ public static void Main() }"; var comp = CreateCompilation(text, parseOptions: TestOptions.Regular10); comp.VerifyDiagnostics( - // (4,4): error CS0171: Field 'MyStruct.i' must be fully assigned before control is returned to the caller. Consider updating to language version 'preview' to auto-default the field. + // (4,4): error CS0171: Field 'MyStruct.i' must be fully assigned before control is returned to the caller. Consider updating to language version '11.0' to auto-default the field. // MyStruct(int initField) // CS0171 - Diagnostic(ErrorCode.ERR_UnassignedThisUnsupportedVersion, "MyStruct").WithArguments("MyStruct.i", "preview").WithLocation(4, 4), + Diagnostic(ErrorCode.ERR_UnassignedThisUnsupportedVersion, "MyStruct").WithArguments("MyStruct.i", "11.0").WithLocation(4, 4), // (15,16): warning CS0219: The variable 'aStruct' is assigned but its value is never used // MyStruct aStruct = new MyStruct(); Diagnostic(ErrorCode.WRN_UnreferencedVarAssg, "aStruct").WithArguments("aStruct").WithLocation(15, 16), @@ -6477,7 +6477,7 @@ public static void Main() Diagnostic(ErrorCode.WRN_UnassignedInternalField, "i").WithArguments("MyStruct.i", "0").WithLocation(8, 15) ); - var verifier = CompileAndVerify(text, parseOptions: TestOptions.RegularNext); + var verifier = CompileAndVerify(text, parseOptions: TestOptions.Regular11); verifier.VerifyDiagnostics( // (15,16): warning CS0219: The variable 'aStruct' is assigned but its value is never used // MyStruct aStruct = new MyStruct(); @@ -6982,14 +6982,14 @@ public static void Main() }"; CreateCompilation(text, parseOptions: TestOptions.Regular10). VerifyDiagnostics( - // (17,17): error CS0188: The 'this' object cannot be used before all of its fields have been assigned. Consider updating to language version 'preview' to auto-default the unassigned fields. + // (17,17): error CS0188: The 'this' object cannot be used before all of its fields have been assigned. Consider updating to language version '11.0' to auto-default the unassigned fields. // Goo(); // CS0188 - Diagnostic(ErrorCode.ERR_UseDefViolationThisUnsupportedVersion, "Goo").WithArguments("preview").WithLocation(17, 17), + Diagnostic(ErrorCode.ERR_UseDefViolationThisUnsupportedVersion, "Goo").WithArguments("11.0").WithLocation(17, 17), // (8,24): warning CS0649: Field 'MyClass.S.a' is never assigned to, and will always have its default value 0 // public int a; Diagnostic(ErrorCode.WRN_UnassignedInternalField, "a").WithArguments("MyNamespace.MyClass.S.a", "0").WithLocation(8, 24)); - var verifier = CompileAndVerify(text, parseOptions: TestOptions.RegularNext). + var verifier = CompileAndVerify(text, parseOptions: TestOptions.Regular11). VerifyDiagnostics( // (8,24): warning CS0649: Field 'MyNamespace.MyClass.S.a' is never assigned to, and will always have its default value 0 // public int a; @@ -7032,11 +7032,11 @@ void F() // (10,18): error CS0837: The first operand of an 'is' or 'as' operator may not be a lambda expression, anonymous method, or method group. // var b1 = F is Action; Diagnostic(ErrorCode.ERR_LambdaInIsAs, "F is Action").WithLocation(10, 18), - // (10,18): error CS0188: The 'this' object cannot be used before all of its fields have been assigned. Consider updating to language version 'preview' to auto-default the unassigned fields. + // (10,18): error CS0188: The 'this' object cannot be used before all of its fields have been assigned. Consider updating to language version '11.0' to auto-default the unassigned fields. // var b1 = F is Action; - Diagnostic(ErrorCode.ERR_UseDefViolationThisUnsupportedVersion, "F").WithArguments("preview").WithLocation(10, 18)); + Diagnostic(ErrorCode.ERR_UseDefViolationThisUnsupportedVersion, "F").WithArguments("11.0").WithLocation(10, 18)); - CreateCompilationWithMscorlib40AndSystemCore(source, parseOptions: TestOptions.RegularNext).VerifyDiagnostics( + CreateCompilationWithMscorlib40AndSystemCore(source, parseOptions: TestOptions.Regular11).VerifyDiagnostics( // (10,18): error CS0837: The first operand of an 'is' or 'as' operator may not be a lambda expression, anonymous method, or method group. Diagnostic(ErrorCode.ERR_LambdaInIsAs, "F is Action").WithLocation(10, 18)); } @@ -7066,11 +7066,11 @@ void F() // (10,18): error CS0837: The first operand of an 'is' or 'as' operator may not be a lambda expression, anonymous method, or method group. // var b1 = this.F is Action; Diagnostic(ErrorCode.ERR_LambdaInIsAs, "this.F is Action").WithLocation(10, 18), - // (10,18): error CS0188: The 'this' object cannot be used before all of its fields have been assigned. Consider updating to language version 'preview' to auto-default the unassigned fields. + // (10,18): error CS0188: The 'this' object cannot be used before all of its fields have been assigned. Consider updating to language version '11.0' to auto-default the unassigned fields. // var b1 = this.F is Action; - Diagnostic(ErrorCode.ERR_UseDefViolationThisUnsupportedVersion, "this").WithArguments("preview").WithLocation(10, 18)); + Diagnostic(ErrorCode.ERR_UseDefViolationThisUnsupportedVersion, "this").WithArguments("11.0").WithLocation(10, 18)); - CreateCompilationWithMscorlib40AndSystemCore(source, parseOptions: TestOptions.RegularNext).VerifyDiagnostics( + CreateCompilationWithMscorlib40AndSystemCore(source, parseOptions: TestOptions.Regular11).VerifyDiagnostics( // (10,18): error CS0837: The first operand of an 'is' or 'as' operator may not be a lambda expression, anonymous method, or method group. // var b1 = this.F is Action; Diagnostic(ErrorCode.ERR_LambdaInIsAs, "this.F is Action").WithLocation(10, 18)); @@ -7099,11 +7099,11 @@ void Add(int value) } "; CreateCompilationWithMscorlib40AndSystemCore(source, parseOptions: TestOptions.Regular10).VerifyDiagnostics( - // (10,19): error CS0188: The 'this' object cannot be used before all of its fields have been assigned. Consider updating to language version 'preview' to auto-default the unassigned fields. + // (10,19): error CS0188: The 'this' object cannot be used before all of its fields have been assigned. Consider updating to language version '11.0' to auto-default the unassigned fields. // /*this.*/ Add(d); - Diagnostic(ErrorCode.ERR_UseDefViolationThisUnsupportedVersion, "Add").WithArguments("preview").WithLocation(10, 19)); + Diagnostic(ErrorCode.ERR_UseDefViolationThisUnsupportedVersion, "Add").WithArguments("11.0").WithLocation(10, 19)); - var verifier = CompileAndVerify(source, new[] { CSharpRef }, parseOptions: TestOptions.RegularNext); + var verifier = CompileAndVerify(source, new[] { CSharpRef }, parseOptions: TestOptions.Regular11); verifier.VerifyDiagnostics(); verifier.VerifyIL("S..ctor", @" { @@ -7170,11 +7170,11 @@ void Add(int value) } "; CreateCompilationWithMscorlib40AndSystemCore(source, parseOptions: TestOptions.Regular10).VerifyDiagnostics( - // (10,9): error CS0188: The 'this' object cannot be used before all of its fields have been assigned. Consider updating to language version 'preview' to auto-default the unassigned fields. + // (10,9): error CS0188: The 'this' object cannot be used before all of its fields have been assigned. Consider updating to language version '11.0' to auto-default the unassigned fields. // this.Add(d); - Diagnostic(ErrorCode.ERR_UseDefViolationThisUnsupportedVersion, "this").WithArguments("preview").WithLocation(10, 9)); + Diagnostic(ErrorCode.ERR_UseDefViolationThisUnsupportedVersion, "this").WithArguments("11.0").WithLocation(10, 9)); - var verifier = CompileAndVerify(source, new[] { CSharpRef }, parseOptions: TestOptions.RegularNext); + var verifier = CompileAndVerify(source, new[] { CSharpRef }, parseOptions: TestOptions.Regular11); verifier.VerifyDiagnostics(); verifier.VerifyIL("S..ctor", @" { @@ -12922,11 +12922,11 @@ static int Main() "; CreateCompilation(text, parseOptions: TestOptions.Regular10) .VerifyDiagnostics( - // (5,12): error CS0843: Auto-implemented property 'S.AIProp' must be fully assigned before control is returned to the caller. Consider updating to language version 'preview' to auto-default the property. + // (5,12): error CS0843: Auto-implemented property 'S.AIProp' must be fully assigned before control is returned to the caller. Consider updating to language version '11.0' to auto-default the property. // public S(int i) { } //CS0843 - Diagnostic(ErrorCode.ERR_UnassignedThisAutoPropertyUnsupportedVersion, "S").WithArguments("S.AIProp", "preview").WithLocation(5, 12)); + Diagnostic(ErrorCode.ERR_UnassignedThisAutoPropertyUnsupportedVersion, "S").WithArguments("S.AIProp", "11.0").WithLocation(5, 12)); - var verifier = CompileAndVerify(text, parseOptions: TestOptions.RegularNext); + var verifier = CompileAndVerify(text, parseOptions: TestOptions.Regular11); verifier.VerifyDiagnostics(); verifier.VerifyIL("S..ctor", @" { diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/SpanStackSafetyTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/SpanStackSafetyTests.cs index b56dbc0bd280b..3606edaa3fc93 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/SpanStackSafetyTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/SpanStackSafetyTests.cs @@ -482,11 +482,13 @@ static void Main() ); } - [Fact] - public void ByrefParam() + [Theory] + [InlineData(LanguageVersion.CSharp10)] + [InlineData(LanguageVersion.CSharp11)] + public void ByrefParam(LanguageVersion languageVersion) { - var text = @" -using System; + var text = @"using System; +using System.Diagnostics.CodeAnalysis; class Program { @@ -516,19 +518,17 @@ static void M3l(in SpanLike ss) } // OK - static ref Span M4(ref Span ss) { return ref ss; } + static ref Span M4([UnscopedRef] ref Span ss) { return ref ss; } // OK - static ref readonly Span M5(ref Span ss) => ref ss; + static ref readonly Span M5([UnscopedRef] ref Span ss) => ref ss; // Not OK // TypedReference baseline static ref TypedReference M1(ref TypedReference ss) => ref ss; } "; - - CSharpCompilation comp = CreateCompilationWithMscorlibAndSpan(text); - + var comp = CreateCompilationWithMscorlibAndSpan(new[] { text, UnscopedRefAttributeDefinition }, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion)); comp.VerifyDiagnostics( // (39,34): error CS1601: Cannot make reference to variable of type 'TypedReference' // static ref TypedReference M1(ref TypedReference ss) => ref ss; @@ -1448,13 +1448,14 @@ static void Main() ); } - [Fact] [WorkItem(27874, "https://github.com/dotnet/roslyn/issues/27874")] - public void PassingSpansToLocals_EscapeScope() + [Theory] + [InlineData(LanguageVersion.CSharp10)] + [InlineData(LanguageVersion.CSharp11)] + public void PassingSpansToLocals_EscapeScope(LanguageVersion languageVersion) { - CompileAndVerify( - CreateCompilationWithMscorlibAndSpan(@" -using System; + var source = @"using System; +using System.Diagnostics.CodeAnalysis; class C { static void Main() @@ -1465,18 +1466,19 @@ static void Main() Console.WriteLine(M2(ref x).Length); } - static ref Span M1(ref Span x) + static ref Span M1([UnscopedRef] ref Span x) { ref Span q = ref x; return ref q; } - static ref Span M2(ref Span x) + static ref Span M2([UnscopedRef] ref Span x) { return ref x; } -}", - options: TestOptions.ReleaseExe), verify: Verification.Fails, expectedOutput: @" +}"; + var comp = CreateCompilationWithMscorlibAndSpan(new[] { source, UnscopedRefAttributeDefinition }, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion), options: TestOptions.ReleaseExe); + CompileAndVerify(comp, verify: Verification.Fails, expectedOutput: @" 10 10"); } diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/StructConstructorTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/StructConstructorTests.cs index d5b22b207de24..6fd294b8f8934 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/StructConstructorTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/StructConstructorTests.cs @@ -1324,21 +1324,21 @@ static void Main() var comp = CreateCompilation(source, parseOptions: TestOptions.Regular10); comp.VerifyDiagnostics( - // (11,12): error CS0171: Field 'S1.y' must be fully assigned before control is returned to the caller. Consider updating to language version 'preview' to auto-default the field. + // (11,12): error CS0171: Field 'S1.y' must be fully assigned before control is returned to the caller. Consider updating to language version '11.0' to auto-default the field. // public S1() { } - Diagnostic(ErrorCode.ERR_UnassignedThisUnsupportedVersion, "S1").WithArguments("S1.y", "preview").WithLocation(11, 12), - // (11,12): error CS0171: Field 'S1.x' must be fully assigned before control is returned to the caller. Consider updating to language version 'preview' to auto-default the field. + Diagnostic(ErrorCode.ERR_UnassignedThisUnsupportedVersion, "S1").WithArguments("S1.y", "11.0").WithLocation(11, 12), + // (11,12): error CS0171: Field 'S1.x' must be fully assigned before control is returned to the caller. Consider updating to language version '11.0' to auto-default the field. // public S1() { } - Diagnostic(ErrorCode.ERR_UnassignedThisUnsupportedVersion, "S1").WithArguments("S1.x", "preview").WithLocation(11, 12), - // (22,12): error CS0171: Field 'S2.y' must be fully assigned before control is returned to the caller. Consider updating to language version 'preview' to auto-default the field. + Diagnostic(ErrorCode.ERR_UnassignedThisUnsupportedVersion, "S1").WithArguments("S1.x", "11.0").WithLocation(11, 12), + // (22,12): error CS0171: Field 'S2.y' must be fully assigned before control is returned to the caller. Consider updating to language version '11.0' to auto-default the field. // public S2() { } - Diagnostic(ErrorCode.ERR_UnassignedThisUnsupportedVersion, "S2").WithArguments("S2.y", "preview").WithLocation(22, 12), - // (22,12): error CS0171: Field 'S2.x' must be fully assigned before control is returned to the caller. Consider updating to language version 'preview' to auto-default the field. + Diagnostic(ErrorCode.ERR_UnassignedThisUnsupportedVersion, "S2").WithArguments("S2.y", "11.0").WithLocation(22, 12), + // (22,12): error CS0171: Field 'S2.x' must be fully assigned before control is returned to the caller. Consider updating to language version '11.0' to auto-default the field. // public S2() { } - Diagnostic(ErrorCode.ERR_UnassignedThisUnsupportedVersion, "S2").WithArguments("S2.x", "preview").WithLocation(22, 12), - // (32,12): error CS0171: Field 'S3.x' must be fully assigned before control is returned to the caller. Consider updating to language version 'preview' to auto-default the field. + Diagnostic(ErrorCode.ERR_UnassignedThisUnsupportedVersion, "S2").WithArguments("S2.x", "11.0").WithLocation(22, 12), + // (32,12): error CS0171: Field 'S3.x' must be fully assigned before control is returned to the caller. Consider updating to language version '11.0' to auto-default the field. // public S3() - Diagnostic(ErrorCode.ERR_UnassignedThisUnsupportedVersion, "S3").WithArguments("S3.x", "preview").WithLocation(32, 12)); + Diagnostic(ErrorCode.ERR_UnassignedThisUnsupportedVersion, "S3").WithArguments("S3.x", "11.0").WithLocation(32, 12)); var verifier = CompileAndVerify(source, expectedOutput: @"(0, 0) @@ -1469,12 +1469,12 @@ static void Main() var comp = CreateCompilation(source, parseOptions: TestOptions.Regular10); comp.VerifyDiagnostics( - // (11,12): error CS0171: Field 'S1.y' must be fully assigned before control is returned to the caller. Consider updating to language version 'preview' to auto-default the field. + // (11,12): error CS0171: Field 'S1.y' must be fully assigned before control is returned to the caller. Consider updating to language version '11.0' to auto-default the field. // public S1() { } - Diagnostic(ErrorCode.ERR_UnassignedThisUnsupportedVersion, "S1").WithArguments("S1.y", "preview").WithLocation(11, 12), - // (22,12): error CS0171: Field 'S2.y' must be fully assigned before control is returned to the caller. Consider updating to language version 'preview' to auto-default the field. + Diagnostic(ErrorCode.ERR_UnassignedThisUnsupportedVersion, "S1").WithArguments("S1.y", "11.0").WithLocation(11, 12), + // (22,12): error CS0171: Field 'S2.y' must be fully assigned before control is returned to the caller. Consider updating to language version '11.0' to auto-default the field. // public S2() { } - Diagnostic(ErrorCode.ERR_UnassignedThisUnsupportedVersion, "S2").WithArguments("S2.y", "preview").WithLocation(22, 12)); + Diagnostic(ErrorCode.ERR_UnassignedThisUnsupportedVersion, "S2").WithArguments("S2.y", "11.0").WithLocation(22, 12)); var verifier = CompileAndVerify(source, expectedOutput: @"(1, 0) @@ -1577,15 +1577,15 @@ public R1(int y) // (3,14): error CS0236: A field initializer cannot reference the non-static field, method, or property 'S1.y1' // int x1 = y1 + 1; Diagnostic(ErrorCode.ERR_FieldInitRefNonstatic, "y1").WithArguments("S1.y1").WithLocation(3, 14), - // (3,14): error CS9015: Use of possibly unassigned field 'y1'. Consider updating to language version 'preview' to auto-default the field. + // (3,14): error CS9015: Use of possibly unassigned field 'y1'. Consider updating to language version '11.0' to auto-default the field. // int x1 = y1 + 1; - Diagnostic(ErrorCode.ERR_UseDefViolationFieldUnsupportedVersion, "y1").WithArguments("y1", "preview").WithLocation(3, 14), + Diagnostic(ErrorCode.ERR_UseDefViolationFieldUnsupportedVersion, "y1").WithArguments("y1", "11.0").WithLocation(3, 14), // (12,14): error CS0236: A field initializer cannot reference the non-static field, method, or property 'R1.y1' // int x1 = y1 + 1; Diagnostic(ErrorCode.ERR_FieldInitRefNonstatic, "y1").WithArguments("R1.y1").WithLocation(12, 14), - // (12,14): error CS9015: Use of possibly unassigned field 'y1'. Consider updating to language version 'preview' to auto-default the field. + // (12,14): error CS9015: Use of possibly unassigned field 'y1'. Consider updating to language version '11.0' to auto-default the field. // int x1 = y1 + 1; - Diagnostic(ErrorCode.ERR_UseDefViolationFieldUnsupportedVersion, "y1").WithArguments("y1", "preview").WithLocation(12, 14)); + Diagnostic(ErrorCode.ERR_UseDefViolationFieldUnsupportedVersion, "y1").WithArguments("y1", "11.0").WithLocation(12, 14)); comp = CreateCompilation(source); comp.VerifyDiagnostics( @@ -1663,15 +1663,15 @@ public R3(int y) // (3,14): error CS0236: A field initializer cannot reference the non-static field, method, or property 'S3.y3' // int x3 = y3 + 1; Diagnostic(ErrorCode.ERR_FieldInitRefNonstatic, "y3").WithArguments("S3.y3").WithLocation(3, 14), - // (3,14): error CS9015: Use of possibly unassigned field 'y3'. Consider updating to language version 'preview' to auto-default the field. + // (3,14): error CS9015: Use of possibly unassigned field 'y3'. Consider updating to language version '11.0' to auto-default the field. // int x3 = y3 + 1; - Diagnostic(ErrorCode.ERR_UseDefViolationFieldUnsupportedVersion, "y3").WithArguments("y3", "preview").WithLocation(3, 14), + Diagnostic(ErrorCode.ERR_UseDefViolationFieldUnsupportedVersion, "y3").WithArguments("y3", "11.0").WithLocation(3, 14), // (13,14): error CS0236: A field initializer cannot reference the non-static field, method, or property 'R3.y3' // int x3 = y3 + 1; Diagnostic(ErrorCode.ERR_FieldInitRefNonstatic, "y3").WithArguments("R3.y3").WithLocation(13, 14), - // (13,14): error CS9015: Use of possibly unassigned field 'y3'. Consider updating to language version 'preview' to auto-default the field. + // (13,14): error CS9015: Use of possibly unassigned field 'y3'. Consider updating to language version '11.0' to auto-default the field. // int x3 = y3 + 1; - Diagnostic(ErrorCode.ERR_UseDefViolationFieldUnsupportedVersion, "y3").WithArguments("y3", "preview").WithLocation(13, 14)); + Diagnostic(ErrorCode.ERR_UseDefViolationFieldUnsupportedVersion, "y3").WithArguments("y3", "11.0").WithLocation(13, 14)); comp = CreateCompilation(source); comp.VerifyDiagnostics( @@ -1720,12 +1720,12 @@ static void Main() var comp = CreateCompilation(source, parseOptions: TestOptions.Regular10); comp.VerifyDiagnostics( - // (8,12): error CS0171: Field 'S.x1' must be fully assigned before control is returned to the caller. Consider updating to language version 'preview' to auto-default the field. + // (8,12): error CS0171: Field 'S.x1' must be fully assigned before control is returned to the caller. Consider updating to language version '11.0' to auto-default the field. // public S(int unused) { } - Diagnostic(ErrorCode.ERR_UnassignedThisUnsupportedVersion, "S").WithArguments("S.x1", "preview").WithLocation(8, 12), - // (16,12): error CS0171: Field 'R.x2' must be fully assigned before control is returned to the caller. Consider updating to language version 'preview' to auto-default the field. + Diagnostic(ErrorCode.ERR_UnassignedThisUnsupportedVersion, "S").WithArguments("S.x1", "11.0").WithLocation(8, 12), + // (16,12): error CS0171: Field 'R.x2' must be fully assigned before control is returned to the caller. Consider updating to language version '11.0' to auto-default the field. // public R(int unused) { } - Diagnostic(ErrorCode.ERR_UnassignedThisUnsupportedVersion, "R").WithArguments("R.x2", "preview").WithLocation(16, 12)); + Diagnostic(ErrorCode.ERR_UnassignedThisUnsupportedVersion, "R").WithArguments("R.x2", "11.0").WithLocation(16, 12)); var verifier = CompileAndVerify(source, expectedOutput: @"(0, 1) @@ -1975,14 +1975,14 @@ static void Main() // (13,12): error CS8773: Feature 'parameterless struct constructors' is not available in C# 9.0. Please use language version 10.0 or greater. // public S1() { Y = 1; } Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion9, "S1").WithArguments("parameterless struct constructors", "10.0").WithLocation(13, 12), - // (13,12): error CS0171: Field 'S1.X' must be fully assigned before control is returned to the caller. Consider updating to language version 'preview' to auto-default the field. + // (13,12): error CS0171: Field 'S1.X' must be fully assigned before control is returned to the caller. Consider updating to language version '11.0' to auto-default the field. // public S1() { Y = 1; } - Diagnostic(ErrorCode.ERR_UnassignedThisUnsupportedVersion, "S1").WithArguments("S1.X", "preview").WithLocation(13, 12), - // (20,12): error CS0171: Field 'S2.X' must be fully assigned before control is returned to the caller. Consider updating to language version 'preview' to auto-default the field. + Diagnostic(ErrorCode.ERR_UnassignedThisUnsupportedVersion, "S1").WithArguments("S1.X", "11.0").WithLocation(13, 12), + // (20,12): error CS0171: Field 'S2.X' must be fully assigned before control is returned to the caller. Consider updating to language version '11.0' to auto-default the field. // public S2(object y) { Y = y; } - Diagnostic(ErrorCode.ERR_UnassignedThisUnsupportedVersion, "S2").WithArguments("S2.X", "preview").WithLocation(20, 12)); + Diagnostic(ErrorCode.ERR_UnassignedThisUnsupportedVersion, "S2").WithArguments("S2.X", "11.0").WithLocation(20, 12)); - var verifier = CompileAndVerify(source, parseOptions: TestOptions.RegularNext, expectedOutput: + var verifier = CompileAndVerify(source, parseOptions: TestOptions.Regular11, expectedOutput: @"(, ) (, 1) (, )"); @@ -2015,14 +2015,14 @@ static void Main() // (7,12): error CS8773: Feature 'parameterless struct constructors' is not available in C# 9.0. Please use language version 10.0 or greater. // public S0() { } Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion9, "S0").WithArguments("parameterless struct constructors", "10.0").WithLocation(7, 12), - // (7,12): error CS0171: Field 'S0.Y' must be fully assigned before control is returned to the caller. Consider updating to language version 'preview' to auto-default the field. + // (7,12): error CS0171: Field 'S0.Y' must be fully assigned before control is returned to the caller. Consider updating to language version '11.0' to auto-default the field. // public S0() { } - Diagnostic(ErrorCode.ERR_UnassignedThisUnsupportedVersion, "S0").WithArguments("S0.Y", "preview").WithLocation(7, 12), - // (7,12): error CS0171: Field 'S0.X' must be fully assigned before control is returned to the caller. Consider updating to language version 'preview' to auto-default the field. + Diagnostic(ErrorCode.ERR_UnassignedThisUnsupportedVersion, "S0").WithArguments("S0.Y", "11.0").WithLocation(7, 12), + // (7,12): error CS0171: Field 'S0.X' must be fully assigned before control is returned to the caller. Consider updating to language version '11.0' to auto-default the field. // public S0() { } - Diagnostic(ErrorCode.ERR_UnassignedThisUnsupportedVersion, "S0").WithArguments("S0.X", "preview").WithLocation(7, 12)); + Diagnostic(ErrorCode.ERR_UnassignedThisUnsupportedVersion, "S0").WithArguments("S0.X", "11.0").WithLocation(7, 12)); - var verifier = CompileAndVerify(source, parseOptions: TestOptions.RegularNext, expectedOutput: "(, )"); + var verifier = CompileAndVerify(source, parseOptions: TestOptions.Regular11, expectedOutput: "(, )"); verifier.VerifyDiagnostics(); verifier.VerifyIL("S0..ctor", @" @@ -2546,18 +2546,18 @@ struct S4 // (11,12): error CS8773: Feature 'parameterless struct constructors' is not available in C# 9.0. Please use language version 10.0 or greater. // public S2() { } Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion9, "S2").WithArguments("parameterless struct constructors", "10.0").WithLocation(11, 12), - // (11,12): error CS0171: Field 'S2.Y' must be fully assigned before control is returned to the caller. Consider updating to language version 'preview' to auto-default the field. + // (11,12): error CS0171: Field 'S2.Y' must be fully assigned before control is returned to the caller. Consider updating to language version '11.0' to auto-default the field. // public S2() { } - Diagnostic(ErrorCode.ERR_UnassignedThisUnsupportedVersion, "S2").WithArguments("S2.Y", "preview").WithLocation(11, 12), + Diagnostic(ErrorCode.ERR_UnassignedThisUnsupportedVersion, "S2").WithArguments("S2.Y", "11.0").WithLocation(11, 12), // (16,21): error CS8773: Feature 'struct field initializers' is not available in C# 9.0. Please use language version 10.0 or greater. // internal object Y = 3; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion9, "Y").WithArguments("struct field initializers", "10.0").WithLocation(16, 21), // (17,12): error CS8773: Feature 'parameterless struct constructors' is not available in C# 9.0. Please use language version 10.0 or greater. // public S3() { Y = 3; } Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion9, "S3").WithArguments("parameterless struct constructors", "10.0").WithLocation(17, 12), - // (17,12): error CS0171: Field 'S3.X' must be fully assigned before control is returned to the caller. Consider updating to language version 'preview' to auto-default the field. + // (17,12): error CS0171: Field 'S3.X' must be fully assigned before control is returned to the caller. Consider updating to language version '11.0' to auto-default the field. // public S3() { Y = 3; } - Diagnostic(ErrorCode.ERR_UnassignedThisUnsupportedVersion, "S3").WithArguments("S3.X", "preview").WithLocation(17, 12), + Diagnostic(ErrorCode.ERR_UnassignedThisUnsupportedVersion, "S3").WithArguments("S3.X", "11.0").WithLocation(17, 12), // (22,21): error CS8773: Feature 'struct field initializers' is not available in C# 9.0. Please use language version 10.0 or greater. // internal object Y = 4; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion9, "Y").WithArguments("struct field initializers", "10.0").WithLocation(22, 21), @@ -2570,14 +2570,14 @@ struct S4 // (2,8): error CS8983: A 'struct' with field initializers must include an explicitly declared constructor. // struct S1 Diagnostic(ErrorCode.ERR_StructHasInitializersAndNoDeclaredConstructor, "S1").WithLocation(2, 8), - // (11,12): error CS0171: Field 'S2.Y' must be fully assigned before control is returned to the caller. Consider updating to language version 'preview' to auto-default the field. + // (11,12): error CS0171: Field 'S2.Y' must be fully assigned before control is returned to the caller. Consider updating to language version '11.0' to auto-default the field. // public S2() { } - Diagnostic(ErrorCode.ERR_UnassignedThisUnsupportedVersion, "S2").WithArguments("S2.Y", "preview").WithLocation(11, 12), - // (17,12): error CS0171: Field 'S3.X' must be fully assigned before control is returned to the caller. Consider updating to language version 'preview' to auto-default the field. + Diagnostic(ErrorCode.ERR_UnassignedThisUnsupportedVersion, "S2").WithArguments("S2.Y", "11.0").WithLocation(11, 12), + // (17,12): error CS0171: Field 'S3.X' must be fully assigned before control is returned to the caller. Consider updating to language version '11.0' to auto-default the field. // public S3() { Y = 3; } - Diagnostic(ErrorCode.ERR_UnassignedThisUnsupportedVersion, "S3").WithArguments("S3.X", "preview").WithLocation(17, 12)); + Diagnostic(ErrorCode.ERR_UnassignedThisUnsupportedVersion, "S3").WithArguments("S3.X", "11.0").WithLocation(17, 12)); - comp = CreateCompilation(source, parseOptions: TestOptions.RegularNext); + comp = CreateCompilation(source, parseOptions: TestOptions.Regular11); comp.VerifyDiagnostics( // (2,8): error CS8983: A 'struct' with field initializers must include an explicitly declared constructor. // struct S1 @@ -2628,18 +2628,18 @@ struct S4 // (11,12): error CS8773: Feature 'parameterless struct constructors' is not available in C# 9.0. Please use language version 10.0 or greater. // public S2() { } Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion9, "S2").WithArguments("parameterless struct constructors", "10.0").WithLocation(11, 12), - // (11,12): error CS0843: Auto-implemented property 'S2.Y' must be fully assigned before control is returned to the caller. Consider updating to language version 'preview' to auto-default the property. + // (11,12): error CS0843: Auto-implemented property 'S2.Y' must be fully assigned before control is returned to the caller. Consider updating to language version '11.0' to auto-default the property. // public S2() { } - Diagnostic(ErrorCode.ERR_UnassignedThisAutoPropertyUnsupportedVersion, "S2").WithArguments("S2.Y", "preview").WithLocation(11, 12), + Diagnostic(ErrorCode.ERR_UnassignedThisAutoPropertyUnsupportedVersion, "S2").WithArguments("S2.Y", "11.0").WithLocation(11, 12), // (16,21): error CS8773: Feature 'struct field initializers' is not available in C# 9.0. Please use language version 10.0 or greater. // internal object Y { get; } = 3; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion9, "Y").WithArguments("struct field initializers", "10.0").WithLocation(16, 21), // (17,12): error CS8773: Feature 'parameterless struct constructors' is not available in C# 9.0. Please use language version 10.0 or greater. // public S3() { Y = 3; } Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion9, "S3").WithArguments("parameterless struct constructors", "10.0").WithLocation(17, 12), - // (17,12): error CS0843: Auto-implemented property 'S3.X' must be fully assigned before control is returned to the caller. Consider updating to language version 'preview' to auto-default the property. + // (17,12): error CS0843: Auto-implemented property 'S3.X' must be fully assigned before control is returned to the caller. Consider updating to language version '11.0' to auto-default the property. // public S3() { Y = 3; } - Diagnostic(ErrorCode.ERR_UnassignedThisAutoPropertyUnsupportedVersion, "S3").WithArguments("S3.X", "preview").WithLocation(17, 12), + Diagnostic(ErrorCode.ERR_UnassignedThisAutoPropertyUnsupportedVersion, "S3").WithArguments("S3.X", "11.0").WithLocation(17, 12), // (22,21): error CS8773: Feature 'struct field initializers' is not available in C# 9.0. Please use language version 10.0 or greater. // internal object Y { get; } = 4; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion9, "Y").WithArguments("struct field initializers", "10.0").WithLocation(22, 21), @@ -2652,14 +2652,14 @@ struct S4 // (2,8): error CS8983: A 'struct' with field initializers must include an explicitly declared constructor. // struct S1 Diagnostic(ErrorCode.ERR_StructHasInitializersAndNoDeclaredConstructor, "S1").WithLocation(2, 8), - // (11,12): error CS0843: Auto-implemented property 'S2.Y' must be fully assigned before control is returned to the caller. Consider updating to language version 'preview' to auto-default the property. + // (11,12): error CS0843: Auto-implemented property 'S2.Y' must be fully assigned before control is returned to the caller. Consider updating to language version '11.0' to auto-default the property. // public S2() { } - Diagnostic(ErrorCode.ERR_UnassignedThisAutoPropertyUnsupportedVersion, "S2").WithArguments("S2.Y", "preview").WithLocation(11, 12), - // (17,12): error CS0843: Auto-implemented property 'S3.X' must be fully assigned before control is returned to the caller. Consider updating to language version 'preview' to auto-default the property. + Diagnostic(ErrorCode.ERR_UnassignedThisAutoPropertyUnsupportedVersion, "S2").WithArguments("S2.Y", "11.0").WithLocation(11, 12), + // (17,12): error CS0843: Auto-implemented property 'S3.X' must be fully assigned before control is returned to the caller. Consider updating to language version '11.0' to auto-default the property. // public S3() { Y = 3; } - Diagnostic(ErrorCode.ERR_UnassignedThisAutoPropertyUnsupportedVersion, "S3").WithArguments("S3.X", "preview").WithLocation(17, 12)); + Diagnostic(ErrorCode.ERR_UnassignedThisAutoPropertyUnsupportedVersion, "S3").WithArguments("S3.X", "11.0").WithLocation(17, 12)); - comp = CreateCompilation(source, parseOptions: TestOptions.RegularNext); + comp = CreateCompilation(source, parseOptions: TestOptions.Regular11); comp.VerifyDiagnostics( // (2,8): error CS8983: A 'struct' with field initializers must include an explicitly declared constructor. // struct S1 @@ -2702,14 +2702,14 @@ record struct S4 // (2,15): error CS8983: A 'struct' with field initializers must include an explicitly declared constructor. // record struct S1 Diagnostic(ErrorCode.ERR_StructHasInitializersAndNoDeclaredConstructor, "S1").WithLocation(2, 15), - // (11,12): error CS0843: Auto-implemented property 'S2.Y' must be fully assigned before control is returned to the caller. Consider updating to language version 'preview' to auto-default the property. + // (11,12): error CS0843: Auto-implemented property 'S2.Y' must be fully assigned before control is returned to the caller. Consider updating to language version '11.0' to auto-default the property. // public S2() { } - Diagnostic(ErrorCode.ERR_UnassignedThisAutoPropertyUnsupportedVersion, "S2").WithArguments("S2.Y", "preview").WithLocation(11, 12), - // (17,12): error CS0843: Auto-implemented property 'S3.X' must be fully assigned before control is returned to the caller. Consider updating to language version 'preview' to auto-default the property. + Diagnostic(ErrorCode.ERR_UnassignedThisAutoPropertyUnsupportedVersion, "S2").WithArguments("S2.Y", "11.0").WithLocation(11, 12), + // (17,12): error CS0843: Auto-implemented property 'S3.X' must be fully assigned before control is returned to the caller. Consider updating to language version '11.0' to auto-default the property. // public S3() { Y = 3; } - Diagnostic(ErrorCode.ERR_UnassignedThisAutoPropertyUnsupportedVersion, "S3").WithArguments("S3.X", "preview").WithLocation(17, 12)); + Diagnostic(ErrorCode.ERR_UnassignedThisAutoPropertyUnsupportedVersion, "S3").WithArguments("S3.X", "11.0").WithLocation(17, 12)); - comp = CreateCompilation(new[] { source, IsExternalInitTypeDefinition }, parseOptions: TestOptions.RegularNext); + comp = CreateCompilation(new[] { source, IsExternalInitTypeDefinition }, parseOptions: TestOptions.Regular11); comp.VerifyDiagnostics( // (2,15): error CS8983: A 'struct' with field initializers must include an explicitly declared constructor. // record struct S1 @@ -2752,17 +2752,17 @@ static void Main() var comp = CreateCompilation(new[] { source, IsExternalInitTypeDefinition }, parseOptions: TestOptions.Regular10); comp.VerifyDiagnostics( - // (5,15): error CS0171: Field 'S1.Y' must be fully assigned before control is returned to the caller. Consider updating to language version 'preview' to auto-default the field. + // (5,15): error CS0171: Field 'S1.Y' must be fully assigned before control is returned to the caller. Consider updating to language version '11.0' to auto-default the field. // record struct S1() - Diagnostic(ErrorCode.ERR_UnassignedThisUnsupportedVersion, "S1").WithArguments("S1.Y", "preview").WithLocation(5, 15), - // (10,15): error CS0843: Auto-implemented property 'S2.Y' must be fully assigned before control is returned to the caller. Consider updating to language version 'preview' to auto-default the property. + Diagnostic(ErrorCode.ERR_UnassignedThisUnsupportedVersion, "S1").WithArguments("S1.Y", "11.0").WithLocation(5, 15), + // (10,15): error CS0843: Auto-implemented property 'S2.Y' must be fully assigned before control is returned to the caller. Consider updating to language version '11.0' to auto-default the property. // record struct S2() - Diagnostic(ErrorCode.ERR_UnassignedThisAutoPropertyUnsupportedVersion, "S2").WithArguments("S2.Y", "preview").WithLocation(10, 15), - // (15,15): error CS0843: Auto-implemented property 'S3.X' must be fully assigned before control is returned to the caller. Consider updating to language version 'preview' to auto-default the property. + Diagnostic(ErrorCode.ERR_UnassignedThisAutoPropertyUnsupportedVersion, "S2").WithArguments("S2.Y", "11.0").WithLocation(10, 15), + // (15,15): error CS0843: Auto-implemented property 'S3.X' must be fully assigned before control is returned to the caller. Consider updating to language version '11.0' to auto-default the property. // record struct S3() - Diagnostic(ErrorCode.ERR_UnassignedThisAutoPropertyUnsupportedVersion, "S3").WithArguments("S3.X", "preview").WithLocation(15, 15)); + Diagnostic(ErrorCode.ERR_UnassignedThisAutoPropertyUnsupportedVersion, "S3").WithArguments("S3.X", "11.0").WithLocation(15, 15)); - var verifier = CompileAndVerify(new[] { source, IsExternalInitTypeDefinition }, parseOptions: TestOptions.RegularNext, expectedOutput: + var verifier = CompileAndVerify(new[] { source, IsExternalInitTypeDefinition }, parseOptions: TestOptions.Regular11, expectedOutput: @" S1 { X = 1, Y = } S2 { X = 2, Y = } @@ -2854,26 +2854,26 @@ static void Main() var comp = CreateCompilation(new[] { source, IsExternalInitTypeDefinition }, parseOptions: TestOptions.Regular10); comp.VerifyDiagnostics( - // (5,15): error CS0171: Field 'S1.Y' must be fully assigned before control is returned to the caller. Consider updating to language version 'preview' to auto-default the field. + // (5,15): error CS0171: Field 'S1.Y' must be fully assigned before control is returned to the caller. Consider updating to language version '11.0' to auto-default the field. // record struct S1(object X) - Diagnostic(ErrorCode.ERR_UnassignedThisUnsupportedVersion, "S1").WithArguments("S1.Y", "preview").WithLocation(5, 15), + Diagnostic(ErrorCode.ERR_UnassignedThisUnsupportedVersion, "S1").WithArguments("S1.Y", "11.0").WithLocation(5, 15), // (5,25): warning CS8907: Parameter 'X' is unread. Did you forget to use it to initialize the property with that name? // record struct S1(object X) Diagnostic(ErrorCode.WRN_UnreadRecordParameter, "X").WithArguments("X").WithLocation(5, 25), - // (10,15): error CS0843: Auto-implemented property 'S2.Y' must be fully assigned before control is returned to the caller. Consider updating to language version 'preview' to auto-default the property. + // (10,15): error CS0843: Auto-implemented property 'S2.Y' must be fully assigned before control is returned to the caller. Consider updating to language version '11.0' to auto-default the property. // record struct S2(object X) - Diagnostic(ErrorCode.ERR_UnassignedThisAutoPropertyUnsupportedVersion, "S2").WithArguments("S2.Y", "preview").WithLocation(10, 15), + Diagnostic(ErrorCode.ERR_UnassignedThisAutoPropertyUnsupportedVersion, "S2").WithArguments("S2.Y", "11.0").WithLocation(10, 15), // (10,25): warning CS8907: Parameter 'X' is unread. Did you forget to use it to initialize the property with that name? // record struct S2(object X) Diagnostic(ErrorCode.WRN_UnreadRecordParameter, "X").WithArguments("X").WithLocation(10, 25), - // (15,15): error CS0843: Auto-implemented property 'S3.X' must be fully assigned before control is returned to the caller. Consider updating to language version 'preview' to auto-default the property. + // (15,15): error CS0843: Auto-implemented property 'S3.X' must be fully assigned before control is returned to the caller. Consider updating to language version '11.0' to auto-default the property. // record struct S3(object Y) - Diagnostic(ErrorCode.ERR_UnassignedThisAutoPropertyUnsupportedVersion, "S3").WithArguments("S3.X", "preview").WithLocation(15, 15), + Diagnostic(ErrorCode.ERR_UnassignedThisAutoPropertyUnsupportedVersion, "S3").WithArguments("S3.X", "11.0").WithLocation(15, 15), // (15,25): warning CS8907: Parameter 'Y' is unread. Did you forget to use it to initialize the property with that name? // record struct S3(object Y) Diagnostic(ErrorCode.WRN_UnreadRecordParameter, "Y").WithArguments("Y").WithLocation(15, 25)); - var verifier = CompileAndVerify(new[] { source, IsExternalInitTypeDefinition }, parseOptions: TestOptions.RegularNext, expectedOutput: + var verifier = CompileAndVerify(new[] { source, IsExternalInitTypeDefinition }, parseOptions: TestOptions.Regular11, expectedOutput: @"S1 { X = 1, Y = } S2 { X = 2, Y = } S3 { X = , Y = 3 } @@ -2925,26 +2925,26 @@ static void Main() "; var comp = CreateCompilation(new[] { source, IsExternalInitTypeDefinition }, parseOptions: TestOptions.Regular10); comp.VerifyDiagnostics( - // (5,15): error CS0171: Field 'S1.X' must be fully assigned before control is returned to the caller. Consider updating to language version 'preview' to auto-default the field. + // (5,15): error CS0171: Field 'S1.X' must be fully assigned before control is returned to the caller. Consider updating to language version '11.0' to auto-default the field. // record struct S1(object X) - Diagnostic(ErrorCode.ERR_UnassignedThisUnsupportedVersion, "S1").WithArguments("S1.X", "preview").WithLocation(5, 15), + Diagnostic(ErrorCode.ERR_UnassignedThisUnsupportedVersion, "S1").WithArguments("S1.X", "11.0").WithLocation(5, 15), // (5,25): warning CS8907: Parameter 'X' is unread. Did you forget to use it to initialize the property with that name? // record struct S1(object X) Diagnostic(ErrorCode.WRN_UnreadRecordParameter, "X").WithArguments("X").WithLocation(5, 25), - // (10,15): error CS0843: Auto-implemented property 'S2.X' must be fully assigned before control is returned to the caller. Consider updating to language version 'preview' to auto-default the property. + // (10,15): error CS0843: Auto-implemented property 'S2.X' must be fully assigned before control is returned to the caller. Consider updating to language version '11.0' to auto-default the property. // record struct S2(object X) - Diagnostic(ErrorCode.ERR_UnassignedThisAutoPropertyUnsupportedVersion, "S2").WithArguments("S2.X", "preview").WithLocation(10, 15), + Diagnostic(ErrorCode.ERR_UnassignedThisAutoPropertyUnsupportedVersion, "S2").WithArguments("S2.X", "11.0").WithLocation(10, 15), // (10,25): warning CS8907: Parameter 'X' is unread. Did you forget to use it to initialize the property with that name? // record struct S2(object X) Diagnostic(ErrorCode.WRN_UnreadRecordParameter, "X").WithArguments("X").WithLocation(10, 25), - // (15,15): error CS0843: Auto-implemented property 'S3.Y' must be fully assigned before control is returned to the caller. Consider updating to language version 'preview' to auto-default the property. + // (15,15): error CS0843: Auto-implemented property 'S3.Y' must be fully assigned before control is returned to the caller. Consider updating to language version '11.0' to auto-default the property. // record struct S3(object Y) - Diagnostic(ErrorCode.ERR_UnassignedThisAutoPropertyUnsupportedVersion, "S3").WithArguments("S3.Y", "preview").WithLocation(15, 15), + Diagnostic(ErrorCode.ERR_UnassignedThisAutoPropertyUnsupportedVersion, "S3").WithArguments("S3.Y", "11.0").WithLocation(15, 15), // (15,25): warning CS8907: Parameter 'Y' is unread. Did you forget to use it to initialize the property with that name? // record struct S3(object Y) Diagnostic(ErrorCode.WRN_UnreadRecordParameter, "Y").WithArguments("Y").WithLocation(15, 25)); - var verifier = CompileAndVerify(new[] { source, IsExternalInitTypeDefinition }, parseOptions: TestOptions.RegularNext, expectedOutput: + var verifier = CompileAndVerify(new[] { source, IsExternalInitTypeDefinition }, parseOptions: TestOptions.Regular11, expectedOutput: @"S1 { X = , Y = 1 } S2 { X = , Y = 2 } S3 { X = 3, Y = }", verify: Verification.Skipped); @@ -3278,15 +3278,15 @@ struct S3 // (10,12): warning CS8618: Non-nullable field 'F1' must contain a non-null value when exiting constructor. Consider declaring the field as nullable. // public S1() { } Diagnostic(ErrorCode.WRN_UninitializedNonNullableField, "S1").WithArguments("field", "F1").WithLocation(10, 12), - // (10,12): error CS0171: Field 'S1.F1' must be fully assigned before control is returned to the caller. Consider updating to language version 'preview' to auto-default the field. + // (10,12): error CS0171: Field 'S1.F1' must be fully assigned before control is returned to the caller. Consider updating to language version '11.0' to auto-default the field. // public S1() { } - Diagnostic(ErrorCode.ERR_UnassignedThisUnsupportedVersion, "S1").WithArguments("S1.F1", "preview").WithLocation(10, 12), + Diagnostic(ErrorCode.ERR_UnassignedThisUnsupportedVersion, "S1").WithArguments("S1.F1", "11.0").WithLocation(10, 12), // (16,5): warning CS8618: Non-nullable field 'F2' must contain a non-null value when exiting constructor. Consider declaring the field as nullable. // S2(object? obj) { } Diagnostic(ErrorCode.WRN_UninitializedNonNullableField, "S2").WithArguments("field", "F2").WithLocation(16, 5), - // (16,5): error CS0171: Field 'S2.F2' must be fully assigned before control is returned to the caller. Consider updating to language version 'preview' to auto-default the field. + // (16,5): error CS0171: Field 'S2.F2' must be fully assigned before control is returned to the caller. Consider updating to language version '11.0' to auto-default the field. // S2(object? obj) { } - Diagnostic(ErrorCode.ERR_UnassignedThisUnsupportedVersion, "S2").WithArguments("S2.F2", "preview").WithLocation(16, 5), + Diagnostic(ErrorCode.ERR_UnassignedThisUnsupportedVersion, "S2").WithArguments("S2.F2", "11.0").WithLocation(16, 5), // (21,12): warning CS8618: Non-nullable field 'F3' must contain a non-null value when exiting constructor. Consider declaring the field as nullable. // public S3() { F3 = GetValue(); } Diagnostic(ErrorCode.WRN_UninitializedNonNullableField, "S3").WithArguments("field", "F3").WithLocation(21, 12), @@ -3294,7 +3294,7 @@ struct S3 // public S3() { F3 = GetValue(); } Diagnostic(ErrorCode.WRN_NullReferenceAssignment, "GetValue()").WithLocation(21, 24)); - comp = CreateCompilation(source, parseOptions: TestOptions.RegularNext); + comp = CreateCompilation(source, parseOptions: TestOptions.Regular11); comp.VerifyDiagnostics( // (10,12): warning CS8618: Non-nullable field 'F1' must contain a non-null value when exiting constructor. Consider declaring the field as nullable. // public S1() { } @@ -3405,9 +3405,9 @@ unsafe struct S5 var comp = CreateCompilation(source, options: TestOptions.UnsafeReleaseDll, parseOptions: TestOptions.Regular10); comp.VerifyDiagnostics( - // (20,12): error CS0171: Field 'S3.X' must be fully assigned before control is returned to the caller. Consider updating to language version 'preview' to auto-default the field. + // (20,12): error CS0171: Field 'S3.X' must be fully assigned before control is returned to the caller. Consider updating to language version '11.0' to auto-default the field. // public S3() { } - Diagnostic(ErrorCode.ERR_UnassignedThisUnsupportedVersion, "S3").WithArguments("S3.X", "preview").WithLocation(20, 12), + Diagnostic(ErrorCode.ERR_UnassignedThisUnsupportedVersion, "S3").WithArguments("S3.X", "11.0").WithLocation(20, 12), // (22,15): error CS8983: A 'struct' with field initializers must include an explicitly declared constructor. // unsafe struct S4 Diagnostic(ErrorCode.ERR_StructHasInitializersAndNoDeclaredConstructor, "S4").WithLocation(22, 15), @@ -3415,7 +3415,7 @@ unsafe struct S5 // int X; Diagnostic(ErrorCode.WRN_UnreferencedFieldAssg, "X").WithArguments("S5.X").WithLocation(29, 9)); - comp = CreateCompilation(source, options: TestOptions.UnsafeReleaseDll, parseOptions: TestOptions.RegularNext); + comp = CreateCompilation(source, options: TestOptions.UnsafeReleaseDll, parseOptions: TestOptions.Regular11); comp.VerifyDiagnostics( // (22,15): error CS8983: A 'struct' with field initializers must include an explicitly declared constructor. // unsafe struct S4 @@ -3767,9 +3767,9 @@ public Example() {} }"; var comp = CreateCompilationWithSpan(source, parseOptions: TestOptions.Regular10); comp.VerifyDiagnostics( - // (5,31): error CS0188: The 'this' object cannot be used before all of its fields have been assigned. Consider updating to language version 'preview' to auto-default the unassigned fields. + // (5,31): error CS0188: The 'this' object cannot be used before all of its fields have been assigned. Consider updating to language version '11.0' to auto-default the unassigned fields. // public Span Field = F(() => stackalloc byte[512]); - Diagnostic(ErrorCode.ERR_UseDefViolationThisUnsupportedVersion, "F").WithArguments("preview").WithLocation(5, 31), + Diagnostic(ErrorCode.ERR_UseDefViolationThisUnsupportedVersion, "F").WithArguments("11.0").WithLocation(5, 31), // (5,39): error CS8353: A result of a stackalloc expression of type 'Span' cannot be used in this context because it may be exposed outside of the containing method // public Span Field = F(() => stackalloc byte[512]); Diagnostic(ErrorCode.ERR_EscapeStackAlloc, "stackalloc byte[512]").WithArguments("System.Span").WithLocation(5, 39), @@ -3898,23 +3898,23 @@ public S() { } }"; CreateCompilation(source, parseOptions: TestOptions.Regular10) .VerifyDiagnostics( - // (5,12): error CS0171: Field 'S.x' must be fully assigned before control is returned to the caller. Consider updating to language version 'preview' to auto-default the field. + // (5,12): error CS0171: Field 'S.x' must be fully assigned before control is returned to the caller. Consider updating to language version '11.0' to auto-default the field. // public S() { } - Diagnostic(ErrorCode.ERR_UnassignedThisUnsupportedVersion, "S").WithArguments("S.x", "preview").WithLocation(5, 12)); + Diagnostic(ErrorCode.ERR_UnassignedThisUnsupportedVersion, "S").WithArguments("S.x", "11.0").WithLocation(5, 12)); - CreateCompilation(source, options: TestOptions.DebugDll.WithSpecificDiagnosticOptions(ReportStructInitializationWarnings), parseOptions: TestOptions.RegularNext) + CreateCompilation(source, options: TestOptions.DebugDll.WithSpecificDiagnosticOptions(ReportStructInitializationWarnings), parseOptions: TestOptions.Regular11) .VerifyDiagnostics( // (5,12): warning CS9021: Control is returned to caller before field 'S.x' is explicitly assigned, causing a preceding implicit assignment of 'default'. // public S() { } Diagnostic(ErrorCode.WRN_UnassignedThisSupportedVersion, "S").WithArguments("S.x").WithLocation(5, 12)); - CreateCompilation(source, options: TestOptions.DebugDll.WithSpecificDiagnosticOptions(GetIdForErrorCode(ErrorCode.WRN_UnassignedThisSupportedVersion), ReportDiagnostic.Error), parseOptions: TestOptions.RegularNext) + CreateCompilation(source, options: TestOptions.DebugDll.WithSpecificDiagnosticOptions(GetIdForErrorCode(ErrorCode.WRN_UnassignedThisSupportedVersion), ReportDiagnostic.Error), parseOptions: TestOptions.Regular11) .VerifyDiagnostics( // (5,12): error CS9021: Control is returned to caller before field 'S.x' is explicitly assigned, causing a preceding implicit assignment of 'default'. // public S() { } Diagnostic(ErrorCode.WRN_UnassignedThisSupportedVersion, "S").WithArguments("S.x").WithLocation(5, 12).WithWarningAsError(true)); - var verifier = CompileAndVerify(source, parseOptions: TestOptions.RegularNext); + var verifier = CompileAndVerify(source, parseOptions: TestOptions.Regular11); verifier.VerifyDiagnostics(); verifier.VerifyIL("S..ctor()", @" @@ -3929,6 +3929,46 @@ .maxstack 2 "); } + [Fact] + public void ImplicitlyInitializedField_Pointer() + { + var source = """ +using System; + +_ = new R(); + +unsafe struct R +{ + public int* field; + + public R() + { + Console.WriteLine("explicit ctor"); + } +} +"""; + var comp = CreateCompilation(source, options: TestOptions.UnsafeDebugExe); + comp.VerifyDiagnostics( + // (7,17): warning CS0649: Field 'R.field' is never assigned to, and will always have its default value + // public int* field; + Diagnostic(ErrorCode.WRN_UnassignedInternalField, "field").WithArguments("R.field", "").WithLocation(7, 17) + ); + var verifier = CompileAndVerify(comp, verify: Verification.Skipped, expectedOutput: "explicit ctor"); + verifier.VerifyIL("R..ctor()", @" +{ + // Code size 25 (0x19) + .maxstack 1 + IL_0000: nop + IL_0001: ldarg.0 + IL_0002: ldflda ""int* R.field"" + IL_0007: initobj ""int*"" + IL_000d: ldstr ""explicit ctor"" + IL_0012: call ""void System.Console.WriteLine(string)"" + IL_0017: nop + IL_0018: ret +}"); + } + [Fact] public void ImplicitlyInitializedField_NotOtherStruct() { @@ -3947,9 +3987,9 @@ public S() // 1 }"; CreateCompilation(source, parseOptions: TestOptions.Regular10) .VerifyDiagnostics( - // (5,12): error CS0171: Field 'S.x' must be fully assigned before control is returned to the caller. Consider updating to language version 'preview' to auto-default the field. + // (5,12): error CS0171: Field 'S.x' must be fully assigned before control is returned to the caller. Consider updating to language version '11.0' to auto-default the field. // public S() // 1 - Diagnostic(ErrorCode.ERR_UnassignedThisUnsupportedVersion, "S").WithArguments("S.x", "preview").WithLocation(5, 12), + Diagnostic(ErrorCode.ERR_UnassignedThisUnsupportedVersion, "S").WithArguments("S.x", "11.0").WithLocation(5, 12), // (8,9): error CS0170: Use of possibly unassigned field 'x' // other.x.ToString(); // 2 Diagnostic(ErrorCode.ERR_UseDefViolationField, "other.x").WithArguments("x").WithLocation(8, 9), @@ -3957,7 +3997,7 @@ public S() // 1 // other2.ToString(); // 3 Diagnostic(ErrorCode.ERR_UseDefViolation, "other2").WithArguments("other2").WithLocation(11, 9)); - CreateCompilation(source, options: TestOptions.DebugDll.WithSpecificDiagnosticOptions(ReportStructInitializationWarnings), parseOptions: TestOptions.RegularNext) + CreateCompilation(source, options: TestOptions.DebugDll.WithSpecificDiagnosticOptions(ReportStructInitializationWarnings), parseOptions: TestOptions.Regular11) .VerifyDiagnostics( // (5,12): warning CS9021: Control is returned to caller before field 'S.x' is explicitly assigned, causing a preceding implicit assignment of 'default'. // public S() // 1 @@ -3984,11 +4024,11 @@ public S() }"; var comp = CreateCompilation(source, parseOptions: TestOptions.Regular10); comp.VerifyDiagnostics( - // (7,9): error CS0171: Field 'S.x' must be fully assigned before control is returned to the caller. Consider updating to language version 'preview' to auto-default the field. + // (7,9): error CS0171: Field 'S.x' must be fully assigned before control is returned to the caller. Consider updating to language version '11.0' to auto-default the field. // return; - Diagnostic(ErrorCode.ERR_UnassignedThisUnsupportedVersion, "return;").WithArguments("S.x", "preview").WithLocation(7, 9)); + Diagnostic(ErrorCode.ERR_UnassignedThisUnsupportedVersion, "return;").WithArguments("S.x", "11.0").WithLocation(7, 9)); - var verifier = CompileAndVerify(source, options: TestOptions.DebugDll.WithSpecificDiagnosticOptions(ReportStructInitializationWarnings), parseOptions: TestOptions.RegularNext); + var verifier = CompileAndVerify(source, options: TestOptions.DebugDll.WithSpecificDiagnosticOptions(ReportStructInitializationWarnings), parseOptions: TestOptions.Regular11); verifier.VerifyDiagnostics( // (7,9): warning CS9021: Control is returned to caller before field 'S.x' is explicitly assigned, causing a preceding implicit assignment of 'default'. // return; @@ -4024,14 +4064,14 @@ public S() }"; var comp = CreateCompilation(source, parseOptions: TestOptions.Regular10); comp.VerifyDiagnostics( - // (7,12): error CS0171: Field 'S.E' must be fully assigned before control is returned to the caller. Consider updating to language version 'preview' to auto-default the field. + // (7,12): error CS0171: Field 'S.E' must be fully assigned before control is returned to the caller. Consider updating to language version '11.0' to auto-default the field. // public S() - Diagnostic(ErrorCode.ERR_UnassignedThisUnsupportedVersion, "S").WithArguments("S.E", "preview").WithLocation(7, 12), - // (9,9): error CS9014: Use of possibly unassigned field 'E'. Consider updating to language version 'preview' to auto-default the field. + Diagnostic(ErrorCode.ERR_UnassignedThisUnsupportedVersion, "S").WithArguments("S.E", "11.0").WithLocation(7, 12), + // (9,9): error CS9015: Use of possibly unassigned field 'E'. Consider updating to language version '11.0' to auto-default the field. // E?.Invoke(); - Diagnostic(ErrorCode.ERR_UseDefViolationFieldUnsupportedVersion, "E").WithArguments("E", "preview").WithLocation(9, 9)); + Diagnostic(ErrorCode.ERR_UseDefViolationFieldUnsupportedVersion, "E").WithArguments("E", "11.0").WithLocation(9, 9)); - var verifier = CompileAndVerify(source, options: TestOptions.DebugDll.WithSpecificDiagnosticOptions(ReportStructInitializationWarnings), parseOptions: TestOptions.RegularNext); + var verifier = CompileAndVerify(source, options: TestOptions.DebugDll.WithSpecificDiagnosticOptions(ReportStructInitializationWarnings), parseOptions: TestOptions.Regular11); verifier.VerifyDiagnostics( // (7,12): warning CS9021: Control is returned to caller before field 'S.E' is explicitly assigned, causing a preceding implicit assignment of 'default'. // public S() @@ -4063,7 +4103,7 @@ .maxstack 2 [Theory] [InlineData(LanguageVersion.CSharp10)] - [InlineData(LanguageVersionFacts.CSharpNext)] + [InlineData(LanguageVersion.CSharp11)] public void ImplicitlyInitializedFields_EmptyStruct(LanguageVersion languageVersion) { var source = @" @@ -4606,12 +4646,12 @@ public S(bool unused) // (4,12): warning CS8618: Non-nullable field 'Item' must contain a non-null value when exiting constructor. Consider declaring the field as nullable. // public S(bool unused) Diagnostic(ErrorCode.WRN_UninitializedNonNullableField, "S").WithArguments("field", "Item").WithLocation(4, 12), - // (4,12): error CS0171: Field 'S.Item' must be fully assigned before control is returned to the caller. Consider updating to language version 'preview' to auto-default the field. + // (4,12): error CS0171: Field 'S.Item' must be fully assigned before control is returned to the caller. Consider updating to language version '11.0' to auto-default the field. // public S(bool unused) - Diagnostic(ErrorCode.ERR_UnassignedThisUnsupportedVersion, "S").WithArguments("S.Item", "preview").WithLocation(4, 12) + Diagnostic(ErrorCode.ERR_UnassignedThisUnsupportedVersion, "S").WithArguments("S.Item", "11.0").WithLocation(4, 12) ); - var verifier = CompileAndVerify(new[] { source }, options: WithNullableEnable(), parseOptions: TestOptions.RegularNext); + var verifier = CompileAndVerify(new[] { source }, options: WithNullableEnable(), parseOptions: TestOptions.Regular11); verifier.VerifyDiagnostics( // (4,12): warning CS8618: Non-nullable field 'Item' must contain a non-null value when exiting constructor. Consider declaring the field as nullable. // public S(bool unused) @@ -4630,7 +4670,7 @@ .maxstack 2 [Theory] [InlineData(LanguageVersion.CSharp10)] - [InlineData(LanguageVersionFacts.CSharpNext)] + [InlineData(LanguageVersion.CSharp11)] public void Struct_ExplicitThisConstructorInitializer_01(LanguageVersion languageVersion) { var source = @@ -4661,7 +4701,7 @@ .maxstack 1 [Theory] [InlineData(LanguageVersion.CSharp10)] - [InlineData(LanguageVersionFacts.CSharpNext)] + [InlineData(LanguageVersion.CSharp11)] public void Struct_ExplicitThisConstructorInitializer_02(LanguageVersion languageVersion) { var source = diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/TopLevelStatementsTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/TopLevelStatementsTests.cs index 1355a19ac9cb8..98065b0ae78f7 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/TopLevelStatementsTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/TopLevelStatementsTests.cs @@ -7610,9 +7610,9 @@ public void Return_01() - + - + @@ -7657,9 +7657,9 @@ public void Return_02() - + - + @@ -7704,9 +7704,9 @@ public void Return_03() - + - + @@ -7735,8 +7735,8 @@ public void Return_03() - - + + @@ -7773,9 +7773,9 @@ public void Return_04() - + - + @@ -7805,8 +7805,8 @@ public void Return_04() - - + + diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/UninitializedNonNullableFieldTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/UninitializedNonNullableFieldTests.cs index 6d5516d56cb9e..9fc5c93299504 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/UninitializedNonNullableFieldTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/UninitializedNonNullableFieldTests.cs @@ -855,15 +855,15 @@ public S1(string s1, string s2) : this(s1) var comp = CreateCompilation(source, options: WithNullableEnable(), parseOptions: TestOptions.Regular10); comp.VerifyDiagnostics( - // (5,12): error CS0843: Auto-implemented property 'S1.Prop' must be fully assigned before control is returned to the caller. Consider updating to language version 'preview' to auto-default the property. + // (5,12): error CS0843: Auto-implemented property 'S1.Prop' must be fully assigned before control is returned to the caller. Consider updating to language version '11.0' to auto-default the property. // public S1(string s) // 1 - Diagnostic(ErrorCode.ERR_UnassignedThisAutoPropertyUnsupportedVersion, "S1").WithArguments("S1.Prop", "preview").WithLocation(5, 12), + Diagnostic(ErrorCode.ERR_UnassignedThisAutoPropertyUnsupportedVersion, "S1").WithArguments("S1.Prop", "11.0").WithLocation(5, 12), // (7,9): warning CS8602: Dereference of a possibly null reference. // Prop.ToString(); // 2 Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "Prop").WithLocation(7, 9), - // (7,9): error CS9013: Use of possibly unassigned auto-implemented property 'Prop'. Consider updating to language version 'preview' to auto-default the property. + // (7,9): error CS9014: Use of possibly unassigned auto-implemented property 'Prop'. Consider updating to language version '11.0' to auto-default the property. // Prop.ToString(); // 2 - Diagnostic(ErrorCode.ERR_UseDefViolationPropertyUnsupportedVersion, "Prop").WithArguments("Prop", "preview").WithLocation(7, 9), + Diagnostic(ErrorCode.ERR_UseDefViolationPropertyUnsupportedVersion, "Prop").WithArguments("Prop", "11.0").WithLocation(7, 9), // (12,9): warning CS8602: Dereference of a possibly null reference. // Prop.ToString(); // 3 Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "Prop").WithLocation(12, 9), @@ -871,7 +871,7 @@ public S1(string s1, string s2) : this(s1) // public S1(object obj1, object obj2) : this() // 4 Diagnostic(ErrorCode.WRN_UninitializedNonNullableField, "S1").WithArguments("property", "Prop").WithLocation(15, 12)); - var verifier = CompileAndVerify(source, options: WithNullableEnable(), parseOptions: TestOptions.RegularNext); + var verifier = CompileAndVerify(source, options: WithNullableEnable(), parseOptions: TestOptions.Regular11); verifier.VerifyDiagnostics( // (7,9): warning CS8602: Dereference of a possibly null reference. // Prop.ToString(); // 2 @@ -980,7 +980,7 @@ public struct S2 public object F2; } "; - var comp = CreateCompilation(source, parseOptions: TestOptions.RegularNext); + var comp = CreateCompilation(source, parseOptions: TestOptions.Regular11); comp.VerifyDiagnostics( // (10,9): warning CS8602: Dereference of a possibly null reference. // F1.ToString(); // 1 @@ -1054,15 +1054,15 @@ public S1(string s) // 1, 2 // (13,12): warning CS8618: Non-nullable field 'field' must contain a non-null value when exiting constructor. Consider declaring the field as nullable. // public S1(string s) // 1, 2 Diagnostic(ErrorCode.WRN_UninitializedNonNullableField, "S1").WithArguments("field", "field").WithLocation(13, 12), - // (13,12): error CS0171: Field 'S1.field' must be fully assigned before control is returned to the caller. Consider updating to language version 'preview' to auto-default the field. + // (13,12): error CS0171: Field 'S1.field' must be fully assigned before control is returned to the caller. Consider updating to language version '11.0' to auto-default the field. // public S1(string s) // 1, 2 - Diagnostic(ErrorCode.ERR_UnassignedThisUnsupportedVersion, "S1").WithArguments("S1.field", "preview").WithLocation(13, 12), - // (15,30): error CS9014: Use of possibly unassigned field 'field'. Consider updating to language version 'preview' to auto-default the field. + Diagnostic(ErrorCode.ERR_UnassignedThisUnsupportedVersion, "S1").WithArguments("S1.field", "11.0").WithLocation(13, 12), + // (15,30): error CS9015: Use of possibly unassigned field 'field'. Consider updating to language version '11.0' to auto-default the field. // System.Console.Write(field); // 3 - Diagnostic(ErrorCode.ERR_UseDefViolationFieldUnsupportedVersion, "field").WithArguments("field", "preview").WithLocation(15, 30) + Diagnostic(ErrorCode.ERR_UseDefViolationFieldUnsupportedVersion, "field").WithArguments("field", "11.0").WithLocation(15, 30) ); - var verifier = CompileAndVerify(source, parseOptions: TestOptions.RegularNext); + var verifier = CompileAndVerify(source, parseOptions: TestOptions.Regular11); verifier.VerifyDiagnostics( // (13,12): warning CS8618: Non-nullable field 'field' must contain a non-null value when exiting constructor. Consider declaring the field as nullable. // public S1(string s) // 1, 2 @@ -1787,14 +1787,14 @@ internal S(string s) // (6,14): warning CS8618: Non-nullable field 'F' must contain a non-null value when exiting constructor. Consider declaring the field as nullable. // internal S(string s) Diagnostic(ErrorCode.WRN_UninitializedNonNullableField, "S").WithArguments("field", "F").WithLocation(6, 14), - // (6,14): error CS0843: Auto-implemented property 'S.P' must be fully assigned before control is returned to the caller. Consider updating to language version 'preview' to auto-default the property. + // (6,14): error CS0843: Auto-implemented property 'S.P' must be fully assigned before control is returned to the caller. Consider updating to language version '11.0' to auto-default the property. // internal S(string s) - Diagnostic(ErrorCode.ERR_UnassignedThisAutoPropertyUnsupportedVersion, "S").WithArguments("S.P", "preview").WithLocation(6, 14), - // (6,14): error CS0171: Field 'S.F' must be fully assigned before control is returned to the caller. Consider updating to language version 'preview' to auto-default the field. + Diagnostic(ErrorCode.ERR_UnassignedThisAutoPropertyUnsupportedVersion, "S").WithArguments("S.P", "11.0").WithLocation(6, 14), + // (6,14): error CS0171: Field 'S.F' must be fully assigned before control is returned to the caller. Consider updating to language version '11.0' to auto-default the field. // internal S(string s) - Diagnostic(ErrorCode.ERR_UnassignedThisUnsupportedVersion, "S").WithArguments("S.F", "preview").WithLocation(6, 14)); + Diagnostic(ErrorCode.ERR_UnassignedThisUnsupportedVersion, "S").WithArguments("S.F", "11.0").WithLocation(6, 14)); - var verifier = CompileAndVerify(new[] { source }, options: WithNullableEnable(), parseOptions: TestOptions.RegularNext); + var verifier = CompileAndVerify(new[] { source }, options: WithNullableEnable(), parseOptions: TestOptions.Regular11); verifier.VerifyDiagnostics( // (6,14): warning CS8618: Non-nullable property 'P' must contain a non-null value when exiting constructor. Consider declaring the property as nullable. // internal S(string s) diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/Utf8StringsLiteralsTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/Utf8StringsLiteralsTests.cs index 3e81e3f9372cb..e8f5483509a24 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/Utf8StringsLiteralsTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/Utf8StringsLiteralsTests.cs @@ -7,6 +7,7 @@ using System.Collections; using System.Collections.Generic; using System.Linq; +using System.Text; using Microsoft.CodeAnalysis.CSharp.Symbols; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.CSharp.Test.Utilities; @@ -269,7 +270,7 @@ .maxstack 1 } "); - comp = CreateCompilation(source, targetFramework: TargetFramework.NetCoreApp, options: TestOptions.DebugExe, parseOptions: TestOptions.RegularNext); + comp = CreateCompilation(source, targetFramework: TargetFramework.NetCoreApp, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular11); CompileAndVerify(comp, expectedOutput: @" -1 @@ -1482,7 +1483,7 @@ .maxstack 2 } "); - comp = CreateCompilation(source + HelpersSource, targetFramework: TargetFramework.NetCoreApp, options: TestOptions.DebugExe, parseOptions: TestOptions.RegularNext); + comp = CreateCompilation(source + HelpersSource, targetFramework: TargetFramework.NetCoreApp, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular11); CompileAndVerify(comp, expectedOutput: @" { 0x63 0x61 0x74 } @@ -1490,9 +1491,9 @@ .maxstack 2 comp = CreateCompilation(source + HelpersSource, targetFramework: TargetFramework.NetCoreApp, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular10); comp.VerifyDiagnostics( - // (15,42): error CS8652: The feature 'UTF-8 string literals' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // (15,42): error CS8936: Feature 'UTF-8 string literals' is not available in C# 10.0. Please use language version 11.0 or greater. // static ReadOnlySpan Test3() => "cat"u8; - Diagnostic(ErrorCode.ERR_FeatureInPreview, @"""cat""" + suffix).WithArguments("UTF-8 string literals").WithLocation(15, 42) + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, @"""cat""" + suffix).WithArguments("UTF-8 string literals", "11.0").WithLocation(15, 42) ); } @@ -1535,7 +1536,7 @@ .maxstack 2 } "); - comp = CreateCompilation(source + HelpersSource, targetFramework: TargetFramework.NetCoreApp, options: TestOptions.DebugExe, parseOptions: TestOptions.RegularNext); + comp = CreateCompilation(source + HelpersSource, targetFramework: TargetFramework.NetCoreApp, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular11); CompileAndVerify(comp, expectedOutput: @" { 0x63 0x61 0x74 } @@ -1543,9 +1544,9 @@ .maxstack 2 comp = CreateCompilation(source + HelpersSource, targetFramework: TargetFramework.NetCoreApp, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular10); comp.VerifyDiagnostics( - // (15,42): error CS8652: The feature 'UTF-8 string literals' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. - // static ReadOnlySpan Test3() => "cat"u8; - Diagnostic(ErrorCode.ERR_FeatureInPreview, @"@""cat""" + suffix).WithArguments("UTF-8 string literals").WithLocation(15, 42) + // (15,42): error CS8936: Feature 'UTF-8 string literals' is not available in C# 10.0. Please use language version 11.0 or greater. + // static ReadOnlySpan Test3() => @"cat"u8; + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, @"@""cat""" + suffix).WithArguments("UTF-8 string literals", "11.0").WithLocation(15, 42) ); } @@ -1588,7 +1589,7 @@ .maxstack 2 } "); - comp = CreateCompilation(source + HelpersSource, targetFramework: TargetFramework.NetCoreApp, options: TestOptions.DebugExe, parseOptions: TestOptions.RegularNext); + comp = CreateCompilation(source + HelpersSource, targetFramework: TargetFramework.NetCoreApp, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular11); CompileAndVerify(comp, expectedOutput: @" { 0x63 0x61 0x74 } @@ -1596,12 +1597,12 @@ .maxstack 2 comp = CreateCompilation(source + HelpersSource, targetFramework: TargetFramework.NetCoreApp, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular10); comp.VerifyDiagnostics( - // (15,42): error CS8652: The feature 'raw string literals' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. - // static ReadOnlySpan Test3() => """cat"""u8; - Diagnostic(ErrorCode.ERR_FeatureInPreview, @"""""""cat""""""" + suffix).WithArguments("raw string literals").WithLocation(15, 42), - // (15,42): error CS8652: The feature 'UTF-8 string literals' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. - // static ReadOnlySpan Test3() => """cat"""u8; - Diagnostic(ErrorCode.ERR_FeatureInPreview, @"""""""cat""""""" + suffix).WithArguments("UTF-8 string literals").WithLocation(15, 42) + // (15,42): error CS8936: Feature 'raw string literals' is not available in C# 10.0. Please use language version 11.0 or greater. + // static ReadOnlySpan Test3() => """cat"""U8; + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, @"""""""cat""""""" + suffix).WithArguments("raw string literals", "11.0").WithLocation(15, 42), + // (15,42): error CS8936: Feature 'UTF-8 string literals' is not available in C# 10.0. Please use language version 11.0 or greater. + // static ReadOnlySpan Test3() => """cat"""U8; + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, @"""""""cat""""""" + suffix).WithArguments("UTF-8 string literals", "11.0").WithLocation(15, 42) ); } @@ -1650,7 +1651,7 @@ .maxstack 2 } "); - comp = CreateCompilation(source + HelpersSource, targetFramework: TargetFramework.NetCoreApp, options: TestOptions.DebugExe, parseOptions: TestOptions.RegularNext); + comp = CreateCompilation(source + HelpersSource, targetFramework: TargetFramework.NetCoreApp, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular11); CompileAndVerify(comp, expectedOutput: @" { 0x63 0x61 0x74 } @@ -1658,16 +1659,16 @@ .maxstack 2 comp = CreateCompilation(source + HelpersSource, targetFramework: TargetFramework.NetCoreApp, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular10); comp.VerifyDiagnostics( - // (19,42): error CS8652: The feature 'raw string literals' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // (19,42): error CS8936: Feature 'raw string literals' is not available in C# 10.0. Please use language version 11.0 or greater. // static ReadOnlySpan Test3() => """ - Diagnostic(ErrorCode.ERR_FeatureInPreview, @""""""" + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, @""""""" cat - """"""" + suffix).WithArguments("raw string literals").WithLocation(19, 42), - // (19,42): error CS8652: The feature 'UTF-8 string literals' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + """"""" + suffix).WithArguments("raw string literals", "11.0").WithLocation(19, 42), + // (19,42): error CS8936: Feature 'UTF-8 string literals' is not available in C# 10.0. Please use language version 11.0 or greater. // static ReadOnlySpan Test3() => """ - Diagnostic(ErrorCode.ERR_FeatureInPreview, @""""""" + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, @""""""" cat - """"""" + suffix).WithArguments("UTF-8 string literals").WithLocation(19, 42) + """"""" + suffix).WithArguments("UTF-8 string literals", "11.0").WithLocation(19, 42) ); } @@ -3547,8 +3548,8 @@ static void Main() [Fact] public void PassAround_02() { - var source = @" -using System; + var source = @"using System; +using System.Diagnostics.CodeAnalysis; class C { static ref readonly ReadOnlySpan Test2() @@ -3556,10 +3557,10 @@ static ref readonly ReadOnlySpan Test2() return ref Test3(""cat""u8); } - static ref readonly ReadOnlySpan Test3(in ReadOnlySpan x) => ref x; + static ref readonly ReadOnlySpan Test3([UnscopedRef] in ReadOnlySpan x) => ref x; } "; - var comp = CreateCompilation(source + HelpersSource, targetFramework: TargetFramework.NetCoreApp, options: TestOptions.DebugDll); + var comp = CreateCompilation(new[] { source + HelpersSource, UnscopedRefAttributeDefinition }, targetFramework: TargetFramework.NetCoreApp, options: TestOptions.DebugDll); comp.VerifyDiagnostics( // (7,20): error CS8347: Cannot use a result of 'C.Test3(in ReadOnlySpan)' in this context because it may expose variables referenced by parameter 'x' outside of their declaration scope @@ -4043,5 +4044,26 @@ static void Main() Diagnostic(ErrorCode.ERR_BadBinaryOps, expression).WithArguments("+", "System.ReadOnlySpan", "C").WithLocation(7, 13) ); } + + [ConditionalFact(typeof(CoreClrOnly)), WorkItem(62361, "https://github.com/dotnet/roslyn/issues/62361")] + public void DeeplyNestedConcatenation() + { + var longConcat = new StringBuilder(); + for (int i = 0; i < 800; i++) + { + longConcat.Append(""" "a"u8 + """); + } + + var source = $$""" +System.Console.Write(X.Y.Length); + +class X +{ + public static System.ReadOnlySpan Y => {{longConcat}} "a"u8; +} +"""; + var comp = CreateCompilation(source, targetFramework: TargetFramework.NetCoreApp); + CompileAndVerify(comp, expectedOutput: "801", verify: Verification.Fails).VerifyDiagnostics(); + } } } diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/WarningVersionTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/WarningVersionTests.cs index 0ffb1a2b8767c..1adeb143c6d60 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/WarningVersionTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/WarningVersionTests.cs @@ -167,9 +167,9 @@ .maxstack 1 parseOptions: TestOptions.Regular10, verify: Verification.Skipped); verifier.VerifyDiagnostics( - // (4,12): warning CS8880: Auto-implemented property 'Program.Property' must be fully assigned before control is returned to the caller. Consider updating to language version 'preview' to auto-default the property. + // (4,12): warning CS8880: Auto-implemented property 'Program.Property' must be fully assigned before control is returned to the caller. Consider updating to language version '11.0' to auto-default the property. // public Program(int dummy) - Diagnostic(ErrorCode.WRN_UnassignedThisAutoPropertyUnsupportedVersion, "Program").WithArguments("Program.Property", "preview").WithLocation(4, 12)); + Diagnostic(ErrorCode.WRN_UnassignedThisAutoPropertyUnsupportedVersion, "Program").WithArguments("Program.Property", "11.0").WithLocation(4, 12)); verifier.VerifyIL("Program..ctor", expectedIL); // C# 11+ @@ -177,7 +177,7 @@ .maxstack 1 source2, references: moduleReference, options: TestOptions.DebugDll.WithWarningLevel(5), - parseOptions: TestOptions.RegularNext, + parseOptions: TestOptions.Regular11, verify: Verification.Skipped); verifier.VerifyDiagnostics(); verifier.VerifyIL("Program..ctor", expectedIL); @@ -188,7 +188,7 @@ .maxstack 1 options: TestOptions.DebugDll .WithWarningLevel(5) .WithSpecificDiagnosticOptions(ReportStructInitializationWarnings), - parseOptions: TestOptions.RegularNext, + parseOptions: TestOptions.Regular11, verify: Verification.Skipped); verifier.VerifyDiagnostics( // (4,12): warning CS9020: Control is returned to caller before auto-implemented property 'Program.Property' is explicitly assigned, causing a preceding implicit assignment of 'default'. @@ -245,9 +245,9 @@ .maxstack 1 parseOptions: TestOptions.Regular10, verify: Verification.Skipped); verifier.VerifyDiagnostics( - // (4,12): warning CS8881: Field 'Program.Field' must be fully assigned before control is returned to the caller. Consider updating to language version 'preview' to auto-default the field. + // (4,12): warning CS8881: Field 'Program.Field' must be fully assigned before control is returned to the caller. Consider updating to language version '11.0' to auto-default the field. // public Program(int dummy) - Diagnostic(ErrorCode.WRN_UnassignedThisUnsupportedVersion, "Program").WithArguments("Program.Field", "preview").WithLocation(4, 12)); + Diagnostic(ErrorCode.WRN_UnassignedThisUnsupportedVersion, "Program").WithArguments("Program.Field", "11.0").WithLocation(4, 12)); verifier.VerifyIL("Program..ctor", expectedIL); // C# 11+ @@ -256,7 +256,7 @@ .maxstack 1 references: moduleReference, options: TestOptions.DebugDll .WithWarningLevel(5), - parseOptions: TestOptions.RegularNext, + parseOptions: TestOptions.Regular11, verify: Verification.Skipped); verifier.VerifyDiagnostics(); verifier.VerifyIL("Program..ctor", expectedIL); @@ -267,7 +267,7 @@ .maxstack 1 options: TestOptions.DebugDll .WithWarningLevel(5) .WithSpecificDiagnosticOptions(ReportStructInitializationWarnings), - parseOptions: TestOptions.RegularNext, + parseOptions: TestOptions.Regular11, verify: Verification.Skipped); verifier.VerifyDiagnostics( // (4,12): warning CS9021: Control is returned to caller before field 'Program.Field' is explicitly assigned, causing a preceding implicit assignment of 'default'. @@ -331,9 +331,9 @@ .locals init (Struct V_0) //s parseOptions: TestOptions.Regular10, verify: Verification.Skipped); verifier.VerifyDiagnostics( - // (4,12): warning CS8881: Field 'Program.Field' must be fully assigned before control is returned to the caller. Consider updating to language version 'preview' to auto-default the field. + // (4,12): warning CS8881: Field 'Program.Field' must be fully assigned before control is returned to the caller. Consider updating to language version '11.0' to auto-default the field. // public Program(int dummy) - Diagnostic(ErrorCode.WRN_UnassignedThisUnsupportedVersion, "Program").WithArguments("Program.Field", "preview").WithLocation(4, 12), + Diagnostic(ErrorCode.WRN_UnassignedThisUnsupportedVersion, "Program").WithArguments("Program.Field", "11.0").WithLocation(4, 12), // (7,9): warning CS8887: Use of unassigned local variable 's' // s.ToString(); Diagnostic(ErrorCode.WRN_UseDefViolation, "s").WithArguments("s").WithLocation(7, 9)); @@ -344,7 +344,7 @@ .locals init (Struct V_0) //s source2, references: moduleReference, options: TestOptions.DebugDll.WithWarningLevel(5), - parseOptions: TestOptions.RegularNext, + parseOptions: TestOptions.Regular11, verify: Verification.Skipped); verifier.VerifyDiagnostics( // (7,9): warning CS8887: Use of unassigned local variable 's' @@ -358,7 +358,7 @@ .locals init (Struct V_0) //s options: TestOptions.DebugDll .WithWarningLevel(5) .WithSpecificDiagnosticOptions(ReportStructInitializationWarnings), - parseOptions: TestOptions.RegularNext, + parseOptions: TestOptions.Regular11, verify: Verification.Skipped); verifier.VerifyDiagnostics( // (4,12): warning CS9021: Control is returned to caller before field 'Program.Field' is explicitly assigned, causing a preceding implicit assignment of 'default'. @@ -455,9 +455,9 @@ .locals init (Struct V_0) //v2 parseOptions: TestOptions.Regular10, verify: Verification.Skipped); verifier.VerifyDiagnostics( - // (6,21): warning CS9015: Use of possibly unassigned auto-implemented property 'Property'. Consider updating to language version 'preview' to auto-default the property. + // (6,21): warning CS9016: Use of possibly unassigned auto-implemented property 'Property'. Consider updating to language version '11.0' to auto-default the property. // Struct v2 = Property; - Diagnostic(ErrorCode.WRN_UseDefViolationPropertyUnsupportedVersion, "Property").WithArguments("Property", "preview").WithLocation(6, 21)); + Diagnostic(ErrorCode.WRN_UseDefViolationPropertyUnsupportedVersion, "Property").WithArguments("Property", "11.0").WithLocation(6, 21)); verifier.VerifyIL("Program..ctor", expectedIL); // C# 11+ @@ -465,7 +465,7 @@ .locals init (Struct V_0) //v2 source2, references: moduleReference, options: TestOptions.DebugDll.WithWarningLevel(5), - parseOptions: TestOptions.RegularNext, + parseOptions: TestOptions.Regular11, verify: Verification.Skipped); verifier.VerifyDiagnostics(); verifier.VerifyIL("Program..ctor", expectedIL); @@ -476,7 +476,7 @@ .locals init (Struct V_0) //v2 options: TestOptions.DebugDll .WithWarningLevel(5) .WithSpecificDiagnosticOptions(ReportStructInitializationWarnings), - parseOptions: TestOptions.RegularNext, + parseOptions: TestOptions.Regular11, verify: Verification.Skipped); verifier.VerifyDiagnostics( // (6,21): warning CS9014: Use of possibly unassigned auto-implemented property 'Property' @@ -542,9 +542,9 @@ .locals init (Struct V_0) //v2 parseOptions: TestOptions.Regular10, verify: Verification.Skipped); verifier.VerifyDiagnostics( - // (6,21): warning CS9016: Use of possibly unassigned field 'Field'. Consider updating to language version 'preview' to auto-default the field. + // (6,21): warning CS9017: Use of possibly unassigned field 'Field'. Consider updating to language version '11.0' to auto-default the field. // Struct v2 = Field; - Diagnostic(ErrorCode.WRN_UseDefViolationFieldUnsupportedVersion, "Field").WithArguments("Field", "preview").WithLocation(6, 21)); + Diagnostic(ErrorCode.WRN_UseDefViolationFieldUnsupportedVersion, "Field").WithArguments("Field", "11.0").WithLocation(6, 21)); verifier.VerifyIL("Program..ctor", expectedIL); // C# 11+ @@ -552,7 +552,7 @@ .locals init (Struct V_0) //v2 source2, references: moduleReference, options: TestOptions.DebugDll.WithWarningLevel(5), - parseOptions: TestOptions.RegularNext, + parseOptions: TestOptions.Regular11, verify: Verification.Skipped); verifier.VerifyDiagnostics(); @@ -563,7 +563,7 @@ .locals init (Struct V_0) //v2 options: TestOptions.DebugDll .WithWarningLevel(5) .WithSpecificDiagnosticOptions(ReportStructInitializationWarnings), - parseOptions: TestOptions.RegularNext, + parseOptions: TestOptions.Regular11, verify: Verification.Skipped); verifier.VerifyDiagnostics( // (6,21): warning CS9014: Use of possibly unassigned field 'Field' @@ -629,9 +629,9 @@ .locals init (Program V_0) //p2 parseOptions: TestOptions.Regular10, verify: Verification.Skipped); verifier.VerifyDiagnostics( - // (6,22): warning CS8885: The 'this' object cannot be used before all of its fields have been assigned. Consider updating to language version 'preview' to auto-default the unassigned fields. + // (6,22): warning CS8885: The 'this' object cannot be used before all of its fields have been assigned. Consider updating to language version '11.0' to auto-default the unassigned fields. // Program p2 = this; - Diagnostic(ErrorCode.WRN_UseDefViolationThisUnsupportedVersion, "this").WithArguments("preview").WithLocation(6, 22)); + Diagnostic(ErrorCode.WRN_UseDefViolationThisUnsupportedVersion, "this").WithArguments("11.0").WithLocation(6, 22)); verifier.VerifyIL("Program..ctor", expectedIL); // C# 11+ @@ -639,7 +639,7 @@ .locals init (Program V_0) //p2 source2, references: moduleReference, options: TestOptions.DebugDll.WithWarningLevel(5), - parseOptions: TestOptions.RegularNext, + parseOptions: TestOptions.Regular11, verify: Verification.Skipped); verifier.VerifyDiagnostics(); verifier.VerifyIL("Program..ctor", expectedIL); @@ -650,7 +650,7 @@ .locals init (Program V_0) //p2 options: TestOptions.DebugDll .WithWarningLevel(5) .WithSpecificDiagnosticOptions(ReportStructInitializationWarnings), - parseOptions: TestOptions.RegularNext, + parseOptions: TestOptions.Regular11, verify: Verification.Skipped); verifier.VerifyDiagnostics( // (6,22): warning CS9020: The 'this' object is read before all of its fields have been assigned, causing preceding implicit assignments of 'default' to non-explicitly assigned fields. diff --git a/src/Compilers/CSharp/Test/Semantic/SourceGeneration/GeneratorDriverTests.cs b/src/Compilers/CSharp/Test/Semantic/SourceGeneration/GeneratorDriverTests.cs index 7dd6ef2239007..a9cd72a3c0984 100644 --- a/src/Compilers/CSharp/Test/Semantic/SourceGeneration/GeneratorDriverTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/SourceGeneration/GeneratorDriverTests.cs @@ -32,7 +32,7 @@ public void Running_With_No_Changes_Is_NoOp() class C { } "; var parseOptions = TestOptions.Regular; - Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDll, parseOptions: parseOptions); + Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); compilation.VerifyDiagnostics(); Assert.Single(compilation.SyntaxTrees); @@ -52,7 +52,7 @@ public void Generator_Is_Initialized_Before_Running() class C { } "; var parseOptions = TestOptions.Regular; - Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDll, parseOptions: parseOptions); + Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); compilation.VerifyDiagnostics(); Assert.Single(compilation.SyntaxTrees); @@ -74,7 +74,7 @@ public void Generator_Is_Not_Initialized_If_Not_Run() class C { } "; var parseOptions = TestOptions.Regular; - Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDll, parseOptions: parseOptions); + Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); compilation.VerifyDiagnostics(); Assert.Single(compilation.SyntaxTrees); @@ -95,7 +95,7 @@ public void Generator_Is_Only_Initialized_Once() class C { } "; var parseOptions = TestOptions.Regular; - Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDll, parseOptions: parseOptions); + Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); compilation.VerifyDiagnostics(); Assert.Single(compilation.SyntaxTrees); @@ -124,7 +124,7 @@ class GeneratedClass { } "; var parseOptions = TestOptions.Regular; - Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDll, parseOptions: parseOptions); + Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); compilation.VerifyDiagnostics(); Assert.Single(compilation.SyntaxTrees); @@ -155,7 +155,7 @@ class GeneratedClass { } var parseOptions = TestOptions.Regular; var analyzer = new Analyzer_Is_Run_Analyzer(); - Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDll, parseOptions: parseOptions); + Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); compilation.VerifyDiagnostics(); compilation.GetAnalyzerDiagnostics(new[] { analyzer }, null).Verify(); @@ -214,7 +214,7 @@ class GeneratedClass { } "; var parseOptions = TestOptions.Regular; - Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDll, parseOptions: parseOptions); + Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); compilation.VerifyDiagnostics(); Assert.Single(compilation.SyntaxTrees); @@ -246,7 +246,7 @@ class C } "; var parseOptions = TestOptions.Regular; - Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDll, parseOptions: parseOptions); + Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); compilation.VerifyDiagnostics( // (5,12): error CS0246: The type or namespace name 'D' could not be found (are you missing a using directive or an assembly reference?) // public D d; @@ -271,7 +271,7 @@ public void Error_During_Initialization_Is_Reported() class C { } "; var parseOptions = TestOptions.Regular; - Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDll, parseOptions: parseOptions); + Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); compilation.VerifyDiagnostics(); Assert.Single(compilation.SyntaxTrees); @@ -297,7 +297,7 @@ public void Error_During_Initialization_Generator_Does_Not_Run() class C { } "; var parseOptions = TestOptions.Regular; - Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDll, parseOptions: parseOptions); + Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); compilation.VerifyDiagnostics(); Assert.Single(compilation.SyntaxTrees); @@ -318,7 +318,7 @@ public void Error_During_Generation_Is_Reported() class C { } "; var parseOptions = TestOptions.Regular; - Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDll, parseOptions: parseOptions); + Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); compilation.VerifyDiagnostics(); Assert.Single(compilation.SyntaxTrees); @@ -344,7 +344,7 @@ public void Error_During_Generation_Does_Not_Affect_Other_Generators() class C { } "; var parseOptions = TestOptions.Regular; - Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDll, parseOptions: parseOptions); + Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); compilation.VerifyDiagnostics(); Assert.Single(compilation.SyntaxTrees); @@ -377,7 +377,7 @@ class C } "; var parseOptions = TestOptions.Regular; - Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDll, parseOptions: parseOptions); + Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); compilation.VerifyDiagnostics( // (5,12): error CS0246: The type or namespace name 'D' could not be found (are you missing a using directive or an assembly reference?) // public D d; @@ -411,7 +411,7 @@ public void Error_During_Generation_Has_Exception_In_Description() class C { } "; var parseOptions = TestOptions.Regular; - Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDll, parseOptions: parseOptions); + Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); compilation.VerifyDiagnostics(); Assert.Single(compilation.SyntaxTrees); @@ -437,7 +437,7 @@ public void Generator_Can_Report_Diagnostics() class C { } "; var parseOptions = TestOptions.Regular; - Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDll, parseOptions: parseOptions); + Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); compilation.VerifyDiagnostics(); Assert.Single(compilation.SyntaxTrees); @@ -463,7 +463,7 @@ public void Generator_HintName_MustBe_Unique() class C { } "; var parseOptions = TestOptions.Regular; - Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDll, parseOptions: parseOptions); + Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); compilation.VerifyDiagnostics(); Assert.Single(compilation.SyntaxTrees); @@ -492,7 +492,7 @@ public void Generator_HintName_MustBe_Unique_Across_Outputs() class C { } "; var parseOptions = TestOptions.Regular.WithLanguageVersion(LanguageVersion.Preview); - Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDll, parseOptions: parseOptions); + Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); compilation.VerifyDiagnostics(); Assert.Single(compilation.SyntaxTrees); @@ -533,7 +533,7 @@ public void Generator_HintName_Is_Appended_With_GeneratorName() class C { } "; var parseOptions = TestOptions.Regular; - Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDll, parseOptions: parseOptions); + Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); compilation.VerifyDiagnostics(); Assert.Single(compilation.SyntaxTrees); @@ -571,7 +571,7 @@ public void RunResults_Are_Available_After_Generation() class C { } "; var parseOptions = TestOptions.Regular; - Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDll, parseOptions: parseOptions); + Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); compilation.VerifyDiagnostics(); Assert.Single(compilation.SyntaxTrees); @@ -601,7 +601,7 @@ public void RunResults_Combine_SyntaxTrees() class C { } "; var parseOptions = TestOptions.Regular; - Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDll, parseOptions: parseOptions); + Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); compilation.VerifyDiagnostics(); Assert.Single(compilation.SyntaxTrees); @@ -646,7 +646,7 @@ public void RunResults_Combine_Diagnostics() class C { } "; var parseOptions = TestOptions.Regular; - Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDll, parseOptions: parseOptions); + Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); compilation.VerifyDiagnostics(); Assert.Single(compilation.SyntaxTrees); @@ -693,7 +693,7 @@ public void FullGeneration_Diagnostics_AreSame_As_RunResults() class C { } "; var parseOptions = TestOptions.Regular; - Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDll, parseOptions: parseOptions); + Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); compilation.VerifyDiagnostics(); Assert.Single(compilation.SyntaxTrees); @@ -728,7 +728,7 @@ class C } "; var parseOptions = TestOptions.Regular; - Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDll, parseOptions: parseOptions); + Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); compilation.VerifyDiagnostics(); Assert.Single(compilation.SyntaxTrees); @@ -766,7 +766,7 @@ public void Adding_A_Source_Text_Without_Encoding_Fails_Generation() class C { } "; var parseOptions = TestOptions.Regular; - Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDll, parseOptions: parseOptions); + Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); compilation.VerifyDiagnostics(); Assert.Single(compilation.SyntaxTrees); @@ -790,7 +790,7 @@ class C } "; var parseOptions = TestOptions.Regular; - Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDll, parseOptions: parseOptions); + Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); compilation.VerifyDiagnostics(); Assert.Single(compilation.SyntaxTrees); @@ -815,7 +815,7 @@ class C } "; var parseOptions = TestOptions.Regular; - Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDll, parseOptions: parseOptions); + Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); compilation.VerifyDiagnostics(); Assert.Single(compilation.SyntaxTrees); @@ -843,7 +843,7 @@ class C } "; var parseOptions = TestOptions.Regular; - Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDll, parseOptions: parseOptions); + Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); compilation.VerifyDiagnostics(); Assert.Single(compilation.SyntaxTrees); @@ -874,7 +874,7 @@ public void Generator_Can_Provide_Source_In_PostInit() class C { } "; var parseOptions = TestOptions.Regular; - Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDll, parseOptions: parseOptions); + Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); compilation.VerifyDiagnostics(); Assert.Single(compilation.SyntaxTrees); @@ -901,7 +901,7 @@ public void PostInit_Source_Is_Available_During_Execute() class C { } "; var parseOptions = TestOptions.Regular; - Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDll, parseOptions: parseOptions); + Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); compilation.VerifyDiagnostics(); Assert.Single(compilation.SyntaxTrees); @@ -928,7 +928,7 @@ public void PostInit_Source_Is_Available_To_Other_Generators_During_Execute() class C { } "; var parseOptions = TestOptions.Regular; - Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDll, parseOptions: parseOptions); + Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); compilation.VerifyDiagnostics(); Assert.Single(compilation.SyntaxTrees); @@ -956,7 +956,7 @@ public void PostInit_Is_Only_Called_Once() class C { } "; var parseOptions = TestOptions.Regular; - Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDll, parseOptions: parseOptions); + Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); compilation.VerifyDiagnostics(); Assert.Single(compilation.SyntaxTrees); @@ -988,7 +988,7 @@ public void Error_During_PostInit_Is_Reported() class C { } "; var parseOptions = TestOptions.Regular; - Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDll, parseOptions: parseOptions); + Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); compilation.VerifyDiagnostics(); Assert.Single(compilation.SyntaxTrees); @@ -1020,7 +1020,7 @@ public void Error_During_Initialization_PostInit_Does_Not_Run() class C { } "; var parseOptions = TestOptions.Regular; - Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDll, parseOptions: parseOptions); + Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); compilation.VerifyDiagnostics(); Assert.Single(compilation.SyntaxTrees); @@ -1058,7 +1058,7 @@ public void PostInit_SyntaxTrees_Are_Available_In_RunResults() class C { } "; var parseOptions = TestOptions.Regular; - Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDll, parseOptions: parseOptions); + Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); compilation.VerifyDiagnostics(); Assert.Single(compilation.SyntaxTrees); @@ -1085,7 +1085,7 @@ public void PostInit_SyntaxTrees_Are_Combined_In_RunResults() class C { } "; var parseOptions = TestOptions.Regular; - Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDll, parseOptions: parseOptions); + Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); compilation.VerifyDiagnostics(); Assert.Single(compilation.SyntaxTrees); @@ -1130,7 +1130,7 @@ public void SyntaxTrees_Are_Lazy() class C { } "; var parseOptions = TestOptions.Regular; - Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDll, parseOptions: parseOptions); + Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); compilation.VerifyDiagnostics(); Assert.Single(compilation.SyntaxTrees); @@ -1157,7 +1157,7 @@ public void Diagnostics_Respect_Suppression() class C { } "; var parseOptions = TestOptions.Regular; - Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDll, parseOptions: parseOptions); + Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); compilation.VerifyDiagnostics(); Assert.Single(compilation.SyntaxTrees); @@ -1257,7 +1257,7 @@ void verifyDiagnosticsWithSource(string source, (Diagnostic, TextSpan)[] reportD { var parseOptions = TestOptions.Regular; source = source.Replace(Environment.NewLine, "\r\n"); - Compilation compilation = CreateCompilation(source, sourceFileName: "sourcefile.cs", options: TestOptions.DebugDll, parseOptions: parseOptions); + Compilation compilation = CreateCompilation(source, sourceFileName: "sourcefile.cs", options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); compilation.VerifyDiagnostics(); Assert.Single(compilation.SyntaxTrees); @@ -1290,7 +1290,7 @@ public void GeneratorDriver_Prefers_Incremental_Generators() class C { } "; var parseOptions = TestOptions.Regular; - Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDll, parseOptions: parseOptions); + Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); compilation.VerifyDiagnostics(); Assert.Single(compilation.SyntaxTrees); @@ -1326,7 +1326,7 @@ public void GeneratorDriver_Initializes_Incremental_Generators() class C { } "; var parseOptions = TestOptions.Regular; - Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDll, parseOptions: parseOptions); + Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); compilation.VerifyDiagnostics(); Assert.Single(compilation.SyntaxTrees); @@ -1348,7 +1348,7 @@ public void Incremental_Generators_Exception_During_Initialization() class C { } "; var parseOptions = TestOptions.RegularPreview; - Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDll, parseOptions: parseOptions); + Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); compilation.VerifyDiagnostics(); Assert.Single(compilation.SyntaxTrees); @@ -1373,7 +1373,7 @@ public void Incremental_Generators_Exception_During_Execution() class C { } "; var parseOptions = TestOptions.RegularPreview; - Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDll, parseOptions: parseOptions); + Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); compilation.VerifyDiagnostics(); Assert.Single(compilation.SyntaxTrees); @@ -1398,7 +1398,7 @@ public void Incremental_Generators_Exception_During_Execution_Doesnt_Produce_Any class C { } "; var parseOptions = TestOptions.RegularPreview; - Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDll, parseOptions: parseOptions); + Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); compilation.VerifyDiagnostics(); Assert.Single(compilation.SyntaxTrees); @@ -1427,7 +1427,7 @@ public void Incremental_Generators_Exception_During_Execution_Doesnt_Stop_Other_ class C { } "; var parseOptions = TestOptions.RegularPreview; - Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDll, parseOptions: parseOptions); + Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); compilation.VerifyDiagnostics(); Assert.Single(compilation.SyntaxTrees); @@ -1460,7 +1460,7 @@ public void IncrementalGenerator_With_No_Pipeline_Callback_Is_Valid() class C { } "; var parseOptions = TestOptions.RegularPreview; - Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDll, parseOptions: parseOptions); + Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); compilation.VerifyDiagnostics(); Assert.Single(compilation.SyntaxTrees); @@ -1481,7 +1481,7 @@ public void IncrementalGenerator_Can_Add_PostInit_Source() class C { } "; var parseOptions = TestOptions.RegularPreview; - Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDll, parseOptions: parseOptions); + Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); compilation.VerifyDiagnostics(); Assert.Single(compilation.SyntaxTrees); @@ -1543,7 +1543,7 @@ public void IncrementalGenerator_Doesnt_Run_For_Same_Input() class C { } "; var parseOptions = TestOptions.RegularPreview; - Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDll, parseOptions: parseOptions); + Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); compilation.VerifyDiagnostics(); Assert.Single(compilation.SyntaxTrees); @@ -1587,7 +1587,7 @@ public void IncrementalGenerator_Runs_Only_For_Changed_Inputs() class C { } "; var parseOptions = TestOptions.RegularPreview; - Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDll, parseOptions: parseOptions); + Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); compilation.VerifyDiagnostics(); Assert.Single(compilation.SyntaxTrees); @@ -1806,7 +1806,7 @@ public void IncrementalGenerator_Can_Add_Comparer_To_Input_Node() class C { } "; var parseOptions = TestOptions.RegularPreview; - Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDll, parseOptions: parseOptions); + Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); compilation.VerifyDiagnostics(); Assert.Single(compilation.SyntaxTrees); @@ -1842,7 +1842,7 @@ public void IncrementalGenerator_Can_Add_Comparer_To_Combine_Node() class C { } "; var parseOptions = TestOptions.RegularPreview; - Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDll, parseOptions: parseOptions); + Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); compilation.VerifyDiagnostics(); Assert.Single(compilation.SyntaxTrees); @@ -1980,7 +1980,7 @@ public void IncrementalGenerator_Register_End_Node_Only_Once_Through_Combines() class C { } "; var parseOptions = TestOptions.RegularPreview; - Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDll, parseOptions: parseOptions); + Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); compilation.VerifyDiagnostics(); Assert.Single(compilation.SyntaxTrees); @@ -2015,7 +2015,7 @@ public void IncrementalGenerator_PostInit_Source_Is_Cached() class C { } "; var parseOptions = TestOptions.RegularPreview; - Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDll, parseOptions: parseOptions); + Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); compilation.VerifyDiagnostics(); Assert.Single(compilation.SyntaxTrees); @@ -2087,7 +2087,7 @@ public void Incremental_Generators_Can_Be_Cancelled() class C { } "; var parseOptions = TestOptions.RegularPreview; - Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDll, parseOptions: parseOptions); + Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); compilation.VerifyDiagnostics(); Assert.Single(compilation.SyntaxTrees); @@ -2115,7 +2115,7 @@ public void ParseOptions_Can_Be_Updated() class C { } "; var parseOptions = TestOptions.RegularPreview; - Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDll, parseOptions: parseOptions); + Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); compilation.VerifyDiagnostics(); Assert.Single(compilation.SyntaxTrees); @@ -2174,7 +2174,7 @@ public void RemoveTriggeringSyntaxAndVerifySyntaxTreeConsistentWithCompilation() class C { } "; var parseOptions = TestOptions.RegularPreview; - Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDll, parseOptions: parseOptions); + Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); compilation.VerifyDiagnostics(); Assert.Single(compilation.SyntaxTrees); @@ -2200,7 +2200,7 @@ class C { } var newSource = @" class C { } "; - Compilation newCompilation = CreateCompilation(newSource, options: TestOptions.DebugDll, parseOptions: parseOptions); + Compilation newCompilation = CreateCompilation(newSource, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); // check we ran driver = driver.RunGenerators(newCompilation); @@ -2236,7 +2236,7 @@ public void AnalyzerConfig_Can_Be_Updated() class C { } "; var parseOptions = TestOptions.RegularPreview; - Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDll, parseOptions: parseOptions); + Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); compilation.VerifyDiagnostics(); Assert.Single(compilation.SyntaxTrees); @@ -2320,7 +2320,7 @@ public void AdditionalText_Can_Be_Replaced() class C { } "; var parseOptions = TestOptions.RegularPreview; - Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDll, parseOptions: parseOptions); + Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); compilation.VerifyDiagnostics(); Assert.Single(compilation.SyntaxTrees); @@ -2507,7 +2507,7 @@ public void Replaced_Input_Is_Treated_As_Modified() class C { } "; var parseOptions = TestOptions.RegularPreview; - Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDll, parseOptions: parseOptions); + Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); compilation.VerifyDiagnostics(); Assert.Single(compilation.SyntaxTrees); @@ -2697,7 +2697,7 @@ public void Generator_Output_Kinds_Can_Be_Disabled(IncrementalGeneratorOutputKin class C { } "; var parseOptions = TestOptions.RegularPreview; - Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDll, parseOptions: parseOptions); + Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); compilation.VerifyDiagnostics(); Assert.Single(compilation.SyntaxTrees); @@ -2742,7 +2742,7 @@ public void IncrementalGeneratorInputSourcesHaveNames() class C { } "; var parseOptions = TestOptions.RegularPreview; - Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDll, parseOptions: parseOptions); + Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); compilation.VerifyDiagnostics(); Assert.Single(compilation.SyntaxTrees); @@ -2788,7 +2788,7 @@ public void Steps_From_Common_Input_Nodes_Recorded_In_All_Generators_Steps() class C { } "; var parseOptions = TestOptions.RegularPreview; - Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDll, parseOptions: parseOptions); + Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); compilation.VerifyDiagnostics(); Assert.Single(compilation.SyntaxTrees); @@ -2822,7 +2822,7 @@ class C { } MetadataReference.CreateFromAssemblyInternal(this.GetType().Assembly), MetadataReference.CreateFromAssemblyInternal(typeof(object).Assembly) }; - Compilation compilation = CreateEmptyCompilation(source, options: TestOptions.DebugDll, parseOptions: parseOptions, references: metadataRefs); + Compilation compilation = CreateEmptyCompilation(source, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions, references: metadataRefs); compilation.VerifyDiagnostics(); Assert.Single(compilation.SyntaxTrees); @@ -2872,7 +2872,7 @@ class C { } "; var parseOptions = TestOptions.RegularPreview; - Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDll, parseOptions: parseOptions); + Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); compilation.VerifyDiagnostics(); Assert.Single(compilation.SyntaxTrees); @@ -2898,7 +2898,7 @@ public void Binary_Additional_Files_Do_Not_Throw_When_Compared() var source = "class C{}"; var parseOptions = TestOptions.RegularPreview; - Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDll, parseOptions: parseOptions); + Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); compilation.VerifyDiagnostics(); var generator = new PipelineCallbackGenerator(ctx => @@ -2931,7 +2931,7 @@ public void Incremental_Generators_Can_Recover_From_Exceptions() var source = "class C{}"; var parseOptions = TestOptions.RegularPreview; - Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDll, parseOptions: parseOptions); + Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); compilation.VerifyDiagnostics(); bool shouldThrow = true; @@ -2977,7 +2977,7 @@ public void Timing_Info_Is_Empty_If_Not_Run() var source = "class C{}"; var parseOptions = TestOptions.RegularPreview; - Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDll, parseOptions: parseOptions); + Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); compilation.VerifyDiagnostics(); var generator = new PipelineCallbackGenerator(ctx => @@ -3005,7 +3005,7 @@ public void Can_Get_Timing_Info() var source = "class C{}"; var parseOptions = TestOptions.RegularPreview; - Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDll, parseOptions: parseOptions); + Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); compilation.VerifyDiagnostics(); var generator = new PipelineCallbackGenerator(ctx => @@ -3036,7 +3036,7 @@ public void Can_Get_Timing_Info_From_Multiple_Generators() var source = "class C{}"; var parseOptions = TestOptions.RegularPreview; - Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDll, parseOptions: parseOptions); + Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); compilation.VerifyDiagnostics(); var generator = new PipelineCallbackGenerator(ctx => @@ -3084,7 +3084,7 @@ public void Timing_Info_Only_Includes_Last_Run() var source = "class C{}"; var parseOptions = TestOptions.RegularPreview; - Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDll, parseOptions: parseOptions); + Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); compilation.VerifyDiagnostics(); var generator = new PipelineCallbackGenerator(ctx => @@ -3121,5 +3121,33 @@ public void Timing_Info_Only_Includes_Last_Run() Assert.NotEqual(TimeSpan.Zero, generatorTiming2.ElapsedTime); Assert.True(generatorTiming.ElapsedTime > generatorTiming2.ElapsedTime); } + + [Fact] + public void Returning_Null_From_SelectMany_Gives_Empty_Array() + { + var source = "class C{}"; + + var parseOptions = TestOptions.RegularPreview; + Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDll, parseOptions: parseOptions); + compilation.VerifyDiagnostics(); + + var generator = new PipelineCallbackGenerator(ctx => + { + var nullArray = ctx.CompilationProvider.Select((c, _) => null as object[]); + var flatArray = nullArray.SelectMany((a, _) => a!); + ctx.RegisterSourceOutput(flatArray, (_, _) => { }); + + }).AsSourceGenerator(); + + GeneratorDriver driver = CSharpGeneratorDriver.Create(new[] { generator }, parseOptions: parseOptions, driverOptions: new GeneratorDriverOptions(IncrementalGeneratorOutputKind.None, trackIncrementalGeneratorSteps: true)); + driver = driver.RunGenerators(compilation); + var runResult = driver.GetRunResult(); + + Assert.Empty(runResult.GeneratedTrees); + Assert.Empty(runResult.Diagnostics); + var result = Assert.Single(runResult.Results); + Assert.Empty(result.GeneratedSources); + Assert.Empty(result.Diagnostics); + } } } diff --git a/src/Compilers/CSharp/Test/Semantic/SourceGeneration/GeneratorDriverTests_Attributes_FullyQualifiedName.cs b/src/Compilers/CSharp/Test/Semantic/SourceGeneration/GeneratorDriverTests_Attributes_FullyQualifiedName.cs index 0d3f9e0751b75..2de2973782a5e 100644 --- a/src/Compilers/CSharp/Test/Semantic/SourceGeneration/GeneratorDriverTests_Attributes_FullyQualifiedName.cs +++ b/src/Compilers/CSharp/Test/Semantic/SourceGeneration/GeneratorDriverTests_Attributes_FullyQualifiedName.cs @@ -3,6 +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.CSharp.Syntax; @@ -22,7 +24,7 @@ public static IncrementalValuesProvider ForAttributeWithSimpleName( { return context.SyntaxProvider.ForAttributeWithSimpleName( simpleName, - (node, _) => node is T).Select((node, _) => (T)node); + (node, _) => node is T).SelectMany((t, _) => t.matches.Cast()).WithTrackingName("result_ForAttribute"); } public static IncrementalValuesProvider ForAttributeWithMetadataName( @@ -63,7 +65,7 @@ class XAttribute : System.Attribute { } } "; var parseOptions = TestOptions.RegularPreview; - Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDll, parseOptions: parseOptions); + Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); Assert.Single(compilation.SyntaxTrees); @@ -105,7 +107,7 @@ class XAttribute : System.Attribute { } } "; var parseOptions = TestOptions.RegularPreview; - Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDll, parseOptions: parseOptions); + Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); Assert.Single(compilation.SyntaxTrees); @@ -142,7 +144,7 @@ class XAttribute : System.Attribute { } } "; var parseOptions = TestOptions.RegularPreview; - Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDll, parseOptions: parseOptions); + Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); Assert.Single(compilation.SyntaxTrees); @@ -172,7 +174,7 @@ public void FindAssemblyAttribute1(string attribute) [assembly: {attribute}] "; var parseOptions = TestOptions.RegularPreview; - Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDll, parseOptions: parseOptions); + Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); Assert.Single(compilation.SyntaxTrees); @@ -202,7 +204,7 @@ public void FindModuleAttribute1(string attribute) [module: {attribute}] "; var parseOptions = TestOptions.RegularPreview; - Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDll, parseOptions: parseOptions); + Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); Assert.Single(compilation.SyntaxTrees); @@ -231,7 +233,7 @@ public void FindAssemblyAttribute2(string source2) "; var parseOptions = TestOptions.RegularPreview; - Compilation compilation = CreateCompilation(new[] { source1, source2 }, options: TestOptions.DebugDll, parseOptions: parseOptions); + Compilation compilation = CreateCompilation(new[] { source1, source2 }, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); var generator = new IncrementalGeneratorWrapper(new PipelineCallbackGenerator(ctx => { @@ -258,7 +260,7 @@ public void FindAssemblyAttribute3(string source1) "; var parseOptions = TestOptions.RegularPreview; - Compilation compilation = CreateCompilation(new[] { source1, source2 }, options: TestOptions.DebugDll, parseOptions: parseOptions); + Compilation compilation = CreateCompilation(new[] { source1, source2 }, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); var generator = new IncrementalGeneratorWrapper(new PipelineCallbackGenerator(ctx => { @@ -286,7 +288,7 @@ public void FindAssemblyAttribute4() [assembly: CLSCompliant(false)] "; var parseOptions = TestOptions.RegularPreview; - Compilation compilation = CreateCompilation(new[] { source1, source2 }, options: TestOptions.DebugDll, parseOptions: parseOptions); + Compilation compilation = CreateCompilation(new[] { source1, source2 }, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); var generator = new IncrementalGeneratorWrapper(new PipelineCallbackGenerator(ctx => { @@ -315,7 +317,7 @@ void LocalFunc() } "; var parseOptions = TestOptions.RegularPreview; - Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDll, parseOptions: parseOptions); + Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); Assert.Single(compilation.SyntaxTrees); @@ -351,7 +353,7 @@ void LocalFunc() } "; var parseOptions = TestOptions.RegularPreview; - Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDll, parseOptions: parseOptions); + Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); Assert.Single(compilation.SyntaxTrees); @@ -390,7 +392,7 @@ void LocalFunc() } "; var parseOptions = TestOptions.RegularPreview; - Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDll, parseOptions: parseOptions); + Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); Assert.Single(compilation.SyntaxTrees); @@ -419,7 +421,7 @@ class C<[CLSCompliant(true)] T> } "; var parseOptions = TestOptions.RegularPreview; - Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDll, parseOptions: parseOptions); + Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); Assert.Single(compilation.SyntaxTrees); @@ -452,7 +454,7 @@ void M() } "; var parseOptions = TestOptions.RegularPreview; - Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDll, parseOptions: parseOptions); + Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); Assert.Single(compilation.SyntaxTrees); @@ -485,7 +487,7 @@ void M() } "; var parseOptions = TestOptions.RegularPreview; - Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDll, parseOptions: parseOptions); + Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); Assert.Single(compilation.SyntaxTrees); @@ -517,7 +519,7 @@ internal partial void M() { } } "; var parseOptions = TestOptions.RegularPreview; - Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDll, parseOptions: parseOptions); + Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); Assert.Single(compilation.SyntaxTrees); @@ -549,7 +551,7 @@ internal partial void M() { } } "; var parseOptions = TestOptions.RegularPreview; - Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDll, parseOptions: parseOptions); + Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); Assert.Single(compilation.SyntaxTrees); @@ -580,7 +582,7 @@ class C } "; var parseOptions = TestOptions.RegularPreview; - Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDll, parseOptions: parseOptions); + Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); Assert.Single(compilation.SyntaxTrees); @@ -611,7 +613,7 @@ class C } "; var parseOptions = TestOptions.RegularPreview; - Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDll, parseOptions: parseOptions); + Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); Assert.Single(compilation.SyntaxTrees); @@ -644,7 +646,7 @@ class C } "; var parseOptions = TestOptions.RegularPreview; - Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDll, parseOptions: parseOptions); + Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); Assert.Single(compilation.SyntaxTrees); @@ -675,7 +677,7 @@ class C } "; var parseOptions = TestOptions.RegularPreview; - Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDll, parseOptions: parseOptions); + Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); Assert.Single(compilation.SyntaxTrees); @@ -704,7 +706,7 @@ public void FindParenthesizedLambdaAttribute1() Func v = [CLSCompliant(true)] (int i) => i; "; var parseOptions = TestOptions.RegularPreview; - Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDll, parseOptions: parseOptions); + Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); Assert.Single(compilation.SyntaxTrees); @@ -738,7 +740,7 @@ int Prop } "; var parseOptions = TestOptions.RegularPreview; - Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDll, parseOptions: parseOptions); + Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); Assert.Single(compilation.SyntaxTrees); @@ -767,7 +769,7 @@ class C<[CLSCompliant(true)]T> } "; var parseOptions = TestOptions.RegularPreview; - Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDll, parseOptions: parseOptions); + Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); Assert.Single(compilation.SyntaxTrees); @@ -804,7 +806,7 @@ public class InnerAttribute : System.Attribute { } } "; var parseOptions = TestOptions.RegularPreview; - Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDll, parseOptions: parseOptions); + Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); Assert.Single(compilation.SyntaxTrees); @@ -841,7 +843,7 @@ public class InnerAttribute : System.Attribute { } } "; var parseOptions = TestOptions.RegularPreview; - Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDll, parseOptions: parseOptions); + Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); Assert.Single(compilation.SyntaxTrees); @@ -878,7 +880,7 @@ public class InnerAttribute : System.Attribute { } } "; var parseOptions = TestOptions.RegularPreview; - Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDll, parseOptions: parseOptions); + Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); Assert.Single(compilation.SyntaxTrees); @@ -915,7 +917,7 @@ public class InnerAttribute : System.Attribute { } } "; var parseOptions = TestOptions.RegularPreview; - Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDll, parseOptions: parseOptions); + Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); Assert.Single(compilation.SyntaxTrees); @@ -952,7 +954,7 @@ public class InnerAttribute : System.Attribute { } } "; var parseOptions = TestOptions.RegularPreview; - Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDll, parseOptions: parseOptions); + Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); Assert.Single(compilation.SyntaxTrees); @@ -988,7 +990,7 @@ public class InnerAttribute : System.Attribute { } } "; var parseOptions = TestOptions.RegularPreview; - Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDll, parseOptions: parseOptions); + Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); Assert.Single(compilation.SyntaxTrees); @@ -1015,7 +1017,7 @@ class C { } class XAttribute : System.Attribute { } "; var parseOptions = TestOptions.RegularPreview; - Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDll, parseOptions: parseOptions); + Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); Assert.Single(compilation.SyntaxTrees); @@ -1052,7 +1054,7 @@ class C { } class XAttribute : System.Attribute { } "; var parseOptions = TestOptions.RegularPreview; - Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDll, parseOptions: parseOptions); + Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); Assert.Single(compilation.SyntaxTrees); @@ -1090,7 +1092,7 @@ class XAttribute : System.Attribute { } class YAttribute : System.Attribute { } "; var parseOptions = TestOptions.RegularPreview; - Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDll, parseOptions: parseOptions); + Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); Assert.Single(compilation.SyntaxTrees); @@ -1128,7 +1130,7 @@ class XAttribute : System.Attribute { } class YAttribute : System.Attribute { } "; var parseOptions = TestOptions.RegularPreview; - Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDll, parseOptions: parseOptions); + Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); Assert.Single(compilation.SyntaxTrees); @@ -1166,7 +1168,7 @@ class XAttribute : System.Attribute { } class YAttribute : System.Attribute { } "; var parseOptions = TestOptions.RegularPreview; - Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDll, parseOptions: parseOptions); + Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); Assert.Single(compilation.SyntaxTrees); @@ -1204,7 +1206,7 @@ class XAttribute : System.Attribute { } class YAttribute : System.Attribute { } "; var parseOptions = TestOptions.RegularPreview; - Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDll, parseOptions: parseOptions); + Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); Assert.Single(compilation.SyntaxTrees); @@ -1249,7 +1251,7 @@ class XAttribute : System.Attribute } "; var parseOptions = TestOptions.RegularPreview; - Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDll, parseOptions: parseOptions); + Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); Assert.Single(compilation.SyntaxTrees); @@ -1273,15 +1275,13 @@ class XAttribute : System.Attribute Assert.Collection(runResult.TrackedSteps["result_ForAttributeWithMetadataName"], step => Assert.True(step.Outputs.Single().Value is ClassDeclarationSyntax { Identifier.ValueText: "C" })); - Assert.Equal(IncrementalStepRunReason.Cached, runResult.TrackedSteps["individualFileGlobalAliases_ForAttribute"].Single().Outputs.Single().Reason); - Assert.Equal(IncrementalStepRunReason.Cached, runResult.TrackedSteps["collectedGlobalAliases_ForAttribute"].Single().Outputs.Single().Reason); + Assert.False(runResult.TrackedSteps.ContainsKey("individualFileGlobalAliases_ForAttribute")); + Assert.Equal(IncrementalStepRunReason.Unchanged, runResult.TrackedSteps["collectedGlobalAliases_ForAttribute"].Single().Outputs.Single().Reason); Assert.Equal(IncrementalStepRunReason.Cached, runResult.TrackedSteps["compilationGlobalAliases_ForAttribute"].Single().Outputs.Single().Reason); Assert.Equal(IncrementalStepRunReason.Cached, runResult.TrackedSteps["allUpGlobalAliases_ForAttribute"].Single().Outputs.Single().Reason); Assert.Equal(IncrementalStepRunReason.Cached, runResult.TrackedSteps["compilationUnit_ForAttribute"].Single().Outputs.Single().Reason); Assert.Equal(IncrementalStepRunReason.Cached, runResult.TrackedSteps["compilationUnitAndGlobalAliases_ForAttribute"].Single().Outputs.Single().Reason); - Assert.Equal(IncrementalStepRunReason.Cached, runResult.TrackedSteps["result_ForAttribute"].Single().Outputs.Single().Reason); - Assert.Equal(IncrementalStepRunReason.Cached, runResult.TrackedSteps["collectedNodes_ForAttributeWithMetadataName"].Single().Outputs.Single().Reason); - Assert.Equal(IncrementalStepRunReason.Cached, runResult.TrackedSteps["groupedNodes_ForAttributeWithMetadataName"].Single().Outputs.Single().Reason); + Assert.Equal(IncrementalStepRunReason.Cached, runResult.TrackedSteps["result_ForAttributeInternal"].Single().Outputs.Single().Reason); Assert.Equal(IncrementalStepRunReason.Cached, runResult.TrackedSteps["compilationAndGroupedNodes_ForAttributeWithMetadataName"].Single().Outputs.Single().Reason); Assert.Equal(IncrementalStepRunReason.Cached, runResult.TrackedSteps["result_ForAttributeWithMetadataName"].Single().Outputs.Single().Reason); } @@ -1298,7 +1298,7 @@ class XAttribute : System.Attribute } "; var parseOptions = TestOptions.RegularPreview; - Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDll, parseOptions: parseOptions); + Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); Assert.Single(compilation.SyntaxTrees); @@ -1322,15 +1322,13 @@ class XAttribute : System.Attribute Assert.Collection(runResult.TrackedSteps["result_ForAttributeWithMetadataName"], step => Assert.True(step.Outputs.Single().Value is ClassDeclarationSyntax { Identifier.ValueText: "C" })); - Assert.Equal(IncrementalStepRunReason.Cached, runResult.TrackedSteps["individualFileGlobalAliases_ForAttribute"].Single().Outputs.Single().Reason); - Assert.Equal(IncrementalStepRunReason.Cached, runResult.TrackedSteps["collectedGlobalAliases_ForAttribute"].Single().Outputs.Single().Reason); + Assert.False(runResult.TrackedSteps.ContainsKey("individualFileGlobalAliases_ForAttribute")); + Assert.Equal(IncrementalStepRunReason.Unchanged, runResult.TrackedSteps["collectedGlobalAliases_ForAttribute"].Single().Outputs.Single().Reason); Assert.Equal(IncrementalStepRunReason.Cached, runResult.TrackedSteps["compilationGlobalAliases_ForAttribute"].Single().Outputs.Single().Reason); Assert.Equal(IncrementalStepRunReason.Cached, runResult.TrackedSteps["allUpGlobalAliases_ForAttribute"].Single().Outputs.Single().Reason); Assert.Equal(IncrementalStepRunReason.Unchanged, runResult.TrackedSteps["compilationUnit_ForAttribute"].Single().Outputs.Single().Reason); Assert.Equal(IncrementalStepRunReason.Cached, runResult.TrackedSteps["compilationUnitAndGlobalAliases_ForAttribute"].Single().Outputs.Single().Reason); - Assert.Equal(IncrementalStepRunReason.Cached, runResult.TrackedSteps["result_ForAttribute"].Single().Outputs.Single().Reason); - Assert.Equal(IncrementalStepRunReason.Cached, runResult.TrackedSteps["collectedNodes_ForAttributeWithMetadataName"].Single().Outputs.Single().Reason); - Assert.Equal(IncrementalStepRunReason.Cached, runResult.TrackedSteps["groupedNodes_ForAttributeWithMetadataName"].Single().Outputs.Single().Reason); + Assert.Equal(IncrementalStepRunReason.Cached, runResult.TrackedSteps["result_ForAttributeInternal"].Single().Outputs.Single().Reason); Assert.Equal(IncrementalStepRunReason.Modified, runResult.TrackedSteps["compilationAndGroupedNodes_ForAttributeWithMetadataName"].Single().Outputs.Single().Reason); Assert.Equal(IncrementalStepRunReason.Unchanged, runResult.TrackedSteps["result_ForAttributeWithMetadataName"].Single().Outputs.Single().Reason); } @@ -1347,7 +1345,7 @@ class XAttribute : System.Attribute } "; var parseOptions = TestOptions.RegularPreview; - Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDll, parseOptions: parseOptions); + Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); Assert.Single(compilation.SyntaxTrees); @@ -1370,19 +1368,14 @@ class XAttribute : System.Attribute Assert.Collection(runResult.TrackedSteps["result_ForAttributeWithMetadataName"], step => Assert.True(step.Outputs.Single().Value is ClassDeclarationSyntax { Identifier.ValueText: "C" })); - Assert.Collection(runResult.TrackedSteps["individualFileGlobalAliases_ForAttribute"], - s => Assert.Equal(IncrementalStepRunReason.Cached, s.Outputs.Single().Reason), - s => Assert.Equal(IncrementalStepRunReason.New, s.Outputs.Single().Reason)); - Assert.Equal(IncrementalStepRunReason.Modified, runResult.TrackedSteps["collectedGlobalAliases_ForAttribute"].Single().Outputs.Single().Reason); + Assert.False(runResult.TrackedSteps.ContainsKey("individualFileGlobalAliases_ForAttribute")); + Assert.Equal(IncrementalStepRunReason.Unchanged, runResult.TrackedSteps["collectedGlobalAliases_ForAttribute"].Single().Outputs.Single().Reason); Assert.Equal(IncrementalStepRunReason.Cached, runResult.TrackedSteps["compilationGlobalAliases_ForAttribute"].Single().Outputs.Single().Reason); - Assert.Equal(IncrementalStepRunReason.Unchanged, runResult.TrackedSteps["allUpGlobalAliases_ForAttribute"].Single().Outputs.Single().Reason); + Assert.Equal(IncrementalStepRunReason.Cached, runResult.TrackedSteps["allUpGlobalAliases_ForAttribute"].Single().Outputs.Single().Reason); Assert.Collection(runResult.TrackedSteps["compilationUnit_ForAttribute"].Single().Outputs, - o => Assert.Equal(IncrementalStepRunReason.Unchanged, o.Reason), - o => Assert.Equal(IncrementalStepRunReason.Modified, o.Reason)); + o => Assert.Equal(IncrementalStepRunReason.Unchanged, o.Reason)); Assert.Equal(IncrementalStepRunReason.Cached, runResult.TrackedSteps["compilationUnitAndGlobalAliases_ForAttribute"].Single().Outputs.Single().Reason); - Assert.Equal(IncrementalStepRunReason.Cached, runResult.TrackedSteps["result_ForAttribute"].Single().Outputs.Single().Reason); - Assert.Equal(IncrementalStepRunReason.Unchanged, runResult.TrackedSteps["collectedNodes_ForAttributeWithMetadataName"].Single().Outputs.Single().Reason); - Assert.Equal(IncrementalStepRunReason.Cached, runResult.TrackedSteps["groupedNodes_ForAttributeWithMetadataName"].Single().Outputs.Single().Reason); + Assert.Equal(IncrementalStepRunReason.Cached, runResult.TrackedSteps["result_ForAttributeInternal"].Single().Outputs.Single().Reason); Assert.Equal(IncrementalStepRunReason.Modified, runResult.TrackedSteps["compilationAndGroupedNodes_ForAttributeWithMetadataName"].Single().Outputs.Single().Reason); Assert.Equal(IncrementalStepRunReason.Unchanged, runResult.TrackedSteps["result_ForAttributeWithMetadataName"].Single().Outputs.Single().Reason); } @@ -1395,7 +1388,7 @@ public void RerunWithAddedFile2() class C { } "; var parseOptions = TestOptions.RegularPreview; - Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDll, parseOptions: parseOptions); + Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); Assert.Single(compilation.SyntaxTrees); @@ -1420,19 +1413,14 @@ class XAttribute : System.Attribute Assert.Collection(runResult.TrackedSteps["result_ForAttributeWithMetadataName"], step => Assert.True(step.Outputs.Single().Value is ClassDeclarationSyntax { Identifier.ValueText: "C" })); - Assert.Collection(runResult.TrackedSteps["individualFileGlobalAliases_ForAttribute"], - s => Assert.Equal(IncrementalStepRunReason.Cached, s.Outputs.Single().Reason), - s => Assert.Equal(IncrementalStepRunReason.New, s.Outputs.Single().Reason)); - Assert.Equal(IncrementalStepRunReason.Modified, runResult.TrackedSteps["collectedGlobalAliases_ForAttribute"].Single().Outputs.Single().Reason); + Assert.False(runResult.TrackedSteps.ContainsKey("individualFileGlobalAliases_ForAttribute")); + Assert.Equal(IncrementalStepRunReason.Unchanged, runResult.TrackedSteps["collectedGlobalAliases_ForAttribute"].Single().Outputs.Single().Reason); Assert.Equal(IncrementalStepRunReason.Cached, runResult.TrackedSteps["compilationGlobalAliases_ForAttribute"].Single().Outputs.Single().Reason); - Assert.Equal(IncrementalStepRunReason.Unchanged, runResult.TrackedSteps["allUpGlobalAliases_ForAttribute"].Single().Outputs.Single().Reason); + Assert.Equal(IncrementalStepRunReason.Cached, runResult.TrackedSteps["allUpGlobalAliases_ForAttribute"].Single().Outputs.Single().Reason); Assert.Collection(runResult.TrackedSteps["compilationUnit_ForAttribute"].Single().Outputs, - o => Assert.Equal(IncrementalStepRunReason.Unchanged, o.Reason), - o => Assert.Equal(IncrementalStepRunReason.Modified, o.Reason)); + o => Assert.Equal(IncrementalStepRunReason.Unchanged, o.Reason)); Assert.Equal(IncrementalStepRunReason.Cached, runResult.TrackedSteps["compilationUnitAndGlobalAliases_ForAttribute"].Single().Outputs.Single().Reason); - Assert.Equal(IncrementalStepRunReason.Cached, runResult.TrackedSteps["result_ForAttribute"].Single().Outputs.Single().Reason); - Assert.Equal(IncrementalStepRunReason.Unchanged, runResult.TrackedSteps["collectedNodes_ForAttributeWithMetadataName"].Single().Outputs.Single().Reason); - Assert.Equal(IncrementalStepRunReason.Cached, runResult.TrackedSteps["groupedNodes_ForAttributeWithMetadataName"].Single().Outputs.Single().Reason); + Assert.Equal(IncrementalStepRunReason.Cached, runResult.TrackedSteps["result_ForAttributeInternal"].Single().Outputs.Single().Reason); Assert.Equal(IncrementalStepRunReason.Modified, runResult.TrackedSteps["compilationAndGroupedNodes_ForAttributeWithMetadataName"].Single().Outputs.Single().Reason); Assert.Equal(IncrementalStepRunReason.Modified, runResult.TrackedSteps["result_ForAttributeWithMetadataName"].Single().Outputs.Single().Reason); } @@ -1447,7 +1435,7 @@ class C1 { } class C2 { } "; var parseOptions = TestOptions.RegularPreview; - Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDll, parseOptions: parseOptions); + Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); Assert.Single(compilation.SyntaxTrees); @@ -1474,21 +1462,15 @@ class XAttribute : System.Attribute t => Assert.True(t.Value is ClassDeclarationSyntax { Identifier.ValueText: "C1" }), t => Assert.True(t.Value is ClassDeclarationSyntax { Identifier.ValueText: "C2" }))); - Assert.Collection(runResult.TrackedSteps["individualFileGlobalAliases_ForAttribute"], - s => Assert.Equal(IncrementalStepRunReason.Cached, s.Outputs.Single().Reason), - s => Assert.Equal(IncrementalStepRunReason.New, s.Outputs.Single().Reason)); - Assert.Equal(IncrementalStepRunReason.Modified, runResult.TrackedSteps["collectedGlobalAliases_ForAttribute"].Single().Outputs.Single().Reason); + Assert.False(runResult.TrackedSteps.ContainsKey("individualFileGlobalAliases_ForAttribute")); + Assert.Equal(IncrementalStepRunReason.Unchanged, runResult.TrackedSteps["collectedGlobalAliases_ForAttribute"].Single().Outputs.Single().Reason); Assert.Equal(IncrementalStepRunReason.Cached, runResult.TrackedSteps["compilationGlobalAliases_ForAttribute"].Single().Outputs.Single().Reason); - Assert.Equal(IncrementalStepRunReason.Unchanged, runResult.TrackedSteps["allUpGlobalAliases_ForAttribute"].Single().Outputs.Single().Reason); + Assert.Equal(IncrementalStepRunReason.Cached, runResult.TrackedSteps["allUpGlobalAliases_ForAttribute"].Single().Outputs.Single().Reason); Assert.Collection(runResult.TrackedSteps["compilationUnit_ForAttribute"].Single().Outputs, - o => Assert.Equal(IncrementalStepRunReason.Unchanged, o.Reason), - o => Assert.Equal(IncrementalStepRunReason.Modified, o.Reason)); + o => Assert.Equal(IncrementalStepRunReason.Unchanged, o.Reason)); Assert.Equal(IncrementalStepRunReason.Cached, runResult.TrackedSteps["compilationUnitAndGlobalAliases_ForAttribute"].Single().Outputs.Single().Reason); - Assert.Collection(runResult.TrackedSteps["result_ForAttribute"].Single().Outputs, - t => Assert.Equal(IncrementalStepRunReason.Cached, t.Reason), + Assert.Collection(runResult.TrackedSteps["result_ForAttributeInternal"].Single().Outputs, t => Assert.Equal(IncrementalStepRunReason.Cached, t.Reason)); - Assert.Equal(IncrementalStepRunReason.Unchanged, runResult.TrackedSteps["collectedNodes_ForAttributeWithMetadataName"].Single().Outputs.Single().Reason); - Assert.Equal(IncrementalStepRunReason.Cached, runResult.TrackedSteps["groupedNodes_ForAttributeWithMetadataName"].Single().Outputs.Single().Reason); Assert.Equal(IncrementalStepRunReason.Modified, runResult.TrackedSteps["compilationAndGroupedNodes_ForAttributeWithMetadataName"].Single().Outputs.Single().Reason); Assert.Collection(runResult.TrackedSteps["result_ForAttributeWithMetadataName"].Single().Outputs, t => Assert.Equal(IncrementalStepRunReason.Modified, t.Reason), @@ -1507,7 +1489,7 @@ class C1 { } class C2 { } "; var parseOptions = TestOptions.RegularPreview; - Compilation compilation = CreateCompilation(new[] { source1, source2 }, options: TestOptions.DebugDll, parseOptions: parseOptions); + Compilation compilation = CreateCompilation(new[] { source1, source2 }, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); var generator = new IncrementalGeneratorWrapper(new PipelineCallbackGenerator(ctx => { @@ -1531,27 +1513,19 @@ class XAttribute : System.Attribute step => Assert.Collection(step.Outputs, t => Assert.True(t.Value is ClassDeclarationSyntax { Identifier.ValueText: "C1" })), step => Assert.Collection(step.Outputs, t => Assert.True(t.Value is ClassDeclarationSyntax { Identifier.ValueText: "C2" }))); - Assert.Collection(runResult.TrackedSteps["individualFileGlobalAliases_ForAttribute"], - s => Assert.Equal(IncrementalStepRunReason.Cached, s.Outputs.Single().Reason), - s => Assert.Equal(IncrementalStepRunReason.Cached, s.Outputs.Single().Reason), - s => Assert.Equal(IncrementalStepRunReason.New, s.Outputs.Single().Reason)); - Assert.Equal(IncrementalStepRunReason.Modified, runResult.TrackedSteps["collectedGlobalAliases_ForAttribute"].Single().Outputs.Single().Reason); + Assert.False(runResult.TrackedSteps.ContainsKey("individualFileGlobalAliases_ForAttribute")); + Assert.Equal(IncrementalStepRunReason.Unchanged, runResult.TrackedSteps["collectedGlobalAliases_ForAttribute"].Single().Outputs.Single().Reason); Assert.Equal(IncrementalStepRunReason.Cached, runResult.TrackedSteps["compilationGlobalAliases_ForAttribute"].Single().Outputs.Single().Reason); - Assert.Equal(IncrementalStepRunReason.Unchanged, runResult.TrackedSteps["allUpGlobalAliases_ForAttribute"].Single().Outputs.Single().Reason); + Assert.Equal(IncrementalStepRunReason.Cached, runResult.TrackedSteps["allUpGlobalAliases_ForAttribute"].Single().Outputs.Single().Reason); Assert.Collection(runResult.TrackedSteps["compilationUnit_ForAttribute"].Single().Outputs, o => Assert.Equal(IncrementalStepRunReason.Unchanged, o.Reason), - o => Assert.Equal(IncrementalStepRunReason.Unchanged, o.Reason), - o => Assert.Equal(IncrementalStepRunReason.Modified, o.Reason)); + o => Assert.Equal(IncrementalStepRunReason.Unchanged, o.Reason)); Assert.Collection(runResult.TrackedSteps["compilationUnitAndGlobalAliases_ForAttribute"], s => Assert.Equal(IncrementalStepRunReason.Cached, s.Outputs.Single().Reason), s => Assert.Equal(IncrementalStepRunReason.Cached, s.Outputs.Single().Reason)); - Assert.Collection(runResult.TrackedSteps["result_ForAttribute"], + Assert.Collection(runResult.TrackedSteps["result_ForAttributeInternal"], s => Assert.Equal(IncrementalStepRunReason.Cached, s.Outputs.Single().Reason), s => Assert.Equal(IncrementalStepRunReason.Cached, s.Outputs.Single().Reason)); - Assert.Equal(IncrementalStepRunReason.Unchanged, runResult.TrackedSteps["collectedNodes_ForAttributeWithMetadataName"].Single().Outputs.Single().Reason); - Assert.Collection(runResult.TrackedSteps["groupedNodes_ForAttributeWithMetadataName"].Single().Outputs, - t => Assert.Equal(IncrementalStepRunReason.Cached, t.Reason), - t => Assert.Equal(IncrementalStepRunReason.Cached, t.Reason)); Assert.Collection(runResult.TrackedSteps["compilationAndGroupedNodes_ForAttributeWithMetadataName"], s => Assert.Equal(IncrementalStepRunReason.Modified, s.Outputs.Single().Reason), s => Assert.Equal(IncrementalStepRunReason.Modified, s.Outputs.Single().Reason)); @@ -1571,7 +1545,7 @@ class XAttribute : System.Attribute } "; var parseOptions = TestOptions.RegularPreview; - Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDll, parseOptions: parseOptions); + Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); Assert.Single(compilation.SyntaxTrees); @@ -1602,16 +1576,13 @@ class XAttribute : System.Attribute Assert.Collection(runResult.TrackedSteps["result_ForAttributeWithMetadataName"], step => Assert.True(step.Outputs.Single().Value is ClassDeclarationSyntax { Identifier.ValueText: "C" })); - Assert.Collection(runResult.TrackedSteps["individualFileGlobalAliases_ForAttribute"], - s => Assert.Equal(IncrementalStepRunReason.Unchanged, s.Outputs.Single().Reason)); - Assert.Equal(IncrementalStepRunReason.Cached, runResult.TrackedSteps["collectedGlobalAliases_ForAttribute"].Single().Outputs.Single().Reason); + Assert.False(runResult.TrackedSteps.ContainsKey("individualFileGlobalAliases_ForAttribute")); + Assert.Equal(IncrementalStepRunReason.Unchanged, runResult.TrackedSteps["collectedGlobalAliases_ForAttribute"].Single().Outputs.Single().Reason); Assert.Equal(IncrementalStepRunReason.Cached, runResult.TrackedSteps["compilationGlobalAliases_ForAttribute"].Single().Outputs.Single().Reason); Assert.Equal(IncrementalStepRunReason.Cached, runResult.TrackedSteps["allUpGlobalAliases_ForAttribute"].Single().Outputs.Single().Reason); Assert.Equal(IncrementalStepRunReason.Modified, runResult.TrackedSteps["compilationUnit_ForAttribute"].Single().Outputs.Single().Reason); - Assert.Equal(IncrementalStepRunReason.Modified, runResult.TrackedSteps["compilationUnitAndGlobalAliases_ForAttribute"].Single().Outputs.Single().Reason); - Assert.Equal(IncrementalStepRunReason.Modified, runResult.TrackedSteps["result_ForAttribute"].Single().Outputs.Single().Reason); - Assert.Equal(IncrementalStepRunReason.Modified, runResult.TrackedSteps["collectedNodes_ForAttributeWithMetadataName"].Single().Outputs.Single().Reason); - Assert.Equal(IncrementalStepRunReason.Modified, runResult.TrackedSteps["groupedNodes_ForAttributeWithMetadataName"].Single().Outputs.Single().Reason); + Assert.Equal(IncrementalStepRunReason.New, runResult.TrackedSteps["compilationUnitAndGlobalAliases_ForAttribute"].Single().Outputs.Single().Reason); + Assert.Equal(IncrementalStepRunReason.New, runResult.TrackedSteps["result_ForAttributeInternal"].Single().Outputs.Single().Reason); Assert.Equal(IncrementalStepRunReason.New, runResult.TrackedSteps["compilationAndGroupedNodes_ForAttributeWithMetadataName"].Single().Outputs.Single().Reason); Assert.Equal(IncrementalStepRunReason.New, runResult.TrackedSteps["result_ForAttributeWithMetadataName"].Single().Outputs.Single().Reason); } @@ -1628,7 +1599,7 @@ class XAttribute : System.Attribute } "; var parseOptions = TestOptions.RegularPreview; - Compilation compilation = CreateCompilation(new[] { source1, source2 }, options: TestOptions.DebugDll, parseOptions: parseOptions); + Compilation compilation = CreateCompilation(new[] { source1, source2 }, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); var generator = new IncrementalGeneratorWrapper(new PipelineCallbackGenerator(ctx => { @@ -1653,19 +1624,14 @@ class C { } Assert.Collection(runResult.TrackedSteps["result_ForAttributeWithMetadataName"], step => Assert.True(step.Outputs.Single().Value is ClassDeclarationSyntax { Identifier.ValueText: "C" })); - Assert.Collection(runResult.TrackedSteps["individualFileGlobalAliases_ForAttribute"], - s => Assert.Equal(IncrementalStepRunReason.Unchanged, s.Outputs.Single().Reason), - s => Assert.Equal(IncrementalStepRunReason.Cached, s.Outputs.Single().Reason)); - Assert.Equal(IncrementalStepRunReason.Cached, runResult.TrackedSteps["collectedGlobalAliases_ForAttribute"].Single().Outputs.Single().Reason); + Assert.False(runResult.TrackedSteps.ContainsKey("individualFileGlobalAliases_ForAttribute")); + Assert.Equal(IncrementalStepRunReason.Unchanged, runResult.TrackedSteps["collectedGlobalAliases_ForAttribute"].Single().Outputs.Single().Reason); Assert.Equal(IncrementalStepRunReason.Cached, runResult.TrackedSteps["compilationGlobalAliases_ForAttribute"].Single().Outputs.Single().Reason); Assert.Equal(IncrementalStepRunReason.Cached, runResult.TrackedSteps["allUpGlobalAliases_ForAttribute"].Single().Outputs.Single().Reason); Assert.Collection(runResult.TrackedSteps["compilationUnit_ForAttribute"].Single().Outputs, - o => Assert.Equal(IncrementalStepRunReason.Modified, o.Reason), - o => Assert.Equal(IncrementalStepRunReason.Unchanged, o.Reason)); - Assert.Equal(IncrementalStepRunReason.Modified, runResult.TrackedSteps["compilationUnitAndGlobalAliases_ForAttribute"].Single().Outputs.Single().Reason); - Assert.Equal(IncrementalStepRunReason.Modified, runResult.TrackedSteps["result_ForAttribute"].Single().Outputs.Single().Reason); - Assert.Equal(IncrementalStepRunReason.Modified, runResult.TrackedSteps["collectedNodes_ForAttributeWithMetadataName"].Single().Outputs.Single().Reason); - Assert.Equal(IncrementalStepRunReason.Modified, runResult.TrackedSteps["groupedNodes_ForAttributeWithMetadataName"].Single().Outputs.Single().Reason); + o => Assert.Equal(IncrementalStepRunReason.Modified, o.Reason)); + Assert.Equal(IncrementalStepRunReason.New, runResult.TrackedSteps["compilationUnitAndGlobalAliases_ForAttribute"].Single().Outputs.Single().Reason); + Assert.Equal(IncrementalStepRunReason.New, runResult.TrackedSteps["result_ForAttributeInternal"].Single().Outputs.Single().Reason); Assert.Equal(IncrementalStepRunReason.New, runResult.TrackedSteps["compilationAndGroupedNodes_ForAttributeWithMetadataName"].Single().Outputs.Single().Reason); Assert.Equal(IncrementalStepRunReason.New, runResult.TrackedSteps["result_ForAttributeWithMetadataName"].Single().Outputs.Single().Reason); } 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 0aa0a01e55287..2f94d34906029 100644 --- a/src/Compilers/CSharp/Test/Semantic/SourceGeneration/GeneratorDriverTests_Attributes_SimpleName.cs +++ b/src/Compilers/CSharp/Test/Semantic/SourceGeneration/GeneratorDriverTests_Attributes_SimpleName.cs @@ -3,7 +3,9 @@ // See the LICENSE file in the project root for more information. using System; +using System.Collections.Generic; using System.Linq; +using System.Text; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.CSharp.Test.Utilities; @@ -36,7 +38,7 @@ public void FindAttributeOnTopLevelClass_WhenSearchingForClassDeclaration1(strin class C {{ }} "; var parseOptions = TestOptions.RegularPreview; - Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDll, parseOptions: parseOptions); + Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); Assert.Single(compilation.SyntaxTrees); @@ -68,7 +70,7 @@ public void FindFullAttributeNameOnTopLevelClass(string attribute) class C {{ }} "; var parseOptions = TestOptions.RegularPreview; - Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDll, parseOptions: parseOptions); + Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); Assert.Single(compilation.SyntaxTrees); @@ -94,7 +96,7 @@ public void DoNotFindAttributeOnTopLevelClass_WhenSearchingForDelegateDeclaratio class C { } "; var parseOptions = TestOptions.RegularPreview; - Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDll, parseOptions: parseOptions); + Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); Assert.Single(compilation.SyntaxTrees); @@ -119,7 +121,7 @@ public void DoNotFindAttributeOnTopLevelClass_WhenSearchingForDifferentName() class C { } "; var parseOptions = TestOptions.RegularPreview; - Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDll, parseOptions: parseOptions); + Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); Assert.Single(compilation.SyntaxTrees); @@ -144,7 +146,7 @@ public void FindAttributeOnTopLevelClass_WhenSearchingForSyntaxNode1() class C { } "; var parseOptions = TestOptions.RegularPreview; - Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDll, parseOptions: parseOptions); + Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); Assert.Single(compilation.SyntaxTrees); @@ -172,7 +174,7 @@ class C { } class D { } "; var parseOptions = TestOptions.RegularPreview; - Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDll, parseOptions: parseOptions); + Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); Assert.Single(compilation.SyntaxTrees); @@ -204,7 +206,7 @@ class C { } class D { } "; var parseOptions = TestOptions.RegularPreview; - Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDll, parseOptions: parseOptions); + Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); Assert.Single(compilation.SyntaxTrees); @@ -236,7 +238,7 @@ class C { } class D { } "; var parseOptions = TestOptions.RegularPreview; - Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDll, parseOptions: parseOptions); + Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); Assert.Single(compilation.SyntaxTrees); @@ -270,7 +272,7 @@ class D { } } "; var parseOptions = TestOptions.RegularPreview; - Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDll, parseOptions: parseOptions); + Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); Assert.Single(compilation.SyntaxTrees); @@ -303,7 +305,7 @@ class C { } } "; var parseOptions = TestOptions.RegularPreview; - Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDll, parseOptions: parseOptions); + Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); Assert.Single(compilation.SyntaxTrees); @@ -329,7 +331,7 @@ public void FindAttributeOnTopLevelClass_WhenSearchingForClassDeclaration_FullAt class C { } "; var parseOptions = TestOptions.RegularPreview; - Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDll, parseOptions: parseOptions); + Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); Assert.Single(compilation.SyntaxTrees); @@ -355,7 +357,7 @@ public void FindAttributeOnTopLevelClass_WhenSearchingForClassDeclaration_ShortA class C { } "; var parseOptions = TestOptions.RegularPreview; - Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDll, parseOptions: parseOptions); + Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); Assert.Single(compilation.SyntaxTrees); @@ -381,7 +383,7 @@ public void FindFullAttributeOnTopLevelClass_WhenSearchingForClassDeclaration_Fu class C { } "; var parseOptions = TestOptions.RegularPreview; - Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDll, parseOptions: parseOptions); + Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); Assert.Single(compilation.SyntaxTrees); @@ -414,7 +416,7 @@ public void FindAttributeOnTopLevelClass_WhenSearchingForClassDeclaration_WithLo class C {{ }} "; var parseOptions = TestOptions.RegularPreview; - Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDll, parseOptions: parseOptions); + Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); Assert.Single(compilation.SyntaxTrees); @@ -442,7 +444,7 @@ public void FindAttributeOnTopLevelClass_WhenSearchingForClassDeclaration_WithLo class C { } "; var parseOptions = TestOptions.RegularPreview; - Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDll, parseOptions: parseOptions); + Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); Assert.Single(compilation.SyntaxTrees); @@ -470,7 +472,7 @@ public void DoNotFindAttributeOnTopLevelClass_WhenSearchingForClassDeclaration_W class C { } "; var parseOptions = TestOptions.RegularPreview; - Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDll, parseOptions: parseOptions); + Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); Assert.Single(compilation.SyntaxTrees); @@ -497,7 +499,7 @@ public void DoNotFindAttributeOnTopLevelClass_WhenSearchingForClassDeclaration_W class C { } "; var parseOptions = TestOptions.RegularPreview; - Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDll, parseOptions: parseOptions); + Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); Assert.Single(compilation.SyntaxTrees); @@ -528,7 +530,7 @@ class C { } } "; var parseOptions = TestOptions.RegularPreview; - Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDll, parseOptions: parseOptions); + Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); Assert.Single(compilation.SyntaxTrees); @@ -561,7 +563,7 @@ class C { } } "; var parseOptions = TestOptions.RegularPreview; - Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDll, parseOptions: parseOptions); + Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); Assert.Single(compilation.SyntaxTrees); @@ -593,7 +595,7 @@ class C { } } "; var parseOptions = TestOptions.RegularPreview; - Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDll, parseOptions: parseOptions); + Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); Assert.Single(compilation.SyntaxTrees); @@ -625,7 +627,7 @@ class C { } } "; var parseOptions = TestOptions.RegularPreview; - Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDll, parseOptions: parseOptions); + Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); Assert.Single(compilation.SyntaxTrees); @@ -653,7 +655,7 @@ public void DoNotFindAttributeOnTopLevelClass_WhenSearchingForClassDeclaration_R class C { } "; var parseOptions = TestOptions.RegularPreview; - Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDll, parseOptions: parseOptions); + Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); Assert.Single(compilation.SyntaxTrees); @@ -681,7 +683,7 @@ public void DoNotFindAttributeOnTopLevelClass_WhenSearchingForClassDeclaration_R class C { } "; var parseOptions = TestOptions.RegularPreview; - Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDll, parseOptions: parseOptions); + Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); Assert.Single(compilation.SyntaxTrees); @@ -709,7 +711,7 @@ public void DoNotFindAttributeOnTopLevelClass_WhenSearchingForClassDeclaration_R class C { } "; var parseOptions = TestOptions.RegularPreview; - Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDll, parseOptions: parseOptions); + Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); Assert.Single(compilation.SyntaxTrees); @@ -738,7 +740,7 @@ class C { } "; var parseOptions = TestOptions.RegularPreview; - Compilation compilation = CreateCompilation(new[] { source1, source2 }, options: TestOptions.DebugDll, parseOptions: parseOptions); + Compilation compilation = CreateCompilation(new[] { source1, source2 }, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); var generator = new IncrementalGeneratorWrapper(new PipelineCallbackGenerator(ctx => { @@ -765,7 +767,7 @@ class C { } "; var parseOptions = TestOptions.RegularPreview; - Compilation compilation = CreateCompilation(new[] { source1, source2 }, options: TestOptions.DebugDll, parseOptions: parseOptions); + Compilation compilation = CreateCompilation(new[] { source1, source2 }, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); var generator = new IncrementalGeneratorWrapper(new PipelineCallbackGenerator(ctx => { @@ -792,7 +794,7 @@ public void FindAttributeOnTopLevelClass_WhenSearchingForClassDeclaration_Global class C {{ }} "; var parseOptions = TestOptions.RegularPreview; - Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDll, parseOptions: parseOptions); + Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); Assert.Single(compilation.SyntaxTrees); @@ -823,7 +825,7 @@ public void FindAttributeOnTopLevelClass_WhenSearchingForClassDeclaration_Global class C {{ }} "; var parseOptions = TestOptions.RegularPreview; - Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDll, parseOptions: parseOptions); + Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); Assert.Single(compilation.SyntaxTrees); @@ -855,7 +857,7 @@ class C { } "; var parseOptions = TestOptions.RegularPreview; - Compilation compilation = CreateCompilation(new[] { source1, source2 }, options: TestOptions.DebugDll, parseOptions: parseOptions); + Compilation compilation = CreateCompilation(new[] { source1, source2 }, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); var generator = new IncrementalGeneratorWrapper(new PipelineCallbackGenerator(ctx => { @@ -884,7 +886,7 @@ class C { } "; var parseOptions = TestOptions.RegularPreview; - Compilation compilation = CreateCompilation(new[] { source1, source2 }, options: TestOptions.DebugDll, parseOptions: parseOptions); + Compilation compilation = CreateCompilation(new[] { source1, source2 }, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); var generator = new IncrementalGeneratorWrapper(new PipelineCallbackGenerator(ctx => { @@ -912,7 +914,7 @@ class C { } "; var parseOptions = TestOptions.RegularPreview; - Compilation compilation = CreateCompilation(new[] { source1, source2 }, options: TestOptions.DebugDll, parseOptions: parseOptions); + Compilation compilation = CreateCompilation(new[] { source1, source2 }, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); var generator = new IncrementalGeneratorWrapper(new PipelineCallbackGenerator(ctx => { @@ -940,7 +942,7 @@ class C { } "; var parseOptions = TestOptions.RegularPreview; - Compilation compilation = CreateCompilation(new[] { source1, source2 }, options: TestOptions.DebugDll, parseOptions: parseOptions); + Compilation compilation = CreateCompilation(new[] { source1, source2 }, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); var generator = new IncrementalGeneratorWrapper(new PipelineCallbackGenerator(ctx => { @@ -969,7 +971,7 @@ class C { } "; var parseOptions = TestOptions.RegularPreview; - Compilation compilation = CreateCompilation(new[] { source1, source2 }, options: TestOptions.DebugDll, parseOptions: parseOptions); + Compilation compilation = CreateCompilation(new[] { source1, source2 }, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); var generator = new IncrementalGeneratorWrapper(new PipelineCallbackGenerator(ctx => { @@ -999,7 +1001,7 @@ public void RerunOnSameCompilationCachesResultFully() class C { } "; var parseOptions = TestOptions.RegularPreview; - Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDll, parseOptions: parseOptions); + Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); Assert.Single(compilation.SyntaxTrees); @@ -1023,8 +1025,8 @@ class C { } Assert.Collection(runResult.TrackedSteps["result_ForAttribute"], step => Assert.True(step.Outputs.Single().Value is ClassDeclarationSyntax { Identifier.ValueText: "C" })); - Assert.Equal(IncrementalStepRunReason.Cached, runResult.TrackedSteps["individualFileGlobalAliases_ForAttribute"].Single().Outputs.Single().Reason); - Assert.Equal(IncrementalStepRunReason.Cached, runResult.TrackedSteps["collectedGlobalAliases_ForAttribute"].Single().Outputs.Single().Reason); + Assert.False(runResult.TrackedSteps.ContainsKey("individualFileGlobalAliases_ForAttribute")); + Assert.Equal(IncrementalStepRunReason.Unchanged, runResult.TrackedSteps["collectedGlobalAliases_ForAttribute"].Single().Outputs.Single().Reason); Assert.Equal(IncrementalStepRunReason.Cached, runResult.TrackedSteps["allUpGlobalAliases_ForAttribute"].Single().Outputs.Single().Reason); Assert.Equal(IncrementalStepRunReason.Cached, runResult.TrackedSteps["compilationUnit_ForAttribute"].Single().Outputs.Single().Reason); Assert.Equal(IncrementalStepRunReason.Cached, runResult.TrackedSteps["compilationUnitAndGlobalAliases_ForAttribute"].Single().Outputs.Single().Reason); @@ -1039,7 +1041,7 @@ public void RerunOnCompilationWithReferencesChangeCachesResultFully() class C { } "; var parseOptions = TestOptions.RegularPreview; - Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDll, parseOptions: parseOptions); + Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); Assert.Single(compilation.SyntaxTrees); @@ -1063,8 +1065,8 @@ class C { } Assert.Collection(runResult.TrackedSteps["result_ForAttribute"], step => Assert.True(step.Outputs.Single().Value is ClassDeclarationSyntax { Identifier.ValueText: "C" })); - Assert.Equal(IncrementalStepRunReason.Cached, runResult.TrackedSteps["individualFileGlobalAliases_ForAttribute"].Single().Outputs.Single().Reason); - Assert.Equal(IncrementalStepRunReason.Cached, runResult.TrackedSteps["collectedGlobalAliases_ForAttribute"].Single().Outputs.Single().Reason); + Assert.False(runResult.TrackedSteps.ContainsKey("individualFileGlobalAliases_ForAttribute")); + Assert.Equal(IncrementalStepRunReason.Unchanged, runResult.TrackedSteps["collectedGlobalAliases_ForAttribute"].Single().Outputs.Single().Reason); Assert.Equal(IncrementalStepRunReason.Cached, runResult.TrackedSteps["allUpGlobalAliases_ForAttribute"].Single().Outputs.Single().Reason); Assert.Equal(IncrementalStepRunReason.Unchanged, runResult.TrackedSteps["compilationUnit_ForAttribute"].Single().Outputs.Single().Reason); Assert.Equal(IncrementalStepRunReason.Cached, runResult.TrackedSteps["compilationUnitAndGlobalAliases_ForAttribute"].Single().Outputs.Single().Reason); @@ -1085,7 +1087,7 @@ public void TestSourceFileRemoved1() class C { } "; var parseOptions = TestOptions.RegularPreview; - Compilation compilation = CreateCompilation(new[] { source1, source2, source3 }, options: TestOptions.DebugDll, parseOptions: parseOptions); + Compilation compilation = CreateCompilation(new[] { source1, source2, source3 }, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); var generator = new IncrementalGeneratorWrapper(new PipelineCallbackGenerator(ctx => { @@ -1106,14 +1108,13 @@ class C { } Assert.Collection(runResult.TrackedSteps["individualFileGlobalAliases_ForAttribute"], s => Assert.Equal(IncrementalStepRunReason.Cached, s.Outputs.Single().Reason), - s => Assert.Equal(IncrementalStepRunReason.Cached, s.Outputs.Single().Reason), - s => Assert.Equal(IncrementalStepRunReason.Removed, s.Outputs.Single().Reason)); + s => Assert.Equal(IncrementalStepRunReason.Cached, s.Outputs.Single().Reason)); // the per-file global aliases get changed (because the last file is removed). - Assert.Equal(IncrementalStepRunReason.Modified, runResult.TrackedSteps["collectedGlobalAliases_ForAttribute"].Single().Outputs.Single().Reason); + Assert.Equal(IncrementalStepRunReason.Cached, runResult.TrackedSteps["collectedGlobalAliases_ForAttribute"].Single().Outputs.Single().Reason); // however, the collected global aliases stays the same. - Assert.Equal(IncrementalStepRunReason.Unchanged, runResult.TrackedSteps["allUpGlobalAliases_ForAttribute"].Single().Outputs.Single().Reason); + Assert.Equal(IncrementalStepRunReason.Cached, runResult.TrackedSteps["allUpGlobalAliases_ForAttribute"].Single().Outputs.Single().Reason); Assert.Collection(runResult.TrackedSteps["compilationUnit_ForAttribute"].Single().Outputs, o => Assert.Equal(IncrementalStepRunReason.Unchanged, o.Reason), @@ -1137,7 +1138,7 @@ public void TestSourceFileChanged_AttributeRemoved1() class C { } "; var parseOptions = TestOptions.RegularPreview; - Compilation compilation = CreateCompilation(new[] { source1, source2, source3 }, options: TestOptions.DebugDll, parseOptions: parseOptions); + Compilation compilation = CreateCompilation(new[] { source1, source2, source3 }, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); var generator = new IncrementalGeneratorWrapper(new PipelineCallbackGenerator(ctx => { @@ -1161,16 +1162,15 @@ class C { } Assert.Collection(runResult.TrackedSteps["individualFileGlobalAliases_ForAttribute"], s => Assert.Equal(IncrementalStepRunReason.Cached, s.Outputs.Single().Reason), - s => Assert.Equal(IncrementalStepRunReason.Cached, s.Outputs.Single().Reason), - s => Assert.Equal(IncrementalStepRunReason.Unchanged, s.Outputs.Single().Reason)); + s => Assert.Equal(IncrementalStepRunReason.Cached, s.Outputs.Single().Reason)); Assert.Equal(IncrementalStepRunReason.Cached, runResult.TrackedSteps["collectedGlobalAliases_ForAttribute"].Single().Outputs.Single().Reason); Assert.Equal(IncrementalStepRunReason.Cached, runResult.TrackedSteps["allUpGlobalAliases_ForAttribute"].Single().Outputs.Single().Reason); Assert.Collection(runResult.TrackedSteps["compilationUnit_ForAttribute"].Single().Outputs, o => Assert.Equal(IncrementalStepRunReason.Unchanged, o.Reason), o => Assert.Equal(IncrementalStepRunReason.Unchanged, o.Reason), - o => Assert.Equal(IncrementalStepRunReason.Modified, o.Reason)); - Assert.Equal(IncrementalStepRunReason.Modified, runResult.TrackedSteps["compilationUnitAndGlobalAliases_ForAttribute"].Single().Outputs.Single().Reason); + o => Assert.Equal(IncrementalStepRunReason.Removed, o.Reason)); + Assert.Equal(IncrementalStepRunReason.Removed, runResult.TrackedSteps["compilationUnitAndGlobalAliases_ForAttribute"].Single().Outputs.Single().Reason); Assert.Equal(IncrementalStepRunReason.Removed, runResult.TrackedSteps["result_ForAttribute"].Single().Outputs.Single().Reason); } @@ -1187,7 +1187,7 @@ public void TestSourceFileChanged_AttributeAdded1() class C { } "; var parseOptions = TestOptions.RegularPreview; - Compilation compilation = CreateCompilation(new[] { source1, source2, source3 }, options: TestOptions.DebugDll, parseOptions: parseOptions); + Compilation compilation = CreateCompilation(new[] { source1, source2, source3 }, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); var generator = new IncrementalGeneratorWrapper(new PipelineCallbackGenerator(ctx => { @@ -1211,8 +1211,7 @@ class C { } Assert.Collection(runResult.TrackedSteps["individualFileGlobalAliases_ForAttribute"], s => Assert.Equal(IncrementalStepRunReason.Cached, s.Outputs.Single().Reason), - s => Assert.Equal(IncrementalStepRunReason.Cached, s.Outputs.Single().Reason), - s => Assert.Equal(IncrementalStepRunReason.Unchanged, s.Outputs.Single().Reason)); + s => Assert.Equal(IncrementalStepRunReason.Cached, s.Outputs.Single().Reason)); Assert.Equal(IncrementalStepRunReason.Cached, runResult.TrackedSteps["collectedGlobalAliases_ForAttribute"].Single().Outputs.Single().Reason); Assert.Equal(IncrementalStepRunReason.Cached, runResult.TrackedSteps["allUpGlobalAliases_ForAttribute"].Single().Outputs.Single().Reason); @@ -1220,8 +1219,8 @@ class C { } o => Assert.Equal(IncrementalStepRunReason.Unchanged, o.Reason), o => Assert.Equal(IncrementalStepRunReason.Unchanged, o.Reason), o => Assert.Equal(IncrementalStepRunReason.Modified, o.Reason)); - Assert.Equal(IncrementalStepRunReason.Modified, runResult.TrackedSteps["compilationUnitAndGlobalAliases_ForAttribute"].Single().Outputs.Single().Reason); - Assert.Equal(IncrementalStepRunReason.Modified, runResult.TrackedSteps["result_ForAttribute"].Single().Outputs.Single().Reason); + Assert.Equal(IncrementalStepRunReason.New, runResult.TrackedSteps["compilationUnitAndGlobalAliases_ForAttribute"].Single().Outputs.Single().Reason); + Assert.Equal(IncrementalStepRunReason.New, runResult.TrackedSteps["result_ForAttribute"].Single().Outputs.Single().Reason); Assert.Collection(runResult.TrackedSteps["result_ForAttribute"], step => Assert.True(step.Outputs.Single().Value is ClassDeclarationSyntax { Identifier.ValueText: "C" })); @@ -1241,7 +1240,7 @@ public void TestSourceFileChanged_NonVisibleChangeToGlobalAttributeFile() class C { } "; var parseOptions = TestOptions.RegularPreview; - Compilation compilation = CreateCompilation(new[] { source1, source2, source3 }, options: TestOptions.DebugDll, parseOptions: parseOptions); + Compilation compilation = CreateCompilation(new[] { source1, source2, source3 }, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); var generator = new IncrementalGeneratorWrapper(new PipelineCallbackGenerator(ctx => { @@ -1266,7 +1265,6 @@ class Dummy {} Assert.Collection(runResult.TrackedSteps["individualFileGlobalAliases_ForAttribute"], s => Assert.Equal(IncrementalStepRunReason.Unchanged, s.Outputs.Single().Reason), - s => Assert.Equal(IncrementalStepRunReason.Cached, s.Outputs.Single().Reason), s => Assert.Equal(IncrementalStepRunReason.Cached, s.Outputs.Single().Reason)); Assert.Equal(IncrementalStepRunReason.Cached, runResult.TrackedSteps["collectedGlobalAliases_ForAttribute"].Single().Outputs.Single().Reason); Assert.Equal(IncrementalStepRunReason.Cached, runResult.TrackedSteps["allUpGlobalAliases_ForAttribute"].Single().Outputs.Single().Reason); @@ -1293,7 +1291,51 @@ public void TestRemoveGlobalAttributeFile1() class C { } "; var parseOptions = TestOptions.RegularPreview; - Compilation compilation = CreateCompilation(new[] { source1, source2, source3 }, options: TestOptions.DebugDll, parseOptions: parseOptions); + Compilation compilation = CreateCompilation(new[] { source1, source2, source3 }, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); + + var generator = new IncrementalGeneratorWrapper(new PipelineCallbackGenerator(ctx => + { + var input = ctx.ForAttributeWithSimpleName("XAttribute"); + ctx.RegisterSourceOutput(input, (spc, node) => { }); + })); + + GeneratorDriver driver = CSharpGeneratorDriver.Create(new ISourceGenerator[] { generator }, parseOptions: parseOptions, driverOptions: new GeneratorDriverOptions(IncrementalGeneratorOutputKind.None, trackIncrementalGeneratorSteps: true)); + driver = driver.RunGenerators(compilation); + var runResult = driver.GetRunResult().Results[0]; + + Assert.Collection(runResult.TrackedSteps["result_ForAttribute"], + step => Assert.True(step.Outputs.Single().Value is ClassDeclarationSyntax { Identifier.ValueText: "C" })); + + driver = driver.RunGenerators(compilation.RemoveSyntaxTrees( + compilation.SyntaxTrees.First())); + runResult = driver.GetRunResult().Results[0]; + + Assert.False(runResult.TrackedSteps.ContainsKey("result_ForAttribute")); + Assert.False(runResult.TrackedSteps.ContainsKey("individualFileGlobalAliases_ForAttribute")); + Assert.False(runResult.TrackedSteps.ContainsKey("collectedGlobalAliases_ForAttribute")); + Assert.False(runResult.TrackedSteps.ContainsKey("allUpGlobalAliases_ForAttribute")); + + Assert.False(runResult.TrackedSteps.ContainsKey("compilationUnit_ForAttribute")); + Assert.False(runResult.TrackedSteps.ContainsKey("compilationUnitAndGlobalAliases_ForAttribute")); + } + + [Fact] + public void TestRemoveGlobalAttributeFile2() + { + var source0 = ""; + + var source1 = @" +global using AAttribute = XAttribute;"; + + var source2 = @" +global using BAttribute = AAttribute;"; + + var source3 = @" +[B] +class C { } +"; + var parseOptions = TestOptions.RegularPreview; + Compilation compilation = CreateCompilation(new[] { source0, source1, source2, source3 }, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); var generator = new IncrementalGeneratorWrapper(new PipelineCallbackGenerator(ctx => { @@ -1312,19 +1354,21 @@ class C { } compilation.SyntaxTrees.First())); runResult = driver.GetRunResult().Results[0]; + Assert.Collection(runResult.TrackedSteps["result_ForAttribute"], + step => Assert.True(step.Outputs.Single().Value is ClassDeclarationSyntax { Identifier.ValueText: "C" })); + Assert.Collection(runResult.TrackedSteps["individualFileGlobalAliases_ForAttribute"], - s => Assert.Equal(IncrementalStepRunReason.Modified, s.Outputs.Single().Reason), - s => Assert.Equal(IncrementalStepRunReason.Modified, s.Outputs.Single().Reason), - s => Assert.Equal(IncrementalStepRunReason.Removed, s.Outputs.Single().Reason)); - Assert.Equal(IncrementalStepRunReason.Modified, runResult.TrackedSteps["collectedGlobalAliases_ForAttribute"].Single().Outputs.Single().Reason); - Assert.Equal(IncrementalStepRunReason.Modified, runResult.TrackedSteps["allUpGlobalAliases_ForAttribute"].Single().Outputs.Single().Reason); + s => Assert.Equal(IncrementalStepRunReason.Cached, s.Outputs.Single().Reason), + s => Assert.Equal(IncrementalStepRunReason.Cached, s.Outputs.Single().Reason)); + Assert.Equal(IncrementalStepRunReason.Cached, runResult.TrackedSteps["collectedGlobalAliases_ForAttribute"].Single().Outputs.Single().Reason); + Assert.Equal(IncrementalStepRunReason.Cached, runResult.TrackedSteps["allUpGlobalAliases_ForAttribute"].Single().Outputs.Single().Reason); Assert.Collection(runResult.TrackedSteps["compilationUnit_ForAttribute"].Single().Outputs, - o => Assert.Equal(IncrementalStepRunReason.Modified, o.Reason), - o => Assert.Equal(IncrementalStepRunReason.Modified, o.Reason), - o => Assert.Equal(IncrementalStepRunReason.Removed, o.Reason)); - Assert.Equal(IncrementalStepRunReason.Removed, runResult.TrackedSteps["compilationUnitAndGlobalAliases_ForAttribute"].Single().Outputs.Single().Reason); - Assert.Equal(IncrementalStepRunReason.Removed, runResult.TrackedSteps["result_ForAttribute"].Single().Outputs.Single().Reason); + o => Assert.Equal(IncrementalStepRunReason.Unchanged, o.Reason), + o => Assert.Equal(IncrementalStepRunReason.Unchanged, o.Reason), + o => Assert.Equal(IncrementalStepRunReason.Unchanged, o.Reason)); + Assert.Equal(IncrementalStepRunReason.Cached, runResult.TrackedSteps["compilationUnitAndGlobalAliases_ForAttribute"].Single().Outputs.Single().Reason); + Assert.Equal(IncrementalStepRunReason.Cached, runResult.TrackedSteps["result_ForAttribute"].Single().Outputs.Single().Reason); } [Fact] @@ -1338,7 +1382,7 @@ public void TestAddGlobalAttributeFile1() class C { } "; var parseOptions = TestOptions.RegularPreview; - Compilation compilation = CreateCompilation(new[] { source2, source3 }, options: TestOptions.DebugDll, parseOptions: parseOptions); + Compilation compilation = CreateCompilation(new[] { source2, source3 }, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); var generator = new IncrementalGeneratorWrapper(new PipelineCallbackGenerator(ctx => { @@ -1358,7 +1402,6 @@ class C { } runResult = driver.GetRunResult().Results[0]; Assert.Collection(runResult.TrackedSteps["individualFileGlobalAliases_ForAttribute"], - s => Assert.Equal(IncrementalStepRunReason.Cached, s.Outputs.Single().Reason), s => Assert.Equal(IncrementalStepRunReason.Cached, s.Outputs.Single().Reason), s => Assert.Equal(IncrementalStepRunReason.New, s.Outputs.Single().Reason)); Assert.Equal(IncrementalStepRunReason.Modified, runResult.TrackedSteps["collectedGlobalAliases_ForAttribute"].Single().Outputs.Single().Reason); @@ -1369,7 +1412,7 @@ class C { } o => Assert.Equal(IncrementalStepRunReason.Unchanged, o.Reason), o => Assert.Equal(IncrementalStepRunReason.Modified, o.Reason)); Assert.Equal(IncrementalStepRunReason.Modified, runResult.TrackedSteps["compilationUnitAndGlobalAliases_ForAttribute"].Single().Outputs.Single().Reason); - Assert.Equal(IncrementalStepRunReason.Modified, runResult.TrackedSteps["result_ForAttribute"].Single().Outputs.Single().Reason); + Assert.Equal(IncrementalStepRunReason.New, runResult.TrackedSteps["result_ForAttribute"].Single().Outputs.Single().Reason); Assert.Collection(runResult.TrackedSteps["result_ForAttribute"], step => Assert.True(step.Outputs.Single().Value is ClassDeclarationSyntax { Identifier.ValueText: "C" })); @@ -1383,7 +1426,7 @@ public void TestAddGlobalAttributeFile2() class C { } "; var parseOptions = TestOptions.RegularPreview; - Compilation compilation = CreateCompilation(new[] { source3 }, options: TestOptions.DebugDll, parseOptions: parseOptions); + Compilation compilation = CreateCompilation(new[] { source3 }, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); var generator = new IncrementalGeneratorWrapper(new PipelineCallbackGenerator(ctx => { @@ -1403,7 +1446,6 @@ class C { } runResult = driver.GetRunResult().Results[0]; Assert.Collection(runResult.TrackedSteps["individualFileGlobalAliases_ForAttribute"], - s => Assert.Equal(IncrementalStepRunReason.Cached, s.Outputs.Single().Reason), s => Assert.Equal(IncrementalStepRunReason.New, s.Outputs.Single().Reason)); Assert.Equal(IncrementalStepRunReason.Modified, runResult.TrackedSteps["collectedGlobalAliases_ForAttribute"].Single().Outputs.Single().Reason); Assert.Equal(IncrementalStepRunReason.Modified, runResult.TrackedSteps["allUpGlobalAliases_ForAttribute"].Single().Outputs.Single().Reason); @@ -1412,7 +1454,7 @@ class C { } o => Assert.Equal(IncrementalStepRunReason.Unchanged, o.Reason), o => Assert.Equal(IncrementalStepRunReason.Modified, o.Reason)); Assert.Equal(IncrementalStepRunReason.Modified, runResult.TrackedSteps["compilationUnitAndGlobalAliases_ForAttribute"].Single().Outputs.Single().Reason); - Assert.Equal(IncrementalStepRunReason.Modified, runResult.TrackedSteps["result_ForAttribute"].Single().Outputs.Single().Reason); + Assert.Equal(IncrementalStepRunReason.New, runResult.TrackedSteps["result_ForAttribute"].Single().Outputs.Single().Reason); Assert.Collection(runResult.TrackedSteps["result_ForAttribute"], step => Assert.True(step.Outputs.Single().Value is ClassDeclarationSyntax { Identifier.ValueText: "C" })); @@ -1432,7 +1474,7 @@ public void TestAddSourceFileWithoutAttribute() class C { } "; var parseOptions = TestOptions.RegularPreview; - Compilation compilation = CreateCompilation(new[] { source1, source2, source3 }, options: TestOptions.DebugDll, parseOptions: parseOptions); + Compilation compilation = CreateCompilation(new[] { source1, source2, source3 }, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); var generator = new IncrementalGeneratorWrapper(new PipelineCallbackGenerator(ctx => { @@ -1454,17 +1496,14 @@ class D { }")))); Assert.Collection(runResult.TrackedSteps["individualFileGlobalAliases_ForAttribute"], s => Assert.Equal(IncrementalStepRunReason.Cached, s.Outputs.Single().Reason), - s => Assert.Equal(IncrementalStepRunReason.Cached, s.Outputs.Single().Reason), - s => Assert.Equal(IncrementalStepRunReason.Cached, s.Outputs.Single().Reason), - s => Assert.Equal(IncrementalStepRunReason.New, s.Outputs.Single().Reason)); - Assert.Equal(IncrementalStepRunReason.Modified, runResult.TrackedSteps["collectedGlobalAliases_ForAttribute"].Single().Outputs.Single().Reason); - Assert.Equal(IncrementalStepRunReason.Unchanged, runResult.TrackedSteps["allUpGlobalAliases_ForAttribute"].Single().Outputs.Single().Reason); + s => Assert.Equal(IncrementalStepRunReason.Cached, s.Outputs.Single().Reason)); + Assert.Equal(IncrementalStepRunReason.Cached, runResult.TrackedSteps["collectedGlobalAliases_ForAttribute"].Single().Outputs.Single().Reason); + Assert.Equal(IncrementalStepRunReason.Cached, runResult.TrackedSteps["allUpGlobalAliases_ForAttribute"].Single().Outputs.Single().Reason); Assert.Collection(runResult.TrackedSteps["compilationUnit_ForAttribute"].Single().Outputs, o => Assert.Equal(IncrementalStepRunReason.Unchanged, o.Reason), o => Assert.Equal(IncrementalStepRunReason.Unchanged, o.Reason), - o => Assert.Equal(IncrementalStepRunReason.Unchanged, o.Reason), - o => Assert.Equal(IncrementalStepRunReason.Modified, o.Reason)); + o => Assert.Equal(IncrementalStepRunReason.Unchanged, o.Reason)); Assert.Equal(IncrementalStepRunReason.Cached, runResult.TrackedSteps["compilationUnitAndGlobalAliases_ForAttribute"].Single().Outputs.Single().Reason); Assert.Equal(IncrementalStepRunReason.Cached, runResult.TrackedSteps["result_ForAttribute"].Single().Outputs.Single().Reason); } @@ -1483,7 +1522,7 @@ public void TestAddSourceFileWithAttribute() class C { } "; var parseOptions = TestOptions.RegularPreview; - Compilation compilation = CreateCompilation(new[] { source1, source2, source3 }, options: TestOptions.DebugDll, parseOptions: parseOptions); + Compilation compilation = CreateCompilation(new[] { source1, source2, source3 }, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); var generator = new IncrementalGeneratorWrapper(new PipelineCallbackGenerator(ctx => { @@ -1506,11 +1545,9 @@ class D { }")))); Assert.Collection(runResult.TrackedSteps["individualFileGlobalAliases_ForAttribute"], s => Assert.Equal(IncrementalStepRunReason.Cached, s.Outputs.Single().Reason), - s => Assert.Equal(IncrementalStepRunReason.Cached, s.Outputs.Single().Reason), - s => Assert.Equal(IncrementalStepRunReason.Cached, s.Outputs.Single().Reason), - s => Assert.Equal(IncrementalStepRunReason.New, s.Outputs.Single().Reason)); - Assert.Equal(IncrementalStepRunReason.Modified, runResult.TrackedSteps["collectedGlobalAliases_ForAttribute"].Single().Outputs.Single().Reason); - Assert.Equal(IncrementalStepRunReason.Unchanged, runResult.TrackedSteps["allUpGlobalAliases_ForAttribute"].Single().Outputs.Single().Reason); + s => Assert.Equal(IncrementalStepRunReason.Cached, s.Outputs.Single().Reason)); + Assert.Equal(IncrementalStepRunReason.Cached, runResult.TrackedSteps["collectedGlobalAliases_ForAttribute"].Single().Outputs.Single().Reason); + Assert.Equal(IncrementalStepRunReason.Cached, runResult.TrackedSteps["allUpGlobalAliases_ForAttribute"].Single().Outputs.Single().Reason); Assert.Collection(runResult.TrackedSteps["compilationUnit_ForAttribute"].Single().Outputs, o => Assert.Equal(IncrementalStepRunReason.Unchanged, o.Reason), @@ -1543,7 +1580,7 @@ public void TestReplaceSourceFileWithDifferentAttribute() class C { } "; var parseOptions = TestOptions.RegularPreview; - Compilation compilation = CreateCompilation(new[] { source1, source2, source3 }, options: TestOptions.DebugDll, parseOptions: parseOptions); + Compilation compilation = CreateCompilation(new[] { source1, source2, source3 }, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); var generator = new IncrementalGeneratorWrapper(new PipelineCallbackGenerator(ctx => { @@ -1567,8 +1604,7 @@ class D { }")))); Assert.Collection(runResult.TrackedSteps["individualFileGlobalAliases_ForAttribute"], s => Assert.Equal(IncrementalStepRunReason.Cached, s.Outputs.Single().Reason), - s => Assert.Equal(IncrementalStepRunReason.Cached, s.Outputs.Single().Reason), - s => Assert.Equal(IncrementalStepRunReason.Unchanged, s.Outputs.Single().Reason)); + s => Assert.Equal(IncrementalStepRunReason.Cached, s.Outputs.Single().Reason)); Assert.Equal(IncrementalStepRunReason.Cached, runResult.TrackedSteps["collectedGlobalAliases_ForAttribute"].Single().Outputs.Single().Reason); Assert.Equal(IncrementalStepRunReason.Cached, runResult.TrackedSteps["allUpGlobalAliases_ForAttribute"].Single().Outputs.Single().Reason); diff --git a/src/Compilers/CSharp/Test/Semantic/SourceGeneration/StateTableTests.cs b/src/Compilers/CSharp/Test/Semantic/SourceGeneration/StateTableTests.cs index 2cca62d3c825b..b474ad41ba4de 100644 --- a/src/Compilers/CSharp/Test/Semantic/SourceGeneration/StateTableTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/SourceGeneration/StateTableTests.cs @@ -5,12 +5,13 @@ using System; using System.Collections.Generic; using System.Collections.Immutable; +using System.Linq; using System.Threading; using Microsoft.CodeAnalysis.Diagnostics; -using Xunit; -using Roslyn.Test.Utilities.TestGenerators; using Roslyn.Test.Utilities; -using System.Linq; +using Roslyn.Test.Utilities.TestGenerators; +using Roslyn.Utilities; +using Xunit; namespace Microsoft.CodeAnalysis.CSharp.Semantic.UnitTests.SourceGeneration { @@ -89,11 +90,18 @@ public void Node_Builder_Can_Add_Entries_From_Previous_Table() var expected = ImmutableArray.Create((10, EntryState.Added, 0), (11, EntryState.Added, 1), (2, EntryState.Cached, 0), (3, EntryState.Cached, 1), (20, EntryState.Modified, 0), (21, EntryState.Modified, 1), (22, EntryState.Modified, 2), (6, EntryState.Removed, 0)); AssertTableEntries(newTable, expected); - Assert.Equal(new[] { 2, 3 }, cachedEntries.ToImmutableArray()); - Assert.Equal(6, Assert.Single(removedEntries)); + Assert.Equal(new[] { 2, 3 }, YieldItems(cachedEntries.Items)); + Assert.Equal(1, removedEntries.Count); + Assert.Equal(6, removedEntries[0]); Assert.True(didRemoveEntries); } + private static IEnumerable YieldItems(OneOrMany items) + { + foreach (var value in items) + yield return value; + } + [Fact] public void Node_Table_Entries_Are_Cached_Or_Dropped_When_Cached() { diff --git a/src/Compilers/CSharp/Test/Symbol/Compilation/CSharpCompilationOptionsTests.cs b/src/Compilers/CSharp/Test/Symbol/Compilation/CSharpCompilationOptionsTests.cs index 6402db2ac68d2..13a70fbfb5f7e 100644 --- a/src/Compilers/CSharp/Test/Symbol/Compilation/CSharpCompilationOptionsTests.cs +++ b/src/Compilers/CSharp/Test/Symbol/Compilation/CSharpCompilationOptionsTests.cs @@ -354,7 +354,7 @@ public void ConstructorValidation() } /// - /// If this test fails, please update the + /// If this test fails, please update the /// and methods to /// make sure they are doing the right thing with your new field and then update the baseline /// here. diff --git a/src/Compilers/CSharp/Test/Symbol/Compilation/CompilationAPITests.cs b/src/Compilers/CSharp/Test/Symbol/Compilation/CompilationAPITests.cs index 1dce2da3aa49e..efa1ef466cb08 100644 --- a/src/Compilers/CSharp/Test/Symbol/Compilation/CompilationAPITests.cs +++ b/src/Compilers/CSharp/Test/Symbol/Compilation/CompilationAPITests.cs @@ -2067,7 +2067,7 @@ public void ReferenceManagerReuse_WithSyntaxTrees() var ta = Parse("class C { }", options: TestOptions.Regular10); var tb = Parse(@" -class C { }", options: TestOptions.Script); +class C { }", options: TestOptions.Script.WithLanguageVersion(LanguageVersion.CSharp10)); var tc = Parse(@" #r ""bar"" // error: #r in regular code @@ -2075,11 +2075,11 @@ class D { }", options: TestOptions.Regular10); var tr = Parse(@" #r ""goo"" -class C { }", options: TestOptions.Script); +class C { }", options: TestOptions.Script.WithLanguageVersion(LanguageVersion.CSharp10)); var ts = Parse(@" #r ""bar"" -class C { }", options: TestOptions.Script); +class C { }", options: TestOptions.Script.WithLanguageVersion(LanguageVersion.CSharp10)); var a = CSharpCompilation.Create("c", syntaxTrees: new[] { ta }); diff --git a/src/Compilers/CSharp/Test/Symbol/Compilation/SemanticModelAPITests.cs b/src/Compilers/CSharp/Test/Symbol/Compilation/SemanticModelAPITests.cs index 6387a4000b808..8455823a932c8 100644 --- a/src/Compilers/CSharp/Test/Symbol/Compilation/SemanticModelAPITests.cs +++ b/src/Compilers/CSharp/Test/Symbol/Compilation/SemanticModelAPITests.cs @@ -4450,6 +4450,138 @@ void M() { } Assert.Equal("DEBUG", model.GetConstantValue(root.DescendantNodes().OfType().Single())); } + [Theory, CombinatorialData, WorkItem(54437, "https://github.com/dotnet/roslyn/issues/54437")] + public void TestVarTuple(NullableContextOptions nullableContextOption) + { + var source = """ + var (a1, b1) = ("", 0); + """; + var options = WithNullable(TestOptions.DebugExe, nullableContextOption); + var comp = CreateCompilation(source, options: options, parseOptions: TestOptions.Regular9); + comp.VerifyDiagnostics(); + + var tree = comp.SyntaxTrees.Single(); + var model = comp.GetSemanticModel(tree); + var root = tree.GetCompilationUnitRoot(); + + var declarationExpression = root.DescendantNodes().OfType().Single(); + var varNode = declarationExpression.Type; + + var varTypeInfo = model.GetTypeInfo(varNode); + var declarationExpressionTypeInfo = model.GetTypeInfo(declarationExpression); + assertTypeInfo(varTypeInfo); + Assert.Equal(varTypeInfo, declarationExpressionTypeInfo); + + var varSymbolInfo = model.GetSymbolInfo(varNode); + assertSymbolInfo(varSymbolInfo); + + var declarationExpressionSymbolInfo = model.GetSymbolInfo(declarationExpression); + Assert.Equal(SymbolInfo.None, declarationExpressionSymbolInfo); + + static void assertTypeInfo(TypeInfo typeInfo) + { + Assert.Equal(CodeAnalysis.NullableAnnotation.None, typeInfo.Nullability.Annotation); + Assert.Equal(CodeAnalysis.NullableAnnotation.None, typeInfo.ConvertedNullability.Annotation); + + Assert.NotNull(typeInfo.Type); + Assert.NotNull(typeInfo.ConvertedType); + Assert.Equal(typeInfo.Type, typeInfo.ConvertedType); + + var type = (INamedTypeSymbol)typeInfo.Type; + Assert.True(type.IsTupleType); + Assert.Equal(2, type.Arity); + Assert.Equal(2, type.TupleElements.Length); + Assert.Equal(SpecialType.System_String, type.TupleElements[0].Type.SpecialType); + Assert.Equal(SpecialType.System_Int32, type.TupleElements[1].Type.SpecialType); + } + + static void assertSymbolInfo(SymbolInfo symbolInfo) + { + Assert.False(symbolInfo.IsEmpty); + Assert.Empty(symbolInfo.CandidateSymbols); + Assert.Equal(CandidateReason.None, symbolInfo.CandidateReason); + Assert.Equal("(System.String a1, System.Int32 b1)", symbolInfo.Symbol.ToTestDisplayString()); + } + } + + [Theory, CombinatorialData, WorkItem(54437, "https://github.com/dotnet/roslyn/issues/54437")] + public void TestVarTupleWithVarTypeInScope(NullableContextOptions nullableContextOption) + { + var source = """ + var (a1, b1) = ("", 0); + class @var { } + """; + var options = WithNullable(TestOptions.DebugExe, nullableContextOption); + var comp = CreateCompilation(source, options: options, parseOptions: TestOptions.Regular9); + comp.VerifyDiagnostics( + // (1,5): error CS8136: Deconstruction 'var (...)' form disallows a specific type for 'var'. + // var (a1, b1) = ("", 0); + Diagnostic(ErrorCode.ERR_DeconstructionVarFormDisallowsSpecificType, "(a1, b1)").WithLocation(1, 5), + // (1,17): error CS0029: Cannot implicitly convert type 'string' to 'var' + // var (a1, b1) = ("", 0); + Diagnostic(ErrorCode.ERR_NoImplicitConv, @"""""").WithArguments("string", "var").WithLocation(1, 17), + // (1,21): error CS0029: Cannot implicitly convert type 'int' to 'var' + // var (a1, b1) = ("", 0); + Diagnostic(ErrorCode.ERR_NoImplicitConv, "0").WithArguments("int", "var").WithLocation(1, 21)); + + var tree = comp.SyntaxTrees.Single(); + var model = comp.GetSemanticModel(tree); + var root = tree.GetCompilationUnitRoot(); + + var declarationExpression = root.DescendantNodes().OfType().Single(); + var varNode = declarationExpression.Type; + + var varTypeInfo = model.GetTypeInfo(varNode); + var declarationExpressionTypeInfo = model.GetTypeInfo(declarationExpression); + assertTypeInfoForVar(varTypeInfo); + assertTypeInfoForDeclarationExpression(declarationExpressionTypeInfo); + + var varSymbolInfo = model.GetSymbolInfo(varNode); + assertSymbolInfo(varSymbolInfo); + + var declarationExpressionSymbolInfo = model.GetSymbolInfo(declarationExpression); + Assert.Equal(SymbolInfo.None, declarationExpressionSymbolInfo); + + static void assertTypeInfoForVar(TypeInfo typeInfo) + { + Assert.Equal(CodeAnalysis.NullableAnnotation.None, typeInfo.Nullability.Annotation); + Assert.Equal(CodeAnalysis.NullableAnnotation.None, typeInfo.ConvertedNullability.Annotation); + + Assert.NotNull(typeInfo.Type); + Assert.NotNull(typeInfo.ConvertedType); + Assert.Equal(typeInfo.Type, typeInfo.ConvertedType); + + var type = (INamedTypeSymbol)typeInfo.Type; + Assert.Equal("var", type.ToTestDisplayString()); + Assert.Equal(TypeKind.Class, type.TypeKind); + } + + static void assertTypeInfoForDeclarationExpression(TypeInfo typeInfo) + { + Assert.Equal(CodeAnalysis.NullableAnnotation.None, typeInfo.Nullability.Annotation); + Assert.Equal(CodeAnalysis.NullableAnnotation.None, typeInfo.ConvertedNullability.Annotation); + + Assert.NotNull(typeInfo.Type); + Assert.NotNull(typeInfo.ConvertedType); + Assert.Equal(typeInfo.Type, typeInfo.ConvertedType); + + var type = (INamedTypeSymbol)typeInfo.Type; + Assert.True(type.IsTupleType); + Assert.Equal(2, type.Arity); + Assert.Equal(2, type.TupleElements.Length); + Assert.Equal(TypeKind.Class, type.TupleElements[0].Type.TypeKind); + Assert.Equal(TypeKind.Class, type.TupleElements[1].Type.TypeKind); + } + + static void assertSymbolInfo(SymbolInfo symbolInfo) + { + Assert.False(symbolInfo.IsEmpty); + Assert.Empty(symbolInfo.CandidateSymbols); + Assert.Equal(CandidateReason.None, symbolInfo.CandidateReason); + Assert.Equal("var", symbolInfo.Symbol.ToTestDisplayString()); + } + } + [Fact] public void EqualsOnAliasSymbolWithNullContainingAssembly_NotEquals() { diff --git a/src/Compilers/CSharp/Test/Symbol/SymbolDisplay/SymbolDisplayTests.cs b/src/Compilers/CSharp/Test/Symbol/SymbolDisplay/SymbolDisplayTests.cs index f8c215e0816d5..c20dd5cacc31e 100644 --- a/src/Compilers/CSharp/Test/Symbol/SymbolDisplay/SymbolDisplayTests.cs +++ b/src/Compilers/CSharp/Test/Symbol/SymbolDisplay/SymbolDisplayTests.cs @@ -8151,7 +8151,14 @@ ref struct S }"; var comp = CreateCompilation(source); - comp.VerifyDiagnostics(); + comp.VerifyDiagnostics( + // (4,11): error CS9061: Target runtime doesn't support ref fields. + // ref T F1; + Diagnostic(ErrorCode.ERR_RuntimeDoesNotSupportRefFields, "F1").WithLocation(4, 11), + // (5,20): error CS9061: Target runtime doesn't support ref fields. + // ref readonly T F2; + Diagnostic(ErrorCode.ERR_RuntimeDoesNotSupportRefFields, "F2").WithLocation(5, 20) + ); Verify(comp.GetMember("S.F1").ToDisplayParts(SymbolDisplayFormat.TestFormat), "ref T S.F1", @@ -8189,7 +8196,7 @@ public void ScopedParameter_01() @"ref struct R { } class Program { - static void F(scoped R r1, in scoped R r2, scoped ref R r3) { } + static void F(scoped R r1, scoped ref R r2, scoped in R r3) { } }"; var comp = CreateCompilation(source); @@ -8202,7 +8209,7 @@ static void F(scoped R r1, in scoped R r2, scoped ref R r3) { } var formatTypeRefAndScoped = formatTypeOnly.AddParameterOptions(SymbolDisplayParameterOptions.IncludeParamsRefOut).WithCompilerInternalOptions(SymbolDisplayCompilerInternalOptions.IncludeScoped); ; Verify(method.ToDisplayParts(formatTypeAndRef), - "void Program.F(R r1, in R r2, ref R r3)", + "void Program.F(R r1, ref R r2, in R r3)", SymbolDisplayPartKind.Keyword, SymbolDisplayPartKind.Space, SymbolDisplayPartKind.ClassName, @@ -8229,10 +8236,10 @@ static void F(scoped R r1, in scoped R r2, scoped ref R r3) { } SymbolDisplayPartKind.Punctuation); Verify(method.ToDisplayParts(formatTypeAndScoped), - "void Program.F(scoped R r1, scoped R r2, R r3)"); + "void Program.F(scoped R r1, R r2, R r3)"); Verify(method.ToDisplayParts(formatTypeRefAndScoped), - "void Program.F(scoped R r1, in scoped R r2, scoped ref R r3)", + "void Program.F(scoped R r1, ref R r2, in R r3)", SymbolDisplayPartKind.Keyword, SymbolDisplayPartKind.Space, SymbolDisplayPartKind.ClassName, @@ -8248,8 +8255,6 @@ static void F(scoped R r1, in scoped R r2, scoped ref R r3) { } SymbolDisplayPartKind.Space, SymbolDisplayPartKind.Keyword, SymbolDisplayPartKind.Space, - SymbolDisplayPartKind.Keyword, - SymbolDisplayPartKind.Space, SymbolDisplayPartKind.StructName, SymbolDisplayPartKind.Space, SymbolDisplayPartKind.ParameterName, @@ -8257,8 +8262,6 @@ static void F(scoped R r1, in scoped R r2, scoped ref R r3) { } SymbolDisplayPartKind.Space, SymbolDisplayPartKind.Keyword, SymbolDisplayPartKind.Space, - SymbolDisplayPartKind.Keyword, - SymbolDisplayPartKind.Space, SymbolDisplayPartKind.StructName, SymbolDisplayPartKind.Space, SymbolDisplayPartKind.ParameterName, @@ -8270,7 +8273,7 @@ public void ScopedParameter_02() { var source = @"ref struct R { } -delegate void D(scoped R r1, in scoped R r2, scoped ref R r3); +delegate void D(scoped R r1, scoped ref R r2, scoped in R r3); "; var comp = CreateCompilation(source); @@ -8283,13 +8286,13 @@ public void ScopedParameter_02() var formatTypeRefAndScoped = formatTypeOnly.AddParameterOptions(SymbolDisplayParameterOptions.IncludeParamsRefOut).WithCompilerInternalOptions(SymbolDisplayCompilerInternalOptions.IncludeScoped); Verify(delegateType.ToDisplayParts(formatTypeAndRef), - "delegate void D(R r1, in R r2, ref R r3)"); + "delegate void D(R r1, ref R r2, in R r3)"); Verify(delegateType.ToDisplayParts(formatTypeAndScoped), - "delegate void D(scoped R r1, scoped R r2, R r3)"); + "delegate void D(scoped R r1, R r2, R r3)"); Verify(delegateType.ToDisplayParts(formatTypeRefAndScoped), - "delegate void D(scoped R r1, in scoped R r2, scoped ref R r3)"); + "delegate void D(scoped R r1, ref R r2, in R r3)"); } [Fact] @@ -8329,6 +8332,32 @@ unsafe class Program "delegate*"); } + [Fact] + public void ScopedParameter_04() + { + var source = +@"using System.Diagnostics.CodeAnalysis; +ref struct R { } +class Program +{ + static void F1(out int i1, [UnscopedRef] out int i2) => throw null; + static void F2(ref R r1, [UnscopedRef] ref R r2) => throw null; +}"; + + var comp = CreateCompilation(new[] { source, UnscopedRefAttributeDefinition }); + comp.VerifyDiagnostics(); + + var format = SymbolDisplayFormat.TestFormat. + WithParameterOptions(SymbolDisplayParameterOptions.IncludeType | SymbolDisplayParameterOptions.IncludeName | SymbolDisplayParameterOptions.IncludeParamsRefOut). + WithCompilerInternalOptions(SymbolDisplayCompilerInternalOptions.IncludeScoped); + + Verify(comp.GetMember("Program.F1").ToDisplayParts(format), + "void Program.F1(out System.Int32 i1, out System.Int32 i2)"); + + Verify(comp.GetMember("Program.F2").ToDisplayParts(format), + "void Program.F2(ref R r1, ref R r2)"); + } + [Fact] public void ScopedLocal() { @@ -8338,9 +8367,8 @@ class Program { static void M(R r0) { - scoped R r1; - ref readonly scoped R r2 = ref r1; - scoped ref R r3 = ref r0; + scoped R r1 = r0; + scoped ref readonly R r3 = ref r0; } }"; @@ -8371,7 +8399,7 @@ static void M(R r0) SymbolDisplayPartKind.LocalName); Verify(locals[1].ToDisplayParts(formatTypeAndRef), - "ref readonly R r2", + "ref readonly R r3", SymbolDisplayPartKind.Keyword, SymbolDisplayPartKind.Space, SymbolDisplayPartKind.Keyword, @@ -8380,16 +8408,8 @@ static void M(R r0) SymbolDisplayPartKind.Space, SymbolDisplayPartKind.LocalName); - Verify(locals[1].ToDisplayParts(formatTypeAndScoped), - "scoped R r2", - SymbolDisplayPartKind.Keyword, - SymbolDisplayPartKind.Space, - SymbolDisplayPartKind.StructName, - SymbolDisplayPartKind.Space, - SymbolDisplayPartKind.LocalName); - Verify(locals[1].ToDisplayParts(formatTypeRefAndScoped), - "ref readonly scoped R r2", + "scoped ref readonly R r3", SymbolDisplayPartKind.Keyword, SymbolDisplayPartKind.Space, SymbolDisplayPartKind.Keyword, @@ -8400,25 +8420,7 @@ static void M(R r0) SymbolDisplayPartKind.Space, SymbolDisplayPartKind.LocalName); - Verify(locals[2].ToDisplayParts(formatTypeAndRef), - "ref R r3", - SymbolDisplayPartKind.Keyword, - SymbolDisplayPartKind.Space, - SymbolDisplayPartKind.StructName, - SymbolDisplayPartKind.Space, - SymbolDisplayPartKind.LocalName); - - Verify(locals[2].ToDisplayParts(formatTypeRefAndScoped), - "scoped ref R r3", - SymbolDisplayPartKind.Keyword, - SymbolDisplayPartKind.Space, - SymbolDisplayPartKind.Keyword, - SymbolDisplayPartKind.Space, - SymbolDisplayPartKind.StructName, - SymbolDisplayPartKind.Space, - SymbolDisplayPartKind.LocalName); - - Verify(locals[2].ToDisplayParts(formatTypeAndScoped), + Verify(locals[1].ToDisplayParts(formatTypeAndScoped), "R r3", SymbolDisplayPartKind.StructName, SymbolDisplayPartKind.Space, diff --git a/src/Compilers/CSharp/Test/Symbol/Symbols/CheckedUserDefinedOperatorsTests.cs b/src/Compilers/CSharp/Test/Symbol/Symbols/CheckedUserDefinedOperatorsTests.cs index bdbf65ce2d9cf..e513dd513ace1 100644 --- a/src/Compilers/CSharp/Test/Symbol/Symbols/CheckedUserDefinedOperatorsTests.cs +++ b/src/Compilers/CSharp/Test/Symbol/Symbols/CheckedUserDefinedOperatorsTests.cs @@ -36,13 +36,13 @@ class C compilation1 = CreateCompilation(source1, options: TestOptions.DebugDll, parseOptions: TestOptions.Regular10); compilation1.VerifyDiagnostics( - // (4,30): error CS8652: The feature 'checked user-defined operators' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. - // public static C operator checked -(C x) => x; - Diagnostic(ErrorCode.ERR_FeatureInPreview, "checked").WithArguments("checked user-defined operators").WithLocation(4, 30) + // (4,30): error CS8936: Feature 'checked user-defined operators' is not available in C# 10.0. Please use language version 11.0 or greater. + // public static C operator checked ++(C x) => x; + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "checked").WithArguments("checked user-defined operators", "11.0").WithLocation(4, 30) ); validator(compilation1.SourceModule); - compilation1 = CreateCompilation(source1, options: TestOptions.DebugDll, parseOptions: TestOptions.RegularNext); + compilation1 = CreateCompilation(source1, options: TestOptions.DebugDll, parseOptions: TestOptions.Regular11); CompileAndVerify(compilation1, sourceSymbolValidator: validator, symbolValidator: validator).VerifyDiagnostics(); void validator(ModuleSymbol m) @@ -518,15 +518,15 @@ class C compilation = CreateCompilationWithMscorlib40AndDocumentationComments(source, parseOptions: TestOptions.Regular10.WithDocumentationMode(DocumentationMode.Diagnose)); compilation.VerifyDiagnostics( - // (3,20): warning CS1584: XML comment has syntactically incorrect cref attribute 'operator checked --' - // /// See . + // (3,20): warning CS1584: XML comment has syntactically incorrect cref attribute 'operator checked ++' + // /// See . Diagnostic(ErrorCode.WRN_BadXMLRefSyntax, "operator checked " + op).WithArguments("operator checked " + op).WithLocation(3, 20), - // (3,29): warning CS1658: The feature 'checked user-defined operators' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.. See also error CS8652. - // /// See . - Diagnostic(ErrorCode.WRN_ErrorOverride, "checked").WithArguments("The feature 'checked user-defined operators' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.", "8652").WithLocation(3, 29), - // (7,30): error CS8652: The feature 'checked user-defined operators' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. - // public static C operator checked --(C c) - Diagnostic(ErrorCode.ERR_FeatureInPreview, "checked").WithArguments("checked user-defined operators").WithLocation(7, 30) + // (3,29): warning CS1658: Feature 'checked user-defined operators' is not available in C# 10.0. Please use language version 11.0 or greater.. See also error CS8936. + // /// See . + Diagnostic(ErrorCode.WRN_ErrorOverride, "checked").WithArguments("Feature 'checked user-defined operators' is not available in C# 10.0. Please use language version 11.0 or greater.", "8936").WithLocation(3, 29), + // (7,30): error CS8936: Feature 'checked user-defined operators' is not available in C# 10.0. Please use language version 11.0 or greater. + // public static C operator checked ++(C c) + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "checked").WithArguments("checked user-defined operators", "11.0").WithLocation(7, 30) ); crefSyntax = CrefTests.GetCrefSyntaxes(compilation).Single(); @@ -534,7 +534,7 @@ class C actualSymbol = CrefTests.GetReferencedSymbol(crefSyntax, compilation); Assert.Equal(expectedSymbol, actualSymbol); - compilation = CreateCompilationWithMscorlib40AndDocumentationComments(source, parseOptions: TestOptions.RegularNext.WithDocumentationMode(DocumentationMode.Diagnose)); + compilation = CreateCompilationWithMscorlib40AndDocumentationComments(source, parseOptions: TestOptions.Regular11.WithDocumentationMode(DocumentationMode.Diagnose)); compilation.VerifyDiagnostics(); crefSyntax = CrefTests.GetCrefSyntaxes(compilation).Single(); @@ -642,19 +642,19 @@ class C // (3,20): warning CS1584: XML comment has syntactically incorrect cref attribute 'operator checked -' // /// See . Diagnostic(ErrorCode.WRN_BadXMLRefSyntax, "operator checked -").WithArguments("operator checked -").WithLocation(3, 20), - // (3,29): warning CS1658: The feature 'checked user-defined operators' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.. See also error CS8652. + // (3,29): warning CS1658: Feature 'checked user-defined operators' is not available in C# 10.0. Please use language version 11.0 or greater.. See also error CS8936. // /// See . - Diagnostic(ErrorCode.WRN_ErrorOverride, "checked").WithArguments("The feature 'checked user-defined operators' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.", "8652").WithLocation(3, 29), - // (7,30): error CS8652: The feature 'checked user-defined operators' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + Diagnostic(ErrorCode.WRN_ErrorOverride, "checked").WithArguments("Feature 'checked user-defined operators' is not available in C# 10.0. Please use language version 11.0 or greater.", "8936").WithLocation(3, 29), + // (7,30): error CS8936: Feature 'checked user-defined operators' is not available in C# 10.0. Please use language version 11.0 or greater. // public static C operator checked -(C c) - Diagnostic(ErrorCode.ERR_FeatureInPreview, "checked").WithArguments("checked user-defined operators").WithLocation(7, 30) + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "checked").WithArguments("checked user-defined operators", "11.0").WithLocation(7, 30) ); crefSyntax = CrefTests.GetCrefSyntaxes(compilation).Single(); actualSymbol = CrefTests.GetReferencedSymbol(crefSyntax, compilation, expected); Assert.Null(actualSymbol); - compilation = CreateCompilationWithMscorlib40AndDocumentationComments(source, parseOptions: TestOptions.RegularNext.WithDocumentationMode(DocumentationMode.Diagnose)); + compilation = CreateCompilationWithMscorlib40AndDocumentationComments(source, parseOptions: TestOptions.Regular11.WithDocumentationMode(DocumentationMode.Diagnose)); compilation.GetDiagnostics().Where(d => d.Code is not (int)ErrorCode.ERR_CheckedOperatorNeedsMatch).Verify(expected); crefSyntax = CrefTests.GetCrefSyntaxes(compilation).Single(); @@ -690,15 +690,15 @@ class C compilation = CreateCompilationWithMscorlib40AndDocumentationComments(source, parseOptions: TestOptions.Regular10.WithDocumentationMode(DocumentationMode.Diagnose)); compilation.GetDiagnostics().Where(d => d.Code is not (int)ErrorCode.ERR_CheckedOperatorNeedsMatch).Verify( - // (3,20): warning CS1584: XML comment has syntactically incorrect cref attribute 'operator checked -(C)' - // /// See . + // (3,20): warning CS1584: XML comment has syntactically incorrect cref attribute 'operator checked ++(C)' + // /// See . Diagnostic(ErrorCode.WRN_BadXMLRefSyntax, "operator checked " + op + "(C)").WithArguments("operator checked " + op + "(C)").WithLocation(3, 20), - // (3,29): warning CS1658: The feature 'checked user-defined operators' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.. See also error CS8652. - // /// See . - Diagnostic(ErrorCode.WRN_ErrorOverride, "checked").WithArguments("The feature 'checked user-defined operators' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.", "8652").WithLocation(3, 29), - // (7,30): error CS8652: The feature 'checked user-defined operators' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. - // public static C operator checked -(C c) - Diagnostic(ErrorCode.ERR_FeatureInPreview, "checked").WithArguments("checked user-defined operators").WithLocation(7, 30) + // (3,29): warning CS1658: Feature 'checked user-defined operators' is not available in C# 10.0. Please use language version 11.0 or greater.. See also error CS8936. + // /// See . + Diagnostic(ErrorCode.WRN_ErrorOverride, "checked").WithArguments("Feature 'checked user-defined operators' is not available in C# 10.0. Please use language version 11.0 or greater.", "8936").WithLocation(3, 29), + // (7,30): error CS8936: Feature 'checked user-defined operators' is not available in C# 10.0. Please use language version 11.0 or greater. + // public static C operator checked ++(C c) + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "checked").WithArguments("checked user-defined operators", "11.0").WithLocation(7, 30) ); crefSyntax = CrefTests.GetCrefSyntaxes(compilation).Single(); @@ -706,7 +706,7 @@ class C actualSymbol = CrefTests.GetReferencedSymbol(crefSyntax, compilation); Assert.Equal(expectedSymbol, actualSymbol); - compilation = CreateCompilationWithMscorlib40AndDocumentationComments(source, parseOptions: TestOptions.RegularNext.WithDocumentationMode(DocumentationMode.Diagnose)); + compilation = CreateCompilationWithMscorlib40AndDocumentationComments(source, parseOptions: TestOptions.Regular11.WithDocumentationMode(DocumentationMode.Diagnose)); compilation.GetDiagnostics().Where(d => d.Code is not (int)ErrorCode.ERR_CheckedOperatorNeedsMatch).Verify(); crefSyntax = CrefTests.GetCrefSyntaxes(compilation).Single(); @@ -819,7 +819,7 @@ class C actualSymbol = CrefTests.GetReferencedSymbol(crefSyntax, compilation); Assert.Equal(expectedSymbol, actualSymbol); - compilation = CreateCompilationWithMscorlib40AndDocumentationComments(source, parseOptions: TestOptions.RegularNext.WithDocumentationMode(DocumentationMode.Diagnose)); + compilation = CreateCompilationWithMscorlib40AndDocumentationComments(source, parseOptions: TestOptions.Regular11.WithDocumentationMode(DocumentationMode.Diagnose)); compilation.VerifyDiagnostics(expected); crefSyntax = CrefTests.GetCrefSyntaxes(compilation).Single(); @@ -868,7 +868,7 @@ class C actualSymbol = CrefTests.GetReferencedSymbol(crefSyntax, compilation); Assert.Equal(expectedSymbol, actualSymbol); - compilation = CreateCompilationWithMscorlib40AndDocumentationComments(source, parseOptions: TestOptions.RegularNext.WithDocumentationMode(DocumentationMode.Diagnose)); + compilation = CreateCompilationWithMscorlib40AndDocumentationComments(source, parseOptions: TestOptions.Regular11.WithDocumentationMode(DocumentationMode.Diagnose)); compilation.VerifyDiagnostics(expected); crefSyntax = CrefTests.GetCrefSyntaxes(compilation).Single(); @@ -890,7 +890,7 @@ class C public static C operator checked " + op + @"(C x) => x; } "; - foreach (var options in new[] { TestOptions.RegularPreview, TestOptions.Regular10, TestOptions.RegularNext }) + foreach (var options in new[] { TestOptions.RegularPreview, TestOptions.Regular10, TestOptions.Regular11 }) { var compilation1 = CreateCompilation(source1, options: TestOptions.DebugDll, parseOptions: options); @@ -921,7 +921,7 @@ class C public static bool operator checked false(C x) => false; } "; - foreach (var options in new[] { TestOptions.RegularPreview, TestOptions.Regular10, TestOptions.RegularNext }) + foreach (var options in new[] { TestOptions.RegularPreview, TestOptions.Regular10, TestOptions.Regular11 }) { var compilation1 = CreateCompilation(source1, options: TestOptions.DebugDll, parseOptions: options); @@ -1063,16 +1063,16 @@ class C // (3,20): warning CS1584: XML comment has syntactically incorrect cref attribute 'operator checked +' // /// See . Diagnostic(ErrorCode.WRN_BadXMLRefSyntax, "operator checked " + op).WithArguments("operator checked " + op).WithLocation(3, 20), - // (3,29): warning CS1658: The feature 'checked user-defined operators' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.. See also error CS8652. + // (3,29): warning CS1658: Feature 'checked user-defined operators' is not available in C# 10.0. Please use language version 11.0 or greater.. See also error CS8936. // /// See . - Diagnostic(ErrorCode.WRN_ErrorOverride, "checked").WithArguments("The feature 'checked user-defined operators' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.", "8652").WithLocation(3, 29) + Diagnostic(ErrorCode.WRN_ErrorOverride, "checked").WithArguments("Feature 'checked user-defined operators' is not available in C# 10.0. Please use language version 11.0 or greater.", "8936").WithLocation(3, 29) ); crefSyntax = CrefTests.GetCrefSyntaxes(compilation).Single(); actualSymbol = CrefTests.GetReferencedSymbol(crefSyntax, compilation, expected); Assert.Null(actualSymbol); - compilation = CreateCompilationWithMscorlib40AndDocumentationComments(source, parseOptions: TestOptions.RegularNext.WithDocumentationMode(DocumentationMode.Diagnose)); + compilation = CreateCompilationWithMscorlib40AndDocumentationComments(source, parseOptions: TestOptions.Regular11.WithDocumentationMode(DocumentationMode.Diagnose)); compilation.VerifyDiagnostics(expected); crefSyntax = CrefTests.GetCrefSyntaxes(compilation).Single(); @@ -1113,16 +1113,16 @@ class C // (3,20): warning CS1584: XML comment has syntactically incorrect cref attribute 'operator checked false' // /// See . Diagnostic(ErrorCode.WRN_BadXMLRefSyntax, "operator checked " + op).WithArguments("operator checked " + op).WithLocation(3, 20), - // (3,29): warning CS1658: The feature 'checked user-defined operators' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.. See also error CS8652. - // /// See . - Diagnostic(ErrorCode.WRN_ErrorOverride, "checked").WithArguments("The feature 'checked user-defined operators' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.", "8652").WithLocation(3, 29) + // (3,29): warning CS1658: Feature 'checked user-defined operators' is not available in C# 10.0. Please use language version 11.0 or greater.. See also error CS8936. + // /// See . + Diagnostic(ErrorCode.WRN_ErrorOverride, "checked").WithArguments("Feature 'checked user-defined operators' is not available in C# 10.0. Please use language version 11.0 or greater.", "8936").WithLocation(3, 29) ); crefSyntax = CrefTests.GetCrefSyntaxes(compilation).Single(); actualSymbol = CrefTests.GetReferencedSymbol(crefSyntax, compilation, expected); Assert.Null(actualSymbol); - compilation = CreateCompilationWithMscorlib40AndDocumentationComments(source, parseOptions: TestOptions.RegularNext.WithDocumentationMode(DocumentationMode.Diagnose)); + compilation = CreateCompilationWithMscorlib40AndDocumentationComments(source, parseOptions: TestOptions.Regular11.WithDocumentationMode(DocumentationMode.Diagnose)); compilation.VerifyDiagnostics(expected); crefSyntax = CrefTests.GetCrefSyntaxes(compilation).Single(); @@ -1166,16 +1166,16 @@ class C // (3,20): warning CS1584: XML comment has syntactically incorrect cref attribute 'operator checked +(C)' // /// See . Diagnostic(ErrorCode.WRN_BadXMLRefSyntax, "operator checked " + op + "(C)").WithArguments("operator checked " + op + "(C)").WithLocation(3, 20), - // (3,29): warning CS1658: The feature 'checked user-defined operators' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.. See also error CS8652. + // (3,29): warning CS1658: Feature 'checked user-defined operators' is not available in C# 10.0. Please use language version 11.0 or greater.. See also error CS8936. // /// See . - Diagnostic(ErrorCode.WRN_ErrorOverride, "checked").WithArguments("The feature 'checked user-defined operators' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.", "8652").WithLocation(3, 29) + Diagnostic(ErrorCode.WRN_ErrorOverride, "checked").WithArguments("Feature 'checked user-defined operators' is not available in C# 10.0. Please use language version 11.0 or greater.", "8936").WithLocation(3, 29) ); crefSyntax = CrefTests.GetCrefSyntaxes(compilation).Single(); actualSymbol = CrefTests.GetReferencedSymbol(crefSyntax, compilation, expected); Assert.Null(actualSymbol); - compilation = CreateCompilationWithMscorlib40AndDocumentationComments(source, parseOptions: TestOptions.RegularNext.WithDocumentationMode(DocumentationMode.Diagnose)); + compilation = CreateCompilationWithMscorlib40AndDocumentationComments(source, parseOptions: TestOptions.Regular11.WithDocumentationMode(DocumentationMode.Diagnose)); compilation.VerifyDiagnostics(expected); crefSyntax = CrefTests.GetCrefSyntaxes(compilation).Single(); @@ -1212,20 +1212,19 @@ class C Assert.Null(actualSymbol); compilation = CreateCompilationWithMscorlib40AndDocumentationComments(source, parseOptions: TestOptions.Regular10.WithDocumentationMode(DocumentationMode.Diagnose)); - compilation.VerifyDiagnostics( - // (3,20): warning CS1584: XML comment has syntactically incorrect cref attribute 'operator checked true(C)' - // /// See . + compilation.VerifyDiagnostics( // (3,20): warning CS1584: XML comment has syntactically incorrect cref attribute 'operator checked true(C)' + // /// See . Diagnostic(ErrorCode.WRN_BadXMLRefSyntax, "operator checked " + op + "(C)").WithArguments("operator checked " + op + "(C)").WithLocation(3, 20), - // (3,29): warning CS1658: The feature 'checked user-defined operators' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.. See also error CS8652. + // (3,29): warning CS1658: Feature 'checked user-defined operators' is not available in C# 10.0. Please use language version 11.0 or greater.. See also error CS8936. // /// See . - Diagnostic(ErrorCode.WRN_ErrorOverride, "checked").WithArguments("The feature 'checked user-defined operators' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.", "8652").WithLocation(3, 29) + Diagnostic(ErrorCode.WRN_ErrorOverride, "checked").WithArguments("Feature 'checked user-defined operators' is not available in C# 10.0. Please use language version 11.0 or greater.", "8936").WithLocation(3, 29) ); crefSyntax = CrefTests.GetCrefSyntaxes(compilation).Single(); actualSymbol = CrefTests.GetReferencedSymbol(crefSyntax, compilation, expected); Assert.Null(actualSymbol); - compilation = CreateCompilationWithMscorlib40AndDocumentationComments(source, parseOptions: TestOptions.RegularNext.WithDocumentationMode(DocumentationMode.Diagnose)); + compilation = CreateCompilationWithMscorlib40AndDocumentationComments(source, parseOptions: TestOptions.Regular11.WithDocumentationMode(DocumentationMode.Diagnose)); compilation.VerifyDiagnostics(expected); crefSyntax = CrefTests.GetCrefSyntaxes(compilation).Single(); @@ -1254,13 +1253,13 @@ class C compilation1 = CreateCompilation(source1, options: TestOptions.DebugDll, parseOptions: TestOptions.Regular10); compilation1.VerifyDiagnostics( - // (4,30): error CS8652: The feature 'checked user-defined operators' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. - // public static C operator checked -(C x, C y) => x; - Diagnostic(ErrorCode.ERR_FeatureInPreview, "checked").WithArguments("checked user-defined operators").WithLocation(4, 30) + // (4,30): error CS8936: Feature 'checked user-defined operators' is not available in C# 10.0. Please use language version 11.0 or greater. + // public static C operator checked +(C x, C y) => x; + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "checked").WithArguments("checked user-defined operators", "11.0").WithLocation(4, 30) ); validator(compilation1.SourceModule); - compilation1 = CreateCompilation(source1, options: TestOptions.DebugDll, parseOptions: TestOptions.RegularNext); + compilation1 = CreateCompilation(source1, options: TestOptions.DebugDll, parseOptions: TestOptions.Regular11); CompileAndVerify(compilation1, sourceSymbolValidator: validator, symbolValidator: validator).VerifyDiagnostics(); void validator(ModuleSymbol m) @@ -1698,16 +1697,17 @@ class C Assert.Equal(expectedSymbol, actualSymbol); compilation = CreateCompilationWithMscorlib40AndDocumentationComments(source, parseOptions: TestOptions.Regular10.WithDocumentationMode(DocumentationMode.Diagnose)); + compilation.VerifyDiagnostics( - // (3,20): warning CS1584: XML comment has syntactically incorrect cref attribute 'operator checked -' - // /// See . + // (3,20): warning CS1584: XML comment has syntactically incorrect cref attribute 'operator checked +' + // /// See . Diagnostic(ErrorCode.WRN_BadXMLRefSyntax, "operator checked " + op).WithArguments("operator checked " + op).WithLocation(3, 20), - // (3,29): warning CS1658: The feature 'checked user-defined operators' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.. See also error CS8652. - // /// See . - Diagnostic(ErrorCode.WRN_ErrorOverride, "checked").WithArguments("The feature 'checked user-defined operators' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.", "8652").WithLocation(3, 29), - // (7,30): error CS8652: The feature 'checked user-defined operators' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. - // public static C operator checked -(C c, C y) - Diagnostic(ErrorCode.ERR_FeatureInPreview, "checked").WithArguments("checked user-defined operators").WithLocation(7, 30) + // (3,29): warning CS1658: Feature 'checked user-defined operators' is not available in C# 10.0. Please use language version 11.0 or greater.. See also error CS8936. + // /// See . + Diagnostic(ErrorCode.WRN_ErrorOverride, "checked").WithArguments("Feature 'checked user-defined operators' is not available in C# 10.0. Please use language version 11.0 or greater.", "8936").WithLocation(3, 29), + // (7,30): error CS8936: Feature 'checked user-defined operators' is not available in C# 10.0. Please use language version 11.0 or greater. + // public static C operator checked +(C c, C y) + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "checked").WithArguments("checked user-defined operators", "11.0").WithLocation(7, 30) ); crefSyntax = CrefTests.GetCrefSyntaxes(compilation).Single(); @@ -1715,7 +1715,7 @@ class C actualSymbol = CrefTests.GetReferencedSymbol(crefSyntax, compilation); Assert.Equal(expectedSymbol, actualSymbol); - compilation = CreateCompilationWithMscorlib40AndDocumentationComments(source, parseOptions: TestOptions.RegularNext.WithDocumentationMode(DocumentationMode.Diagnose)); + compilation = CreateCompilationWithMscorlib40AndDocumentationComments(source, parseOptions: TestOptions.Regular11.WithDocumentationMode(DocumentationMode.Diagnose)); compilation.VerifyDiagnostics(); crefSyntax = CrefTests.GetCrefSyntaxes(compilation).Single(); @@ -1827,9 +1827,9 @@ class C // (3,37): warning CS1658: Overloadable operator expected. See also error CS1037. // /// See . Diagnostic(ErrorCode.WRN_ErrorOverride, @"""").WithArguments("Overloadable operator expected", "1037").WithLocation(3, 37), - // (7,30): error CS8652: The feature 'checked user-defined operators' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // (7,30): error CS8936: Feature 'checked user-defined operators' is not available in C# 10.0. Please use language version 11.0 or greater. // public static C operator checked +(C c, C y) - Diagnostic(ErrorCode.ERR_FeatureInPreview, "checked").WithArguments("checked user-defined operators").WithLocation(7, 30) + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "checked").WithArguments("checked user-defined operators", "11.0").WithLocation(7, 30) ); crefSyntax = CrefTests.GetCrefSyntaxes(compilation).Single(); @@ -1837,7 +1837,7 @@ class C actualSymbol = CrefTests.GetReferencedSymbol(crefSyntax, compilation); Assert.Equal(expectedSymbol, actualSymbol); - compilation = CreateCompilationWithMscorlib40AndDocumentationComments(source, parseOptions: TestOptions.RegularNext.WithDocumentationMode(DocumentationMode.Diagnose)); + compilation = CreateCompilationWithMscorlib40AndDocumentationComments(source, parseOptions: TestOptions.Regular11.WithDocumentationMode(DocumentationMode.Diagnose)); compilation.GetDiagnostics().Where(d => d.Code is not (int)ErrorCode.ERR_CheckedOperatorNeedsMatch).Verify( // (3,20): warning CS1584: XML comment has syntactically incorrect cref attribute 'operator checked' // /// See . @@ -1893,7 +1893,7 @@ class C actualSymbol = CrefTests.GetReferencedSymbol(crefSyntax, compilation); Assert.Equal(expectedSymbol, actualSymbol); - compilation = CreateCompilationWithMscorlib40AndDocumentationComments(source, parseOptions: TestOptions.RegularNext.WithDocumentationMode(DocumentationMode.Diagnose)); + compilation = CreateCompilationWithMscorlib40AndDocumentationComments(source, parseOptions: TestOptions.Regular11.WithDocumentationMode(DocumentationMode.Diagnose)); compilation.VerifyDiagnostics(expected); crefSyntax = CrefTests.GetCrefSyntaxes(compilation).Single(); @@ -1931,15 +1931,15 @@ class C compilation = CreateCompilationWithMscorlib40AndDocumentationComments(source, parseOptions: TestOptions.Regular10.WithDocumentationMode(DocumentationMode.Diagnose)); compilation.GetDiagnostics().Where(d => d.Code is not (int)ErrorCode.ERR_CheckedOperatorNeedsMatch).Verify( - // (3,20): warning CS1584: XML comment has syntactically incorrect cref attribute 'operator checked -(C)' - // /// See . + // (3,20): warning CS1584: XML comment has syntactically incorrect cref attribute 'operator checked +(C, C)' + // /// See . Diagnostic(ErrorCode.WRN_BadXMLRefSyntax, "operator checked " + op + "(C, C)").WithArguments("operator checked " + op + "(C, C)").WithLocation(3, 20), - // (3,29): warning CS1658: The feature 'checked user-defined operators' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.. See also error CS8652. - // /// See . - Diagnostic(ErrorCode.WRN_ErrorOverride, "checked").WithArguments("The feature 'checked user-defined operators' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.", "8652").WithLocation(3, 29), - // (7,30): error CS8652: The feature 'checked user-defined operators' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. - // public static C operator checked -(C c, C) - Diagnostic(ErrorCode.ERR_FeatureInPreview, "checked").WithArguments("checked user-defined operators").WithLocation(7, 30) + // (3,29): warning CS1658: Feature 'checked user-defined operators' is not available in C# 10.0. Please use language version 11.0 or greater.. See also error CS8936. + // /// See . + Diagnostic(ErrorCode.WRN_ErrorOverride, "checked").WithArguments("Feature 'checked user-defined operators' is not available in C# 10.0. Please use language version 11.0 or greater.", "8936").WithLocation(3, 29), + // (7,30): error CS8936: Feature 'checked user-defined operators' is not available in C# 10.0. Please use language version 11.0 or greater. + // public static C operator checked +(C c, C y) + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "checked").WithArguments("checked user-defined operators", "11.0").WithLocation(7, 30) ); crefSyntax = CrefTests.GetCrefSyntaxes(compilation).Single(); @@ -1947,7 +1947,7 @@ class C actualSymbol = CrefTests.GetReferencedSymbol(crefSyntax, compilation); Assert.Equal(expectedSymbol, actualSymbol); - compilation = CreateCompilationWithMscorlib40AndDocumentationComments(source, parseOptions: TestOptions.RegularNext.WithDocumentationMode(DocumentationMode.Diagnose)); + compilation = CreateCompilationWithMscorlib40AndDocumentationComments(source, parseOptions: TestOptions.Regular11.WithDocumentationMode(DocumentationMode.Diagnose)); compilation.GetDiagnostics().Where(d => d.Code is not (int)ErrorCode.ERR_CheckedOperatorNeedsMatch).Verify(); crefSyntax = CrefTests.GetCrefSyntaxes(compilation).Single(); @@ -2062,9 +2062,9 @@ class C // (3,37): warning CS1658: Overloadable operator expected. See also error CS1037. // /// See . Diagnostic(ErrorCode.WRN_ErrorOverride, "(").WithArguments("Overloadable operator expected", "1037").WithLocation(3, 37), - // (7,30): error CS8652: The feature 'checked user-defined operators' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // (7,30): error CS8936: Feature 'checked user-defined operators' is not available in C# 10.0. Please use language version 11.0 or greater. // public static C operator checked +(C c, C y) - Diagnostic(ErrorCode.ERR_FeatureInPreview, "checked").WithArguments("checked user-defined operators").WithLocation(7, 30) + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "checked").WithArguments("checked user-defined operators", "11.0").WithLocation(7, 30) ); crefSyntax = CrefTests.GetCrefSyntaxes(compilation).Single(); @@ -2072,7 +2072,7 @@ class C actualSymbol = CrefTests.GetReferencedSymbol(crefSyntax, compilation); Assert.Equal(expectedSymbol, actualSymbol); - compilation = CreateCompilationWithMscorlib40AndDocumentationComments(source, parseOptions: TestOptions.RegularNext.WithDocumentationMode(DocumentationMode.Diagnose)); + compilation = CreateCompilationWithMscorlib40AndDocumentationComments(source, parseOptions: TestOptions.Regular11.WithDocumentationMode(DocumentationMode.Diagnose)); compilation.GetDiagnostics().Where(d => d.Code is not (int)ErrorCode.ERR_CheckedOperatorNeedsMatch).Verify(expected); crefSyntax = CrefTests.GetCrefSyntaxes(compilation).Single(); @@ -2121,7 +2121,7 @@ class C actualSymbol = CrefTests.GetReferencedSymbol(crefSyntax, compilation); Assert.Equal(expectedSymbol, actualSymbol); - compilation = CreateCompilationWithMscorlib40AndDocumentationComments(source, parseOptions: TestOptions.RegularNext.WithDocumentationMode(DocumentationMode.Diagnose)); + compilation = CreateCompilationWithMscorlib40AndDocumentationComments(source, parseOptions: TestOptions.Regular11.WithDocumentationMode(DocumentationMode.Diagnose)); compilation.VerifyDiagnostics(expected); crefSyntax = CrefTests.GetCrefSyntaxes(compilation).Single(); @@ -2153,7 +2153,7 @@ class C public static C operator checked " + op + @"(C x, int y) => x; } "; - foreach (var options in new[] { TestOptions.RegularPreview, TestOptions.Regular10, TestOptions.RegularNext }) + foreach (var options in new[] { TestOptions.RegularPreview, TestOptions.Regular10, TestOptions.Regular11 }) { var compilation1 = CreateCompilation(source1, options: TestOptions.DebugDll, parseOptions: options); @@ -2163,9 +2163,9 @@ class C // (4,30): error CS9023: User-defined operator '>>>' cannot be declared checked // public static C operator checked >>>(C x, int y) => x; Diagnostic(ErrorCode.ERR_OperatorCantBeChecked, "checked").WithArguments(">>>").WithLocation(4, 30), - // (4,38): error CS8652: The feature 'unsigned right shift' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // (4,38): error CS8936: Feature 'unsigned right shift' is not available in C# 10.0. Please use language version 11.0 or greater. // public static C operator checked >>>(C x, int y) => x; - Diagnostic(ErrorCode.ERR_FeatureInPreview, ">>>").WithArguments("unsigned right shift").WithLocation(4, 38) + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, ">>>").WithArguments("unsigned right shift", "11.0").WithLocation(4, 38) ); } else @@ -2283,12 +2283,12 @@ class C { compilation.GetDiagnostics().Where(d => d.Code is not ((int)ErrorCode.ERR_OperatorNeedsMatch or (int)ErrorCode.WRN_EqualityOpWithoutEquals or (int)ErrorCode.WRN_EqualityOpWithoutGetHashCode)). Verify( - // (3,20): warning CS1584: XML comment has syntactically incorrect cref attribute 'operator checked %' - // /// See . + // (3,20): warning CS1584: XML comment has syntactically incorrect cref attribute 'operator checked }}' + // /// See . Diagnostic(ErrorCode.WRN_BadXMLRefSyntax, "operator checked " + opForXml).WithArguments("operator checked " + opForXml).WithLocation(3, 20), - // (3,29): warning CS1658: The feature 'checked user-defined operators' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.. See also error CS8652. - // /// See . - Diagnostic(ErrorCode.WRN_ErrorOverride, "checked").WithArguments("The feature 'checked user-defined operators' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.", "8652").WithLocation(3, 29) + // (3,29): warning CS1658: Feature 'checked user-defined operators' is not available in C# 10.0. Please use language version 11.0 or greater.. See also error CS8936. + // /// See . + Diagnostic(ErrorCode.WRN_ErrorOverride, "checked").WithArguments("Feature 'checked user-defined operators' is not available in C# 10.0. Please use language version 11.0 or greater.", "8936").WithLocation(3, 29) ); } else @@ -2297,15 +2297,15 @@ class C // (3,20): warning CS1584: XML comment has syntactically incorrect cref attribute 'operator checked }}}' // /// See . Diagnostic(ErrorCode.WRN_BadXMLRefSyntax, "operator checked }}}").WithArguments("operator checked }}}").WithLocation(3, 20), - // (3,29): warning CS1658: The feature 'checked user-defined operators' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.. See also error CS8652. + // (3,29): warning CS1658: Feature 'checked user-defined operators' is not available in C# 10.0. Please use language version 11.0 or greater.. See also error CS8936. // /// See . - Diagnostic(ErrorCode.WRN_ErrorOverride, "checked").WithArguments("The feature 'checked user-defined operators' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.", "8652").WithLocation(3, 29), - // (3,37): warning CS1658: The feature 'unsigned right shift' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.. See also error CS8652. + Diagnostic(ErrorCode.WRN_ErrorOverride, "checked").WithArguments("Feature 'checked user-defined operators' is not available in C# 10.0. Please use language version 11.0 or greater.", "8936").WithLocation(3, 29), + // (3,37): warning CS1658: Feature 'unsigned right shift' is not available in C# 10.0. Please use language version 11.0 or greater.. See also error CS8936. // /// See . - Diagnostic(ErrorCode.WRN_ErrorOverride, "}}}").WithArguments("The feature 'unsigned right shift' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.", "8652").WithLocation(3, 37), - // (7,30): error CS8652: The feature 'unsigned right shift' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + Diagnostic(ErrorCode.WRN_ErrorOverride, "}}}").WithArguments("Feature 'unsigned right shift' is not available in C# 10.0. Please use language version 11.0 or greater.", "8936").WithLocation(3, 37), + // (7,30): error CS8936: Feature 'unsigned right shift' is not available in C# 10.0. Please use language version 11.0 or greater. // public static C operator >>>(C c, int y) - Diagnostic(ErrorCode.ERR_FeatureInPreview, ">>>").WithArguments("unsigned right shift").WithLocation(7, 30) + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, ">>>").WithArguments("unsigned right shift", "11.0").WithLocation(7, 30) ); } @@ -2313,7 +2313,7 @@ class C actualSymbol = CrefTests.GetReferencedSymbol(crefSyntax, compilation, expected); Assert.Null(actualSymbol); - compilation = CreateCompilationWithMscorlib40AndDocumentationComments(source, parseOptions: TestOptions.RegularNext.WithDocumentationMode(DocumentationMode.Diagnose)); + compilation = CreateCompilationWithMscorlib40AndDocumentationComments(source, parseOptions: TestOptions.Regular11.WithDocumentationMode(DocumentationMode.Diagnose)); compilation.GetDiagnostics().Where(d => d.Code is not ((int)ErrorCode.ERR_OperatorNeedsMatch or (int)ErrorCode.WRN_EqualityOpWithoutEquals or (int)ErrorCode.WRN_EqualityOpWithoutGetHashCode)). Verify(expected); @@ -2377,12 +2377,12 @@ class C { compilation.GetDiagnostics().Where(d => d.Code is not ((int)ErrorCode.ERR_OperatorNeedsMatch or (int)ErrorCode.WRN_EqualityOpWithoutEquals or (int)ErrorCode.WRN_EqualityOpWithoutGetHashCode)). Verify( - // (3,20): warning CS1584: XML comment has syntactically incorrect cref attribute 'operator checked %(C, int)' - // /// See . + // (3,20): warning CS1584: XML comment has syntactically incorrect cref attribute 'operator checked }}(C, int)' + // /// See . Diagnostic(ErrorCode.WRN_BadXMLRefSyntax, "operator checked " + opForXml + "(C, int)").WithArguments("operator checked " + opForXml + "(C, int)").WithLocation(3, 20), - // (3,29): warning CS1658: The feature 'checked user-defined operators' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.. See also error CS8652. - // /// See . - Diagnostic(ErrorCode.WRN_ErrorOverride, "checked").WithArguments("The feature 'checked user-defined operators' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.", "8652").WithLocation(3, 29) + // (3,29): warning CS1658: Feature 'checked user-defined operators' is not available in C# 10.0. Please use language version 11.0 or greater.. See also error CS8936. + // /// See . + Diagnostic(ErrorCode.WRN_ErrorOverride, "checked").WithArguments("Feature 'checked user-defined operators' is not available in C# 10.0. Please use language version 11.0 or greater.", "8936").WithLocation(3, 29) ); } else @@ -2391,15 +2391,15 @@ class C // (3,20): warning CS1584: XML comment has syntactically incorrect cref attribute 'operator checked }}}(C, int)' // /// See . Diagnostic(ErrorCode.WRN_BadXMLRefSyntax, "operator checked }}}(C, int)").WithArguments("operator checked }}}(C, int)").WithLocation(3, 20), - // (3,29): warning CS1658: The feature 'checked user-defined operators' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.. See also error CS8652. + // (3,29): warning CS1658: Feature 'checked user-defined operators' is not available in C# 10.0. Please use language version 11.0 or greater.. See also error CS8936. // /// See . - Diagnostic(ErrorCode.WRN_ErrorOverride, "checked").WithArguments("The feature 'checked user-defined operators' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.", "8652").WithLocation(3, 29), - // (3,37): warning CS1658: The feature 'unsigned right shift' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.. See also error CS8652. + Diagnostic(ErrorCode.WRN_ErrorOverride, "checked").WithArguments("Feature 'checked user-defined operators' is not available in C# 10.0. Please use language version 11.0 or greater.", "8936").WithLocation(3, 29), + // (3,37): warning CS1658: Feature 'unsigned right shift' is not available in C# 10.0. Please use language version 11.0 or greater.. See also error CS8936. // /// See . - Diagnostic(ErrorCode.WRN_ErrorOverride, "}}}").WithArguments("The feature 'unsigned right shift' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.", "8652").WithLocation(3, 37), - // (7,30): error CS8652: The feature 'unsigned right shift' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + Diagnostic(ErrorCode.WRN_ErrorOverride, "}}}").WithArguments("Feature 'unsigned right shift' is not available in C# 10.0. Please use language version 11.0 or greater.", "8936").WithLocation(3, 37), + // (7,30): error CS8936: Feature 'unsigned right shift' is not available in C# 10.0. Please use language version 11.0 or greater. // public static C operator >>>(C c, int y) - Diagnostic(ErrorCode.ERR_FeatureInPreview, ">>>").WithArguments("unsigned right shift").WithLocation(7, 30) + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, ">>>").WithArguments("unsigned right shift", "11.0").WithLocation(7, 30) ); } @@ -2407,7 +2407,7 @@ class C actualSymbol = CrefTests.GetReferencedSymbol(crefSyntax, compilation, expected); Assert.Null(actualSymbol); - compilation = CreateCompilationWithMscorlib40AndDocumentationComments(source, parseOptions: TestOptions.RegularNext.WithDocumentationMode(DocumentationMode.Diagnose)); + compilation = CreateCompilationWithMscorlib40AndDocumentationComments(source, parseOptions: TestOptions.Regular11.WithDocumentationMode(DocumentationMode.Diagnose)); compilation.GetDiagnostics().Where(d => d.Code is not ((int)ErrorCode.ERR_OperatorNeedsMatch or (int)ErrorCode.WRN_EqualityOpWithoutEquals or (int)ErrorCode.WRN_EqualityOpWithoutGetHashCode)). Verify(expected); @@ -2487,13 +2487,13 @@ class C compilation1 = CreateCompilation(source1, options: TestOptions.DebugDll, parseOptions: TestOptions.Regular10); compilation1.VerifyDiagnostics( - // (4,37): error CS8652: The feature 'checked user-defined operators' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // (4,37): error CS8936: Feature 'checked user-defined operators' is not available in C# 10.0. Please use language version 11.0 or greater. // public static explicit operator checked int(C x) => 0; - Diagnostic(ErrorCode.ERR_FeatureInPreview, "checked").WithArguments("checked user-defined operators").WithLocation(4, 37) + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "checked").WithArguments("checked user-defined operators", "11.0").WithLocation(4, 37) ); validator(compilation1.SourceModule); - compilation1 = CreateCompilation(source1, options: TestOptions.DebugDll, parseOptions: TestOptions.RegularNext); + compilation1 = CreateCompilation(source1, options: TestOptions.DebugDll, parseOptions: TestOptions.Regular11); CompileAndVerify(compilation1, sourceSymbolValidator: validator, symbolValidator: validator).VerifyDiagnostics(); void validator(ModuleSymbol m) @@ -2860,12 +2860,12 @@ public static explicit operator int(C c) // (3,20): warning CS1584: XML comment has syntactically incorrect cref attribute 'explicit operator checked int' // /// See . Diagnostic(ErrorCode.WRN_BadXMLRefSyntax, "explicit operator checked int").WithArguments("explicit operator checked int").WithLocation(3, 20), - // (3,38): warning CS1658: The feature 'checked user-defined operators' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.. See also error CS8652. + // (3,38): warning CS1658: Feature 'checked user-defined operators' is not available in C# 10.0. Please use language version 11.0 or greater.. See also error CS8936. // /// See . - Diagnostic(ErrorCode.WRN_ErrorOverride, "checked").WithArguments("The feature 'checked user-defined operators' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.", "8652").WithLocation(3, 38), - // (7,37): error CS8652: The feature 'checked user-defined operators' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + Diagnostic(ErrorCode.WRN_ErrorOverride, "checked").WithArguments("Feature 'checked user-defined operators' is not available in C# 10.0. Please use language version 11.0 or greater.", "8936").WithLocation(3, 38), + // (7,37): error CS8936: Feature 'checked user-defined operators' is not available in C# 10.0. Please use language version 11.0 or greater. // public static explicit operator checked int(C c) - Diagnostic(ErrorCode.ERR_FeatureInPreview, "checked").WithArguments("checked user-defined operators").WithLocation(7, 37) + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "checked").WithArguments("checked user-defined operators", "11.0").WithLocation(7, 37) ); crefSyntax = CrefTests.GetCrefSyntaxes(compilation).Single(); @@ -2873,7 +2873,7 @@ public static explicit operator int(C c) actualSymbol = CrefTests.GetReferencedSymbol(crefSyntax, compilation); Assert.Equal(expectedSymbol, actualSymbol); - compilation = CreateCompilationWithMscorlib40AndDocumentationComments(source, parseOptions: TestOptions.RegularNext.WithDocumentationMode(DocumentationMode.Diagnose)); + compilation = CreateCompilationWithMscorlib40AndDocumentationComments(source, parseOptions: TestOptions.Regular11.WithDocumentationMode(DocumentationMode.Diagnose)); compilation.VerifyDiagnostics(); crefSyntax = CrefTests.GetCrefSyntaxes(compilation).Single(); @@ -3023,15 +3023,15 @@ public static explicit operator checked int(C c) compilation = CreateCompilationWithMscorlib40AndDocumentationComments(source, parseOptions: TestOptions.Regular10.WithDocumentationMode(DocumentationMode.Diagnose)); compilation.GetDiagnostics().Where(d => d.Code is not (int)ErrorCode.ERR_CheckedOperatorNeedsMatch).Verify( - // (3,20): warning CS1584: XML comment has syntactically incorrect cref attribute 'explicit operator checked int' + // (3,20): warning CS1584: XML comment has syntactically incorrect cref attribute 'explicit operator checked int(C)' // /// See . Diagnostic(ErrorCode.WRN_BadXMLRefSyntax, "explicit operator checked int(C)").WithArguments("explicit operator checked int(C)").WithLocation(3, 20), - // (3,38): warning CS1658: The feature 'checked user-defined operators' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.. See also error CS8652. + // (3,38): warning CS1658: Feature 'checked user-defined operators' is not available in C# 10.0. Please use language version 11.0 or greater.. See also error CS8936. // /// See . - Diagnostic(ErrorCode.WRN_ErrorOverride, "checked").WithArguments("The feature 'checked user-defined operators' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.", "8652").WithLocation(3, 38), - // (7,37): error CS8652: The feature 'checked user-defined operators' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + Diagnostic(ErrorCode.WRN_ErrorOverride, "checked").WithArguments("Feature 'checked user-defined operators' is not available in C# 10.0. Please use language version 11.0 or greater.", "8936").WithLocation(3, 38), + // (7,37): error CS8936: Feature 'checked user-defined operators' is not available in C# 10.0. Please use language version 11.0 or greater. // public static explicit operator checked int(C c) - Diagnostic(ErrorCode.ERR_FeatureInPreview, "checked").WithArguments("checked user-defined operators").WithLocation(7, 37) + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "checked").WithArguments("checked user-defined operators", "11.0").WithLocation(7, 37) ); crefSyntax = CrefTests.GetCrefSyntaxes(compilation).Single(); @@ -3039,7 +3039,7 @@ public static explicit operator checked int(C c) actualSymbol = CrefTests.GetReferencedSymbol(crefSyntax, compilation); Assert.Equal(expectedSymbol, actualSymbol); - compilation = CreateCompilationWithMscorlib40AndDocumentationComments(source, parseOptions: TestOptions.RegularNext.WithDocumentationMode(DocumentationMode.Diagnose)); + compilation = CreateCompilationWithMscorlib40AndDocumentationComments(source, parseOptions: TestOptions.Regular11.WithDocumentationMode(DocumentationMode.Diagnose)); compilation.GetDiagnostics().Where(d => d.Code is not (int)ErrorCode.ERR_CheckedOperatorNeedsMatch).Verify(); crefSyntax = CrefTests.GetCrefSyntaxes(compilation).Single(); @@ -3174,7 +3174,7 @@ class C public static implicit operator checked int(C x) => 0; } "; - foreach (var options in new[] { TestOptions.RegularPreview, TestOptions.Regular10, TestOptions.RegularNext }) + foreach (var options in new[] { TestOptions.RegularPreview, TestOptions.Regular10, TestOptions.Regular11 }) { var compilation1 = CreateCompilation(source1, options: TestOptions.DebugDll, parseOptions: options); @@ -3260,16 +3260,16 @@ public static implicit operator int(C c) // (3,20): warning CS1584: XML comment has syntactically incorrect cref attribute 'implicit operator checked int' // /// See . Diagnostic(ErrorCode.WRN_BadXMLRefSyntax, "implicit operator checked int").WithArguments("implicit operator checked int").WithLocation(3, 20), - // (3,38): warning CS1658: The feature 'checked user-defined operators' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.. See also error CS8652. + // (3,38): warning CS1658: Feature 'checked user-defined operators' is not available in C# 10.0. Please use language version 11.0 or greater.. See also error CS8936. // /// See . - Diagnostic(ErrorCode.WRN_ErrorOverride, "checked").WithArguments("The feature 'checked user-defined operators' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.", "8652").WithLocation(3, 38) + Diagnostic(ErrorCode.WRN_ErrorOverride, "checked").WithArguments("Feature 'checked user-defined operators' is not available in C# 10.0. Please use language version 11.0 or greater.", "8936").WithLocation(3, 38) ); crefSyntax = CrefTests.GetCrefSyntaxes(compilation).Single(); actualSymbol = CrefTests.GetReferencedSymbol(crefSyntax, compilation, expected); Assert.Null(actualSymbol); - compilation = CreateCompilationWithMscorlib40AndDocumentationComments(source, parseOptions: TestOptions.RegularNext.WithDocumentationMode(DocumentationMode.Diagnose)); + compilation = CreateCompilationWithMscorlib40AndDocumentationComments(source, parseOptions: TestOptions.Regular11.WithDocumentationMode(DocumentationMode.Diagnose)); compilation.VerifyDiagnostics(expected); crefSyntax = CrefTests.GetCrefSyntaxes(compilation).Single(); @@ -3307,19 +3307,19 @@ public static implicit operator int(C c) compilation = CreateCompilationWithMscorlib40AndDocumentationComments(source, parseOptions: TestOptions.Regular10.WithDocumentationMode(DocumentationMode.Diagnose)); compilation.VerifyDiagnostics( - // (3,20): warning CS1584: XML comment has syntactically incorrect cref attribute 'implicit operator checked int' + // (3,20): warning CS1584: XML comment has syntactically incorrect cref attribute 'implicit operator checked int(C)' // /// See . Diagnostic(ErrorCode.WRN_BadXMLRefSyntax, "implicit operator checked int(C)").WithArguments("implicit operator checked int(C)").WithLocation(3, 20), - // (3,38): warning CS1658: The feature 'checked user-defined operators' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.. See also error CS8652. + // (3,38): warning CS1658: Feature 'checked user-defined operators' is not available in C# 10.0. Please use language version 11.0 or greater.. See also error CS8936. // /// See . - Diagnostic(ErrorCode.WRN_ErrorOverride, "checked").WithArguments("The feature 'checked user-defined operators' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.", "8652").WithLocation(3, 38) + Diagnostic(ErrorCode.WRN_ErrorOverride, "checked").WithArguments("Feature 'checked user-defined operators' is not available in C# 10.0. Please use language version 11.0 or greater.", "8936").WithLocation(3, 38) ); crefSyntax = CrefTests.GetCrefSyntaxes(compilation).Single(); actualSymbol = CrefTests.GetReferencedSymbol(crefSyntax, compilation, expected); Assert.Null(actualSymbol); - compilation = CreateCompilationWithMscorlib40AndDocumentationComments(source, parseOptions: TestOptions.RegularNext.WithDocumentationMode(DocumentationMode.Diagnose)); + compilation = CreateCompilationWithMscorlib40AndDocumentationComments(source, parseOptions: TestOptions.Regular11.WithDocumentationMode(DocumentationMode.Diagnose)); compilation.VerifyDiagnostics(expected); crefSyntax = CrefTests.GetCrefSyntaxes(compilation).Single(); @@ -3429,7 +3429,7 @@ regular C2 regular C2 ").VerifyDiagnostics(); - compilation1 = CreateCompilation(source1 + source2, options: TestOptions.DebugExe, parseOptions: TestOptions.RegularNext); + compilation1 = CreateCompilation(source1 + source2, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular11); CompileAndVerify(compilation1, expectedOutput: @" checked C0 regular C0 @@ -3442,12 +3442,12 @@ regular C2 var compilation2 = CreateCompilation(source1, options: TestOptions.DebugDll, parseOptions: TestOptions.RegularPreview); var compilation3 = CreateCompilation(source2, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular10, references: new[] { compilation2.ToMetadataReference() }); compilation3.VerifyDiagnostics( - // (16,24): error CS8652: The feature 'checked user-defined operators' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. - // return checked(-x); // C0 - Diagnostic(ErrorCode.ERR_FeatureInPreview, op + "x").WithArguments("checked user-defined operators").WithLocation(16, 24), - // (26,24): error CS8652: The feature 'checked user-defined operators' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. - // return checked(-x); // C1 - Diagnostic(ErrorCode.ERR_FeatureInPreview, op + "x").WithArguments("checked user-defined operators").WithLocation(26, 24) + // (16,24): error CS8936: Feature 'checked user-defined operators' is not available in C# 10.0. Please use language version 11.0 or greater. + // return checked(++x); // C0 + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, op + "x").WithArguments("checked user-defined operators", "11.0").WithLocation(16, 24), + // (26,24): error CS8936: Feature 'checked user-defined operators' is not available in C# 10.0. Please use language version 11.0 or greater. + // return checked(++x); // C1 + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, op + "x").WithArguments("checked user-defined operators", "11.0").WithLocation(26, 24) ); } @@ -3825,7 +3825,7 @@ not null null ").VerifyDiagnostics(); - compilation1 = CreateCompilation(source1 + source2, options: TestOptions.DebugExe, parseOptions: TestOptions.RegularNext); + compilation1 = CreateCompilation(source1 + source2, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular11); CompileAndVerify(compilation1, expectedOutput: @" checked C0 not null @@ -3835,9 +3835,9 @@ not null var compilation2 = CreateCompilation(source1, options: TestOptions.DebugDll, parseOptions: TestOptions.RegularPreview); var compilation3 = CreateCompilation(source2, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular10, references: new[] { compilation2.ToMetadataReference() }); compilation3.VerifyDiagnostics( - // (12,24): error CS8652: The feature 'checked user-defined operators' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. - // return checked(-x); - Diagnostic(ErrorCode.ERR_FeatureInPreview, op + "x").WithArguments("checked user-defined operators").WithLocation(12, 24) + // (12,24): error CS8936: Feature 'checked user-defined operators' is not available in C# 10.0. Please use language version 11.0 or greater. + // return checked(++x); + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, op + "x").WithArguments("checked user-defined operators", "11.0").WithLocation(12, 24) ); } @@ -4204,7 +4204,7 @@ regular C2 regular C2 ").VerifyDiagnostics(); - compilation1 = CreateCompilation(source1 + source2, options: TestOptions.DebugExe, parseOptions: TestOptions.RegularNext); + compilation1 = CreateCompilation(source1 + source2, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular11); CompileAndVerify(compilation1, expectedOutput: @" checked C0 regular C0 @@ -4217,12 +4217,12 @@ regular C2 var compilation2 = CreateCompilation(source1, options: TestOptions.DebugDll, parseOptions: TestOptions.RegularPreview); var compilation3 = CreateCompilation(source2, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular10, references: new[] { compilation2.ToMetadataReference() }); compilation3.VerifyDiagnostics( - // (16,24): error CS8652: The feature 'checked user-defined operators' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. - // return checked(x - x); // C0 - Diagnostic(ErrorCode.ERR_FeatureInPreview, "x " + op + " x").WithArguments("checked user-defined operators").WithLocation(16, 24), - // (26,24): error CS8652: The feature 'checked user-defined operators' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. - // return checked(x - x); // C1 - Diagnostic(ErrorCode.ERR_FeatureInPreview, "x " + op + " x").WithArguments("checked user-defined operators").WithLocation(26, 24) + // (16,24): error CS8936: Feature 'checked user-defined operators' is not available in C# 10.0. Please use language version 11.0 or greater. + // return checked(x + x); // C0 + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "x " + op + " x").WithArguments("checked user-defined operators", "11.0").WithLocation(16, 24), + // (26,24): error CS8936: Feature 'checked user-defined operators' is not available in C# 10.0. Please use language version 11.0 or greater. + // return checked(x + x); // C1 + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "x " + op + " x").WithArguments("checked user-defined operators", "11.0").WithLocation(26, 24) ); } @@ -4665,7 +4665,7 @@ regular C2 regular C2 ").VerifyDiagnostics(); - compilation1 = CreateCompilation(source1 + source2, options: TestOptions.DebugExe, parseOptions: TestOptions.RegularNext); + compilation1 = CreateCompilation(source1 + source2, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular11); CompileAndVerify(compilation1, expectedOutput: @" checked C0 regular C0 @@ -4678,12 +4678,12 @@ regular C2 var compilation2 = CreateCompilation(source1, options: TestOptions.DebugDll, parseOptions: TestOptions.RegularPreview); var compilation3 = CreateCompilation(source2, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular10, references: new[] { compilation2.ToMetadataReference() }); compilation3.VerifyDiagnostics( - // (16,19): error CS8652: The feature 'checked user-defined operators' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. - // checked { x -= x; } // C0 - Diagnostic(ErrorCode.ERR_FeatureInPreview, "x " + op + "= x").WithArguments("checked user-defined operators").WithLocation(16, 19), - // (26,19): error CS8652: The feature 'checked user-defined operators' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. - // checked { x -= x; } // C1 - Diagnostic(ErrorCode.ERR_FeatureInPreview, "x " + op + "= x").WithArguments("checked user-defined operators").WithLocation(26, 19) + // (16,19): error CS8936: Feature 'checked user-defined operators' is not available in C# 10.0. Please use language version 11.0 or greater. + // checked { x += x; } // C0 + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "x " + op + "= x").WithArguments("checked user-defined operators", "11.0").WithLocation(16, 19), + // (26,19): error CS8936: Feature 'checked user-defined operators' is not available in C# 10.0. Please use language version 11.0 or greater. + // checked { x += x; } // C1 + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "x " + op + "= x").WithArguments("checked user-defined operators", "11.0").WithLocation(26, 19) ); } @@ -4785,7 +4785,7 @@ not null null ").VerifyDiagnostics(); - compilation1 = CreateCompilation(source1 + source2, options: TestOptions.DebugExe, parseOptions: TestOptions.RegularNext); + compilation1 = CreateCompilation(source1 + source2, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular11); CompileAndVerify(compilation1, expectedOutput: @" checked C0 not null @@ -4797,9 +4797,9 @@ not null var compilation2 = CreateCompilation(source1, options: TestOptions.DebugDll, parseOptions: TestOptions.RegularPreview); var compilation3 = CreateCompilation(source2, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular10, references: new[] { compilation2.ToMetadataReference() }); compilation3.VerifyDiagnostics( - // (14,24): error CS8652: The feature 'checked user-defined operators' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. - // return checked(x - y); - Diagnostic(ErrorCode.ERR_FeatureInPreview, "x " + op + " y").WithArguments("checked user-defined operators").WithLocation(14, 24) + // (14,24): error CS8936: Feature 'checked user-defined operators' is not available in C# 10.0. Please use language version 11.0 or greater. + // return checked(x + y); + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "x " + op + " y").WithArguments("checked user-defined operators", "11.0").WithLocation(14, 24) ); } @@ -5213,7 +5213,7 @@ implicit C0 implicit C0 ").VerifyDiagnostics(); - compilation1 = CreateCompilation(source1 + source2, options: TestOptions.DebugExe, parseOptions: TestOptions.RegularNext); + compilation1 = CreateCompilation(source1 + source2, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular11); CompileAndVerify(compilation1, expectedOutput: @" implicit C0 checked C0 @@ -5228,9 +5228,9 @@ implicit C0 var compilation2 = CreateCompilation(source1, options: TestOptions.DebugDll, parseOptions: TestOptions.RegularPreview); var compilation3 = CreateCompilation(source2, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular10, references: new[] { compilation2.ToMetadataReference() }); compilation3.VerifyDiagnostics( - // (23,26): error CS8652: The feature 'checked user-defined operators' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // (23,26): error CS8936: Feature 'checked user-defined operators' is not available in C# 10.0. Please use language version 11.0 or greater. // checked { return (long)x; } - Diagnostic(ErrorCode.ERR_FeatureInPreview, "(long)x").WithArguments("checked user-defined operators").WithLocation(23, 26) + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "(long)x").WithArguments("checked user-defined operators", "11.0").WithLocation(23, 26) ); } @@ -5686,7 +5686,7 @@ not null null ").VerifyDiagnostics(); - compilation1 = CreateCompilation(source1 + source2, options: TestOptions.DebugExe, parseOptions: TestOptions.RegularNext); + compilation1 = CreateCompilation(source1 + source2, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular11); CompileAndVerify(compilation1, expectedOutput: @" checked C0 not null @@ -5696,9 +5696,9 @@ not null var compilation2 = CreateCompilation(source1, options: TestOptions.DebugDll, parseOptions: TestOptions.RegularPreview); var compilation3 = CreateCompilation(source2, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular10, references: new[] { compilation2.ToMetadataReference() }); compilation3.VerifyDiagnostics( - // (12,26): error CS8652: The feature 'checked user-defined operators' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // (12,26): error CS8936: Feature 'checked user-defined operators' is not available in C# 10.0. Please use language version 11.0 or greater. // checked { return (long?)x; } - Diagnostic(ErrorCode.ERR_FeatureInPreview, "(long?)x").WithArguments("checked user-defined operators").WithLocation(12, 26) + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "(long?)x").WithArguments("checked user-defined operators", "11.0").WithLocation(12, 26) ); } @@ -6313,7 +6313,7 @@ regular C2 regular C2 ").VerifyDiagnostics(); - compilation1 = CreateCompilationWithCSharp(source1 + source2, options: TestOptions.DebugExe, parseOptions: TestOptions.RegularNext); + compilation1 = CreateCompilationWithCSharp(source1 + source2, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular11); CompileAndVerify(compilation1, expectedOutput: @" regular C0 regular C0 @@ -6418,7 +6418,7 @@ regular C2 regular C2 ").VerifyDiagnostics(); - compilation1 = CreateCompilationWithCSharp(source1 + source2, options: TestOptions.DebugExe, parseOptions: TestOptions.RegularNext); + compilation1 = CreateCompilationWithCSharp(source1 + source2, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular11); CompileAndVerify(compilation1, expectedOutput: @" regular C0 regular C0 @@ -6535,7 +6535,7 @@ implicit C0 implicit C0 ").VerifyDiagnostics(); - compilation1 = CreateCompilationWithCSharp(source1 + source2, options: TestOptions.DebugExe, parseOptions: TestOptions.RegularNext); + compilation1 = CreateCompilationWithCSharp(source1 + source2, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular11); CompileAndVerify(compilation1, expectedOutput: @" implicit C0 regular C0 diff --git a/src/Compilers/CSharp/Test/Symbol/Symbols/ConversionTests.cs b/src/Compilers/CSharp/Test/Symbol/Symbols/ConversionTests.cs index 2fcaaecdc8f09..2ccef65358122 100644 --- a/src/Compilers/CSharp/Test/Symbol/Symbols/ConversionTests.cs +++ b/src/Compilers/CSharp/Test/Symbol/Symbols/ConversionTests.cs @@ -23,7 +23,7 @@ public void Test1() var mscorlibRef = TestMetadata.Net40.mscorlib; var compilation = CSharpCompilation.Create("Test", references: new MetadataReference[] { mscorlibRef }); var sys = compilation.GlobalNamespace.ChildNamespace("System"); - Conversions c = new BuckStopsHereBinder(compilation).Conversions; + Conversions c = new BuckStopsHereBinder(compilation, associatedSyntaxTree: null).Conversions; var types = new TypeSymbol[] { sys.ChildType("Object"), @@ -311,7 +311,7 @@ class C Assert.True(typeIntArrayWithCustomModifiers.HasCustomModifiers(flagNonDefaultArraySizesOrLowerBounds: false)); - var conv = new BuckStopsHereBinder(compilation).Conversions; + var conv = new BuckStopsHereBinder(compilation, associatedSyntaxTree: null).Conversions; HashSet useSiteDiagnostics = null; // no custom modifiers to custom modifiers diff --git a/src/Compilers/CSharp/Test/Symbol/Symbols/DefaultInterfaceImplementationTests.cs b/src/Compilers/CSharp/Test/Symbol/Symbols/DefaultInterfaceImplementationTests.cs index 7eee2d724b652..c218eb908e706 100644 --- a/src/Compilers/CSharp/Test/Symbol/Symbols/DefaultInterfaceImplementationTests.cs +++ b/src/Compilers/CSharp/Test/Symbol/Symbols/DefaultInterfaceImplementationTests.cs @@ -1630,7 +1630,7 @@ class Test2 : I1 var compilation3 = CreateCompilation(source2, new[] { compilation1.ToMetadataReference() }, options: TestOptions.DebugDll, targetFramework: TargetFramework.DesktopLatestExtended, - parseOptions: isStatic ? TestOptions.RegularNext : TestOptions.Regular8); + parseOptions: isStatic ? TestOptions.Regular11 : TestOptions.Regular8); m1 = compilation3.GetMember("I1.M1"); var test2 = compilation3.GetTypeByMetadataName("Test2"); @@ -1686,7 +1686,7 @@ class Test2 : I1 { var compilation3 = CreateCompilation(source2, new[] { reference }, options: TestOptions.DebugDll, targetFramework: TargetFramework.DesktopLatestExtended, - parseOptions: isStatic ? TestOptions.RegularNext : TestOptions.Regular8); + parseOptions: isStatic ? TestOptions.Regular11 : TestOptions.Regular8); var m1 = compilation3.GetMember("I1.M1"); var test2 = compilation3.GetTypeByMetadataName("Test2"); @@ -1730,7 +1730,7 @@ public interface I1 "; var compilation1 = CreateCompilation(source1, options: TestOptions.DebugDll, - parseOptions: TestOptions.RegularNext, + parseOptions: TestOptions.Regular11, targetFramework: TargetFramework.Net60); Assert.True(compilation1.Assembly.RuntimeSupportsDefaultInterfaceImplementation); compilation1.VerifyDiagnostics(); @@ -1808,9 +1808,9 @@ class Test1 : I1 else { compilation1.VerifyDiagnostics( - // (4,25): error CS8703: The modifier 'virtual' is not valid for this item in C# 10.0. Please use language version 'preview' or greater. + // (4,25): error CS8703: The modifier 'virtual' is not valid for this item in C# 10.0. Please use language version '11.0' or greater. // static virtual void M1() - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M1").WithArguments("virtual", "10.0", "preview").WithLocation(4, 25), + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M1").WithArguments("virtual", "10.0", "11.0").WithLocation(4, 25), // (4,25): error CS8919: Target runtime doesn't support static abstract members in interfaces. // static virtual void M1() Diagnostic(ErrorCode.ERR_RuntimeDoesNotSupportStaticAbstractMembersInInterfaces, "M1").WithLocation(4, 25) @@ -1848,9 +1848,9 @@ class Test2 : I1 else { compilation3.VerifyDiagnostics( - // (2,15): error CS8706: 'I1.M1()' cannot implement interface member 'I1.M1()' in type 'Test2' because feature 'static abstract members in interfaces' is not available in C# 10.0. Please use language version 'preview' or greater. + // (2,15): error CS8706: 'I1.M1()' cannot implement interface member 'I1.M1()' in type 'Test2' because feature 'static abstract members in interfaces' is not available in C# 10.0. Please use language version '11.0' or greater. // class Test2 : I1 - Diagnostic(ErrorCode.ERR_LanguageVersionDoesNotSupportInterfaceImplementationForMember, "I1").WithArguments("I1.M1()", "I1.M1()", "Test2", "static abstract members in interfaces", "10.0", "preview").WithLocation(2, 15), + Diagnostic(ErrorCode.ERR_LanguageVersionDoesNotSupportInterfaceImplementationForMember, "I1").WithArguments("I1.M1()", "I1.M1()", "Test2", "static abstract members in interfaces", "10.0", "11.0").WithLocation(2, 15), // (2,15): error CS8929: 'I1.M1()' cannot implement interface member 'I1.M1()' in type 'Test2' because the target runtime doesn't support static abstract members in interfaces. // class Test2 : I1 Diagnostic(ErrorCode.ERR_RuntimeDoesNotSupportStaticAbstractMembersInInterfacesForMember, "I1").WithArguments("I1.M1()", "I1.M1()", "Test2").WithLocation(2, 15) @@ -1902,9 +1902,9 @@ class Test1 : I1 else { compilation1.VerifyDiagnostics( - // (4,25): error CS8703: The modifier 'virtual' is not valid for this item in C# 10.0. Please use language version 'preview' or greater. + // (4,25): error CS8703: The modifier 'virtual' is not valid for this item in C# 10.0. Please use language version '11.0' or greater. // static virtual void M1() - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M1").WithArguments("virtual", "10.0", "preview").WithLocation(4, 25) + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M1").WithArguments("virtual", "10.0", "11.0").WithLocation(4, 25) ); } @@ -1917,7 +1917,7 @@ class Test2 : I1 "; var compilation2 = CreateCompilation(source2, new[] { compilation1.ToMetadataReference() }, options: TestOptions.DebugDll, - parseOptions: TestOptions.RegularNext, + parseOptions: TestOptions.Regular11, targetFramework: isStatic ? TargetFramework.Net60 : TargetFramework.NetCoreApp); Assert.True(compilation2.Assembly.RuntimeSupportsDefaultInterfaceImplementation); m1 = compilation2.GetMember("I1.M1"); @@ -1954,9 +1954,9 @@ class Test2 : I1 else { compilation3.VerifyDiagnostics( - // (2,15): error CS8706: 'I1.M1()' cannot implement interface member 'I1.M1()' in type 'Test2' because feature 'static abstract members in interfaces' is not available in C# 10.0. Please use language version 'preview' or greater. + // (2,15): error CS8706: 'I1.M1()' cannot implement interface member 'I1.M1()' in type 'Test2' because feature 'static abstract members in interfaces' is not available in C# 10.0. Please use language version '11.0' or greater. // class Test2 : I1 - Diagnostic(ErrorCode.ERR_LanguageVersionDoesNotSupportInterfaceImplementationForMember, "I1").WithArguments("I1.M1()", "I1.M1()", "Test2", "static abstract members in interfaces", "10.0", "preview").WithLocation(2, 15) + Diagnostic(ErrorCode.ERR_LanguageVersionDoesNotSupportInterfaceImplementationForMember, "I1").WithArguments("I1.M1()", "I1.M1()", "Test2", "static abstract members in interfaces", "10.0", "11.0").WithLocation(2, 15) ); } } @@ -1978,7 +1978,7 @@ public interface I1 } "; var compilation1 = CreateCompilation(source1, options: TestOptions.DebugDll, targetFramework: isStatic ? TargetFramework.Net50 : TargetFramework.DesktopLatestExtended, - parseOptions: TestOptions.RegularNext); + parseOptions: TestOptions.Regular11); var m1 = compilation1.GetMember("I1.M1"); @@ -2109,7 +2109,7 @@ static void Test() where T : I1 } "; var compilation1 = CreateCompilation(source1, options: TestOptions.DebugExe, - parseOptions: TestOptions.RegularNext, + parseOptions: TestOptions.Regular11, targetFramework: TargetFramework.Net60); Assert.True(compilation1.Assembly.RuntimeSupportsDefaultInterfaceImplementation); @@ -2188,7 +2188,7 @@ static void Test() where T : I1 "; var compilation2 = CreateCompilation(source2, new[] { compilation1.ToMetadataReference() }, options: TestOptions.DebugExe, - parseOptions: TestOptions.RegularNext, + parseOptions: TestOptions.Regular11, targetFramework: TargetFramework.Net60); Assert.True(compilation2.Assembly.RuntimeSupportsDefaultInterfaceImplementation); m1 = compilation2.GetMember("I1.M1"); @@ -2210,7 +2210,7 @@ static void Test() where T : I1 }); var compilation3 = CreateCompilation(source2, new[] { compilation1.EmitToImageReference() }, options: TestOptions.DebugExe, - parseOptions: TestOptions.RegularNext, + parseOptions: TestOptions.Regular11, targetFramework: TargetFramework.Net60); Assert.True(compilation3.Assembly.RuntimeSupportsDefaultInterfaceImplementation); m1 = compilation3.GetMember("I1.M1"); @@ -3051,7 +3051,7 @@ public interface I1 } "; var compilation1 = CreateCompilation(source1, options: TestOptions.DebugDll, - parseOptions: TestOptions.RegularNext, + parseOptions: TestOptions.Regular11, targetFramework: TargetFramework.Net60); Assert.True(compilation1.Assembly.RuntimeSupportsDefaultInterfaceImplementation); compilation1.VerifyDiagnostics( @@ -4449,27 +4449,27 @@ class Test1 : I1 parseOptions: TestOptions.Regular10, skipUsesIsNullable: true); compilation1.VerifyDiagnostics( - // (4,24): error CS8703: The modifier 'virtual' is not valid for this item in C# 10.0. Please use language version 'preview' or greater. + // (4,24): error CS8703: The modifier 'virtual' is not valid for this item in C# 10.0. Please use language version '11.0' or greater. // static virtual int P1 => 1; - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "P1").WithArguments("virtual", "10.0", "preview").WithLocation(4, 24), + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "P1").WithArguments("virtual", "10.0", "11.0").WithLocation(4, 24), // (4,30): error CS8919: Target runtime doesn't support static abstract members in interfaces. // static virtual int P1 => 1; Diagnostic(ErrorCode.ERR_RuntimeDoesNotSupportStaticAbstractMembersInInterfaces, "1").WithLocation(4, 30), - // (5,24): error CS8703: The modifier 'virtual' is not valid for this item in C# 10.0. Please use language version 'preview' or greater. + // (5,24): error CS8703: The modifier 'virtual' is not valid for this item in C# 10.0. Please use language version '11.0' or greater. // static virtual int P3 { get => 3; } - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "P3").WithArguments("virtual", "10.0", "preview").WithLocation(5, 24), + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "P3").WithArguments("virtual", "10.0", "11.0").WithLocation(5, 24), // (5,29): error CS8919: Target runtime doesn't support static abstract members in interfaces. // static virtual int P3 { get => 3; } Diagnostic(ErrorCode.ERR_RuntimeDoesNotSupportStaticAbstractMembersInInterfaces, "get").WithLocation(5, 29), - // (6,24): error CS8703: The modifier 'virtual' is not valid for this item in C# 10.0. Please use language version 'preview' or greater. + // (6,24): error CS8703: The modifier 'virtual' is not valid for this item in C# 10.0. Please use language version '11.0' or greater. // static virtual int P5 { set => System.Console.WriteLine(5); } - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "P5").WithArguments("virtual", "10.0", "preview").WithLocation(6, 24), + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "P5").WithArguments("virtual", "10.0", "11.0").WithLocation(6, 24), // (6,29): error CS8919: Target runtime doesn't support static abstract members in interfaces. // static virtual int P5 { set => System.Console.WriteLine(5); } Diagnostic(ErrorCode.ERR_RuntimeDoesNotSupportStaticAbstractMembersInInterfaces, "set").WithLocation(6, 29), - // (7,24): error CS8703: The modifier 'virtual' is not valid for this item in C# 10.0. Please use language version 'preview' or greater. + // (7,24): error CS8703: The modifier 'virtual' is not valid for this item in C# 10.0. Please use language version '11.0' or greater. // static virtual int P7 { get { return 7;} set {} } - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "P7").WithArguments("virtual", "10.0", "preview").WithLocation(7, 24), + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "P7").WithArguments("virtual", "10.0", "11.0").WithLocation(7, 24), // (7,29): error CS8919: Target runtime doesn't support static abstract members in interfaces. // static virtual int P7 { get { return 7;} set {} } Diagnostic(ErrorCode.ERR_RuntimeDoesNotSupportStaticAbstractMembersInInterfaces, "get").WithLocation(7, 29), @@ -4491,36 +4491,36 @@ class Test2 : I1 parseOptions: TestOptions.Regular10); compilation3.VerifyDiagnostics( - // (2,15): error CS8706: 'I1.P7.set' cannot implement interface member 'I1.P7.set' in type 'Test2' because feature 'static abstract members in interfaces' is not available in C# 10.0. Please use language version 'preview' or greater. + // (2,15): error CS8706: 'I1.P1.get' cannot implement interface member 'I1.P1.get' in type 'Test2' because feature 'static abstract members in interfaces' is not available in C# 10.0. Please use language version '11.0' or greater. // class Test2 : I1 - Diagnostic(ErrorCode.ERR_LanguageVersionDoesNotSupportInterfaceImplementationForMember, "I1").WithArguments("I1.P7.set", "I1.P7.set", "Test2", "static abstract members in interfaces", "10.0", "preview").WithLocation(2, 15), - // (2,15): error CS8929: 'I1.P7.set' cannot implement interface member 'I1.P7.set' in type 'Test2' because the target runtime doesn't support static abstract members in interfaces. - // class Test2 : I1 - Diagnostic(ErrorCode.ERR_RuntimeDoesNotSupportStaticAbstractMembersInInterfacesForMember, "I1").WithArguments("I1.P7.set", "I1.P7.set", "Test2").WithLocation(2, 15), - // (2,15): error CS8706: 'I1.P1.get' cannot implement interface member 'I1.P1.get' in type 'Test2' because feature 'static abstract members in interfaces' is not available in C# 10.0. Please use language version 'preview' or greater. - // class Test2 : I1 - Diagnostic(ErrorCode.ERR_LanguageVersionDoesNotSupportInterfaceImplementationForMember, "I1").WithArguments("I1.P1.get", "I1.P1.get", "Test2", "static abstract members in interfaces", "10.0", "preview").WithLocation(2, 15), + Diagnostic(ErrorCode.ERR_LanguageVersionDoesNotSupportInterfaceImplementationForMember, "I1").WithArguments("I1.P1.get", "I1.P1.get", "Test2", "static abstract members in interfaces", "10.0", "11.0").WithLocation(2, 15), // (2,15): error CS8929: 'I1.P1.get' cannot implement interface member 'I1.P1.get' in type 'Test2' because the target runtime doesn't support static abstract members in interfaces. // class Test2 : I1 Diagnostic(ErrorCode.ERR_RuntimeDoesNotSupportStaticAbstractMembersInInterfacesForMember, "I1").WithArguments("I1.P1.get", "I1.P1.get", "Test2").WithLocation(2, 15), - // (2,15): error CS8706: 'I1.P3.get' cannot implement interface member 'I1.P3.get' in type 'Test2' because feature 'static abstract members in interfaces' is not available in C# 10.0. Please use language version 'preview' or greater. + // (2,15): error CS8706: 'I1.P3.get' cannot implement interface member 'I1.P3.get' in type 'Test2' because feature 'static abstract members in interfaces' is not available in C# 10.0. Please use language version '11.0' or greater. // class Test2 : I1 - Diagnostic(ErrorCode.ERR_LanguageVersionDoesNotSupportInterfaceImplementationForMember, "I1").WithArguments("I1.P3.get", "I1.P3.get", "Test2", "static abstract members in interfaces", "10.0", "preview").WithLocation(2, 15), + Diagnostic(ErrorCode.ERR_LanguageVersionDoesNotSupportInterfaceImplementationForMember, "I1").WithArguments("I1.P3.get", "I1.P3.get", "Test2", "static abstract members in interfaces", "10.0", "11.0").WithLocation(2, 15), // (2,15): error CS8929: 'I1.P3.get' cannot implement interface member 'I1.P3.get' in type 'Test2' because the target runtime doesn't support static abstract members in interfaces. // class Test2 : I1 Diagnostic(ErrorCode.ERR_RuntimeDoesNotSupportStaticAbstractMembersInInterfacesForMember, "I1").WithArguments("I1.P3.get", "I1.P3.get", "Test2").WithLocation(2, 15), - // (2,15): error CS8706: 'I1.P5.set' cannot implement interface member 'I1.P5.set' in type 'Test2' because feature 'static abstract members in interfaces' is not available in C# 10.0. Please use language version 'preview' or greater. + // (2,15): error CS8706: 'I1.P5.set' cannot implement interface member 'I1.P5.set' in type 'Test2' because feature 'static abstract members in interfaces' is not available in C# 10.0. Please use language version '11.0' or greater. // class Test2 : I1 - Diagnostic(ErrorCode.ERR_LanguageVersionDoesNotSupportInterfaceImplementationForMember, "I1").WithArguments("I1.P5.set", "I1.P5.set", "Test2", "static abstract members in interfaces", "10.0", "preview").WithLocation(2, 15), + Diagnostic(ErrorCode.ERR_LanguageVersionDoesNotSupportInterfaceImplementationForMember, "I1").WithArguments("I1.P5.set", "I1.P5.set", "Test2", "static abstract members in interfaces", "10.0", "11.0").WithLocation(2, 15), // (2,15): error CS8929: 'I1.P5.set' cannot implement interface member 'I1.P5.set' in type 'Test2' because the target runtime doesn't support static abstract members in interfaces. // class Test2 : I1 Diagnostic(ErrorCode.ERR_RuntimeDoesNotSupportStaticAbstractMembersInInterfacesForMember, "I1").WithArguments("I1.P5.set", "I1.P5.set", "Test2").WithLocation(2, 15), - // (2,15): error CS8706: 'I1.P7.get' cannot implement interface member 'I1.P7.get' in type 'Test2' because feature 'static abstract members in interfaces' is not available in C# 10.0. Please use language version 'preview' or greater. + // (2,15): error CS8706: 'I1.P7.get' cannot implement interface member 'I1.P7.get' in type 'Test2' because feature 'static abstract members in interfaces' is not available in C# 10.0. Please use language version '11.0' or greater. // class Test2 : I1 - Diagnostic(ErrorCode.ERR_LanguageVersionDoesNotSupportInterfaceImplementationForMember, "I1").WithArguments("I1.P7.get", "I1.P7.get", "Test2", "static abstract members in interfaces", "10.0", "preview").WithLocation(2, 15), + Diagnostic(ErrorCode.ERR_LanguageVersionDoesNotSupportInterfaceImplementationForMember, "I1").WithArguments("I1.P7.get", "I1.P7.get", "Test2", "static abstract members in interfaces", "10.0", "11.0").WithLocation(2, 15), // (2,15): error CS8929: 'I1.P7.get' cannot implement interface member 'I1.P7.get' in type 'Test2' because the target runtime doesn't support static abstract members in interfaces. // class Test2 : I1 - Diagnostic(ErrorCode.ERR_RuntimeDoesNotSupportStaticAbstractMembersInInterfacesForMember, "I1").WithArguments("I1.P7.get", "I1.P7.get", "Test2").WithLocation(2, 15) + Diagnostic(ErrorCode.ERR_RuntimeDoesNotSupportStaticAbstractMembersInInterfacesForMember, "I1").WithArguments("I1.P7.get", "I1.P7.get", "Test2").WithLocation(2, 15), + // (2,15): error CS8706: 'I1.P7.set' cannot implement interface member 'I1.P7.set' in type 'Test2' because feature 'static abstract members in interfaces' is not available in C# 10.0. Please use language version '11.0' or greater. + // class Test2 : I1 + Diagnostic(ErrorCode.ERR_LanguageVersionDoesNotSupportInterfaceImplementationForMember, "I1").WithArguments("I1.P7.set", "I1.P7.set", "Test2", "static abstract members in interfaces", "10.0", "11.0").WithLocation(2, 15), + // (2,15): error CS8929: 'I1.P7.set' cannot implement interface member 'I1.P7.set' in type 'Test2' because the target runtime doesn't support static abstract members in interfaces. + // class Test2 : I1 + Diagnostic(ErrorCode.ERR_RuntimeDoesNotSupportStaticAbstractMembersInInterfacesForMember, "I1").WithArguments("I1.P7.set", "I1.P7.set", "Test2").WithLocation(2, 15) ); ValidatePropertyImplementation_501(compilation3.SourceModule, "Test2"); @@ -4574,18 +4574,18 @@ class Test1 : I1 else { compilation1.VerifyDiagnostics( - // (4,24): error CS8703: The modifier 'virtual' is not valid for this item in C# 10.0. Please use language version 'preview' or greater. + // (4,24): error CS8703: The modifier 'virtual' is not valid for this item in C# 10.0. Please use language version '11.0' or greater. // static virtual int P1 => 1; - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "P1").WithArguments("virtual", "10.0", "preview").WithLocation(4, 24), - // (5,24): error CS8703: The modifier 'virtual' is not valid for this item in C# 10.0. Please use language version 'preview' or greater. + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "P1").WithArguments("virtual", "10.0", "11.0").WithLocation(4, 24), + // (5,24): error CS8703: The modifier 'virtual' is not valid for this item in C# 10.0. Please use language version '11.0' or greater. // static virtual int P3 { get => 3; } - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "P3").WithArguments("virtual", "10.0", "preview").WithLocation(5, 24), - // (6,24): error CS8703: The modifier 'virtual' is not valid for this item in C# 10.0. Please use language version 'preview' or greater. + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "P3").WithArguments("virtual", "10.0", "11.0").WithLocation(5, 24), + // (6,24): error CS8703: The modifier 'virtual' is not valid for this item in C# 10.0. Please use language version '11.0' or greater. // static virtual int P5 { set => System.Console.WriteLine(5); } - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "P5").WithArguments("virtual", "10.0", "preview").WithLocation(6, 24), - // (7,24): error CS8703: The modifier 'virtual' is not valid for this item in C# 10.0. Please use language version 'preview' or greater. + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "P5").WithArguments("virtual", "10.0", "11.0").WithLocation(6, 24), + // (7,24): error CS8703: The modifier 'virtual' is not valid for this item in C# 10.0. Please use language version '11.0' or greater. // static virtual int P7 { get { return 7;} set {} } - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "P7").WithArguments("virtual", "10.0", "preview").WithLocation(7, 24) + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "P7").WithArguments("virtual", "10.0", "11.0").WithLocation(7, 24) ); } @@ -4641,21 +4641,21 @@ class Test2 : I1 else { compilation3.VerifyDiagnostics( - // (2,15): error CS8706: 'I1.P1.get' cannot implement interface member 'I1.P1.get' in type 'Test2' because feature 'static abstract members in interfaces' is not available in C# 10.0. Please use language version 'preview' or greater. + // (2,15): error CS8706: 'I1.P1.get' cannot implement interface member 'I1.P1.get' in type 'Test2' because feature 'static abstract members in interfaces' is not available in C# 10.0. Please use language version '11.0' or greater. // class Test2 : I1 - Diagnostic(ErrorCode.ERR_LanguageVersionDoesNotSupportInterfaceImplementationForMember, "I1").WithArguments("I1.P1.get", "I1.P1.get", "Test2", "static abstract members in interfaces", "10.0", "preview").WithLocation(2, 15), - // (2,15): error CS8706: 'I1.P3.get' cannot implement interface member 'I1.P3.get' in type 'Test2' because feature 'static abstract members in interfaces' is not available in C# 10.0. Please use language version 'preview' or greater. + Diagnostic(ErrorCode.ERR_LanguageVersionDoesNotSupportInterfaceImplementationForMember, "I1").WithArguments("I1.P1.get", "I1.P1.get", "Test2", "static abstract members in interfaces", "10.0", "11.0").WithLocation(2, 15), + // (2,15): error CS8706: 'I1.P3.get' cannot implement interface member 'I1.P3.get' in type 'Test2' because feature 'static abstract members in interfaces' is not available in C# 10.0. Please use language version '11.0' or greater. // class Test2 : I1 - Diagnostic(ErrorCode.ERR_LanguageVersionDoesNotSupportInterfaceImplementationForMember, "I1").WithArguments("I1.P3.get", "I1.P3.get", "Test2", "static abstract members in interfaces", "10.0", "preview").WithLocation(2, 15), - // (2,15): error CS8706: 'I1.P5.set' cannot implement interface member 'I1.P5.set' in type 'Test2' because feature 'static abstract members in interfaces' is not available in C# 10.0. Please use language version 'preview' or greater. + Diagnostic(ErrorCode.ERR_LanguageVersionDoesNotSupportInterfaceImplementationForMember, "I1").WithArguments("I1.P3.get", "I1.P3.get", "Test2", "static abstract members in interfaces", "10.0", "11.0").WithLocation(2, 15), + // (2,15): error CS8706: 'I1.P5.set' cannot implement interface member 'I1.P5.set' in type 'Test2' because feature 'static abstract members in interfaces' is not available in C# 10.0. Please use language version '11.0' or greater. // class Test2 : I1 - Diagnostic(ErrorCode.ERR_LanguageVersionDoesNotSupportInterfaceImplementationForMember, "I1").WithArguments("I1.P5.set", "I1.P5.set", "Test2", "static abstract members in interfaces", "10.0", "preview").WithLocation(2, 15), - // (2,15): error CS8706: 'I1.P7.get' cannot implement interface member 'I1.P7.get' in type 'Test2' because feature 'static abstract members in interfaces' is not available in C# 10.0. Please use language version 'preview' or greater. + Diagnostic(ErrorCode.ERR_LanguageVersionDoesNotSupportInterfaceImplementationForMember, "I1").WithArguments("I1.P5.set", "I1.P5.set", "Test2", "static abstract members in interfaces", "10.0", "11.0").WithLocation(2, 15), + // (2,15): error CS8706: 'I1.P7.get' cannot implement interface member 'I1.P7.get' in type 'Test2' because feature 'static abstract members in interfaces' is not available in C# 10.0. Please use language version '11.0' or greater. // class Test2 : I1 - Diagnostic(ErrorCode.ERR_LanguageVersionDoesNotSupportInterfaceImplementationForMember, "I1").WithArguments("I1.P7.get", "I1.P7.get", "Test2", "static abstract members in interfaces", "10.0", "preview").WithLocation(2, 15), - // (2,15): error CS8706: 'I1.P7.set' cannot implement interface member 'I1.P7.set' in type 'Test2' because feature 'static abstract members in interfaces' is not available in C# 10.0. Please use language version 'preview' or greater. + Diagnostic(ErrorCode.ERR_LanguageVersionDoesNotSupportInterfaceImplementationForMember, "I1").WithArguments("I1.P7.get", "I1.P7.get", "Test2", "static abstract members in interfaces", "10.0", "11.0").WithLocation(2, 15), + // (2,15): error CS8706: 'I1.P7.set' cannot implement interface member 'I1.P7.set' in type 'Test2' because feature 'static abstract members in interfaces' is not available in C# 10.0. Please use language version '11.0' or greater. // class Test2 : I1 - Diagnostic(ErrorCode.ERR_LanguageVersionDoesNotSupportInterfaceImplementationForMember, "I1").WithArguments("I1.P7.set", "I1.P7.set", "Test2", "static abstract members in interfaces", "10.0", "preview").WithLocation(2, 15) + Diagnostic(ErrorCode.ERR_LanguageVersionDoesNotSupportInterfaceImplementationForMember, "I1").WithArguments("I1.P7.set", "I1.P7.set", "Test2", "static abstract members in interfaces", "10.0", "11.0").WithLocation(2, 15) ); } @@ -7412,9 +7412,9 @@ class Test1 : I1 parseOptions: TestOptions.Regular10, skipUsesIsNullable: true); compilation1.VerifyDiagnostics( - // (4,40): error CS8703: The modifier 'virtual' is not valid for this item in C# 10.0. Please use language version 'preview' or greater. + // (4,40): error CS8703: The modifier 'virtual' is not valid for this item in C# 10.0. Please use language version '11.0' or greater. // static virtual event System.Action E7 - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "E7").WithArguments("virtual", "10.0", "preview").WithLocation(4, 40), + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "E7").WithArguments("virtual", "10.0", "11.0").WithLocation(4, 40), // (6,9): error CS8919: Target runtime doesn't support static abstract members in interfaces. // add {} Diagnostic(ErrorCode.ERR_RuntimeDoesNotSupportStaticAbstractMembersInInterfaces, "add").WithLocation(6, 9), @@ -7436,18 +7436,18 @@ class Test2 : I1 parseOptions: TestOptions.Regular10); compilation3.VerifyDiagnostics( - // (2,15): error CS8706: 'I1.E7.remove' cannot implement interface member 'I1.E7.remove' in type 'Test2' because feature 'static abstract members in interfaces' is not available in C# 10.0. Please use language version 'preview' or greater. + // (2,15): error CS8706: 'I1.E7.add' cannot implement interface member 'I1.E7.add' in type 'Test2' because feature 'static abstract members in interfaces' is not available in C# 10.0. Please use language version '11.0' or greater. // class Test2 : I1 - Diagnostic(ErrorCode.ERR_LanguageVersionDoesNotSupportInterfaceImplementationForMember, "I1").WithArguments("I1.E7.remove", "I1.E7.remove", "Test2", "static abstract members in interfaces", "10.0", "preview").WithLocation(2, 15), - // (2,15): error CS8929: 'I1.E7.remove' cannot implement interface member 'I1.E7.remove' in type 'Test2' because the target runtime doesn't support static abstract members in interfaces. + Diagnostic(ErrorCode.ERR_LanguageVersionDoesNotSupportInterfaceImplementationForMember, "I1").WithArguments("I1.E7.add", "I1.E7.add", "Test2", "static abstract members in interfaces", "10.0", "11.0").WithLocation(2, 15), + // (2,15): error CS8929: 'I1.E7.add' cannot implement interface member 'I1.E7.add' in type 'Test2' because the target runtime doesn't support static abstract members in interfaces. // class Test2 : I1 - Diagnostic(ErrorCode.ERR_RuntimeDoesNotSupportStaticAbstractMembersInInterfacesForMember, "I1").WithArguments("I1.E7.remove", "I1.E7.remove", "Test2").WithLocation(2, 15), - // (2,15): error CS8706: 'I1.E7.add' cannot implement interface member 'I1.E7.add' in type 'Test2' because feature 'static abstract members in interfaces' is not available in C# 10.0. Please use language version 'preview' or greater. + Diagnostic(ErrorCode.ERR_RuntimeDoesNotSupportStaticAbstractMembersInInterfacesForMember, "I1").WithArguments("I1.E7.add", "I1.E7.add", "Test2").WithLocation(2, 15), + // (2,15): error CS8706: 'I1.E7.remove' cannot implement interface member 'I1.E7.remove' in type 'Test2' because feature 'static abstract members in interfaces' is not available in C# 10.0. Please use language version '11.0' or greater. // class Test2 : I1 - Diagnostic(ErrorCode.ERR_LanguageVersionDoesNotSupportInterfaceImplementationForMember, "I1").WithArguments("I1.E7.add", "I1.E7.add", "Test2", "static abstract members in interfaces", "10.0", "preview").WithLocation(2, 15), - // (2,15): error CS8929: 'I1.E7.add' cannot implement interface member 'I1.E7.add' in type 'Test2' because the target runtime doesn't support static abstract members in interfaces. + Diagnostic(ErrorCode.ERR_LanguageVersionDoesNotSupportInterfaceImplementationForMember, "I1").WithArguments("I1.E7.remove", "I1.E7.remove", "Test2", "static abstract members in interfaces", "10.0", "11.0").WithLocation(2, 15), + // (2,15): error CS8929: 'I1.E7.remove' cannot implement interface member 'I1.E7.remove' in type 'Test2' because the target runtime doesn't support static abstract members in interfaces. // class Test2 : I1 - Diagnostic(ErrorCode.ERR_RuntimeDoesNotSupportStaticAbstractMembersInInterfacesForMember, "I1").WithArguments("I1.E7.add", "I1.E7.add", "Test2").WithLocation(2, 15) + Diagnostic(ErrorCode.ERR_RuntimeDoesNotSupportStaticAbstractMembersInInterfacesForMember, "I1").WithArguments("I1.E7.remove", "I1.E7.remove", "Test2").WithLocation(2, 15) ); ValidateEventImplementation_501(compilation3.SourceModule, "Test2"); @@ -7493,9 +7493,9 @@ class Test1 : I1 else { compilation1.VerifyDiagnostics( - // (4,40): error CS8703: The modifier 'virtual' is not valid for this item in C# 10.0. Please use language version 'preview' or greater. + // (4,40): error CS8703: The modifier 'virtual' is not valid for this item in C# 10.0. Please use language version '11.0' or greater. // static virtual event System.Action E7 - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "E7").WithArguments("virtual", "10.0", "preview").WithLocation(4, 40) + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "E7").WithArguments("virtual", "10.0", "11.0").WithLocation(4, 40) ); } @@ -7542,12 +7542,12 @@ class Test2 : I1 else { compilation3.VerifyDiagnostics( - // (2,15): error CS8706: 'I1.E7.add' cannot implement interface member 'I1.E7.add' in type 'Test2' because feature 'static abstract members in interfaces' is not available in C# 10.0. Please use language version 'preview' or greater. + // (2,15): error CS8706: 'I1.E7.add' cannot implement interface member 'I1.E7.add' in type 'Test2' because feature 'static abstract members in interfaces' is not available in C# 10.0. Please use language version '11.0' or greater. // class Test2 : I1 - Diagnostic(ErrorCode.ERR_LanguageVersionDoesNotSupportInterfaceImplementationForMember, "I1").WithArguments("I1.E7.add", "I1.E7.add", "Test2", "static abstract members in interfaces", "10.0", "preview").WithLocation(2, 15), - // (2,15): error CS8706: 'I1.E7.remove' cannot implement interface member 'I1.E7.remove' in type 'Test2' because feature 'static abstract members in interfaces' is not available in C# 10.0. Please use language version 'preview' or greater. + Diagnostic(ErrorCode.ERR_LanguageVersionDoesNotSupportInterfaceImplementationForMember, "I1").WithArguments("I1.E7.add", "I1.E7.add", "Test2", "static abstract members in interfaces", "10.0", "11.0").WithLocation(2, 15), + // (2,15): error CS8706: 'I1.E7.remove' cannot implement interface member 'I1.E7.remove' in type 'Test2' because feature 'static abstract members in interfaces' is not available in C# 10.0. Please use language version '11.0' or greater. // class Test2 : I1 - Diagnostic(ErrorCode.ERR_LanguageVersionDoesNotSupportInterfaceImplementationForMember, "I1").WithArguments("I1.E7.remove", "I1.E7.remove", "Test2", "static abstract members in interfaces", "10.0", "preview").WithLocation(2, 15) + Diagnostic(ErrorCode.ERR_LanguageVersionDoesNotSupportInterfaceImplementationForMember, "I1").WithArguments("I1.E7.remove", "I1.E7.remove", "Test2", "static abstract members in interfaces", "10.0", "11.0").WithLocation(2, 15) ); } @@ -8753,18 +8753,18 @@ class Test2 : I1 targetFramework: TargetFramework.Net60); compilation1.VerifyDiagnostics( - // (10,24): error CS8703: The modifier 'sealed' is not valid for this item in C# 9.0. Please use language version 'preview' or greater. - // sealed static void M3() - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M3").WithArguments("sealed", "9.0", "preview").WithLocation(10, 24), - // (6,25): error CS8703: The modifier 'virtual' is not valid for this item in C# 9.0. Please use language version 'preview' or greater. - // virtual static void M2() - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M2").WithArguments("virtual", "9.0", "preview").WithLocation(6, 25), - // (4,26): error CS8703: The modifier 'abstract' is not valid for this item in C# 9.0. Please use language version 'preview' or greater. + // (4,26): error CS8703: The modifier 'abstract' is not valid for this item in C# 9.0. Please use language version '11.0' or greater. // abstract static void M1(); - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M1").WithArguments("abstract", "9.0", "preview").WithLocation(4, 26), - // (21,13): error CS0539: 'Test1.M4()' in explicit interface declaration is not found among members of the interface that can be implemented - // void I1.M4() {} - Diagnostic(ErrorCode.ERR_InterfaceMemberNotFound, "M4").WithArguments("Test1.M4()").WithLocation(21, 13), + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M1").WithArguments("abstract", "9.0", "11.0").WithLocation(4, 26), + // (6,25): error CS8703: The modifier 'virtual' is not valid for this item in C# 9.0. Please use language version '11.0' or greater. + // virtual static void M2() + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M2").WithArguments("virtual", "9.0", "11.0").WithLocation(6, 25), + // (10,24): error CS8703: The modifier 'sealed' is not valid for this item in C# 9.0. Please use language version '11.0' or greater. + // sealed static void M3() + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M3").WithArguments("sealed", "9.0", "11.0").WithLocation(10, 24), + // (27,15): error CS0535: 'Test2' does not implement interface member 'I1.M1()' + // class Test2 : I1 + Diagnostic(ErrorCode.ERR_UnimplementedInterfaceMember, "I1").WithArguments("Test2", "I1.M1()").WithLocation(27, 15), // (22,13): error CS0539: 'Test1.M1()' in explicit interface declaration is not found among members of the interface that can be implemented // void I1.M1() {} Diagnostic(ErrorCode.ERR_InterfaceMemberNotFound, "M1").WithArguments("Test1.M1()").WithLocation(22, 13), @@ -8774,12 +8774,12 @@ class Test2 : I1 // (24,13): error CS0539: 'Test1.M3()' in explicit interface declaration is not found among members of the interface that can be implemented // void I1.M3() {} Diagnostic(ErrorCode.ERR_InterfaceMemberNotFound, "M3").WithArguments("Test1.M3()").WithLocation(24, 13), + // (21,13): error CS0539: 'Test1.M4()' in explicit interface declaration is not found among members of the interface that can be implemented + // void I1.M4() {} + Diagnostic(ErrorCode.ERR_InterfaceMemberNotFound, "M4").WithArguments("Test1.M4()").WithLocation(21, 13), // (19,15): error CS0535: 'Test1' does not implement interface member 'I1.M1()' // class Test1 : I1 - Diagnostic(ErrorCode.ERR_UnimplementedInterfaceMember, "I1").WithArguments("Test1", "I1.M1()").WithLocation(19, 15), - // (27,15): error CS0535: 'Test2' does not implement interface member 'I1.M1()' - // class Test2 : I1 - Diagnostic(ErrorCode.ERR_UnimplementedInterfaceMember, "I1").WithArguments("Test2", "I1.M1()").WithLocation(27, 15) + Diagnostic(ErrorCode.ERR_UnimplementedInterfaceMember, "I1").WithArguments("Test1", "I1.M1()").WithLocation(19, 15) ); var test1 = compilation1.GetTypeByMetadataName("Test1"); @@ -9057,19 +9057,19 @@ static void Test() where T : I1 else { compilation1.VerifyDiagnostics( - // (4,28): error CS8703: The modifier 'abstract' is not valid for this item in C# 9.0. Please use language version 'preview' or greater. + // (4,28): error CS8703: The modifier 'abstract' is not valid for this item in C# 9.0. Please use language version '11.0' or greater. // internal abstract void M1(); - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M1").WithArguments("abstract", "9.0", "preview").WithLocation(4, 28), - // (9,9): error CS8652: The feature 'static abstract members in interfaces' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M1").WithArguments("abstract", "9.0", "11.0").WithLocation(4, 28), + // (9,9): error CS8773: Feature 'static abstract members in interfaces' is not available in C# 9.0. Please use language version 11.0 or greater. // T.M1(); - Diagnostic(ErrorCode.ERR_FeatureInPreview, "T").WithArguments("static abstract members in interfaces").WithLocation(9, 9) + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion9, "T").WithArguments("static abstract members in interfaces", "11.0").WithLocation(9, 9) ); } ValidateMethodModifiersImplicit_10(compilation1.SourceModule, Accessibility.Internal, isStatic: isStatic); compilation1 = CreateCompilation(source1 + source2, options: TestOptions.DebugExe, - parseOptions: isStatic ? TestOptions.RegularNext : TestOptions.Regular10, + parseOptions: isStatic ? TestOptions.Regular11 : TestOptions.Regular10, targetFramework: TargetFramework.Net60); Assert.True(compilation1.Assembly.RuntimeSupportsDefaultInterfaceImplementation); CompileAndVerify(compilation1, expectedOutput: !Execute(isStatic) ? null : "M1", verify: Verify(isStatic), symbolValidator: (m) => ValidateMethodModifiersImplicit_10(m, Accessibility.Internal, isStatic: isStatic)).VerifyDiagnostics(); @@ -10499,6 +10499,9 @@ void I1.M5() {} // (5,27): error CS0500: 'I1.M2()' cannot declare a body because it is marked abstract // abstract private void M2() {} Diagnostic(ErrorCode.ERR_AbstractHasBody, "M2").WithArguments("I1.M2()").WithLocation(5, 27), + // (6,26): error CS8703: The modifier 'abstract' is not valid for this item in C# 9.0. Please use language version '11.0' or greater. + // abstract static void M3() {} + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M3").WithArguments("abstract", "9.0", "11.0").WithLocation(6, 26), // (6,26): error CS0500: 'I1.M3()' cannot declare a body because it is marked abstract // abstract static void M3() {} Diagnostic(ErrorCode.ERR_AbstractHasBody, "M3").WithArguments("I1.M3()").WithLocation(6, 26), @@ -10511,18 +10514,15 @@ void I1.M5() {} // (5,27): error CS0621: 'I1.M2()': virtual or abstract members cannot be private // abstract private void M2() {} Diagnostic(ErrorCode.ERR_VirtualPrivate, "M2").WithArguments("I1.M2()").WithLocation(5, 27), - // (6,26): error CS8703: The modifier 'abstract' is not valid for this item in C# 9.0. Please use language version 'preview' or greater. - // abstract static void M3() {} - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M3").WithArguments("abstract", "9.0", "preview").WithLocation(6, 26), + // (11,15): error CS0535: 'Test1' does not implement interface member 'I1.M1()' + // class Test1 : I1 + Diagnostic(ErrorCode.ERR_UnimplementedInterfaceMember, "I1").WithArguments("Test1", "I1.M1()").WithLocation(11, 15), // (11,15): error CS0535: 'Test1' does not implement interface member 'I1.M2()' // class Test1 : I1 Diagnostic(ErrorCode.ERR_UnimplementedInterfaceMember, "I1").WithArguments("Test1", "I1.M2()").WithLocation(11, 15), // (11,15): error CS0535: 'Test1' does not implement interface member 'I1.M3()' // class Test1 : I1 Diagnostic(ErrorCode.ERR_UnimplementedInterfaceMember, "I1").WithArguments("Test1", "I1.M3()").WithLocation(11, 15), - // (11,15): error CS0535: 'Test1' does not implement interface member 'I1.M1()' - // class Test1 : I1 - Diagnostic(ErrorCode.ERR_UnimplementedInterfaceMember, "I1").WithArguments("Test1", "I1.M1()").WithLocation(11, 15), // (18,13): error CS0122: 'I1.M2()' is inaccessible due to its protection level // void I1.M2() {} Diagnostic(ErrorCode.ERR_BadAccess, "M2").WithArguments("I1.M2()").WithLocation(18, 13), @@ -12281,15 +12281,15 @@ static void Test() where T : I1 Diagnostic(ErrorCode.ERR_ImplicitImplementationOfNonPublicInterfaceMember, "M1").WithArguments("Test1", "I1.M1()", "Test1.M1()", "9.0", "10.0").WithLocation(5, 17) ) : ExpectedDiagnostics( - // (24,29): error CS8703: The modifier 'abstract' is not valid for this item in C# 9.0. Please use language version 'preview' or greater. + // (24,29): error CS8703: The modifier 'abstract' is not valid for this item in C# 9.0. Please use language version '11.0' or greater. // protected abstract void M1(); - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M1").WithArguments("abstract", "9.0", "preview").WithLocation(24, 29), - // (29,9): error CS8652: The feature 'static abstract members in interfaces' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M1").WithArguments("abstract", "9.0", "11.0").WithLocation(24, 29), + // (29,9): error CS8773: Feature 'static abstract members in interfaces' is not available in C# 9.0. Please use language version 11.0 or greater. // T.M1(); - Diagnostic(ErrorCode.ERR_FeatureInPreview, "T").WithArguments("static abstract members in interfaces").WithLocation(29, 9), - // (36,13): error CS8703: The modifier 'static' is not valid for this item in C# 9.0. Please use language version 'preview' or greater. + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion9, "T").WithArguments("static abstract members in interfaces", "11.0").WithLocation(29, 9), + // (36,13): error CS8703: The modifier 'static' is not valid for this item in C# 9.0. Please use language version '11.0' or greater. // void I1.M1() - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M1").WithArguments("static", "9.0", "preview").WithLocation(36, 13) + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M1").WithArguments("static", "9.0", "11.0").WithLocation(36, 13) ), expectedIn9AcrossAssemblyBoundaries: !isStatic ? ExpectedDiagnostics( @@ -12298,9 +12298,9 @@ static void Test() where T : I1 Diagnostic(ErrorCode.ERR_ImplicitImplementationOfNonPublicInterfaceMember, "M1").WithArguments("Test1", "I1.M1()", "Test1.M1()", "9.0", "10.0").WithLocation(5, 17) ) : ExpectedDiagnostics( - // (5,17): error CS8706: 'Test1.M1()' cannot implement interface member 'I1.M1()' in type 'Test1' because feature 'static abstract members in interfaces' is not available in C# 9.0. Please use language version 'preview' or greater. + // (5,17): error CS8706: 'Test1.M1()' cannot implement interface member 'I1.M1()' in type 'Test1' because feature 'static abstract members in interfaces' is not available in C# 9.0. Please use language version '11.0' or greater. // public void M1() - Diagnostic(ErrorCode.ERR_LanguageVersionDoesNotSupportInterfaceImplementationForMember, "M1").WithArguments("Test1.M1()", "I1.M1()", "Test1", "static abstract members in interfaces", "9.0", "preview").WithLocation(5, 17) + Diagnostic(ErrorCode.ERR_LanguageVersionDoesNotSupportInterfaceImplementationForMember, "M1").WithArguments("Test1.M1()", "I1.M1()", "Test1", "static abstract members in interfaces", "9.0", "11.0").WithLocation(5, 17) ), expectedAcrossAssemblyBoundaries: Array.Empty(), isStatic: isStatic @@ -14178,15 +14178,15 @@ class Test2 : I1 targetFramework: TargetFramework.Net60); compilation1.VerifyDiagnostics( - // (4,25): error CS8703: The modifier 'abstract' is not valid for this item in C# 9.0. Please use language version 'preview' or greater. + // (4,25): error CS8703: The modifier 'abstract' is not valid for this item in C# 9.0. Please use language version '11.0' or greater. // abstract static int P1 {get;} - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "P1").WithArguments("abstract", "9.0", "preview").WithLocation(4, 25), - // (6,24): error CS8703: The modifier 'virtual' is not valid for this item in C# 9.0. Please use language version 'preview' or greater. + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "P1").WithArguments("abstract", "9.0", "11.0").WithLocation(4, 25), + // (6,24): error CS8703: The modifier 'virtual' is not valid for this item in C# 9.0. Please use language version '11.0' or greater. // virtual static int P2 {set {}} - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "P2").WithArguments("virtual", "9.0", "preview").WithLocation(6, 24), - // (8,23): error CS8703: The modifier 'sealed' is not valid for this item in C# 9.0. Please use language version 'preview' or greater. + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "P2").WithArguments("virtual", "9.0", "11.0").WithLocation(6, 24), + // (8,23): error CS8703: The modifier 'sealed' is not valid for this item in C# 9.0. Please use language version '11.0' or greater. // sealed static int P3 => 0; - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "P3").WithArguments("sealed", "9.0", "preview").WithLocation(8, 23), + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "P3").WithArguments("sealed", "9.0", "11.0").WithLocation(8, 23), // (13,15): error CS0535: 'Test1' does not implement interface member 'I1.P1' // class Test1 : I1 Diagnostic(ErrorCode.ERR_UnimplementedInterfaceMember, "I1").WithArguments("Test1", "I1.P1").WithLocation(13, 15), @@ -17014,42 +17014,42 @@ class Test2 : I1, I2, I3, I4, I5 } "; ValidatePropertyModifiers_18(source1, + // (8,32): error CS0500: 'I2.P2.get' cannot declare a body because it is marked abstract + // abstract private int P2 => 0; + Diagnostic(ErrorCode.ERR_AbstractHasBody, "0").WithArguments("I2.P2.get").WithLocation(8, 32), // (4,22): error CS0500: 'I1.P1.get' cannot declare a body because it is marked abstract // abstract int P1 {get => 0; set => throw null;} Diagnostic(ErrorCode.ERR_AbstractHasBody, "get").WithArguments("I1.P1.get").WithLocation(4, 22), // (4,32): error CS0500: 'I1.P1.set' cannot declare a body because it is marked abstract // abstract int P1 {get => 0; set => throw null;} Diagnostic(ErrorCode.ERR_AbstractHasBody, "set").WithArguments("I1.P1.set").WithLocation(4, 32), - // (8,26): error CS0621: 'I2.P2': virtual or abstract members cannot be private - // abstract private int P2 => 0; - Diagnostic(ErrorCode.ERR_VirtualPrivate, "P2").WithArguments("I2.P2").WithLocation(8, 26), - // (8,32): error CS0500: 'I2.P2.get' cannot declare a body because it is marked abstract - // abstract private int P2 => 0; - Diagnostic(ErrorCode.ERR_AbstractHasBody, "0").WithArguments("I2.P2.get").WithLocation(8, 32), - // (16,25): error CS8703: The modifier 'abstract' is not valid for this item in C# 9.0. Please use language version 'preview' or greater. + // (20,25): error CS0106: The modifier 'override' is not valid for this item + // override sealed int P5 {get;} = 0; + Diagnostic(ErrorCode.ERR_BadMemberFlag, "P5").WithArguments("override").WithLocation(20, 25), + // (20,29): error CS0501: 'I5.P5.get' must declare a body because it is not marked abstract, extern, or partial + // override sealed int P5 {get;} = 0; + Diagnostic(ErrorCode.ERR_ConcreteMissingBody, "get").WithArguments("I5.P5.get").WithLocation(20, 29), + // (16,25): error CS8703: The modifier 'abstract' is not valid for this item in C# 9.0. Please use language version '11.0' or greater. // abstract static int P4 { get {throw null;} set {throw null;}} - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "P4").WithArguments("abstract", "9.0", "preview").WithLocation(16, 25), + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "P4").WithArguments("abstract", "9.0", "11.0").WithLocation(16, 25), // (16,30): error CS0500: 'I4.P4.get' cannot declare a body because it is marked abstract // abstract static int P4 { get {throw null;} set {throw null;}} Diagnostic(ErrorCode.ERR_AbstractHasBody, "get").WithArguments("I4.P4.get").WithLocation(16, 30), // (16,48): error CS0500: 'I4.P4.set' cannot declare a body because it is marked abstract // abstract static int P4 { get {throw null;} set {throw null;}} Diagnostic(ErrorCode.ERR_AbstractHasBody, "set").WithArguments("I4.P4.set").WithLocation(16, 48), - // (20,25): error CS0106: The modifier 'override' is not valid for this item - // override sealed int P5 {get;} = 0; - Diagnostic(ErrorCode.ERR_BadMemberFlag, "P5").WithArguments("override").WithLocation(20, 25), + // (8,26): error CS0621: 'I2.P2': virtual or abstract members cannot be private + // abstract private int P2 => 0; + Diagnostic(ErrorCode.ERR_VirtualPrivate, "P2").WithArguments("I2.P2").WithLocation(8, 26), // (20,25): error CS8053: Instance properties in interfaces cannot have initializers. // override sealed int P5 {get;} = 0; Diagnostic(ErrorCode.ERR_InstancePropertyInitializerInInterface, "P5").WithLocation(20, 25), - // (20,29): error CS0501: 'I5.P5.get' must declare a body because it is not marked abstract, extern, or partial - // override sealed int P5 {get;} = 0; - Diagnostic(ErrorCode.ERR_ConcreteMissingBody, "get").WithArguments("I5.P5.get").WithLocation(20, 29), - // (23,15): error CS0535: 'Test1' does not implement interface member 'I1.P1' - // class Test1 : I1, I2, I3, I4, I5 - Diagnostic(ErrorCode.ERR_UnimplementedInterfaceMember, "I1").WithArguments("Test1", "I1.P1").WithLocation(23, 15), - // (23,19): error CS0535: 'Test1' does not implement interface member 'I2.P2' - // class Test1 : I1, I2, I3, I4, I5 - Diagnostic(ErrorCode.ERR_UnimplementedInterfaceMember, "I2").WithArguments("Test1", "I2.P2").WithLocation(23, 19), + // (12,32): warning CS0626: Method, operator, or accessor 'I3.P3.set' is marked external and has no attributes on it. Consider adding a DllImport attribute to specify the external implementation. + // static extern int P3 {get; set;} + Diagnostic(ErrorCode.WRN_ExternMethodNoImplementation, "set").WithArguments("I3.P3.set").WithLocation(12, 32), + // (12,27): warning CS0626: Method, operator, or accessor 'I3.P3.get' is marked external and has no attributes on it. Consider adding a DllImport attribute to specify the external implementation. + // static extern int P3 {get; set;} + Diagnostic(ErrorCode.WRN_ExternMethodNoImplementation, "get").WithArguments("I3.P3.get").WithLocation(12, 27), // (30,12): error CS0122: 'I2.P2' is inaccessible due to its protection level // int I2.P2 => 0; Diagnostic(ErrorCode.ERR_BadAccess, "P2").WithArguments("I2.P2").WithLocation(30, 12), @@ -17062,12 +17062,12 @@ class Test2 : I1, I2, I3, I4, I5 // (33,12): error CS0539: 'Test2.P5' in explicit interface declaration is not found among members of the interface that can be implemented // int I5.P5 => 0; Diagnostic(ErrorCode.ERR_InterfaceMemberNotFound, "P5").WithArguments("Test2.P5").WithLocation(33, 12), - // (12,27): warning CS0626: Method, operator, or accessor 'I3.P3.get' is marked external and has no attributes on it. Consider adding a DllImport attribute to specify the external implementation. - // static extern int P3 {get; set;} - Diagnostic(ErrorCode.WRN_ExternMethodNoImplementation, "get").WithArguments("I3.P3.get").WithLocation(12, 27), - // (12,32): warning CS0626: Method, operator, or accessor 'I3.P3.set' is marked external and has no attributes on it. Consider adding a DllImport attribute to specify the external implementation. - // static extern int P3 {get; set;} - Diagnostic(ErrorCode.WRN_ExternMethodNoImplementation, "set").WithArguments("I3.P3.set").WithLocation(12, 32), + // (23,15): error CS0535: 'Test1' does not implement interface member 'I1.P1' + // class Test1 : I1, I2, I3, I4, I5 + Diagnostic(ErrorCode.ERR_UnimplementedInterfaceMember, "I1").WithArguments("Test1", "I1.P1").WithLocation(23, 15), + // (23,19): error CS0535: 'Test1' does not implement interface member 'I2.P2' + // class Test1 : I1, I2, I3, I4, I5 + Diagnostic(ErrorCode.ERR_UnimplementedInterfaceMember, "I2").WithArguments("Test1", "I2.P2").WithLocation(23, 19), // (23,27): error CS0535: 'Test1' does not implement interface member 'I4.P4' // class Test1 : I1, I2, I3, I4, I5 Diagnostic(ErrorCode.ERR_UnimplementedInterfaceMember, "I4").WithArguments("Test1", "I4.P4").WithLocation(23, 27), @@ -27760,21 +27760,21 @@ class Test2 : I1 targetFramework: TargetFramework.Net60); compilation1.VerifyDiagnostics( + // (4,41): error CS8703: The modifier 'abstract' is not valid for this item in C# 9.0. Please use language version '11.0' or greater. + // abstract static event System.Action P1; + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "P1").WithArguments("abstract", "9.0", "11.0").WithLocation(4, 41), + // (6,40): error CS8703: The modifier 'virtual' is not valid for this item in C# 9.0. Please use language version '11.0' or greater. + // virtual static event System.Action P2 {add {} remove{}} + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "P2").WithArguments("virtual", "9.0", "11.0").WithLocation(6, 40), + // (8,39): error CS8703: The modifier 'sealed' is not valid for this item in C# 9.0. Please use language version '11.0' or greater. + // sealed static event System.Action P3 {add; remove;} + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "P3").WithArguments("sealed", "9.0", "11.0").WithLocation(8, 39), // (8,46): error CS0073: An add or remove accessor must have a body // sealed static event System.Action P3 {add; remove;} Diagnostic(ErrorCode.ERR_AddRemoveMustHaveBody, ";").WithLocation(8, 46), // (8,54): error CS0073: An add or remove accessor must have a body // sealed static event System.Action P3 {add; remove;} Diagnostic(ErrorCode.ERR_AddRemoveMustHaveBody, ";").WithLocation(8, 54), - // (6,40): error CS8703: The modifier 'virtual' is not valid for this item in C# 9.0. Please use language version 'preview' or greater. - // virtual static event System.Action P2 {add {} remove{}} - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "P2").WithArguments("virtual", "9.0", "preview").WithLocation(6, 40), - // (8,39): error CS8703: The modifier 'sealed' is not valid for this item in C# 9.0. Please use language version 'preview' or greater. - // sealed static event System.Action P3 {add; remove;} - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "P3").WithArguments("sealed", "9.0", "preview").WithLocation(8, 39), - // (4,41): error CS8703: The modifier 'abstract' is not valid for this item in C# 9.0. Please use language version 'preview' or greater. - // abstract static event System.Action P1; - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "P1").WithArguments("abstract", "9.0", "preview").WithLocation(4, 41), // (13,28): error CS0539: 'Test1.P1' in explicit interface declaration is not found among members of the interface that can be implemented // event System.Action I1.P1 {add {} remove{}} Diagnostic(ErrorCode.ERR_InterfaceMemberNotFound, "P1").WithArguments("Test1.P1").WithLocation(13, 28), @@ -30427,24 +30427,30 @@ class Test2 : I1, I2, I3, I4, I5 // (8,42): error CS0068: 'I2.P2': instance event in interface cannot have initializer // abstract private event System.Action P2 = null; Diagnostic(ErrorCode.ERR_InterfaceEventInitializer, "P2").WithArguments("I2.P2").WithLocation(8, 42), - // (8,42): error CS0621: 'I2.P2': virtual or abstract members cannot be private - // abstract private event System.Action P2 = null; - Diagnostic(ErrorCode.ERR_VirtualPrivate, "P2").WithArguments("I2.P2").WithLocation(8, 42), + // (16,41): error CS8703: The modifier 'abstract' is not valid for this item in C# 9.0. Please use language version '11.0' or greater. + // abstract static event System.Action P4 { add {throw null;} remove {throw null;}} + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "P4").WithArguments("abstract", "9.0", "11.0").WithLocation(16, 41), // (16,44): error CS8712: 'I4.P4': abstract event cannot use event accessor syntax // abstract static event System.Action P4 { add {throw null;} remove {throw null;}} Diagnostic(ErrorCode.ERR_AbstractEventHasAccessors, "{").WithArguments("I4.P4").WithLocation(16, 44), - // (16,41): error CS8703: The modifier 'abstract' is not valid for this item in C# 9.0. Please use language version 'preview' or greater. - // abstract static event System.Action P4 { add {throw null;} remove {throw null;}} - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "P4").WithArguments("abstract", "9.0", "preview").WithLocation(16, 41), // (20,41): error CS0106: The modifier 'override' is not valid for this item // override sealed event System.Action P5 { add {throw null;} remove {throw null;}} Diagnostic(ErrorCode.ERR_BadMemberFlag, "P5").WithArguments("override").WithLocation(20, 41), + // (12,39): warning CS0626: Method, operator, or accessor 'I3.P3.remove' is marked external and has no attributes on it. Consider adding a DllImport attribute to specify the external implementation. + // static extern event System.Action P3; + Diagnostic(ErrorCode.WRN_ExternMethodNoImplementation, "P3").WithArguments("I3.P3.remove").WithLocation(12, 39), + // (8,42): error CS0621: 'I2.P2': virtual or abstract members cannot be private + // abstract private event System.Action P2 = null; + Diagnostic(ErrorCode.ERR_VirtualPrivate, "P2").WithArguments("I2.P2").WithLocation(8, 42), // (23,15): error CS0535: 'Test1' does not implement interface member 'I1.P1' // class Test1 : I1, I2, I3, I4, I5 Diagnostic(ErrorCode.ERR_UnimplementedInterfaceMember, "I1").WithArguments("Test1", "I1.P1").WithLocation(23, 15), // (23,19): error CS0535: 'Test1' does not implement interface member 'I2.P2' // class Test1 : I1, I2, I3, I4, I5 Diagnostic(ErrorCode.ERR_UnimplementedInterfaceMember, "I2").WithArguments("Test1", "I2.P2").WithLocation(23, 19), + // (23,27): error CS0535: 'Test1' does not implement interface member 'I4.P4' + // class Test1 : I1, I2, I3, I4, I5 + Diagnostic(ErrorCode.ERR_UnimplementedInterfaceMember, "I4").WithArguments("Test1", "I4.P4").WithLocation(23, 27), // (30,28): error CS0122: 'I2.P2' is inaccessible due to its protection level // event System.Action I2.P2 { add {throw null;} remove {throw null;}} Diagnostic(ErrorCode.ERR_BadAccess, "P2").WithArguments("I2.P2").WithLocation(30, 28), @@ -30457,12 +30463,6 @@ class Test2 : I1, I2, I3, I4, I5 // (33,28): error CS0539: 'Test2.P5' in explicit interface declaration is not found among members of the interface that can be implemented // event System.Action I5.P5 { add {throw null;} remove {throw null;}} Diagnostic(ErrorCode.ERR_InterfaceMemberNotFound, "P5").WithArguments("Test2.P5").WithLocation(33, 28), - // (12,39): warning CS0626: Method, operator, or accessor 'I3.P3.remove' is marked external and has no attributes on it. Consider adding a DllImport attribute to specify the external implementation. - // static extern event System.Action P3; - Diagnostic(ErrorCode.WRN_ExternMethodNoImplementation, "P3").WithArguments("I3.P3.remove").WithLocation(12, 39), - // (23,27): error CS0535: 'Test1' does not implement interface member 'I4.P4' - // class Test1 : I1, I2, I3, I4, I5 - Diagnostic(ErrorCode.ERR_UnimplementedInterfaceMember, "I4").WithArguments("Test1", "I4.P4").WithLocation(23, 27), // (27,27): error CS0535: 'Test2' does not implement interface member 'I4.P4' // class Test2 : I1, I2, I3, I4, I5 Diagnostic(ErrorCode.ERR_UnimplementedInterfaceMember, "I4").WithArguments("Test2", "I4.P4").WithLocation(27, 27), @@ -32596,6 +32596,102 @@ interface IB : IA> { } ); } + [Fact] + [WorkItem(58424, "https://github.com/dotnet/roslyn/issues/58424")] + public void NestedTypes_53() + { + var source1 = +@" +public class Test : Test.IInner.IOuter +{ + public interface IInner : Other + { + public interface IOuter + { + } + } +} + +public interface Other +{ +} +"; + + var compilation1 = CreateCompilation(source1, options: TestOptions.DebugDll, + targetFramework: TargetFramework.NetCoreApp); + + compilation1.VerifyDiagnostics(); + } + + [Fact] + [WorkItem(58424, "https://github.com/dotnet/roslyn/issues/58424")] + public void NestedTypes_54() + { + var source1 = +@" +public class Test : Test.IInner.IOuter +{ + public interface IInner : Other + { + } +} + +public interface Other +{ + public interface IOuter + { + } +} +"; + + var compilation1 = CreateCompilation(source1, options: TestOptions.DebugDll, + targetFramework: TargetFramework.NetCoreApp); + + compilation1.VerifyDiagnostics( + // (2,33): error CS0426: The type name 'IOuter' does not exist in the type 'Test.IInner' + // public class Test : Test.IInner.IOuter + Diagnostic(ErrorCode.ERR_DottedTypeNameNotFoundInAgg, "IOuter").WithArguments("IOuter", "Test.IInner").WithLocation(2, 33), + // (4,31): error CS0146: Circular base type dependency involving 'Test' and 'Test.IInner' + // public interface IInner : Other + Diagnostic(ErrorCode.ERR_CircularBase, "Other").WithArguments("Test", "Test.IInner").WithLocation(4, 31) + ); + } + + [Fact] + [WorkItem(58424, "https://github.com/dotnet/roslyn/issues/58424")] + [WorkItem(62795, "https://github.com/dotnet/roslyn/issues/62795")] + public void NestedTypes_55() + { + var source1 = +@" +namespace Ns0 +{ + public class Test : Test.IInner.IOuter + { + public interface IInner : global::Ns0.Other + { + new public interface IOuter + { + } + } + } + + public interface Other + { + public interface IOuter + { + void M1(); + } + } +} +"; + + var compilation1 = CreateCompilation(source1, options: TestOptions.DebugDll, + targetFramework: TargetFramework.NetCoreApp); + + compilation1.VerifyDiagnostics(); + } + [Theory] [CombinatorialData] [WorkItem(32540, "https://github.com/dotnet/roslyn/issues/32540")] @@ -32918,18 +33014,18 @@ class Test1 : I1 targetFramework: TargetFramework.Net60); compilation1.VerifyDiagnostics( - // (4,26): error CS8703: The modifier 'abstract' is not valid for this item in C# 10.0. Please use language version 'preview' or greater. + // (4,26): error CS8703: The modifier 'abstract' is not valid for this item in C# 10.0. Please use language version '11.0' or greater. // static abstract void M1(); - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M1").WithArguments("abstract", "10.0", "preview").WithLocation(4, 26), - // (9,26): error CS8703: The modifier 'abstract' is not valid for this item in C# 10.0. Please use language version 'preview' or greater. + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M1").WithArguments("abstract", "10.0", "11.0").WithLocation(4, 26), + // (9,26): error CS8703: The modifier 'abstract' is not valid for this item in C# 10.0. Please use language version '11.0' or greater. // static abstract void M1(); - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M1").WithArguments("abstract", "10.0", "preview").WithLocation(9, 26), - // (14,20): error CS8703: The modifier 'static' is not valid for this item in C# 10.0. Please use language version 'preview' or greater. + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M1").WithArguments("abstract", "10.0", "11.0").WithLocation(9, 26), + // (14,20): error CS8703: The modifier 'static' is not valid for this item in C# 10.0. Please use language version '11.0' or greater. // static void I2.M1() - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M1").WithArguments("static", "10.0", "preview").WithLocation(14, 20), - // (18,20): error CS8703: The modifier 'static' is not valid for this item in C# 10.0. Please use language version 'preview' or greater. + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M1").WithArguments("static", "10.0", "11.0").WithLocation(14, 20), + // (18,20): error CS8703: The modifier 'static' is not valid for this item in C# 10.0. Please use language version '11.0' or greater. // static void I4.M1() - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M1").WithArguments("static", "10.0", "preview").WithLocation(18, 20) + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M1").WithArguments("static", "10.0", "11.0").WithLocation(18, 20) ); ValidateMethodImplementationInDerived_01(compilation1.SourceModule, isStatic: true); @@ -32953,12 +33049,12 @@ class Test1 : I1 Assert.True(compilation2.Assembly.RuntimeSupportsDefaultInterfaceImplementation); compilation2.VerifyDiagnostics( - // (6,15): error CS8706: 'I1.I2.M1()' cannot implement interface member 'I2.M1()' in type 'Test1' because feature 'static abstract members in interfaces' is not available in C# 10.0. Please use language version 'preview' or greater. + // (6,15): error CS8706: 'I1.I2.M1()' cannot implement interface member 'I2.M1()' in type 'Test1' because feature 'static abstract members in interfaces' is not available in C# 10.0. Please use language version '11.0' or greater. // class Test1 : I1 - Diagnostic(ErrorCode.ERR_LanguageVersionDoesNotSupportInterfaceImplementationForMember, "I1").WithArguments("I1.I2.M1()", "I2.M1()", "Test1", "static abstract members in interfaces", "10.0", "preview").WithLocation(6, 15), - // (6,15): error CS8706: 'I1.I4.M1()' cannot implement interface member 'I4.M1()' in type 'Test1' because feature 'static abstract members in interfaces' is not available in C# 10.0. Please use language version 'preview' or greater. + Diagnostic(ErrorCode.ERR_LanguageVersionDoesNotSupportInterfaceImplementationForMember, "I1").WithArguments("I1.I2.M1()", "I2.M1()", "Test1", "static abstract members in interfaces", "10.0", "11.0").WithLocation(6, 15), + // (6,15): error CS8706: 'I1.I4.M1()' cannot implement interface member 'I4.M1()' in type 'Test1' because feature 'static abstract members in interfaces' is not available in C# 10.0. Please use language version '11.0' or greater. // class Test1 : I1 - Diagnostic(ErrorCode.ERR_LanguageVersionDoesNotSupportInterfaceImplementationForMember, "I1").WithArguments("I1.I4.M1()", "I4.M1()", "Test1", "static abstract members in interfaces", "10.0", "preview").WithLocation(6, 15) + Diagnostic(ErrorCode.ERR_LanguageVersionDoesNotSupportInterfaceImplementationForMember, "I1").WithArguments("I1.I4.M1()", "I4.M1()", "Test1", "static abstract members in interfaces", "10.0", "11.0").WithLocation(6, 15) ); ValidateMethodImplementationInDerived_01(compilation2.SourceModule, isStatic: true); @@ -33538,12 +33634,12 @@ void Validate1(ModuleSymbol m) else { compilation2.VerifyDiagnostics( - // (4,26): error CS8703: The modifier 'abstract' is not valid for this item in C# 10.0. Please use language version 'preview' or greater. + // (4,26): error CS8703: The modifier 'abstract' is not valid for this item in C# 10.0. Please use language version '11.0' or greater. // static abstract void M1(); - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M1").WithArguments("abstract", "10.0", "preview").WithLocation(4, 26), - // (9,27): error CS8703: The modifier 'static' is not valid for this item in C# 10.0. Please use language version 'preview' or greater. + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M1").WithArguments("abstract", "10.0", "11.0").WithLocation(4, 26), + // (9,27): error CS8703: The modifier 'static' is not valid for this item in C# 10.0. Please use language version '11.0' or greater. // static extern void I2.M1(); - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M1").WithArguments("static", "10.0", "preview").WithLocation(9, 27), + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M1").WithArguments("static", "10.0", "11.0").WithLocation(9, 27), // (9,27): warning CS0626: Method, operator, or accessor 'I1.I2.M1()' is marked external and has no attributes on it. Consider adding a DllImport attribute to specify the external implementation. // static extern void I2.M1(); Diagnostic(ErrorCode.WRN_ExternMethodNoImplementation, "M1").WithArguments("I1.I2.M1()").WithLocation(9, 27) @@ -36970,25 +37066,25 @@ class Test1 : I1 ValidatePropertyImplementationInDerived_02(source1, isStatic: true, new DiagnosticDescription[] { - // (4,25): error CS8703: The modifier 'abstract' is not valid for this item in C# 10.0. Please use language version 'preview' or greater. + // (4,25): error CS8703: The modifier 'abstract' is not valid for this item in C# 10.0. Please use language version '11.0' or greater. // static abstract int M1 {get;} - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M1").WithArguments("abstract", "10.0", "preview").WithLocation(4, 25), - // (9,25): error CS8703: The modifier 'abstract' is not valid for this item in C# 10.0. Please use language version 'preview' or greater. + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M1").WithArguments("abstract", "10.0", "11.0").WithLocation(4, 25), + // (9,25): error CS8703: The modifier 'abstract' is not valid for this item in C# 10.0. Please use language version '11.0' or greater. // static abstract int M1 {set;} - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M1").WithArguments("abstract", "10.0", "preview").WithLocation(9, 25), - // (14,19): error CS8703: The modifier 'static' is not valid for this item in C# 10.0. Please use language version 'preview' or greater. + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M1").WithArguments("abstract", "10.0", "11.0").WithLocation(9, 25), + // (14,19): error CS8703: The modifier 'static' is not valid for this item in C# 10.0. Please use language version '11.0' or greater. // static int I2.M1 => Getter(); - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M1").WithArguments("static", "10.0", "preview").WithLocation(14, 19), - // (22,19): error CS8703: The modifier 'static' is not valid for this item in C# 10.0. Please use language version 'preview' or greater. + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M1").WithArguments("static", "10.0", "11.0").WithLocation(14, 19), + // (22,19): error CS8703: The modifier 'static' is not valid for this item in C# 10.0. Please use language version '11.0' or greater. // static int I4.M1 - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M1").WithArguments("static", "10.0", "preview").WithLocation(22, 19) + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M1").WithArguments("static", "10.0", "11.0").WithLocation(22, 19) }, - // (6,15): error CS8706: 'I1.I2.M1.get' cannot implement interface member 'I2.M1.get' in type 'Test1' because feature 'static abstract members in interfaces' is not available in C# 10.0. Please use language version 'preview' or greater. + // (6,15): error CS8706: 'I1.I2.M1.get' cannot implement interface member 'I2.M1.get' in type 'Test1' because feature 'static abstract members in interfaces' is not available in C# 10.0. Please use language version '11.0' or greater. // class Test1 : I1 - Diagnostic(ErrorCode.ERR_LanguageVersionDoesNotSupportInterfaceImplementationForMember, "I1").WithArguments("I1.I2.M1.get", "I2.M1.get", "Test1", "static abstract members in interfaces", "10.0", "preview").WithLocation(6, 15), - // (6,15): error CS8706: 'I1.I4.M1.set' cannot implement interface member 'I4.M1.set' in type 'Test1' because feature 'static abstract members in interfaces' is not available in C# 10.0. Please use language version 'preview' or greater. + Diagnostic(ErrorCode.ERR_LanguageVersionDoesNotSupportInterfaceImplementationForMember, "I1").WithArguments("I1.I2.M1.get", "I2.M1.get", "Test1", "static abstract members in interfaces", "10.0", "11.0").WithLocation(6, 15), + // (6,15): error CS8706: 'I1.I4.M1.set' cannot implement interface member 'I4.M1.set' in type 'Test1' because feature 'static abstract members in interfaces' is not available in C# 10.0. Please use language version '11.0' or greater. // class Test1 : I1 - Diagnostic(ErrorCode.ERR_LanguageVersionDoesNotSupportInterfaceImplementationForMember, "I1").WithArguments("I1.I4.M1.set", "I4.M1.set", "Test1", "static abstract members in interfaces", "10.0", "preview").WithLocation(6, 15) + Diagnostic(ErrorCode.ERR_LanguageVersionDoesNotSupportInterfaceImplementationForMember, "I1").WithArguments("I1.I4.M1.set", "I4.M1.set", "Test1", "static abstract members in interfaces", "10.0", "11.0").WithLocation(6, 15) ); } @@ -37806,12 +37902,12 @@ class Test1 : I1 }, new DiagnosticDescription[] { - // (4,25): error CS8703: The modifier 'abstract' is not valid for this item in C# 10.0. Please use language version 'preview' or greater. + // (4,25): error CS8703: The modifier 'abstract' is not valid for this item in C# 10.0. Please use language version '11.0' or greater. // static abstract int M1 {get;} - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M1").WithArguments("abstract", "10.0", "preview").WithLocation(4, 25), - // (9,26): error CS8703: The modifier 'static' is not valid for this item in C# 10.0. Please use language version 'preview' or greater. + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M1").WithArguments("abstract", "10.0", "11.0").WithLocation(4, 25), + // (9,26): error CS8703: The modifier 'static' is not valid for this item in C# 10.0. Please use language version '11.0' or greater. // static extern int I2.M1 {get;} - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M1").WithArguments("static", "10.0", "preview").WithLocation(9, 26), + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M1").WithArguments("static", "10.0", "11.0").WithLocation(9, 26), // (9,30): warning CS0626: Method, operator, or accessor 'I1.I2.M1.get' is marked external and has no attributes on it. Consider adding a DllImport attribute to specify the external implementation. // static extern int I2.M1 {get;} Diagnostic(ErrorCode.WRN_ExternMethodNoImplementation, "get").WithArguments("I1.I2.M1.get").WithLocation(9, 30) @@ -40028,18 +40124,18 @@ class Test1 : I1 targetFramework: TargetFramework.Net60); compilation1.VerifyDiagnostics( - // (4,41): error CS8703: The modifier 'abstract' is not valid for this item in C# 10.0. Please use language version 'preview' or greater. + // (4,41): error CS8703: The modifier 'abstract' is not valid for this item in C# 10.0. Please use language version '11.0' or greater. // static abstract event System.Action M1; - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M1").WithArguments("abstract", "10.0", "preview").WithLocation(4, 41), - // (9,41): error CS8703: The modifier 'abstract' is not valid for this item in C# 10.0. Please use language version 'preview' or greater. + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M1").WithArguments("abstract", "10.0", "11.0").WithLocation(4, 41), + // (9,41): error CS8703: The modifier 'abstract' is not valid for this item in C# 10.0. Please use language version '11.0' or greater. // static abstract event System.Action M1; - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M1").WithArguments("abstract", "10.0", "preview").WithLocation(9, 41), - // (14,35): error CS8703: The modifier 'static' is not valid for this item in C# 10.0. Please use language version 'preview' or greater. + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M1").WithArguments("abstract", "10.0", "11.0").WithLocation(9, 41), + // (14,35): error CS8703: The modifier 'static' is not valid for this item in C# 10.0. Please use language version '11.0' or greater. // static event System.Action I2.M1 - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M1").WithArguments("static", "10.0", "preview").WithLocation(14, 35), - // (20,35): error CS8703: The modifier 'static' is not valid for this item in C# 10.0. Please use language version 'preview' or greater. + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M1").WithArguments("static", "10.0", "11.0").WithLocation(14, 35), + // (20,35): error CS8703: The modifier 'static' is not valid for this item in C# 10.0. Please use language version '11.0' or greater. // static event System.Action I4.M1 - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M1").WithArguments("static", "10.0", "preview").WithLocation(20, 35) + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M1").WithArguments("static", "10.0", "11.0").WithLocation(20, 35) ); ValidateEventImplementationInDerived_01(compilation1.SourceModule, isStatic: true); @@ -40058,18 +40154,18 @@ class Test1 : I1 targetFramework: TargetFramework.Net60); compilation2.VerifyDiagnostics( - // (6,15): error CS8706: 'I1.I2.M1.add' cannot implement interface member 'I2.M1.add' in type 'Test1' because feature 'static abstract members in interfaces' is not available in C# 10.0. Please use language version 'preview' or greater. + // (6,15): error CS8706: 'I1.I2.M1.add' cannot implement interface member 'I2.M1.add' in type 'Test1' because feature 'static abstract members in interfaces' is not available in C# 10.0. Please use language version '11.0' or greater. // class Test1 : I1 - Diagnostic(ErrorCode.ERR_LanguageVersionDoesNotSupportInterfaceImplementationForMember, "I1").WithArguments("I1.I2.M1.add", "I2.M1.add", "Test1", "static abstract members in interfaces", "10.0", "preview").WithLocation(6, 15), - // (6,15): error CS8706: 'I1.I2.M1.remove' cannot implement interface member 'I2.M1.remove' in type 'Test1' because feature 'static abstract members in interfaces' is not available in C# 10.0. Please use language version 'preview' or greater. + Diagnostic(ErrorCode.ERR_LanguageVersionDoesNotSupportInterfaceImplementationForMember, "I1").WithArguments("I1.I2.M1.add", "I2.M1.add", "Test1", "static abstract members in interfaces", "10.0", "11.0").WithLocation(6, 15), + // (6,15): error CS8706: 'I1.I2.M1.remove' cannot implement interface member 'I2.M1.remove' in type 'Test1' because feature 'static abstract members in interfaces' is not available in C# 10.0. Please use language version '11.0' or greater. // class Test1 : I1 - Diagnostic(ErrorCode.ERR_LanguageVersionDoesNotSupportInterfaceImplementationForMember, "I1").WithArguments("I1.I2.M1.remove", "I2.M1.remove", "Test1", "static abstract members in interfaces", "10.0", "preview").WithLocation(6, 15), - // (6,15): error CS8706: 'I1.I4.M1.add' cannot implement interface member 'I4.M1.add' in type 'Test1' because feature 'static abstract members in interfaces' is not available in C# 10.0. Please use language version 'preview' or greater. + Diagnostic(ErrorCode.ERR_LanguageVersionDoesNotSupportInterfaceImplementationForMember, "I1").WithArguments("I1.I2.M1.remove", "I2.M1.remove", "Test1", "static abstract members in interfaces", "10.0", "11.0").WithLocation(6, 15), + // (6,15): error CS8706: 'I1.I4.M1.add' cannot implement interface member 'I4.M1.add' in type 'Test1' because feature 'static abstract members in interfaces' is not available in C# 10.0. Please use language version '11.0' or greater. // class Test1 : I1 - Diagnostic(ErrorCode.ERR_LanguageVersionDoesNotSupportInterfaceImplementationForMember, "I1").WithArguments("I1.I4.M1.add", "I4.M1.add", "Test1", "static abstract members in interfaces", "10.0", "preview").WithLocation(6, 15), - // (6,15): error CS8706: 'I1.I4.M1.remove' cannot implement interface member 'I4.M1.remove' in type 'Test1' because feature 'static abstract members in interfaces' is not available in C# 10.0. Please use language version 'preview' or greater. + Diagnostic(ErrorCode.ERR_LanguageVersionDoesNotSupportInterfaceImplementationForMember, "I1").WithArguments("I1.I4.M1.add", "I4.M1.add", "Test1", "static abstract members in interfaces", "10.0", "11.0").WithLocation(6, 15), + // (6,15): error CS8706: 'I1.I4.M1.remove' cannot implement interface member 'I4.M1.remove' in type 'Test1' because feature 'static abstract members in interfaces' is not available in C# 10.0. Please use language version '11.0' or greater. // class Test1 : I1 - Diagnostic(ErrorCode.ERR_LanguageVersionDoesNotSupportInterfaceImplementationForMember, "I1").WithArguments("I1.I4.M1.remove", "I4.M1.remove", "Test1", "static abstract members in interfaces", "10.0", "preview").WithLocation(6, 15) + Diagnostic(ErrorCode.ERR_LanguageVersionDoesNotSupportInterfaceImplementationForMember, "I1").WithArguments("I1.I4.M1.remove", "I4.M1.remove", "Test1", "static abstract members in interfaces", "10.0", "11.0").WithLocation(6, 15) ); ValidateEventImplementationInDerived_01(compilation2.SourceModule, isStatic: true); @@ -46338,75 +46434,75 @@ static void Main() parseOptions: TestOptions.Regular7_3); compilation6.VerifyDiagnostics( - // (4,31): error CS8652: The feature 'default interface implementation' is not available in C# 7.3. Please use language version 8.0 or greater. + // (4,31): error CS8370: Feature 'default interface implementation' is not available in C# 7.3. Please use language version 8.0 or greater. // public static I1 operator +(I1 x) Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7_3, "+").WithArguments("default interface implementation", "8.0").WithLocation(4, 31), - // (10,31): error CS8652: The feature 'default interface implementation' is not available in C# 7.3. Please use language version 8.0 or greater. + // (10,31): error CS8370: Feature 'default interface implementation' is not available in C# 7.3. Please use language version 8.0 or greater. // public static I1 operator -(I1 x) Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7_3, "-").WithArguments("default interface implementation", "8.0").WithLocation(10, 31), - // (16,31): error CS8652: The feature 'default interface implementation' is not available in C# 7.3. Please use language version 8.0 or greater. + // (16,31): error CS8370: Feature 'default interface implementation' is not available in C# 7.3. Please use language version 8.0 or greater. // public static I1 operator !(I1 x) Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7_3, "!").WithArguments("default interface implementation", "8.0").WithLocation(16, 31), - // (22,31): error CS8652: The feature 'default interface implementation' is not available in C# 7.3. Please use language version 8.0 or greater. + // (22,31): error CS8370: Feature 'default interface implementation' is not available in C# 7.3. Please use language version 8.0 or greater. // public static I1 operator ~(I1 x) Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7_3, "~").WithArguments("default interface implementation", "8.0").WithLocation(22, 31), - // (28,31): error CS8652: The feature 'default interface implementation' is not available in C# 7.3. Please use language version 8.0 or greater. + // (28,31): error CS8370: Feature 'default interface implementation' is not available in C# 7.3. Please use language version 8.0 or greater. // public static I1 operator ++(I1 x) Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7_3, "++").WithArguments("default interface implementation", "8.0").WithLocation(28, 31), - // (34,31): error CS8652: The feature 'default interface implementation' is not available in C# 7.3. Please use language version 8.0 or greater. + // (34,31): error CS8370: Feature 'default interface implementation' is not available in C# 7.3. Please use language version 8.0 or greater. // public static I1 operator --(I1 x) Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7_3, "--").WithArguments("default interface implementation", "8.0").WithLocation(34, 31), - // (40,33): error CS8652: The feature 'default interface implementation' is not available in C# 7.3. Please use language version 8.0 or greater. + // (40,33): error CS8370: Feature 'default interface implementation' is not available in C# 7.3. Please use language version 8.0 or greater. // public static bool operator true(I1 x) Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7_3, "true").WithArguments("default interface implementation", "8.0").WithLocation(40, 33), - // (46,33): error CS8652: The feature 'default interface implementation' is not available in C# 7.3. Please use language version 8.0 or greater. + // (46,33): error CS8370: Feature 'default interface implementation' is not available in C# 7.3. Please use language version 8.0 or greater. // public static bool operator false(I1 x) Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7_3, "false").WithArguments("default interface implementation", "8.0").WithLocation(46, 33), - // (52,31): error CS8652: The feature 'default interface implementation' is not available in C# 7.3. Please use language version 8.0 or greater. + // (52,31): error CS8370: Feature 'default interface implementation' is not available in C# 7.3. Please use language version 8.0 or greater. // public static I1 operator +(I1 x, I1 y) Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7_3, "+").WithArguments("default interface implementation", "8.0").WithLocation(52, 31), - // (58,31): error CS8652: The feature 'default interface implementation' is not available in C# 7.3. Please use language version 8.0 or greater. + // (58,31): error CS8370: Feature 'default interface implementation' is not available in C# 7.3. Please use language version 8.0 or greater. // public static I1 operator -(I1 x, I1 y) Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7_3, "-").WithArguments("default interface implementation", "8.0").WithLocation(58, 31), - // (64,31): error CS8652: The feature 'default interface implementation' is not available in C# 7.3. Please use language version 8.0 or greater. + // (64,31): error CS8370: Feature 'default interface implementation' is not available in C# 7.3. Please use language version 8.0 or greater. // public static I1 operator *(I1 x, I1 y) Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7_3, "*").WithArguments("default interface implementation", "8.0").WithLocation(64, 31), - // (70,31): error CS8652: The feature 'default interface implementation' is not available in C# 7.3. Please use language version 8.0 or greater. + // (70,31): error CS8370: Feature 'default interface implementation' is not available in C# 7.3. Please use language version 8.0 or greater. // public static I1 operator /(I1 x, I1 y) Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7_3, "/").WithArguments("default interface implementation", "8.0").WithLocation(70, 31), - // (76,31): error CS8652: The feature 'default interface implementation' is not available in C# 7.3. Please use language version 8.0 or greater. + // (76,31): error CS8370: Feature 'default interface implementation' is not available in C# 7.3. Please use language version 8.0 or greater. // public static I1 operator %(I1 x, I1 y) Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7_3, "%").WithArguments("default interface implementation", "8.0").WithLocation(76, 31), - // (82,31): error CS8652: The feature 'default interface implementation' is not available in C# 7.3. Please use language version 8.0 or greater. + // (82,31): error CS8370: Feature 'default interface implementation' is not available in C# 7.3. Please use language version 8.0 or greater. // public static I1 operator &(I1 x, I1 y) Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7_3, "&").WithArguments("default interface implementation", "8.0").WithLocation(82, 31), - // (88,31): error CS8652: The feature 'default interface implementation' is not available in C# 7.3. Please use language version 8.0 or greater. + // (88,31): error CS8370: Feature 'default interface implementation' is not available in C# 7.3. Please use language version 8.0 or greater. // public static I1 operator |(I1 x, I1 y) Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7_3, "|").WithArguments("default interface implementation", "8.0").WithLocation(88, 31), - // (94,31): error CS8652: The feature 'default interface implementation' is not available in C# 7.3. Please use language version 8.0 or greater. + // (94,31): error CS8370: Feature 'default interface implementation' is not available in C# 7.3. Please use language version 8.0 or greater. // public static I1 operator ^(I1 x, I1 y) Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7_3, "^").WithArguments("default interface implementation", "8.0").WithLocation(94, 31), - // (100,31): error CS8652: The feature 'default interface implementation' is not available in C# 7.3. Please use language version 8.0 or greater. + // (100,31): error CS8370: Feature 'default interface implementation' is not available in C# 7.3. Please use language version 8.0 or greater. // public static I1 operator <<(I1 x, int y) Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7_3, "<<").WithArguments("default interface implementation", "8.0").WithLocation(100, 31), - // (106,31): error CS8652: The feature 'default interface implementation' is not available in C# 7.3. Please use language version 8.0 or greater. + // (106,31): error CS8370: Feature 'default interface implementation' is not available in C# 7.3. Please use language version 8.0 or greater. // public static I1 operator >>(I1 x, int y) Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7_3, ">>").WithArguments("default interface implementation", "8.0").WithLocation(106, 31), - // (112,31): error CS8652: The feature 'default interface implementation' is not available in C# 7.3. Please use language version 8.0 or greater. + // (112,31): error CS8370: Feature 'default interface implementation' is not available in C# 7.3. Please use language version 8.0 or greater. // public static I1 operator >(I1 x, I1 y) Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7_3, ">").WithArguments("default interface implementation", "8.0").WithLocation(112, 31), - // (118,31): error CS8652: The feature 'default interface implementation' is not available in C# 7.3. Please use language version 8.0 or greater. + // (118,31): error CS8370: Feature 'default interface implementation' is not available in C# 7.3. Please use language version 8.0 or greater. // public static I1 operator <(I1 x, I1 y) Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7_3, "<").WithArguments("default interface implementation", "8.0").WithLocation(118, 31), - // (124,31): error CS8652: The feature 'default interface implementation' is not available in C# 7.3. Please use language version 8.0 or greater. + // (124,31): error CS8370: Feature 'default interface implementation' is not available in C# 7.3. Please use language version 8.0 or greater. // public static I1 operator >=(I1 x, I1 y) Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7_3, ">=").WithArguments("default interface implementation", "8.0").WithLocation(124, 31), - // (130,31): error CS8652: The feature 'default interface implementation' is not available in C# 7.3. Please use language version 8.0 or greater. + // (130,31): error CS8370: Feature 'default interface implementation' is not available in C# 7.3. Please use language version 8.0 or greater. // public static I1 operator <=(I1 x, I1 y) Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7_3, "<=").WithArguments("default interface implementation", "8.0").WithLocation(130, 31), - // (136,31): error CS8652: The feature 'unsigned right shift' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // (136,31): error CS8370: Feature 'unsigned right shift' is not available in C# 7.3. Please use language version 11.0 or greater. // public static I1 operator >>>(I1 x, int y) - Diagnostic(ErrorCode.ERR_FeatureInPreview, ">>>").WithArguments("unsigned right shift").WithLocation(136, 31), + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7_3, ">>>").WithArguments("unsigned right shift", "11.0").WithLocation(136, 31), // (136,31): error CS8370: Feature 'default interface implementation' is not available in C# 7.3. Please use language version 8.0 or greater. // public static I1 operator >>>(I1 x, int y) Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7_3, ">>>").WithArguments("default interface implementation", "8.0").WithLocation(136, 31) @@ -46494,75 +46590,75 @@ static void Main() var expected7 = new DiagnosticDescription[] { - // (9,13): error CS8652: The feature 'default interface implementation' is not available in C# 7.3. Please use language version 8.0 or greater. + // (9,13): error CS8370: Feature 'default interface implementation' is not available in C# 7.3. Please use language version 8.0 or greater. // x = +x; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7_3, "+x").WithArguments("default interface implementation", "8.0").WithLocation(9, 13), - // (10,13): error CS8652: The feature 'default interface implementation' is not available in C# 7.3. Please use language version 8.0 or greater. + // (10,13): error CS8370: Feature 'default interface implementation' is not available in C# 7.3. Please use language version 8.0 or greater. // x = -x; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7_3, "-x").WithArguments("default interface implementation", "8.0").WithLocation(10, 13), - // (11,13): error CS8652: The feature 'default interface implementation' is not available in C# 7.3. Please use language version 8.0 or greater. + // (11,13): error CS8370: Feature 'default interface implementation' is not available in C# 7.3. Please use language version 8.0 or greater. // x = !x; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7_3, "!x").WithArguments("default interface implementation", "8.0").WithLocation(11, 13), - // (12,13): error CS8652: The feature 'default interface implementation' is not available in C# 7.3. Please use language version 8.0 or greater. + // (12,13): error CS8370: Feature 'default interface implementation' is not available in C# 7.3. Please use language version 8.0 or greater. // x = ~x; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7_3, "~x").WithArguments("default interface implementation", "8.0").WithLocation(12, 13), - // (13,13): error CS8652: The feature 'default interface implementation' is not available in C# 7.3. Please use language version 8.0 or greater. + // (13,13): error CS8370: Feature 'default interface implementation' is not available in C# 7.3. Please use language version 8.0 or greater. // x = ++x; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7_3, "++x").WithArguments("default interface implementation", "8.0").WithLocation(13, 13), - // (14,13): error CS8652: The feature 'default interface implementation' is not available in C# 7.3. Please use language version 8.0 or greater. + // (14,13): error CS8370: Feature 'default interface implementation' is not available in C# 7.3. Please use language version 8.0 or greater. // x = x--; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7_3, "x--").WithArguments("default interface implementation", "8.0").WithLocation(14, 13), - // (16,13): error CS8652: The feature 'default interface implementation' is not available in C# 7.3. Please use language version 8.0 or greater. + // (16,13): error CS8370: Feature 'default interface implementation' is not available in C# 7.3. Please use language version 8.0 or greater. // x = x + y; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7_3, "x + y").WithArguments("default interface implementation", "8.0").WithLocation(16, 13), - // (17,13): error CS8652: The feature 'default interface implementation' is not available in C# 7.3. Please use language version 8.0 or greater. + // (17,13): error CS8370: Feature 'default interface implementation' is not available in C# 7.3. Please use language version 8.0 or greater. // x = x - y; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7_3, "x - y").WithArguments("default interface implementation", "8.0").WithLocation(17, 13), - // (18,13): error CS8652: The feature 'default interface implementation' is not available in C# 7.3. Please use language version 8.0 or greater. + // (18,13): error CS8370: Feature 'default interface implementation' is not available in C# 7.3. Please use language version 8.0 or greater. // x = x * y; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7_3, "x * y").WithArguments("default interface implementation", "8.0").WithLocation(18, 13), - // (19,13): error CS8652: The feature 'default interface implementation' is not available in C# 7.3. Please use language version 8.0 or greater. + // (19,13): error CS8370: Feature 'default interface implementation' is not available in C# 7.3. Please use language version 8.0 or greater. // x = x / y; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7_3, "x / y").WithArguments("default interface implementation", "8.0").WithLocation(19, 13), - // (20,13): error CS8652: The feature 'default interface implementation' is not available in C# 7.3. Please use language version 8.0 or greater. + // (20,13): error CS8370: Feature 'default interface implementation' is not available in C# 7.3. Please use language version 8.0 or greater. // x = x % y; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7_3, "x % y").WithArguments("default interface implementation", "8.0").WithLocation(20, 13), - // (21,13): error CS8652: The feature 'default interface implementation' is not available in C# 7.3. Please use language version 8.0 or greater. + // (21,13): error CS8370: Feature 'default interface implementation' is not available in C# 7.3. Please use language version 8.0 or greater. // if (x && y) { } Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7_3, "x && y").WithArguments("default interface implementation", "8.0").WithLocation(21, 13), - // (21,13): error CS8652: The feature 'default interface implementation' is not available in C# 7.3. Please use language version 8.0 or greater. + // (21,13): error CS8370: Feature 'default interface implementation' is not available in C# 7.3. Please use language version 8.0 or greater. // if (x && y) { } Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7_3, "x && y").WithArguments("default interface implementation", "8.0").WithLocation(21, 13), - // (22,13): error CS8652: The feature 'default interface implementation' is not available in C# 7.3. Please use language version 8.0 or greater. + // (22,13): error CS8370: Feature 'default interface implementation' is not available in C# 7.3. Please use language version 8.0 or greater. // x = x | y; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7_3, "x | y").WithArguments("default interface implementation", "8.0").WithLocation(22, 13), - // (23,13): error CS8652: The feature 'default interface implementation' is not available in C# 7.3. Please use language version 8.0 or greater. + // (23,13): error CS8370: Feature 'default interface implementation' is not available in C# 7.3. Please use language version 8.0 or greater. // x = x ^ y; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7_3, "x ^ y").WithArguments("default interface implementation", "8.0").WithLocation(23, 13), - // (24,13): error CS8652: The feature 'default interface implementation' is not available in C# 7.3. Please use language version 8.0 or greater. + // (24,13): error CS8370: Feature 'default interface implementation' is not available in C# 7.3. Please use language version 8.0 or greater. // x = x << 1; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7_3, "x << 1").WithArguments("default interface implementation", "8.0").WithLocation(24, 13), - // (25,13): error CS8652: The feature 'default interface implementation' is not available in C# 7.3. Please use language version 8.0 or greater. + // (25,13): error CS8370: Feature 'default interface implementation' is not available in C# 7.3. Please use language version 8.0 or greater. // x = x >> 2; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7_3, "x >> 2").WithArguments("default interface implementation", "8.0").WithLocation(25, 13), - // (26,13): error CS8652: The feature 'default interface implementation' is not available in C# 7.3. Please use language version 8.0 or greater. + // (26,13): error CS8370: Feature 'default interface implementation' is not available in C# 7.3. Please use language version 8.0 or greater. // x = x > y; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7_3, "x > y").WithArguments("default interface implementation", "8.0").WithLocation(26, 13), - // (27,13): error CS8652: The feature 'default interface implementation' is not available in C# 7.3. Please use language version 8.0 or greater. + // (27,13): error CS8370: Feature 'default interface implementation' is not available in C# 7.3. Please use language version 8.0 or greater. // x = x < y; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7_3, "x < y").WithArguments("default interface implementation", "8.0").WithLocation(27, 13), - // (28,13): error CS8652: The feature 'default interface implementation' is not available in C# 7.3. Please use language version 8.0 or greater. + // (28,13): error CS8370: Feature 'default interface implementation' is not available in C# 7.3. Please use language version 8.0 or greater. // x = x >= y; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7_3, "x >= y").WithArguments("default interface implementation", "8.0").WithLocation(28, 13), - // (29,13): error CS8652: The feature 'default interface implementation' is not available in C# 7.3. Please use language version 8.0 or greater. + // (29,13): error CS8370: Feature 'default interface implementation' is not available in C# 7.3. Please use language version 8.0 or greater. // x = x <= y; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7_3, "x <= y").WithArguments("default interface implementation", "8.0").WithLocation(29, 13), // (31,13): error CS8370: Feature 'default interface implementation' is not available in C# 7.3. Please use language version 8.0 or greater. // x = x >>> 3; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7_3, "x >>> 3").WithArguments("default interface implementation", "8.0").WithLocation(31, 13), - // (31,13): error CS8652: The feature 'unsigned right shift' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // (31,13): error CS8370: Feature 'unsigned right shift' is not available in C# 7.3. Please use language version 11.0 or greater. // x = x >>> 3; - Diagnostic(ErrorCode.ERR_FeatureInPreview, "x >>> 3").WithArguments("unsigned right shift").WithLocation(31, 13) + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7_3, "x >>> 3").WithArguments("unsigned right shift", "11.0").WithLocation(31, 13) }; compilation7.VerifyDiagnostics(expected7); @@ -46726,12 +46822,12 @@ static void Main() // (10,31): error CS0567: Conversion, equality, or inequality operators declared in interfaces must be abstract or virtual // public static I1 operator !=(I1 x, I1 y) Diagnostic(ErrorCode.ERR_InterfacesCantContainConversionOrEqualityOperators, "!=").WithLocation(10, 31), - // (24,13): error CS8652: The feature 'static abstract members in interfaces' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // (24,13): error CS8773: Feature 'static abstract members in interfaces' is not available in C# 9.0. Please use language version 11.0 or greater. // x = x == y; - Diagnostic(ErrorCode.ERR_FeatureInPreview, "x == y").WithArguments("static abstract members in interfaces").WithLocation(24, 13), - // (25,13): error CS8652: The feature 'static abstract members in interfaces' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion9, "x == y").WithArguments("static abstract members in interfaces", "11.0").WithLocation(24, 13), + // (25,13): error CS8773: Feature 'static abstract members in interfaces' is not available in C# 9.0. Please use language version 11.0 or greater. // x = x != y; - Diagnostic(ErrorCode.ERR_FeatureInPreview, "x != y").WithArguments("static abstract members in interfaces").WithLocation(25, 13) + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion9, "x != y").WithArguments("static abstract members in interfaces", "11.0").WithLocation(25, 13) ); CreateCompilation(source1 + source2, options: TestOptions.DebugExe, targetFramework: TargetFramework.NetCoreApp, @@ -46752,12 +46848,12 @@ static void Main() CreateCompilation(source2, new[] { compilationReference }, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular9, targetFramework: TargetFramework.NetCoreApp).VerifyDiagnostics( - // (9,13): error CS8652: The feature 'static abstract members in interfaces' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // (9,13): error CS8773: Feature 'static abstract members in interfaces' is not available in C# 9.0. Please use language version 11.0 or greater. // x = x == y; - Diagnostic(ErrorCode.ERR_FeatureInPreview, "x == y").WithArguments("static abstract members in interfaces").WithLocation(9, 13), - // (10,13): error CS8652: The feature 'static abstract members in interfaces' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion9, "x == y").WithArguments("static abstract members in interfaces", "11.0").WithLocation(9, 13), + // (10,13): error CS8773: Feature 'static abstract members in interfaces' is not available in C# 9.0. Please use language version 11.0 or greater. // x = x != y; - Diagnostic(ErrorCode.ERR_FeatureInPreview, "x != y").WithArguments("static abstract members in interfaces").WithLocation(10, 13) + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion9, "x != y").WithArguments("static abstract members in interfaces", "11.0").WithLocation(10, 13) ); var ilSource = @" @@ -46811,12 +46907,12 @@ .locals init (class I1 V_0) ").VerifyDiagnostics(); CreateCompilationWithIL(source2, ilSource, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular9).VerifyDiagnostics( - // (9,13): error CS8652: The feature 'static abstract members in interfaces' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // (9,13): error CS8773: Feature 'static abstract members in interfaces' is not available in C# 9.0. Please use language version 11.0 or greater. // x = x == y; - Diagnostic(ErrorCode.ERR_FeatureInPreview, "x == y").WithArguments("static abstract members in interfaces").WithLocation(9, 13), - // (10,13): error CS8652: The feature 'static abstract members in interfaces' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion9, "x == y").WithArguments("static abstract members in interfaces", "11.0").WithLocation(9, 13), + // (10,13): error CS8773: Feature 'static abstract members in interfaces' is not available in C# 9.0. Please use language version 11.0 or greater. // x = x != y; - Diagnostic(ErrorCode.ERR_FeatureInPreview, "x != y").WithArguments("static abstract members in interfaces").WithLocation(10, 13) + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion9, "x != y").WithArguments("static abstract members in interfaces", "11.0").WithLocation(10, 13) ); var source3 = @@ -46843,12 +46939,12 @@ static void Main() "); CreateCompilationWithIL(source3, ilSource, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular9).VerifyDiagnostics( - // (9,34): error CS8652: The feature 'static abstract members in interfaces' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // (9,34): error CS8773: Feature 'static abstract members in interfaces' is not available in C# 9.0. Please use language version 11.0 or greater. // System.Console.WriteLine(x == y); - Diagnostic(ErrorCode.ERR_FeatureInPreview, "x == y").WithArguments("static abstract members in interfaces").WithLocation(9, 34), - // (10,34): error CS8652: The feature 'static abstract members in interfaces' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion9, "x == y").WithArguments("static abstract members in interfaces", "11.0").WithLocation(9, 34), + // (10,34): error CS8773: Feature 'static abstract members in interfaces' is not available in C# 9.0. Please use language version 11.0 or greater. // System.Console.WriteLine(x != y); - Diagnostic(ErrorCode.ERR_FeatureInPreview, "x != y").WithArguments("static abstract members in interfaces").WithLocation(10, 34) + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion9, "x != y").WithArguments("static abstract members in interfaces", "11.0").WithLocation(10, 34) ); } @@ -52211,12 +52307,12 @@ public interface I2 : I1 else { compilation1.VerifyDiagnostics( - // (4,26): error CS8703: The modifier 'abstract' is not valid for this item in C# 10.0. Please use language version 'preview' or greater. + // (4,26): error CS8703: The modifier 'abstract' is not valid for this item in C# 10.0. Please use language version '11.0' or greater. // static abstract void M1(); - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M1").WithArguments("abstract", "10.0", "preview").WithLocation(4, 26), - // (9,29): error CS8703: The modifier 'static' is not valid for this item in C# 10.0. Please use language version 'preview' or greater. + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M1").WithArguments("abstract", "10.0", "11.0").WithLocation(4, 26), + // (9,29): error CS8703: The modifier 'static' is not valid for this item in C# 10.0. Please use language version '11.0' or greater. // static abstract void I1.M1(); - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M1").WithArguments("static", "10.0", "preview").WithLocation(9, 29) + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M1").WithArguments("static", "10.0", "11.0").WithLocation(9, 29) ); } @@ -57053,12 +57149,12 @@ public interface I2 : I1 parseOptions: TestOptions.Regular10, targetFramework: TargetFramework.Net60); compilation1.VerifyDiagnostics( - // (4,25): error CS8703: The modifier 'abstract' is not valid for this item in C# 10.0. Please use language version 'preview' or greater. + // (4,25): error CS8703: The modifier 'abstract' is not valid for this item in C# 10.0. Please use language version '11.0' or greater. // static abstract int P1 {get; set;} - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "P1").WithArguments("abstract", "10.0", "preview").WithLocation(4, 25), - // (9,28): error CS8703: The modifier 'static' is not valid for this item in C# 10.0. Please use language version 'preview' or greater. + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "P1").WithArguments("abstract", "10.0", "11.0").WithLocation(4, 25), + // (9,28): error CS8703: The modifier 'static' is not valid for this item in C# 10.0. Please use language version '11.0' or greater. // static abstract int I1.P1 {get; set;} - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "P1").WithArguments("static", "10.0", "preview").WithLocation(9, 28) + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "P1").WithArguments("static", "10.0", "11.0").WithLocation(9, 28) ); var compilation2 = CreateCompilation(source1, options: TestOptions.DebugDll, @@ -57132,12 +57228,12 @@ public interface I2 : I1 parseOptions: TestOptions.Regular10, targetFramework: TargetFramework.Net60); compilation1.VerifyDiagnostics( - // (4,25): error CS8703: The modifier 'abstract' is not valid for this item in C# 10.0. Please use language version 'preview' or greater. + // (4,25): error CS8703: The modifier 'abstract' is not valid for this item in C# 10.0. Please use language version '11.0' or greater. // static abstract int P1 {get;} - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "P1").WithArguments("abstract", "10.0", "preview").WithLocation(4, 25), - // (9,28): error CS8703: The modifier 'static' is not valid for this item in C# 10.0. Please use language version 'preview' or greater. + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "P1").WithArguments("abstract", "10.0", "11.0").WithLocation(4, 25), + // (9,28): error CS8703: The modifier 'static' is not valid for this item in C# 10.0. Please use language version '11.0' or greater. // static abstract int I1.P1 {get;} - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "P1").WithArguments("static", "10.0", "preview").WithLocation(9, 28) + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "P1").WithArguments("static", "10.0", "11.0").WithLocation(9, 28) ); var compilation2 = CreateCompilation(source1, options: TestOptions.DebugDll, @@ -57208,12 +57304,12 @@ public interface I2 : I1 parseOptions: TestOptions.Regular10, targetFramework: TargetFramework.Net60); compilation1.VerifyDiagnostics( - // (4,25): error CS8703: The modifier 'abstract' is not valid for this item in C# 10.0. Please use language version 'preview' or greater. + // (4,25): error CS8703: The modifier 'abstract' is not valid for this item in C# 10.0. Please use language version '11.0' or greater. // static abstract int P1 {set;} - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "P1").WithArguments("abstract", "10.0", "preview").WithLocation(4, 25), - // (9,28): error CS8703: The modifier 'static' is not valid for this item in C# 10.0. Please use language version 'preview' or greater. + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "P1").WithArguments("abstract", "10.0", "11.0").WithLocation(4, 25), + // (9,28): error CS8703: The modifier 'static' is not valid for this item in C# 10.0. Please use language version '11.0' or greater. // static abstract int I1.P1 {set;} - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "P1").WithArguments("static", "10.0", "preview").WithLocation(9, 28) + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "P1").WithArguments("static", "10.0", "11.0").WithLocation(9, 28) ); var compilation2 = CreateCompilation(source1, options: TestOptions.DebugDll, @@ -59242,12 +59338,12 @@ public interface I2 : I1 parseOptions: TestOptions.Regular10, targetFramework: TargetFramework.Net60); compilation1.VerifyDiagnostics( - // (4,41): error CS8703: The modifier 'abstract' is not valid for this item in C# 10.0. Please use language version 'preview' or greater. + // (4,41): error CS8703: The modifier 'abstract' is not valid for this item in C# 10.0. Please use language version '11.0' or greater. // static abstract event System.Action P1; - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "P1").WithArguments("abstract", "10.0", "preview").WithLocation(4, 41), - // (9,44): error CS8703: The modifier 'static' is not valid for this item in C# 10.0. Please use language version 'preview' or greater. + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "P1").WithArguments("abstract", "10.0", "11.0").WithLocation(4, 41), + // (9,44): error CS8703: The modifier 'static' is not valid for this item in C# 10.0. Please use language version '11.0' or greater. // static abstract event System.Action I1.P1; - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "P1").WithArguments("static", "10.0", "preview").WithLocation(9, 44) + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "P1").WithArguments("static", "10.0", "11.0").WithLocation(9, 44) ); var compilation2 = CreateCompilation(source1, options: TestOptions.DebugDll, @@ -68279,35 +68375,35 @@ static void Test(i2 a, i4 b) where i2 : I2 where i4 : I4 if (op is not ("implicit" or "explicit")) { compilation1.VerifyDiagnostics( - // (4,33): error CS8703: The modifier 'abstract' is not valid for this item in C# 10.0. Please use language version 'preview' or greater. - // static abstract T2 operator +(T2 x, int y); - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, op).WithArguments("abstract", "10.0", "preview").WithLocation(4, 33), - // (9,33): error CS8703: The modifier 'abstract' is not valid for this item in C# 10.0. Please use language version 'preview' or greater. - // static abstract T4 operator +(T4 x, int y); - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, op).WithArguments("abstract", "10.0", "preview").WithLocation(9, 33), - // (18,15): error CS8652: The feature 'static abstract members in interfaces' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. - // static T1 I2.operator +(T1 x, int y) - Diagnostic(ErrorCode.ERR_FeatureInPreview, "I2.").WithArguments("static abstract members in interfaces").WithLocation(18, 15), - // (23,15): error CS8652: The feature 'static abstract members in interfaces' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. - // static T1 I4.operator +(T1 x, int y) - Diagnostic(ErrorCode.ERR_FeatureInPreview, "I4.").WithArguments("static abstract members in interfaces").WithLocation(23, 15) + // (4,33): error CS8703: The modifier 'abstract' is not valid for this item in C# 10.0. Please use language version '11.0' or greater. + // static abstract T2 operator >>(T2 x, int y); + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, op).WithArguments("abstract", "10.0", "11.0").WithLocation(4, 33), + // (9,33): error CS8703: The modifier 'abstract' is not valid for this item in C# 10.0. Please use language version '11.0' or greater. + // static abstract T4 operator >>(T4 x, int y); + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, op).WithArguments("abstract", "10.0", "11.0").WithLocation(9, 33), + // (18,15): error CS8936: Feature 'static abstract members in interfaces' is not available in C# 10.0. Please use language version 11.0 or greater. + // static T1 I2.operator >>(T1 x, int y) + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "I2.").WithArguments("static abstract members in interfaces", "11.0").WithLocation(18, 15), + // (23,15): error CS8936: Feature 'static abstract members in interfaces' is not available in C# 10.0. Please use language version 11.0 or greater. + // static T1 I4.operator >>(T1 x, int y) + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "I4.").WithArguments("static abstract members in interfaces", "11.0").WithLocation(23, 15) ); } else { compilation1.VerifyDiagnostics( - // (4,39): error CS8703: The modifier 'abstract' is not valid for this item in C# 10.0. Please use language version 'preview' or greater. + // (4,39): error CS8703: The modifier 'abstract' is not valid for this item in C# 10.0. Please use language version '11.0' or greater. // static abstract implicit operator int(T2 x); - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "int").WithArguments("abstract", "10.0", "preview").WithLocation(4, 39), - // (9,39): error CS8703: The modifier 'abstract' is not valid for this item in C# 10.0. Please use language version 'preview' or greater. + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "int").WithArguments("abstract", "10.0", "11.0").WithLocation(4, 39), + // (9,39): error CS8703: The modifier 'abstract' is not valid for this item in C# 10.0. Please use language version '11.0' or greater. // static abstract implicit operator int(T4 x); - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "int").WithArguments("abstract", "10.0", "preview").WithLocation(9, 39), - // (18,21): error CS8652: The feature 'static abstract members in interfaces' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "int").WithArguments("abstract", "10.0", "11.0").WithLocation(9, 39), + // (18,21): error CS8936: Feature 'static abstract members in interfaces' is not available in C# 10.0. Please use language version 11.0 or greater. // static implicit I2.operator int(T1 x) - Diagnostic(ErrorCode.ERR_FeatureInPreview, "I2.").WithArguments("static abstract members in interfaces").WithLocation(18, 21), - // (23,21): error CS8652: The feature 'static abstract members in interfaces' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "I2.").WithArguments("static abstract members in interfaces", "11.0").WithLocation(18, 21), + // (23,21): error CS8936: Feature 'static abstract members in interfaces' is not available in C# 10.0. Please use language version 11.0 or greater. // static implicit I4.operator int(T1 x) - Diagnostic(ErrorCode.ERR_FeatureInPreview, "I4.").WithArguments("static abstract members in interfaces").WithLocation(23, 21) + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "I4.").WithArguments("static abstract members in interfaces", "11.0").WithLocation(23, 21) ); } diff --git a/src/Compilers/CSharp/Test/Symbol/Symbols/EnumTests.cs b/src/Compilers/CSharp/Test/Symbol/Symbols/EnumTests.cs index 44c3121545ded..e615c2da0e765 100644 --- a/src/Compilers/CSharp/Test/Symbol/Symbols/EnumTests.cs +++ b/src/Compilers/CSharp/Test/Symbol/Symbols/EnumTests.cs @@ -399,5 +399,17 @@ static void Main() Diagnostic(ErrorCode.ERR_NoTypeDef, "F").WithArguments("A", "UseSiteError_sourceA, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null").WithLocation(5, 20) ); } + + [Fact] + public void PartialPublicEnum() + { + CreateCompilation("partial public enum E { }").VerifyDiagnostics( + // (1,1): error CS0267: The 'partial' modifier can only appear immediately before 'class', 'record', 'struct', 'interface', or a method return type. + // partial public enum E { } + Diagnostic(ErrorCode.ERR_PartialMisplaced, "partial").WithLocation(1, 1), + // (1,21): error CS0267: The 'partial' modifier can only appear immediately before 'class', 'record', 'struct', 'interface', or a method return type. + // partial public enum E { } + Diagnostic(ErrorCode.ERR_PartialMisplaced, "E").WithLocation(1, 21)); + } } } diff --git a/src/Compilers/CSharp/Test/Symbol/Symbols/LocalFunctionTests.cs b/src/Compilers/CSharp/Test/Symbol/Symbols/LocalFunctionTests.cs index 5b8464902e893..d00b5f4beaefd 100644 --- a/src/Compilers/CSharp/Test/Symbol/Symbols/LocalFunctionTests.cs +++ b/src/Compilers/CSharp/Test/Symbol/Symbols/LocalFunctionTests.cs @@ -102,5 +102,92 @@ static void staticLocal() {} var staticLocal = semanticModel.GetDeclaredSymbol(localsSyntax[0]).GetSymbol(); Assert.False(staticLocal.RequiresInstanceReceiver); } + + [Fact] + public void PartialStaticLocalFunction() + { + CreateCompilation(""" + public class C + { + public void M() + { + partial static void local() { } + } + } + """).VerifyDiagnostics( + // (5,9): error CS0103: The name 'partial' does not exist in the current context + // partial static void local() { } + Diagnostic(ErrorCode.ERR_NameNotInContext, "partial").WithArguments("partial").WithLocation(5, 9), + // (5,17): error CS1002: ; expected + // partial static void local() { } + Diagnostic(ErrorCode.ERR_SemicolonExpected, "static").WithLocation(5, 17), + // (5,29): warning CS8321: The local function 'local' is declared but never used + // partial static void local() { } + Diagnostic(ErrorCode.WRN_UnreferencedLocalFunction, "local").WithArguments("local").WithLocation(5, 29)); + } + + [Fact] + public void StaticPartialLocalFunction() + { + CreateCompilation(""" + public class C + { + public void M() + { + static partial void local() { } + } + } + """).VerifyDiagnostics( + // (5,9): error CS0106: The modifier 'static' is not valid for this item + // static partial void local() { } + Diagnostic(ErrorCode.ERR_BadMemberFlag, "static").WithArguments("static").WithLocation(5, 9), + // (5,16): error CS1031: Type expected + // static partial void local() { } + Diagnostic(ErrorCode.ERR_TypeExpected, "partial").WithLocation(5, 16), + // (5,16): error CS1525: Invalid expression term 'partial' + // static partial void local() { } + Diagnostic(ErrorCode.ERR_InvalidExprTerm, "partial").WithArguments("partial").WithLocation(5, 16), + // (5,16): error CS1002: ; expected + // static partial void local() { } + Diagnostic(ErrorCode.ERR_SemicolonExpected, "partial").WithLocation(5, 16), + // (5,16): error CS1513: } expected + // static partial void local() { } + Diagnostic(ErrorCode.ERR_RbraceExpected, "partial").WithLocation(5, 16), + // (5,29): error CS0759: No defining declaration found for implementing declaration of partial method 'C.local()' + // static partial void local() { } + Diagnostic(ErrorCode.ERR_PartialMethodMustHaveLatent, "local").WithArguments("C.local()").WithLocation(5, 29), + // (5,29): error CS0751: A partial method must be declared within a partial type + // static partial void local() { } + Diagnostic(ErrorCode.ERR_PartialMethodOnlyInPartialClass, "local").WithLocation(5, 29), + // (7,1): error CS1022: Type or namespace definition, or end-of-file expected + // } + Diagnostic(ErrorCode.ERR_EOFExpected, "}").WithLocation(7, 1)); + } + + [Fact] + public void PartialLocalFunction() + { + CreateCompilation(""" + public class C + { + public void M() + { + partial void local() { } + } + } + """).VerifyDiagnostics( + // (4,6): error CS1513: } expected + // { + Diagnostic(ErrorCode.ERR_RbraceExpected, "").WithLocation(4, 6), + // (5,22): error CS0759: No defining declaration found for implementing declaration of partial method 'C.local()' + // partial void local() { } + Diagnostic(ErrorCode.ERR_PartialMethodMustHaveLatent, "local").WithArguments("C.local()").WithLocation(5, 22), + // (5,22): error CS0751: A partial method must be declared within a partial type + // partial void local() { } + Diagnostic(ErrorCode.ERR_PartialMethodOnlyInPartialClass, "local").WithLocation(5, 22), + // (7,1): error CS1022: Type or namespace definition, or end-of-file expected + // } + Diagnostic(ErrorCode.ERR_EOFExpected, "}").WithLocation(7, 1)); + } } } diff --git a/src/Compilers/CSharp/Test/Symbol/Symbols/Metadata/PE/NoPia.cs b/src/Compilers/CSharp/Test/Symbol/Symbols/Metadata/PE/NoPia.cs index 0bbb6d2adf896..57973c529c8f4 100644 --- a/src/Compilers/CSharp/Test/Symbol/Symbols/Metadata/PE/NoPia.cs +++ b/src/Compilers/CSharp/Test/Symbol/Symbols/Metadata/PE/NoPia.cs @@ -1348,5 +1348,77 @@ public void GenericsClosedOverLocalTypes6() GC.KeepAlive(tc6); GC.KeepAlive(tc7); } + + [Fact] + [WorkItem(62863, "https://github.com/dotnet/roslyn/issues/62863")] + public void ExplicitInterfaceImplementations() + { + var sourcePIA = +@"using System.Runtime.InteropServices; +[assembly: PrimaryInteropAssembly(0, 0)] +[assembly: Guid(""863D5BC0-46A1-49AC-97AA-A5F0D441A9DA"")] +[ComImport] +[Guid(""863D5BC0-46A1-49AD-97AA-A5F0D441A9DA"")] +public interface I1 +{ + int F1(); +} +"; + var sourceBase = +@" +public class C +{ + public long F1() => 0; +} + +public class Base : C, I1 +{ + int I1.F1() + { + throw new System.NotImplementedException(); + } +} +"; + var compilationPIA = CreateCompilation(sourcePIA, options: TestOptions.DebugDll); + compilationPIA.VerifyDiagnostics(); + + var referencePIAImage = compilationPIA.EmitToImageReference(embedInteropTypes: true); + var referencePIASource = compilationPIA.ToMetadataReference(embedInteropTypes: true); + + var compilationBase = CreateCompilation(sourceBase, new[] { referencePIASource }, TestOptions.DebugDll); + compilationBase.VerifyDiagnostics(); + + var referenceBaseImage = compilationBase.EmitToImageReference(); + var referenceBaseSource = compilationBase.ToMetadataReference(); + + var sourceDerived = +@" +public interface I2 : I1 +{ } + +public class Derived : Base, I2 +{ +} +"; + var compilationDerived1 = CreateCompilation(sourceDerived, new[] { referencePIASource, referenceBaseSource }, TestOptions.DebugDll); + verify(compilationDerived1); + + var compilationDerived2 = CreateCompilation(sourceDerived, new[] { referencePIAImage, referenceBaseSource }, TestOptions.DebugDll); + verify(compilationDerived2); + + var compilationDerived3 = CreateCompilation(sourceDerived, new[] { referencePIASource, referenceBaseImage }, TestOptions.DebugDll); + verify(compilationDerived3); + + var compilationDerived4 = CreateCompilation(sourceDerived, new[] { referencePIAImage, referenceBaseImage }, TestOptions.DebugDll); + verify(compilationDerived4); + + static void verify(CSharpCompilation compilationDerived) + { + var i1F1 = compilationDerived.GetTypeByMetadataName("I1").GetMember("F1"); + var baseI1F1 = compilationDerived.GetTypeByMetadataName("Base").GetMember("I1.F1"); + Assert.Same(i1F1, baseI1F1.ExplicitInterfaceImplementations.Single()); + compilationDerived.VerifyDiagnostics(); + } + } } } diff --git a/src/Compilers/CSharp/Test/Symbol/Symbols/Metadata/PE/NoPiaLocalHideAndTypeSubstitutionTests.cs b/src/Compilers/CSharp/Test/Symbol/Symbols/Metadata/PE/NoPiaLocalHideAndTypeSubstitutionTests.cs index 036d09f20a28a..e308985034580 100644 --- a/src/Compilers/CSharp/Test/Symbol/Symbols/Metadata/PE/NoPiaLocalHideAndTypeSubstitutionTests.cs +++ b/src/Compilers/CSharp/Test/Symbol/Symbols/Metadata/PE/NoPiaLocalHideAndTypeSubstitutionTests.cs @@ -349,7 +349,9 @@ public void NoPIATypeSubstitutionForMethodExplicitlyImplementNoPiaInterface() NamedTypeSymbol classRefLocalType = localConsumerRefsAsm.First(arg => arg.Name == "ExternalAsm1").GlobalNamespace.GetTypeMembers("SubFuncProp").Single(); MethodSymbol methodSymbol = classRefLocalType.GetMembers("Foo").OfType().Single(); - Assert.Equal(0, methodSymbol.ExplicitInterfaceImplementations.Length); + MethodSymbol explicitImpl = methodSymbol.ExplicitInterfaceImplementations.Single(); + Assert.Equal("void ISubFuncProp.Foo(System.Int32[missing] p)", explicitImpl.ToTestDisplayString()); + Assert.Same(canonicalType, explicitImpl.ContainingType); } [Fact] diff --git a/src/Compilers/CSharp/Test/Symbol/Symbols/MissingSpecialMember.cs b/src/Compilers/CSharp/Test/Symbol/Symbols/MissingSpecialMember.cs index e61298854268a..87652853a79d2 100644 --- a/src/Compilers/CSharp/Test/Symbol/Symbols/MissingSpecialMember.cs +++ b/src/Compilers/CSharp/Test/Symbol/Symbols/MissingSpecialMember.cs @@ -614,9 +614,11 @@ public void AllWellKnownTypes() case WellKnownType.System_Runtime_CompilerServices_DefaultInterpolatedStringHandler: case WellKnownType.System_Runtime_CompilerServices_RequiredMemberAttribute: case WellKnownType.System_Diagnostics_CodeAnalysis_SetsRequiredMembersAttribute: - case WellKnownType.System_Runtime_CompilerServices_LifetimeAnnotationAttribute: + case WellKnownType.System_Runtime_CompilerServices_ScopedRefAttribute: case WellKnownType.System_MemoryExtensions: case WellKnownType.System_Runtime_CompilerServices_CompilerFeatureRequiredAttribute: + case WellKnownType.System_Diagnostics_CodeAnalysis_UnscopedRefAttribute: + case WellKnownType.System_Runtime_CompilerServices_MetadataUpdateOriginalTypeAttribute: // Not yet in the platform. continue; case WellKnownType.Microsoft_CodeAnalysis_Runtime_Instrumentation: @@ -976,11 +978,13 @@ public void AllWellKnownTypeMembers() case WellKnownMember.System_Runtime_CompilerServices_DefaultInterpolatedStringHandler__ToStringAndClear: case WellKnownMember.System_Runtime_CompilerServices_RequiredMemberAttribute__ctor: case WellKnownMember.System_Diagnostics_CodeAnalysis_SetsRequiredMembersAttribute__ctor: - case WellKnownMember.System_Runtime_CompilerServices_LifetimeAnnotationAttribute__ctor: + case WellKnownMember.System_Runtime_CompilerServices_ScopedRefAttribute__ctor: case WellKnownMember.System_MemoryExtensions__SequenceEqual_Span_T: case WellKnownMember.System_MemoryExtensions__SequenceEqual_ReadOnlySpan_T: case WellKnownMember.System_MemoryExtensions__AsSpan_String: case WellKnownMember.System_Runtime_CompilerServices_CompilerFeatureRequiredAttribute__ctor: + case WellKnownMember.System_Diagnostics_CodeAnalysis_UnscopedRefAttribute__ctor: + case WellKnownMember.System_Runtime_CompilerServices_MetadataUpdateOriginalTypeAttribute__ctor: // Not yet in the platform. continue; case WellKnownMember.Microsoft_CodeAnalysis_Runtime_Instrumentation__CreatePayloadForMethodsSpanningSingleFile: diff --git a/src/Compilers/CSharp/Test/Symbol/Symbols/MockNamedTypeSymbol.cs b/src/Compilers/CSharp/Test/Symbol/Symbols/MockNamedTypeSymbol.cs index d5e358d3b6939..db91e25e01b09 100644 --- a/src/Compilers/CSharp/Test/Symbol/Symbols/MockNamedTypeSymbol.cs +++ b/src/Compilers/CSharp/Test/Symbol/Symbols/MockNamedTypeSymbol.cs @@ -44,6 +44,8 @@ internal override bool MangleName } } + internal override SyntaxTree AssociatedSyntaxTree => null; + public override ImmutableArray TypeParameters { get diff --git a/src/Compilers/CSharp/Test/Symbol/Symbols/ModuleInitializers/SignatureTests.cs b/src/Compilers/CSharp/Test/Symbol/Symbols/ModuleInitializers/SignatureTests.cs index 9b43aac386a25..d15621ed9b810 100644 --- a/src/Compilers/CSharp/Test/Symbol/Symbols/ModuleInitializers/SignatureTests.cs +++ b/src/Compilers/CSharp/Test/Symbol/Symbols/ModuleInitializers/SignatureTests.cs @@ -32,7 +32,7 @@ namespace System.Runtime.CompilerServices { class ModuleInitializerAttribute : S "; var compilation = CreateCompilation(source, parseOptions: s_parseOptions); compilation.VerifyEmitDiagnostics( - // (6,6): error CS8815: Module initializer method 'M' must be static, must have no parameters, and must return 'void' + // (6,6): error CS8815: Module initializer method 'M' must be static, and non-virtual, must have no parameters, and must return 'void' // [ModuleInitializer] Diagnostic(ErrorCode.ERR_ModuleInitializerMethodMustBeStaticParameterlessVoid, "ModuleInitializer").WithArguments("M").WithLocation(6, 6) ); @@ -55,10 +55,10 @@ internal void M2() { } "; var compilation = CreateCompilation(source, parseOptions: s_parseOptions, targetFramework: TargetFramework.NetCoreApp); compilation.VerifyEmitDiagnostics( - // (6,6): error CS8815: Module initializer method 'M1' must be static, must have no parameters, and must return 'void' + // (6,6): error CS8815: Module initializer method 'M1' must be static, and non-virtual, must have no parameters, and must return 'void' // [ModuleInitializer] Diagnostic(ErrorCode.ERR_ModuleInitializerMethodMustBeStaticParameterlessVoid, "ModuleInitializer").WithArguments("M1").WithLocation(6, 6), - // (9,6): error CS8815: Module initializer method 'M2' must be static, must have no parameters, and must return 'void' + // (9,6): error CS8815: Module initializer method 'M2' must be static, and non-virtual, must have no parameters, and must return 'void' // [ModuleInitializer] Diagnostic(ErrorCode.ERR_ModuleInitializerMethodMustBeStaticParameterlessVoid, "ModuleInitializer").WithArguments("M2").WithLocation(9, 6) ); @@ -80,7 +80,7 @@ namespace System.Runtime.CompilerServices { class ModuleInitializerAttribute : S "; var compilation = CreateCompilation(source, parseOptions: s_parseOptions); compilation.VerifyEmitDiagnostics( - // (6,6): error CS8815: Module initializer method 'M' must be static, must have no parameters, and must return 'void' + // (6,6): error CS8815: Module initializer method 'M' must be static, and non-virtual, must have no parameters, and must return 'void' // [ModuleInitializer] Diagnostic(ErrorCode.ERR_ModuleInitializerMethodMustBeStaticParameterlessVoid, "ModuleInitializer").WithArguments("M").WithLocation(6, 6) ); @@ -102,7 +102,7 @@ namespace System.Runtime.CompilerServices { class ModuleInitializerAttribute : S "; var compilation = CreateCompilation(source, parseOptions: s_parseOptions); compilation.VerifyEmitDiagnostics( - // (6,6): error CS8815: Module initializer method 'M' must be static, must have no parameters, and must return 'void' + // (6,6): error CS8815: Module initializer method 'M' must be static, and non-virtual, must have no parameters, and must return 'void' // [ModuleInitializer] Diagnostic(ErrorCode.ERR_ModuleInitializerMethodMustBeStaticParameterlessVoid, "ModuleInitializer").WithArguments("M").WithLocation(6, 6) ); @@ -124,7 +124,7 @@ namespace System.Runtime.CompilerServices { class ModuleInitializerAttribute : S "; var compilation = CreateCompilation(source, parseOptions: s_parseOptions); compilation.VerifyEmitDiagnostics( - // (6,6): error CS8815: Module initializer method 'M' must be static, must have no parameters, and must return 'void' + // (6,6): error CS8815: Module initializer method 'M' must be static, and non-virtual, must have no parameters, and must return 'void' // [ModuleInitializer] Diagnostic(ErrorCode.ERR_ModuleInitializerMethodMustBeStaticParameterlessVoid, "ModuleInitializer").WithArguments("M").WithLocation(6, 6) ); @@ -146,7 +146,7 @@ namespace System.Runtime.CompilerServices { class ModuleInitializerAttribute : S "; var compilation = CreateCompilation(source, parseOptions: s_parseOptions); compilation.VerifyEmitDiagnostics( - // (6,6): error CS8815: Module initializer method 'M' must be static, must have no parameters, and must return 'void' + // (6,6): error CS8815: Module initializer method 'M' must be static, and non-virtual, must have no parameters, and must return 'void' // [ModuleInitializer] Diagnostic(ErrorCode.ERR_ModuleInitializerMethodMustBeStaticParameterlessVoid, "ModuleInitializer").WithArguments("M").WithLocation(6, 6) ); @@ -194,12 +194,52 @@ namespace System.Runtime.CompilerServices { class ModuleInitializerAttribute : S "; var compilation = CreateCompilation(source, parseOptions: s_parseOptions); compilation.VerifyEmitDiagnostics( - // (6,6): error CS8815: Module initializer method 'M' must be static, must have no parameters, and must return 'void' + // (6,6): error CS8815: Module initializer method 'M' must be static, and non-virtual, must have no parameters, and must return 'void' // [ModuleInitializer] Diagnostic(ErrorCode.ERR_ModuleInitializerMethodMustBeStaticParameterlessVoid, "ModuleInitializer").WithArguments("M").WithLocation(7, 6), // (8,32): warning CS1998: This async method lacks 'await' operators and will run synchronously. Consider using the 'await' operator to await non-blocking API calls, or 'await Task.Run(...)' to do CPU-bound work on a background thread. // internal static async Task M() { } Diagnostic(ErrorCode.WRN_AsyncLacksAwaits, "M").WithLocation(8, 32)); } + + [Fact] + public void MustNotBeAbstractMethod() + { + string source = @" +using System.Runtime.CompilerServices; + +interface C +{ + [ModuleInitializer] + public static abstract void M(); +} +"; + var compilation = CreateCompilation(source, targetFramework: StaticAbstractMembersInInterfacesTests._supportingFramework); + compilation.VerifyEmitDiagnostics( + // (6,6): error CS8815: Module initializer method 'M' must be static, and non-virtual, must have no parameters, and must return 'void' + // [ModuleInitializer] + Diagnostic(ErrorCode.ERR_ModuleInitializerMethodMustBeStaticParameterlessVoid, "ModuleInitializer").WithArguments("M").WithLocation(6, 6) + ); + } + + [Fact] + public void MustNotBeVirtualMethod() + { + string source = @" +using System.Runtime.CompilerServices; + +interface C +{ + [ModuleInitializer] + public static virtual void M() { } +} +"; + var compilation = CreateCompilation(source, targetFramework: StaticAbstractMembersInInterfacesTests._supportingFramework); + compilation.VerifyEmitDiagnostics( + // (6,6): error CS8815: Module initializer method 'M' must be static, and non-virtual, must have no parameters, and must return 'void' + // [ModuleInitializer] + Diagnostic(ErrorCode.ERR_ModuleInitializerMethodMustBeStaticParameterlessVoid, "ModuleInitializer").WithArguments("M").WithLocation(6, 6) + ); + } } } diff --git a/src/Compilers/CSharp/Test/Symbol/Symbols/RequiredMembersTests.cs b/src/Compilers/CSharp/Test/Symbol/Symbols/RequiredMembersTests.cs index 2ab22ec974805..e9fafc59148b8 100644 --- a/src/Compilers/CSharp/Test/Symbol/Symbols/RequiredMembersTests.cs +++ b/src/Compilers/CSharp/Test/Symbol/Symbols/RequiredMembersTests.cs @@ -56,14 +56,7 @@ private static Action ValidateRequiredMembersInModule(string[] mem AssertEx.NotNull(member, $"Member {memberPath} was not found"); Assert.True(member is PropertySymbol or FieldSymbol, $"Unexpected member symbol type {member.Kind}"); Assert.True(member.IsRequired()); - if (module is SourceModuleSymbol) - { - Assert.All(member.GetAttributes(), attr => AssertEx.NotEqual("System.Runtime.CompilerServices.RequiredMemberAttribute", attr.AttributeClass.ToTestDisplayString())); - } - else - { - AssertEx.Any(member.GetAttributes(), attr => attr.AttributeClass.ToTestDisplayString() == "System.Runtime.CompilerServices.RequiredMemberAttribute"); - } + Assert.All(member.GetAttributes(), attr => AssertEx.NotEqual("System.Runtime.CompilerServices.RequiredMemberAttribute", attr.AttributeClass.ToTestDisplayString())); requiredTypes.Add((NamedTypeSymbol)member.ContainingType); } @@ -258,15 +251,15 @@ class C var comp = CreateCompilationWithRequiredMembers(code, parseOptions: TestOptions.Regular10); comp.VerifyDiagnostics( - // (5,27): error CS8652: The feature 'required members' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // (5,27): error CS8936: Feature 'required members' is not available in C# 10.0. Please use language version 11.0 or greater. // internal required int Field; - Diagnostic(ErrorCode.ERR_FeatureInPreview, "Field").WithArguments("required members").WithLocation(5, 27), - // (6,27): error CS8652: The feature 'required members' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "Field").WithArguments("required members", "11.0").WithLocation(5, 27), + // (6,27): error CS8936: Feature 'required members' is not available in C# 10.0. Please use language version 11.0 or greater. // internal required int Prop { get; set; } - Diagnostic(ErrorCode.ERR_FeatureInPreview, "Prop").WithArguments("required members").WithLocation(6, 27) + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "Prop").WithArguments("required members", "11.0").WithLocation(6, 27) ); - comp = CreateCompilationWithRequiredMembers(code, parseOptions: TestOptions.RegularNext); + comp = CreateCompilationWithRequiredMembers(code, parseOptions: TestOptions.Regular11); comp.VerifyDiagnostics(); } @@ -335,7 +328,7 @@ namespace N8 class required {} } "; - var comp = CreateCompilationWithRequiredMembers(code, parseOptions: use10 ? TestOptions.Regular10 : TestOptions.RegularNext); + var comp = CreateCompilationWithRequiredMembers(code, parseOptions: use10 ? TestOptions.Regular10 : TestOptions.Regular11); comp.VerifyDiagnostics( use10 ? @@ -396,7 +389,7 @@ class required {} ); code = code.Replace("required", "@required"); - comp = CreateCompilationWithRequiredMembers(code, parseOptions: use10 ? TestOptions.Regular10 : TestOptions.RegularNext); + comp = CreateCompilationWithRequiredMembers(code, parseOptions: use10 ? TestOptions.Regular10 : TestOptions.Regular11); comp.VerifyDiagnostics(); } @@ -3637,7 +3630,10 @@ public C(bool unused) : this() comp.VerifyDiagnostics( // (9,12): warning CS8618: Non-nullable field '_field' must contain a non-null value when exiting constructor. Consider declaring the field as nullable. // public C() { } - Diagnostic(ErrorCode.WRN_UninitializedNonNullableField, "C").WithArguments("field", "_field").WithLocation(9, 12) + Diagnostic(ErrorCode.WRN_UninitializedNonNullableField, "C").WithArguments("field", "_field").WithLocation(9, 12), + // (13,9): warning CS8602: Dereference of a possibly null reference. + // Field.ToString(); + Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "Field").WithLocation(13, 9) ); } @@ -3947,10 +3943,10 @@ public Derived() : base() // 2 } [Fact, CompilerTrait(CompilerFeature.NullableReferenceTypes)] - public void RequiredMemberSuppressesNullabilityWarnings_ChainedConstructor_09() + [WorkItem(61718, "https://github.com/dotnet/roslyn/issues/61718")] + public void RequiredMemberSuppressesNullabilityWarnings_ChainedConstructor_09A() { - var code = """ - using System.Diagnostics.CodeAnalysis; + var @base = $$""" #nullable enable public class Base { @@ -3959,7 +3955,12 @@ public class Base protected Base() {} } - + """; + + var derived = $$""" + using System.Diagnostics.CodeAnalysis; + #nullable enable + public class Derived : Base { public required string Prop3 { get; set; } @@ -3970,7 +3971,7 @@ public Derived(int unused) : base() { Prop4 = null!; } - + public Derived() : this(0) { Prop1.ToString(); @@ -3981,17 +3982,151 @@ public Derived() : this(0) } """; + var comp = CreateCompilationWithRequiredMembers(new[] { derived, @base }); + + comp.VerifyDiagnostics( + // (10,12): warning CS8618: Non-nullable property 'Prop3' must contain a non-null value when exiting constructor. Consider declaring the property as nullable. + // public Derived(int unused) : base() + Diagnostic(ErrorCode.WRN_UninitializedNonNullableField, "Derived").WithArguments("property", "Prop3").WithLocation(10, 12), + // (10,12): warning CS8618: Non-nullable property 'Prop1' must contain a non-null value when exiting constructor. Consider declaring the property as nullable. + // public Derived(int unused) : base() + Diagnostic(ErrorCode.WRN_UninitializedNonNullableField, "Derived").WithArguments("property", "Prop1").WithLocation(10, 12), + // (15,24): error CS9039: This constructor must add 'SetsRequiredMembers' because it chains to a constructor that has that attribute. + // public Derived() : this(0) + Diagnostic(ErrorCode.ERR_ChainingToSetsRequiredMembersRequiresSetsRequiredMembers, "this").WithLocation(15, 24) + ); + + var baseComp = CreateCompilationWithRequiredMembers(@base); + comp = CreateCompilation(derived, new[] { baseComp.EmitToImageReference() }); + comp.VerifyDiagnostics( + // (10,12): warning CS8618: Non-nullable property 'Prop3' must contain a non-null value when exiting constructor. Consider declaring the property as nullable. + // public Derived(int unused) : base() + Diagnostic(ErrorCode.WRN_UninitializedNonNullableField, "Derived").WithArguments("property", "Prop3").WithLocation(10, 12), + // (10,12): warning CS8618: Non-nullable property 'Prop1' must contain a non-null value when exiting constructor. Consider declaring the property as nullable. + // public Derived(int unused) : base() + Diagnostic(ErrorCode.WRN_UninitializedNonNullableField, "Derived").WithArguments("property", "Prop1").WithLocation(10, 12), + // (15,24): error CS9039: This constructor must add 'SetsRequiredMembers' because it chains to a constructor that has that attribute. + // public Derived() : this(0) + Diagnostic(ErrorCode.ERR_ChainingToSetsRequiredMembersRequiresSetsRequiredMembers, "this").WithLocation(15, 24) + ); + } + + [Fact, CompilerTrait(CompilerFeature.NullableReferenceTypes)] + [WorkItem(61718, "https://github.com/dotnet/roslyn/issues/61718")] + public void RequiredMemberSuppressesNullabilityWarnings_ChainedConstructor_09B() + { + var code = """ + using System.Diagnostics.CodeAnalysis; + #nullable enable + public class Base + { + public required string Field1; + public string Field2 = null!; + + protected Base() {} + } + + public class Derived : Base + { + public required string Field3; + public string Field4; + + [SetsRequiredMembers] + public Derived(int unused) : base() + { + Field4 = null!; + } + + public Derived() : this(0) + { + Field1.ToString(); + Field2.ToString(); + Field3.ToString(); + Field4.ToString(); + } + } + """; + var comp = CreateCompilationWithRequiredMembers(code); comp.VerifyDiagnostics( - // (17,12): warning CS8618: Non-nullable property 'Prop3' must contain a non-null value when exiting constructor. Consider declaring the property as nullable. + // (17,12): warning CS8618: Non-nullable field 'Field3' must contain a non-null value when exiting constructor. Consider declaring the field as nullable. + // public Derived(int unused) : base() + Diagnostic(ErrorCode.WRN_UninitializedNonNullableField, "Derived").WithArguments("field", "Field3").WithLocation(17, 12), + // (17,12): warning CS8618: Non-nullable field 'Field1' must contain a non-null value when exiting constructor. Consider declaring the field as nullable. // public Derived(int unused) : base() - Diagnostic(ErrorCode.WRN_UninitializedNonNullableField, "Derived").WithArguments("property", "Prop3").WithLocation(17, 12), + Diagnostic(ErrorCode.WRN_UninitializedNonNullableField, "Derived").WithArguments("field", "Field1").WithLocation(17, 12), // (22,24): error CS9039: This constructor must add 'SetsRequiredMembers' because it chains to a constructor that has that attribute. // public Derived() : this(0) Diagnostic(ErrorCode.ERR_ChainingToSetsRequiredMembersRequiresSetsRequiredMembers, "this").WithLocation(22, 24) ); } + [Fact, CompilerTrait(CompilerFeature.NullableReferenceTypes)] + [WorkItem(61718, "https://github.com/dotnet/roslyn/issues/61718")] + public void RequiredMemberSuppressesNullabilityWarnings_ChainedConstructor_09C() + { + var @base = $$""" + #nullable enable + public class Base + { + private string _field1 = null!; + public required string Prop1 { get => _field1; set => _field1 = value; } + + protected Base() {} + } + """; + + var derived = $$""" + using System.Diagnostics.CodeAnalysis; + #nullable enable + + public class Derived : Base + { + private string _field2 = null!; + public required string Prop2 { get => _field2; set => _field2 = value; } + + [SetsRequiredMembers] + public Derived(int unused) : base() + { + } + + public Derived() : this(0) + { + Prop1.ToString(); + Prop2.ToString(); + } + } + """; + + var comp = CreateCompilationWithRequiredMembers(new[] { derived, @base }); + + comp.VerifyDiagnostics( + // (10,12): warning CS8618: Non-nullable property 'Prop1' must contain a non-null value when exiting constructor. Consider declaring the property as nullable. + // public Derived(int unused) : base() + Diagnostic(ErrorCode.WRN_UninitializedNonNullableField, "Derived").WithArguments("property", "Prop1").WithLocation(10, 12), + // (10,12): warning CS8618: Non-nullable property 'Prop2' must contain a non-null value when exiting constructor. Consider declaring the property as nullable. + // public Derived(int unused) : base() + Diagnostic(ErrorCode.WRN_UninitializedNonNullableField, "Derived").WithArguments("property", "Prop2").WithLocation(10, 12), + // (14,24): error CS9039: This constructor must add 'SetsRequiredMembers' because it chains to a constructor that has that attribute. + // public Derived() : this(0) + Diagnostic(ErrorCode.ERR_ChainingToSetsRequiredMembersRequiresSetsRequiredMembers, "this").WithLocation(14, 24) + ); + + var baseComp = CreateCompilationWithRequiredMembers(@base); + comp = CreateCompilation(derived, new[] { baseComp.EmitToImageReference() }); + comp.VerifyDiagnostics( + // (10,12): warning CS8618: Non-nullable property 'Prop1' must contain a non-null value when exiting constructor. Consider declaring the property as nullable. + // public Derived(int unused) : base() + Diagnostic(ErrorCode.WRN_UninitializedNonNullableField, "Derived").WithArguments("property", "Prop1").WithLocation(10, 12), + // (10,12): warning CS8618: Non-nullable property 'Prop2' must contain a non-null value when exiting constructor. Consider declaring the property as nullable. + // public Derived(int unused) : base() + Diagnostic(ErrorCode.WRN_UninitializedNonNullableField, "Derived").WithArguments("property", "Prop2").WithLocation(10, 12), + // (14,24): error CS9039: This constructor must add 'SetsRequiredMembers' because it chains to a constructor that has that attribute. + // public Derived() : this(0) + Diagnostic(ErrorCode.ERR_ChainingToSetsRequiredMembersRequiresSetsRequiredMembers, "this").WithLocation(14, 24) + ); + } + [Fact, CompilerTrait(CompilerFeature.NullableReferenceTypes)] public void RequiredMemberSuppressesNullabilityWarnings_ChainedConstructor_10() { @@ -4811,6 +4946,67 @@ class C // public required int Test { get; set; } Diagnostic(ErrorCode.ERR_DuplicateNameInClass, "Test").WithArguments("C", "Test").WithLocation(4, 25) ); + } + + [Theory, CombinatorialData] + public void FirstAccessOfIsRequiredDoesNotMatter(bool accessAttributesFirst) + { + // Accessing attributes will populate IsRequired if it's not already populated, so we want to test both codepaths explicitly. + var comp = CreateCompilationWithRequiredMembers(""" + public class C + { + public required int Field1; + public required int Property1 { get; set; } + } + public class D + { + public int Field2; + public int Property2 { get; set; } + } + """); + + CompileAndVerify(comp, symbolValidator: module => + { + var c = module.ContainingAssembly.GetTypeByMetadataName("C"); + AssertEx.NotNull(c); + FieldSymbol field1 = c.GetMember("Field1"); + PropertySymbol property1 = c.GetMember("Property1"); + var d = module.ContainingAssembly.GetTypeByMetadataName("D"); + AssertEx.NotNull(d); + FieldSymbol field2 = d.GetMember("Field2"); + PropertySymbol property2 = d.GetMember("Property2"); + + if (accessAttributesFirst) + { + assertAttributesEmpty(); + assertIsRequired(); + } + else + { + assertIsRequired(); + assertAttributesEmpty(); + } + + void assertIsRequired() + { + Assert.True(c.HasDeclaredRequiredMembers); + Assert.True(field1.IsRequired); + Assert.True(property1.IsRequired); + Assert.False(d.HasDeclaredRequiredMembers); + Assert.False(field2.IsRequired); + Assert.False(property2.IsRequired); + } + + void assertAttributesEmpty() + { + Assert.Empty(c.GetAttributes()); + Assert.Empty(field1.GetAttributes()); + Assert.Empty(property1.GetAttributes()); + Assert.Empty(d.GetAttributes()); + Assert.Empty(field2.GetAttributes()); + Assert.Empty(property2.GetAttributes()); + } + }); } } diff --git a/src/Compilers/CSharp/Test/Symbol/Symbols/Source/DelegateTests.cs b/src/Compilers/CSharp/Test/Symbol/Symbols/Source/DelegateTests.cs index 3272fbc03002f..6475a1433efab 100644 --- a/src/Compilers/CSharp/Test/Symbol/Symbols/Source/DelegateTests.cs +++ b/src/Compilers/CSharp/Test/Symbol/Symbols/Source/DelegateTests.cs @@ -790,5 +790,35 @@ public static void Main() Assert.True(lambda.ReturnsByRefReadonly); Assert.Equal(RefKind.In, lambda.Parameters[0].RefKind); } + + [Fact] + public void PartialPublicDelegate() + { + CreateCompilation("partial public delegate void M();").VerifyDiagnostics( + // (1,1): error CS0267: The 'partial' modifier can only appear immediately before 'class', 'record', 'struct', 'interface', or a method return type. + // partial public delegate void M(); + Diagnostic(ErrorCode.ERR_PartialMisplaced, "partial").WithLocation(1, 1), + // (1,30): error CS0267: The 'partial' modifier can only appear immediately before 'class', 'record', 'struct', 'interface', or a method return type. + // partial public delegate void M(); + Diagnostic(ErrorCode.ERR_PartialMisplaced, "M").WithLocation(1, 30)); + } + + [Fact] + public void PublicPartialDelegate() + { + CreateCompilation("public partial delegate void M();").VerifyDiagnostics( + // (1,30): error CS0267: The 'partial' modifier can only appear immediately before 'class', 'record', 'struct', 'interface', or a method return type. + // public partial delegate void M(); + Diagnostic(ErrorCode.ERR_PartialMisplaced, "M").WithLocation(1, 30)); + } + + [Fact] + public void PartialDelegate() + { + CreateCompilation("public partial delegate void M();").VerifyDiagnostics( + // (1,30): error CS0267: The 'partial' modifier can only appear immediately before 'class', 'record', 'struct', 'interface', or a method return type. + // public partial delegate void M(); + Diagnostic(ErrorCode.ERR_PartialMisplaced, "M").WithLocation(1, 30)); + } } } diff --git a/src/Compilers/CSharp/Test/Symbol/Symbols/Source/EventTests.cs b/src/Compilers/CSharp/Test/Symbol/Symbols/Source/EventTests.cs index d7fdef0e1feef..d898bfb3b6e24 100644 --- a/src/Compilers/CSharp/Test/Symbol/Symbols/Source/EventTests.cs +++ b/src/Compilers/CSharp/Test/Symbol/Symbols/Source/EventTests.cs @@ -1347,14 +1347,14 @@ void Method(S s) } "; CreateCompilation(text, parseOptions: TestOptions.Regular10).VerifyDiagnostics( - // (11,5): error CS0171: Field 'S.E' must be fully assigned before control is returned to the caller. Consider updating to language version 'preview' to auto-default the field. + // (11,5): error CS0171: Field 'S.E' must be fully assigned before control is returned to the caller. Consider updating to language version '11.0' to auto-default the field. // S(int unused1, int unused2) - Diagnostic(ErrorCode.ERR_UnassignedThisUnsupportedVersion, "S").WithArguments("S.E", "preview").WithLocation(11, 5), + Diagnostic(ErrorCode.ERR_UnassignedThisUnsupportedVersion, "S").WithArguments("S.E", "11.0").WithLocation(11, 5), // (22,9): error CS1612: Cannot modify the return value of 'S.This' because it is not a variable // This.E = null; //CS1612: receiver is not a variable Diagnostic(ErrorCode.ERR_ReturnNotLValue, "This").WithArguments("S.This").WithLocation(22, 9)); - CreateCompilation(text, parseOptions: TestOptions.RegularNext).VerifyDiagnostics( + CreateCompilation(text, parseOptions: TestOptions.Regular11).VerifyDiagnostics( // (22,9): error CS1612: Cannot modify the return value of 'S.This' because it is not a variable // This.E = null; //CS1612: receiver is not a variable Diagnostic(ErrorCode.ERR_ReturnNotLValue, "This").WithArguments("S.This").WithLocation(22, 9)); diff --git a/src/Compilers/CSharp/Test/Symbol/Symbols/Source/FileModifierTests.cs b/src/Compilers/CSharp/Test/Symbol/Symbols/Source/FileModifierTests.cs new file mode 100644 index 0000000000000..b27f17ef1d8f8 --- /dev/null +++ b/src/Compilers/CSharp/Test/Symbol/Symbols/Source/FileModifierTests.cs @@ -0,0 +1,3578 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Linq; +using System.Text; +using Microsoft.CodeAnalysis.CSharp.Symbols; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using Microsoft.CodeAnalysis.CSharp.Test.Utilities; +using Microsoft.CodeAnalysis.Test.Utilities; +using Roslyn.Test.Utilities; +using Xunit; + +namespace Microsoft.CodeAnalysis.CSharp.UnitTests; + +public class FileModifierTests : CSharpTestBase +{ + [Fact] + public void LangVersion() + { + var source = """ + file class C { } + """; + + var comp = CreateCompilation(source, parseOptions: TestOptions.Regular10); + comp.VerifyDiagnostics( + // (1,12): error CS8936: Feature 'file types' is not available in C# 10.0. Please use language version 11.0 or greater. + // file class C { } + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "C").WithArguments("file types", "11.0").WithLocation(1, 12)); + + comp = CreateCompilation(source); + comp.VerifyDiagnostics(); + } + + [Fact] + public void Nested_01() + { + var source = """ + class Outer + { + file class C { } + } + """; + + var comp = CreateCompilation(source, parseOptions: TestOptions.Regular10); + comp.VerifyDiagnostics( + // (3,16): error CS8936: Feature 'file types' is not available in C# 10.0. Please use language version 11.0 or greater. + // file class C { } + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "C").WithArguments("file types", "11.0").WithLocation(3, 16), + // (3,16): error CS9054: File-local type 'Outer.C' must be defined in a top level type; 'Outer.C' is a nested type. + // file class C { } + Diagnostic(ErrorCode.ERR_FileTypeNested, "C").WithArguments("Outer.C").WithLocation(3, 16)); + + comp = CreateCompilation(source); + comp.VerifyDiagnostics( + // (3,16): error CS9054: File-local type 'Outer.C' must be defined in a top level type; 'Outer.C' is a nested type. + // file class C { } + Diagnostic(ErrorCode.ERR_FileTypeNested, "C").WithArguments("Outer.C").WithLocation(3, 16)); + } + + [Fact] + public void Nested_02() + { + var source = """ + file class Outer + { + class C { } + } + """; + + var comp = CreateCompilation(source, parseOptions: TestOptions.Regular10); + comp.VerifyDiagnostics( + // (1,12): error CS8936: Feature 'file types' is not available in C# 10.0. Please use language version 11.0 or greater. + // file class Outer + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "Outer").WithArguments("file types", "11.0").WithLocation(1, 12)); + verify(); + + comp = CreateCompilation(source); + comp.VerifyDiagnostics(); + verify(); + + void verify() + { + var outer = comp.GetMember("Outer"); + Assert.Equal(Accessibility.Internal, outer.DeclaredAccessibility); + Assert.True(((SourceMemberContainerTypeSymbol)outer).IsFileLocal); + + var classC = comp.GetMember("Outer.C"); + Assert.Equal(Accessibility.Private, classC.DeclaredAccessibility); + Assert.False(((SourceMemberContainerTypeSymbol)classC).IsFileLocal); + } + } + + [Fact] + public void Nested_03() + { + var source = """ + file class Outer + { + file class C { } + } + """; + + var comp = CreateCompilation(source, parseOptions: TestOptions.Regular10); + comp.VerifyDiagnostics( + // (1,12): error CS8936: Feature 'file types' is not available in C# 10.0. Please use language version 11.0 or greater. + // file class Outer + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "Outer").WithArguments("file types", "11.0").WithLocation(1, 12), + // (3,16): error CS8936: Feature 'file types' is not available in C# 10.0. Please use language version 11.0 or greater. + // file class C { } + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "C").WithArguments("file types", "11.0").WithLocation(3, 16), + // (3,16): error CS9054: File-local type 'Outer.C' must be defined in a top level type; 'Outer.C' is a nested type. + // file class C { } + Diagnostic(ErrorCode.ERR_FileTypeNested, "C").WithArguments("Outer.C").WithLocation(3, 16)); + + comp = CreateCompilation(source); + comp.VerifyDiagnostics( + // (3,16): error CS9054: File-local type 'Outer.C' must be defined in a top level type; 'Outer.C' is a nested type. + // file class C { } + Diagnostic(ErrorCode.ERR_FileTypeNested, "C").WithArguments("Outer.C").WithLocation(3, 16)); + } + + [Fact] + public void Nested_04() + { + var source = """ + file class Outer + { + public class C { } + } + + class D + { + void M(Outer.C c) { } // 1 + } + """; + + var comp = CreateCompilation(source); + comp.VerifyDiagnostics( + // (8,10): error CS9051: File-local type 'Outer.C' cannot be used in a member signature in non-file-local type 'D'. + // void M(Outer.C c) { } // 1 + Diagnostic(ErrorCode.ERR_FileTypeDisallowedInSignature, "M").WithArguments("Outer.C", "D").WithLocation(8, 10)); + } + + [Fact] + public void Nested_05() + { + var source = """ + file class Outer + { + public class C + { + void M1(Outer outer) { } // ok + void M2(C outer) { } // ok + } + } + """; + + var comp = CreateCompilation(source); + comp.VerifyDiagnostics(); + } + + [Fact] + public void Nested_06() + { + var source = """ + class A1 + { + internal class A2 { } + } + file class B : A1 + { + } + class C : B.A2 // ok: base type is bound as A1.A2 + { + } + """; + + var comp = CreateCompilation(source); + comp.VerifyDiagnostics(); + } + + [Fact] + public void SameFileUse_01() + { + var source = """ + using System; + + file class C + { + public static void M() + { + Console.Write(1); + } + } + + class Program + { + static void Main() + { + C.M(); + } + } + """; + + var verifier = CompileAndVerify(source, expectedOutput: "1", symbolValidator: symbolValidator); + verifier.VerifyDiagnostics(); + + var comp = (CSharpCompilation)verifier.Compilation; + var symbol = comp.GetMember("C"); + Assert.Equal("<>F0__C", symbol.MetadataName); + + // The qualified name here is based on `SymbolDisplayCompilerInternalOptions.IncludeContainingFileForFileTypes`. + // We don't actually look up based on the file-encoded name of the type. + // This is similar to how generic types work (lookup based on 'C' instead of 'C`1'). + verifier.VerifyIL("C@.M", @" +{ + // Code size 7 (0x7) + .maxstack 1 + IL_0000: ldc.i4.1 + IL_0001: call ""void System.Console.Write(int)"" + IL_0006: ret +}"); + + void symbolValidator(ModuleSymbol symbol) + { + Assert.Equal(new[] { "", "<>F0__C", "Program" }, symbol.GlobalNamespace.GetMembers().Select(m => m.Name)); + var classC = symbol.GlobalNamespace.GetMember("<>F0__C"); + Assert.Equal(new[] { "M", ".ctor" }, classC.MemberNames); + } + } + + [Fact] + public void SameFileUse_02() + { + var source = """ + using System; + + file class C + { + public static void M() + { + Console.Write(1); + } + } + + class Program + { + static void Main() + { + C.M(); + } + } + """; + + var verifier = CompileAndVerify(new[] { "", source }, expectedOutput: "1", symbolValidator: symbolValidator); + verifier.VerifyDiagnostics(); + + var comp = (CSharpCompilation)verifier.Compilation; + var symbol = comp.GetMember("C"); + Assert.Equal("<>F1__C", symbol.MetadataName); + + // The qualified name here is based on `SymbolDisplayCompilerInternalOptions.IncludeContainingFileForFileTypes`. + // We don't actually look up based on the file-encoded name of the type. + // This is similar to how generic types work (lookup based on 'C' instead of 'C`1'). + verifier.VerifyIL("C@.M", @" +{ + // Code size 7 (0x7) + .maxstack 1 + IL_0000: ldc.i4.1 + IL_0001: call ""void System.Console.Write(int)"" + IL_0006: ret +}"); + + void symbolValidator(ModuleSymbol symbol) + { + Assert.Equal(new[] { "", "<>F1__C", "Program" }, symbol.GlobalNamespace.GetMembers().Select(m => m.Name)); + var classC = symbol.GlobalNamespace.GetMember("<>F1__C"); + Assert.Equal(new[] { "M", ".ctor" }, classC.MemberNames); + } + } + + [Fact] + public void FileEnum_01() + { + var source = """ + using System; + + file enum E + { + E1, E2 + } + + class Program + { + static void Main() + { + Console.Write(E.E2); + } + } + """; + + var verifier = CompileAndVerify(source, expectedOutput: "E2", symbolValidator: symbolValidator); + verifier.VerifyDiagnostics(); + + var comp = (CSharpCompilation)verifier.Compilation; + var symbol = comp.GetMember("E"); + Assert.Equal("<>F0__E", symbol.MetadataName); + + verifier.VerifyIL("Program.Main", @" +{ + // Code size 12 (0xc) + .maxstack 1 + IL_0000: ldc.i4.1 + IL_0001: box ""E"" + IL_0006: call ""void System.Console.Write(object)"" + IL_000b: ret +}"); + + void symbolValidator(ModuleSymbol symbol) + { + Assert.Equal(new[] { "", "<>F0__E", "Program" }, symbol.GlobalNamespace.GetMembers().Select(m => m.Name)); + var classC = symbol.GlobalNamespace.GetMember("<>F0__E"); + Assert.Equal(new[] { "value__", "E1", "E2", ".ctor" }, classC.MemberNames); + } + } + + [Fact] + public void FileEnum_02() + { + var source = """ + using System; + + file enum E + { + E1, E2 + } + + file class Attr : Attribute + { + public Attr(E e) { } + } + + [Attr(E.E2)] + class Program + { + static void Main() + { + var data = typeof(Program).GetCustomAttributesData(); + Console.Write(data[0].ConstructorArguments[0]); + } + } + """; + + var verifier = CompileAndVerify(source, expectedOutput: "(<>F0__E)1", symbolValidator: symbolValidator); + verifier.VerifyDiagnostics(); + + var comp = (CSharpCompilation)verifier.Compilation; + var symbol = comp.GetMember("E"); + Assert.Equal("<>F0__E", symbol.MetadataName); + + void symbolValidator(ModuleSymbol symbol) + { + Assert.Equal(new[] { "", "<>F0__E", "<>F0__Attr", "Program" }, symbol.GlobalNamespace.GetMembers().Select(m => m.Name)); + var classC = symbol.GlobalNamespace.GetMember("<>F0__E"); + Assert.Equal(new[] { "value__", "E1", "E2", ".ctor" }, classC.MemberNames); + } + } + + [Fact] + public void FileEnum_03() + { + var source = """ + using System; + + file enum E + { + E1, E2 + } + + class Attr : Attribute + { + public Attr(E e) { } // 1 + } + + [Attr(E.E2)] + class Program + { + static void Main() + { + var data = typeof(Program).GetCustomAttributesData(); + Console.Write(data[0].ConstructorArguments[0]); + } + } + """; + + var comp = CreateCompilation(source); + comp.VerifyDiagnostics( + // (10,12): error CS9051: File-local type 'E' cannot be used in a member signature in non-file-local type 'Attr'. + // public Attr(E e) { } // 1 + Diagnostic(ErrorCode.ERR_FileTypeDisallowedInSignature, "Attr").WithArguments("E", "Attr").WithLocation(10, 12)); + } + + [Fact] + public void FileEnum_04() + { + var source = """ + using System; + + file enum E + { + E1, E2 + } + + class Attr : Attribute + { + public Attr(object obj) { } + } + + [Attr(E.E2)] + class Program + { + static void Main() + { + var data = typeof(Program).GetCustomAttributesData(); + Console.Write(data[0].ConstructorArguments[0]); + } + } + """; + + var verifier = CompileAndVerify(source, expectedOutput: "(<>F0__E)1", symbolValidator: symbolValidator); + verifier.VerifyDiagnostics(); + + var comp = (CSharpCompilation)verifier.Compilation; + var symbol = comp.GetMember("E"); + Assert.Equal("<>F0__E", symbol.MetadataName); + + void symbolValidator(ModuleSymbol symbol) + { + Assert.Equal(new[] { "", "<>F0__E", "Attr", "Program" }, symbol.GlobalNamespace.GetMembers().Select(m => m.Name)); + var classC = symbol.GlobalNamespace.GetMember("<>F0__E"); + Assert.Equal(new[] { "value__", "E1", "E2", ".ctor" }, classC.MemberNames); + } + } + + [Fact] + public void OtherFileUse() + { + var source1 = """ + using System; + + file class C + { + public static void M() + { + Console.Write(1); + } + } + """; + + var source2 = """ + class Program + { + static void Main() + { + C.M(); // 1 + } + } + """; + + var comp = CreateCompilation(new[] { source1, source2 }); + comp.VerifyDiagnostics( + // (5,9): error CS0103: The name 'C' does not exist in the current context + // C.M(); // 1 + Diagnostic(ErrorCode.ERR_NameNotInContext, "C").WithArguments("C").WithLocation(5, 9)); + } + + [Fact] + public void Generic_01() + { + var source = """ + using System; + + C.M(1); + + file class C + { + public static void M(T t) { Console.Write(t); } + } + """; + + var verifier = CompileAndVerify(SyntaxFactory.ParseSyntaxTree(source, options: TestOptions.RegularPreview, path: "path/to/MyFile.cs", encoding: Encoding.Default), expectedOutput: "1", symbolValidator: symbolValidator); + verifier.VerifyDiagnostics(); + + verifier.VerifyIL("C@MyFile.M(T)", @" +{ + // Code size 12 (0xc) + .maxstack 1 + IL_0000: ldarg.0 + IL_0001: box ""T"" + IL_0006: call ""void System.Console.Write(object)"" + IL_000b: ret +} +"); + + var comp = (CSharpCompilation)verifier.Compilation; + var c = comp.GetMember("C"); + Assert.Equal("F0__C`1", c.MetadataName); + + void symbolValidator(ModuleSymbol module) + { + Assert.Equal(new[] { "", "Program", "F0__C" }, module.GlobalNamespace.GetMembers().Select(m => m.Name)); + + var classC = module.GlobalNamespace.GetMember("F0__C"); + Assert.Equal("F0__C`1", classC.MetadataName); + Assert.Equal(new[] { "M", ".ctor" }, classC.MemberNames); + } + } + + [Fact] + public void BadFileNames_01() + { + var source = """ + using System; + + C.M(); + + file class C + { + public static void M() { Console.Write(1); } + } + """; + + var verifier = CompileAndVerify(SyntaxFactory.ParseSyntaxTree(source, options: TestOptions.RegularPreview, path: "path/to/My<>File.cs", encoding: Encoding.Default), expectedOutput: "1", symbolValidator: symbolValidator); + verifier.VerifyDiagnostics(); + + var comp = (CSharpCompilation)verifier.Compilation; + var c = comp.GetMember("C"); + Assert.Equal("C@My__File", c.ToTestDisplayString()); + Assert.Equal("F0__C", c.MetadataName); + + void symbolValidator(ModuleSymbol module) + { + Assert.Equal(new[] { "", "Program", "F0__C" }, module.GlobalNamespace.GetMembers().Select(m => m.Name)); + var expectedSymbol = module.GlobalNamespace.GetMember("F0__C"); + Assert.Equal("F0__C", expectedSymbol.MetadataName); + Assert.Equal(new[] { "M", ".ctor" }, expectedSymbol.MemberNames); + } + } + + [Fact] + public void BadFileNames_02() + { + var source = """ + using System; + + C.M(); + + file class C + { + public static void M() { Console.Write(1); } + } + """; + + var verifier = CompileAndVerify(SyntaxFactory.ParseSyntaxTree(source, options: TestOptions.RegularPreview, path: "path/to/MyGeneratedFile.g.cs", encoding: Encoding.Default), expectedOutput: "1", symbolValidator: symbolValidator); + verifier.VerifyDiagnostics(); + + var comp = (CSharpCompilation)verifier.Compilation; + var c = comp.GetMember("C"); + Assert.Equal("C@MyGeneratedFile_g", c.ToTestDisplayString()); + Assert.Equal("F0__C", c.MetadataName); + + void symbolValidator(ModuleSymbol module) + { + Assert.Equal(new[] { "", "Program", "F0__C" }, module.GlobalNamespace.GetMembers().Select(m => m.Name)); + var expectedSymbol = module.GlobalNamespace.GetMember("F0__C"); + Assert.Equal("F0__C", expectedSymbol.MetadataName); + Assert.Equal(new[] { "M", ".ctor" }, expectedSymbol.MemberNames); + } + } + + [Fact] + public void DuplicateFileNames_01() + { + var path = "path/to/file.cs"; + var source1 = SyntaxFactory.ParseSyntaxTree(""" + using System; + + C.M(); + + file class C + { + public static void M() { Console.Write(1); } + } + """, options: TestOptions.RegularPreview, path: path, encoding: Encoding.Default); + var source2 = SyntaxFactory.ParseSyntaxTree(""" + using System; + + file class C + { + public static void M() { Console.Write(2); } + } + """, options: TestOptions.RegularPreview, path: path, encoding: Encoding.Default); + + var verifier = CompileAndVerify(new[] { source1, source2 }, expectedOutput: "1", symbolValidator: symbolValidator); + verifier.VerifyDiagnostics(); + + // note that VerifyIL doesn't work in this specific scenario because the files have the same name. + + void symbolValidator(ModuleSymbol module) + { + Assert.NotNull(module.GlobalNamespace.GetMember("F0__C")); + Assert.NotNull(module.GlobalNamespace.GetMember("F1__C")); + } + } + + // Data based on Lexer.ScanIdentifier_FastPath, excluding '/', '\', and ':' because those are path separators. + [Theory] + [InlineData('&')] + [InlineData('\0')] + [InlineData(' ')] + [InlineData('\r')] + [InlineData('\n')] + [InlineData('\t')] + [InlineData('!')] + [InlineData('%')] + [InlineData('(')] + [InlineData(')')] + [InlineData('*')] + [InlineData('+')] + [InlineData(',')] + [InlineData('-')] + [InlineData('.')] + [InlineData(';')] + [InlineData('<')] + [InlineData('=')] + [InlineData('>')] + [InlineData('?')] + [InlineData('[')] + [InlineData(']')] + [InlineData('^')] + [InlineData('{')] + [InlineData('|')] + [InlineData('}')] + [InlineData('~')] + [InlineData('"')] + [InlineData('\'')] + [InlineData('`')] + public void BadFileNames_03(char badChar) + { + var source = """ + using System; + + C.M(); + + file class C + { + public static void M() { Console.Write(1); } + } + """; + + var verifier = CompileAndVerify(SyntaxFactory.ParseSyntaxTree(source, options: TestOptions.RegularPreview, path: $"path/to/My{badChar}File.cs", encoding: Encoding.Default), expectedOutput: "1", symbolValidator: symbolValidator); + verifier.VerifyDiagnostics(); + + var comp = (CSharpCompilation)verifier.Compilation; + var c = comp.GetMember("C"); + Assert.Equal("C@My_File", c.ToTestDisplayString()); + Assert.Equal("F0__C", c.MetadataName); + + void symbolValidator(ModuleSymbol module) + { + Assert.Equal(new[] { "", "Program", "F0__C" }, module.GlobalNamespace.GetMembers().Select(m => m.Name)); + var expectedSymbol = module.GlobalNamespace.GetMember("F0__C"); + Assert.Equal("F0__C", expectedSymbol.MetadataName); + Assert.Equal(new[] { "M", ".ctor" }, expectedSymbol.MemberNames); + } + } + + [Fact] + public void Pdb_01() + { + var source = """ + using System; + + C.M(); + + file class C + { + public static void M() { Console.Write(1); } + } + """; + + var expectedMetadataName = "F0__C"; + var verifier = CompileAndVerify(SyntaxFactory.ParseSyntaxTree(source, options: TestOptions.RegularPreview, path: "path/to/My+File.cs", encoding: Encoding.Default), expectedOutput: "1", symbolValidator: validateSymbols); + verifier.VerifyDiagnostics(); + + var comp = (CSharpCompilation)verifier.Compilation; + var c = comp.GetMember("C"); + Assert.Equal("C@My_File", c.ToTestDisplayString()); + Assert.Equal(expectedMetadataName, c.MetadataName); + + void validateSymbols(ModuleSymbol module) + { + var type = module.GlobalNamespace.GetMember(expectedMetadataName); + Assert.NotNull(type); + Assert.Equal(new[] { "M", ".ctor" }, type.MemberNames); + } + } + + [Theory] + [InlineData("file", "file", "<>F0__C", "<>F1__C")] + [InlineData("file", "", "<>F0__C", "C")] + [InlineData("", "file", "C", "<>F1__C")] + public void Duplication_01(string firstFileModifier, string secondFileModifier, string firstMetadataName, string secondMetadataName) + { + // A file-local type is allowed to have the same name as a non-file-local type from a different file. + // When both a file-local type and non-file-local type with the same name are in scope, the file-local type is preferred, since it's "more local". + var source1 = $$""" + using System; + + {{firstFileModifier}} class C + { + public static void M() + { + Console.Write(1); + } + } + """; + + var source2 = $$""" + using System; + + {{secondFileModifier}} class C + { + public static void M() + { + Console.Write(2); + } + } + """; + + var main = """ + + class Program + { + static void Main() + { + C.M(); + global::C.M(); + } + } + """; + + var verifier = CompileAndVerify(new[] { source1 + main, source2 }, expectedOutput: "11"); + var comp = (CSharpCompilation)verifier.Compilation; + var cs = comp.GetMembers("C"); + var tree = comp.SyntaxTrees[0]; + var expectedSymbol = cs[0]; + Assert.Equal(firstMetadataName, expectedSymbol.MetadataName); + verify(); + + verifier = CompileAndVerify(new[] { source1, source2 + main }, expectedOutput: "22"); + comp = (CSharpCompilation)verifier.Compilation; + cs = comp.GetMembers("C"); + tree = comp.SyntaxTrees[1]; + expectedSymbol = cs[1]; + Assert.Equal(secondMetadataName, expectedSymbol.MetadataName); + verify(); + + void verify() + { + verifier.VerifyDiagnostics(); + Assert.Equal(2, cs.Length); + Assert.Equal(comp.SyntaxTrees[0], cs[0].DeclaringSyntaxReferences.Single().SyntaxTree); + Assert.Equal(comp.SyntaxTrees[1], cs[1].DeclaringSyntaxReferences.Single().SyntaxTree); + + var model = comp.GetSemanticModel(tree, ignoreAccessibility: true); + var cReference = tree.GetRoot().DescendantNodes().OfType().Last().Expression; + var info = model.GetTypeInfo(cReference); + Assert.Equal(expectedSymbol.GetPublicSymbol(), info.Type); + } + } + + [Fact] + public void Duplication_02() + { + // As a sanity check, demonstrate that non-file classes with the same name across different files are disallowed. + var source1 = """ + using System; + + class C + { + public static void M() + { + Console.Write(1); + } + } + """; + + var source2 = """ + using System; + + class C + { + public static void M() + { + Console.Write(2); + } + } + """; + + var main = """ + + class Program + { + static void Main() + { + C.M(); + } + } + """; + + var comp = CreateCompilation(new[] { source1 + main, source2 }); + verify(); + + comp = CreateCompilation(new[] { source1, source2 + main }); + verify(); + + void verify() + { + comp.VerifyDiagnostics( + // (3,7): error CS0101: The namespace '' already contains a definition for 'C' + // class C + Diagnostic(ErrorCode.ERR_DuplicateNameInNS, "C").WithArguments("C", "").WithLocation(3, 7), + // (5,24): error CS0111: Type 'C' already defines a member called 'M' with the same parameter types + // public static void M() + Diagnostic(ErrorCode.ERR_MemberAlreadyExists, "M").WithArguments("M", "C").WithLocation(5, 24), + // (14,11): error CS0121: The call is ambiguous between the following methods or properties: 'C.M()' and 'C.M()' + // C.M(); + Diagnostic(ErrorCode.ERR_AmbigCall, "M").WithArguments("C.M()", "C.M()").WithLocation(14, 11)); + + var cs = comp.GetMember("C"); + var syntaxReferences = cs.DeclaringSyntaxReferences; + Assert.Equal(2, syntaxReferences.Length); + Assert.Equal(comp.SyntaxTrees[0], syntaxReferences[0].SyntaxTree); + Assert.Equal(comp.SyntaxTrees[1], syntaxReferences[1].SyntaxTree); + } + } + + [Fact] + public void Duplication_03() + { + var source1 = """ + using System; + + partial class C + { + public static void M() + { + Console.Write(1); + } + } + """; + + var source2 = """ + partial class C + { + } + """; + + var main = """ + using System; + + file class C + { + public static void M() + { + Console.Write(2); + } + } + + class Program + { + static void Main() + { + C.M(); + } + } + """; + + var verifier = CompileAndVerify(new[] { source1, source2, main }, expectedOutput: "2"); + var comp = (CSharpCompilation)verifier.Compilation; + comp.VerifyDiagnostics(); + + var cs = comp.GetMembers("C"); + Assert.Equal(2, cs.Length); + + var c0 = cs[0]; + Assert.True(c0 is SourceMemberContainerTypeSymbol { IsFileLocal: false }); + + var syntaxReferences = c0.DeclaringSyntaxReferences; + Assert.Equal(2, syntaxReferences.Length); + Assert.Equal(comp.SyntaxTrees[0], syntaxReferences[0].SyntaxTree); + Assert.Equal(comp.SyntaxTrees[1], syntaxReferences[1].SyntaxTree); + + var c1 = cs[1]; + Assert.True(c1 is SourceMemberContainerTypeSymbol { IsFileLocal: true }); + Assert.Equal(comp.SyntaxTrees[2], c1.DeclaringSyntaxReferences.Single().SyntaxTree); + + var tree = comp.SyntaxTrees[2]; + var model = comp.GetSemanticModel(tree, ignoreAccessibility: true); + var cReference = tree.GetRoot().DescendantNodes().OfType().Last().Expression; + var info = model.GetTypeInfo(cReference); + Assert.Equal(c1.GetPublicSymbol(), info.Type); + } + + [Fact] + public void Duplication_04() + { + var source1 = """ + using System; + + class C + { + public static void M() + { + Console.Write(1); + } + } + """; + + var main = """ + using System; + + file partial class C + { + public static void M() + { + Console.Write(Number); + } + } + + file partial class C + { + private static int Number => 2; + } + + class Program + { + static void Main() + { + C.M(); + } + } + """; + + var verifier = CompileAndVerify(new[] { source1, main }, expectedOutput: "2"); + var comp = (CSharpCompilation)verifier.Compilation; + comp.VerifyDiagnostics(); + + var cs = comp.GetMembers("C"); + Assert.Equal(2, cs.Length); + + var c0 = cs[0]; + Assert.True(c0 is SourceMemberContainerTypeSymbol { IsFileLocal: false }); + Assert.Equal(comp.SyntaxTrees[0], c0.DeclaringSyntaxReferences.Single().SyntaxTree); + + var c1 = cs[1]; + Assert.True(c1 is SourceMemberContainerTypeSymbol { IsFileLocal: true }); + + var syntaxReferences = c1.DeclaringSyntaxReferences; + Assert.Equal(2, syntaxReferences.Length); + Assert.Equal(comp.SyntaxTrees[1], syntaxReferences[0].SyntaxTree); + Assert.Equal(comp.SyntaxTrees[1], syntaxReferences[1].SyntaxTree); + + var tree = comp.SyntaxTrees[1]; + var model = comp.GetSemanticModel(tree, ignoreAccessibility: true); + var cReference = tree.GetRoot().DescendantNodes().OfType().Last().Expression; + var info = model.GetTypeInfo(cReference); + Assert.Equal(c1.GetPublicSymbol(), info.Type); + } + + [Theory] + [CombinatorialData] + public void Duplication_05(bool firstClassIsFile) + { + var source1 = $$""" + using System; + + {{(firstClassIsFile ? "file " : "")}}partial class C + { + public static void M() + { + Console.Write(1); + } + } + """; + + var main = """ + using System; + + file partial class C + { + public static void M() + { + Console.Write(2); + } + } + + class Program + { + static void Main() + { + C.M(); + } + } + """; + + var verifier = CompileAndVerify(new[] { source1, main }, expectedOutput: "2"); + var comp = (CSharpCompilation)verifier.Compilation; + comp.VerifyDiagnostics(); + + var cs = comp.GetMembers("C"); + Assert.Equal(2, cs.Length); + + var c0 = cs[0]; + Assert.Equal(firstClassIsFile, ((SourceMemberContainerTypeSymbol)c0).IsFileLocal); + Assert.Equal(comp.SyntaxTrees[0], c0.DeclaringSyntaxReferences.Single().SyntaxTree); + + var c1 = cs[1]; + Assert.True(c1 is SourceMemberContainerTypeSymbol { IsFileLocal: true }); + Assert.Equal(comp.SyntaxTrees[1], c1.DeclaringSyntaxReferences.Single().SyntaxTree); + + var tree = comp.SyntaxTrees[1]; + var model = comp.GetSemanticModel(tree, ignoreAccessibility: true); + var cReference = tree.GetRoot().DescendantNodes().OfType().Last().Expression; + var info = model.GetTypeInfo(cReference); + Assert.Equal(c1.GetPublicSymbol(), info.Type); + } + + [Fact] + public void Duplication_06() + { + var source1 = """ + using System; + + partial class C + { + public static void M() + { + Console.Write(Number); + } + } + """; + + var source2 = """ + using System; + + partial class C + { + private static int Number => 1; + } + + file class C + { + public static void M() + { + Console.Write(2); + } + } + """; + + var comp = CreateCompilation(new[] { source1, source2 }); + // https://github.com/dotnet/roslyn/issues/62333: should this diagnostic be more specific? + // the issue more precisely is that a definition for 'C' already exists in the current file--not that it's already in this namespace. + comp.VerifyDiagnostics( + // (8,12): error CS0101: The namespace '' already contains a definition for 'C' + // file class C + Diagnostic(ErrorCode.ERR_DuplicateNameInNS, "C").WithArguments("C", "").WithLocation(8, 12)); + + var cs = comp.GetMembers("C"); + Assert.Equal(2, cs.Length); + + var c0 = cs[0]; + Assert.True(c0 is SourceMemberContainerTypeSymbol { IsFileLocal: false }); + var syntaxReferences = c0.DeclaringSyntaxReferences; + Assert.Equal(2, syntaxReferences.Length); + Assert.Equal(comp.SyntaxTrees[0], syntaxReferences[0].SyntaxTree); + Assert.Equal(comp.SyntaxTrees[1], syntaxReferences[1].SyntaxTree); + + var c1 = cs[1]; + Assert.True(c1 is SourceMemberContainerTypeSymbol { IsFileLocal: true }); + Assert.Equal(comp.SyntaxTrees[1], c1.DeclaringSyntaxReferences.Single().SyntaxTree); + + + comp = CreateCompilation(new[] { source2, source1 }); + comp.VerifyDiagnostics( + // (5,24): error CS0111: Type 'C' already defines a member called 'M' with the same parameter types + // public static void M() + Diagnostic(ErrorCode.ERR_MemberAlreadyExists, "M").WithArguments("M", "C").WithLocation(5, 24), + // (8,12): error CS0260: Missing partial modifier on declaration of type 'C'; another partial declaration of this type exists + // file class C + Diagnostic(ErrorCode.ERR_MissingPartial, "C").WithArguments("C").WithLocation(8, 12)); + + var c = comp.GetMember("C"); + Assert.True(c is SourceMemberContainerTypeSymbol { IsFileLocal: true }); + syntaxReferences = c.DeclaringSyntaxReferences; + Assert.Equal(3, syntaxReferences.Length); + Assert.Equal(comp.SyntaxTrees[0], syntaxReferences[0].SyntaxTree); + Assert.Equal(comp.SyntaxTrees[0], syntaxReferences[1].SyntaxTree); + Assert.Equal(comp.SyntaxTrees[1], syntaxReferences[2].SyntaxTree); + } + + [Fact] + public void Duplication_07() + { + var source1 = """ + using System; + + file partial class C + { + public static void M() + { + Console.Write(1); + } + } + """; + + var source2 = """ + using System; + + file partial class C + { + public static void M() + { + Console.Write(Number); + } + } + + file class C + { + private static int Number => 2; + } + """; + + var comp = CreateCompilation(new[] { source1, source2 }); + comp.VerifyDiagnostics( + // (11,12): error CS0260: Missing partial modifier on declaration of type 'C'; another partial declaration of this type exists + // file class C + Diagnostic(ErrorCode.ERR_MissingPartial, "C").WithArguments("C").WithLocation(11, 12)); + + var cs = comp.GetMembers("C"); + Assert.Equal(2, cs.Length); + + var c0 = cs[0]; + Assert.True(c0 is SourceMemberContainerTypeSymbol { IsFileLocal: true }); + Assert.Equal(comp.SyntaxTrees[0], c0.DeclaringSyntaxReferences.Single().SyntaxTree); + + var c1 = cs[1]; + Assert.True(c1 is SourceMemberContainerTypeSymbol { IsFileLocal: true }); + var syntaxReferences = c1.DeclaringSyntaxReferences; + Assert.Equal(2, syntaxReferences.Length); + Assert.Equal(comp.SyntaxTrees[1], syntaxReferences[0].SyntaxTree); + Assert.Equal(comp.SyntaxTrees[1], syntaxReferences[1].SyntaxTree); + + + comp = CreateCompilation(new[] { source2, source1 }); + comp.VerifyDiagnostics( + // (11,12): error CS0260: Missing partial modifier on declaration of type 'C'; another partial declaration of this type exists + // file class C + Diagnostic(ErrorCode.ERR_MissingPartial, "C").WithArguments("C").WithLocation(11, 12)); + + cs = comp.GetMembers("C"); + Assert.Equal(2, cs.Length); + + c0 = cs[0]; + Assert.True(c0 is SourceMemberContainerTypeSymbol { IsFileLocal: true }); + syntaxReferences = c0.DeclaringSyntaxReferences; + Assert.Equal(2, syntaxReferences.Length); + Assert.Equal(comp.SyntaxTrees[0], syntaxReferences[0].SyntaxTree); + Assert.Equal(comp.SyntaxTrees[0], syntaxReferences[1].SyntaxTree); + + c1 = cs[1]; + Assert.True(c1 is SourceMemberContainerTypeSymbol { IsFileLocal: true }); + Assert.Equal(comp.SyntaxTrees[1], c1.DeclaringSyntaxReferences.Single().SyntaxTree); + } + + [Fact] + public void Duplication_08() + { + var source1 = """ + partial class Outer + { + file class C + { + public static void M() { } + } + } + """; + + var source2 = """ + partial class Outer + { + file class C + { + public static void M() { } + } + } + """; + + var source3 = """ + partial class Outer + { + public class C + { + public static void M() { } + } + } + """; + + var compilation = CreateCompilation(new[] { source1, source2, source3 }); + compilation.VerifyDiagnostics( + // (3,16): error CS9054: File-local type 'Outer.C' must be defined in a top level type; 'Outer.C' is a nested type. + // file class C + Diagnostic(ErrorCode.ERR_FileTypeNested, "C").WithArguments("Outer.C").WithLocation(3, 16), + // (3,16): error CS9054: File-local type 'Outer.C' must be defined in a top level type; 'Outer.C' is a nested type. + // file class C + Diagnostic(ErrorCode.ERR_FileTypeNested, "C").WithArguments("Outer.C").WithLocation(3, 16)); + + var classOuter = compilation.GetMember("Outer"); + var cs = classOuter.GetMembers("C"); + Assert.Equal(3, cs.Length); + Assert.True(cs[0] is SourceMemberContainerTypeSymbol { IsFileLocal: true }); + Assert.True(cs[1] is SourceMemberContainerTypeSymbol { IsFileLocal: true }); + Assert.True(cs[2] is SourceMemberContainerTypeSymbol { IsFileLocal: false }); + } + + [Fact] + public void Duplication_09() + { + var source1 = """ + namespace NS + { + file class C + { + public static void M() { } + } + } + """; + + var source2 = """ + namespace NS + { + file class C + { + public static void M() { } + } + } + """; + + var source3 = """ + namespace NS + { + public class C + { + public static void M() { } + } + } + """; + + var compilation = CreateCompilation(new[] { source1, source2, source3 }); + compilation.VerifyDiagnostics(); + + var namespaceNS = compilation.GetMember("NS"); + var cs = namespaceNS.GetMembers("C"); + Assert.Equal(3, cs.Length); + Assert.True(cs[0] is SourceMemberContainerTypeSymbol { IsFileLocal: true }); + Assert.True(cs[1] is SourceMemberContainerTypeSymbol { IsFileLocal: true }); + Assert.True(cs[2] is SourceMemberContainerTypeSymbol { IsFileLocal: false }); + } + + [Theory] + [InlineData("file", "file")] + [InlineData("file", "")] + [InlineData("", "file")] + public void Duplication_10(string firstFileModifier, string secondFileModifier) + { + var source1 = $$""" + using System; + + partial class Program + { + {{firstFileModifier}} class C + { + public static void M() + { + Console.Write(1); + } + } + } + """; + + var source2 = $$""" + using System; + + partial class Program + { + {{secondFileModifier}} class C + { + public static void M() + { + Console.Write(2); + } + } + } + """; + + var main = """ + partial class Program + { + static void Main() + { + Program.C.M(); + } + } + """; + + var comp = CreateCompilation(new[] { source1 + main, source2 }); + var cs = comp.GetMembers("Program.C"); + var tree = comp.SyntaxTrees[0]; + var expectedSymbol = cs[0]; + verify(); + + comp = CreateCompilation(new[] { source1, source2 + main }); + cs = comp.GetMembers("Program.C"); + tree = comp.SyntaxTrees[1]; + expectedSymbol = cs[1]; + verify(); + + void verify() + { + comp.GetDiagnostics().Where(d => d.Code is not (int)ErrorCode.ERR_FileTypeNested).Verify(); + Assert.Equal(2, cs.Length); + Assert.Equal(comp.SyntaxTrees[0], cs[0].DeclaringSyntaxReferences.Single().SyntaxTree); + Assert.Equal(comp.SyntaxTrees[1], cs[1].DeclaringSyntaxReferences.Single().SyntaxTree); + + var model = comp.GetSemanticModel(tree, ignoreAccessibility: true); + var cReference = tree.GetRoot().DescendantNodes().OfType().Last(); + var info = model.GetTypeInfo(cReference); + Assert.Equal(expectedSymbol.GetPublicSymbol(), info.Type); + } + } + + [Theory] + [InlineData("file", "file")] + [InlineData("file", "")] + [InlineData("", "file")] + public void Duplication_11(string firstFileModifier, string secondFileModifier) + { + var source1 = $$""" + using System; + + {{firstFileModifier}} partial class Outer + { + internal class C + { + public static void M() + { + Console.Write(1); + } + } + } + """; + + var source2 = $$""" + using System; + + {{secondFileModifier}} partial class Outer + { + internal class C + { + public static void M() + { + Console.Write(2); + } + } + } + """; + + var main = """ + class Program + { + static void Main() + { + Outer.C.M(); + } + } + """; + + var comp = CreateCompilation(new[] { source1 + main, source2 }, options: TestOptions.DebugExe); + comp.GetDiagnostics().Where(d => d.Code is not (int)ErrorCode.ERR_FileTypeNested).Verify(); + var outers = comp.GetMembers("Outer"); + var cs = outers.Select(o => ((NamedTypeSymbol)o).GetMember("C")).ToArray(); + var tree = comp.SyntaxTrees[0]; + var expectedSymbol = cs[0]; + verify(); + + comp = CreateCompilation(new[] { source1, source2 + main }, options: TestOptions.DebugExe); + comp.GetDiagnostics().Where(d => d.Code is not (int)ErrorCode.ERR_FileTypeNested).Verify(); + outers = comp.GetMembers("Outer"); + cs = outers.Select(o => ((NamedTypeSymbol)o).GetMember("C")).ToArray(); + tree = comp.SyntaxTrees[1]; + expectedSymbol = cs[1]; + verify(); + + void verify() + { + Assert.Equal(2, cs.Length); + Assert.Equal(comp.SyntaxTrees[0], cs[0].DeclaringSyntaxReferences.Single().SyntaxTree); + Assert.Equal(comp.SyntaxTrees[1], cs[1].DeclaringSyntaxReferences.Single().SyntaxTree); + + var model = comp.GetSemanticModel(tree, ignoreAccessibility: true); + var cReference = tree.GetRoot().DescendantNodes().OfType().Last(); + var info = model.GetTypeInfo(cReference); + Assert.Equal(expectedSymbol.GetPublicSymbol(), info.Type); + } + } + + [Theory] + [InlineData("file ")] + [InlineData("")] + public void Duplication_13(string fileModifier) + { + var userCode = """ + using System; + + UserCode.Print(); + + partial class UserCode + { + public static partial void Print(); + + private class C + { + public static void M() => Console.Write("Program.cs"); + } + } + """; + + // A source generator must assume that partial classes and namespaces may bring user-defined types into scope. + // Therefore, generators should reference types they introduce with a `global::`-qualified name. + var generatedCode = $$""" + using System; + + partial class UserCode + { + public static partial void Print() + { + global::C.M(); // binds to 'class C'/'file class C' from global namespace + C.M(); // binds to class 'UserCode.C' + } + } + + {{fileModifier}}class C + { + public static void M() => Console.Write("OtherFile.cs"); + } + """; + + var verifier = CompileAndVerify(new[] { userCode, generatedCode }, expectedOutput: "OtherFile.csProgram.cs"); + verifier.VerifyDiagnostics(); + } + + [Theory] + [InlineData("file ")] + [InlineData("")] + public void Duplication_14(string fileModifier) + { + var userCode = """ + using System; + using UserNamespace; + + GeneratedClass.Print(); + + namespace UserNamespace + { + class C + { + public static void M() => Console.Write("Program.cs"); + } + } + """; + + // A source generator must assume that partial classes and namespaces may bring user-defined types into scope. + // Therefore, generators should reference types they introduce with a `global::`-qualified name. + var generatedCode = $$""" + using System; + + namespace UserNamespace + { + class GeneratedClass + { + public static void Print() + { + global::C.M(); // binds to 'class C'/'file class C' from global namespace + C.M(); // binds to class 'UserNamespace.C' + } + } + } + + {{fileModifier}}class C + { + public static void M() => Console.Write("OtherFile.cs"); + } + """; + + var verifier = CompileAndVerify(new[] { userCode, generatedCode }, expectedOutput: "OtherFile.csProgram.cs"); + verifier.VerifyDiagnostics(); + } + + [Fact] + public void Duplication_15() + { + var userCode = """ + using System; + using UserNamespace; + + GeneratedClass.Print(); + + namespace UserNamespace + { + class C + { + public static void M() => Console.Write("Program.cs"); + } + } + """; + + // Generators can also mitigate the "nearer scope" problem by ensuring no namespace or partial class scopes lie between the declaration and usage of a file type. + var generatedCode = $$""" + using System; + + namespace UserNamespace + { + class GeneratedClass + { + public static void Print() + { + C.M(); // binds to 'UserNamespace.C@OtherFile' + } + } + + file class C + { + public static void M() => Console.Write("OtherFile.cs"); + } + } + + """; + + var verifier = CompileAndVerify(new[] { userCode, generatedCode }, expectedOutput: "OtherFile.cs"); + verifier.VerifyDiagnostics(); + } + + [Fact] + public void SignatureUsage_01() + { + var source = """ + file class C + { + } + + class D + { + public void M1(C c) { } // 1 + private void M2(C c) { } // 2 + } + """; + + var comp = CreateCompilation(source); + comp.VerifyDiagnostics( + // (7,17): error CS9051: File-local type 'C' cannot be used in a member signature in non-file-local type 'D'. + // public void M1(C c) { } // 1 + Diagnostic(ErrorCode.ERR_FileTypeDisallowedInSignature, "M1").WithArguments("C", "D").WithLocation(7, 17), + // (8,18): error CS9051: File-local type 'C' cannot be used in a member signature in non-file-local type 'D'. + // private void M2(C c) { } // 2 + Diagnostic(ErrorCode.ERR_FileTypeDisallowedInSignature, "M2").WithArguments("C", "D").WithLocation(8, 18)); + } + + [Fact] + public void SignatureUsage_02() + { + var source = """ + file class C + { + } + + class D + { + public C M1() => new C(); // 1 + private C M2() => new C(); // 2 + } + """; + + var comp = CreateCompilation(source); + comp.VerifyDiagnostics( + // (7,14): error CS9051: File-local type 'C' cannot be used in a member signature in non-file-local type 'D'. + // public C M1() => new C(); // 1 + Diagnostic(ErrorCode.ERR_FileTypeDisallowedInSignature, "M1").WithArguments("C", "D").WithLocation(7, 14), + // (8,15): error CS9051: File-local type 'C' cannot be used in a member signature in non-file-local type 'D'. + // private C M2() => new C(); // 2 + Diagnostic(ErrorCode.ERR_FileTypeDisallowedInSignature, "M2").WithArguments("C", "D").WithLocation(8, 15)); + } + + [Fact] + public void SignatureUsage_03() + { + var source = """ + file class C + { + } + file delegate void D(); + + public class E + { + C field; // 1 + C property { get; set; } // 2 + object this[C c] { get => c; set { } } // 3 + event D @event; // 4 + } + """; + + var comp = CreateCompilation(source); + comp.VerifyDiagnostics( + // (8,7): error CS9051: File-local type 'C' cannot be used in a member signature in non-file-local type 'E'. + // C field; // 1 + Diagnostic(ErrorCode.ERR_FileTypeDisallowedInSignature, "field").WithArguments("C", "E").WithLocation(8, 7), + // (8,7): warning CS0169: The field 'E.field' is never used + // C field; // 1 + Diagnostic(ErrorCode.WRN_UnreferencedField, "field").WithArguments("E.field").WithLocation(8, 7), + // (9,7): error CS9051: File-local type 'C' cannot be used in a member signature in non-file-local type 'E'. + // C property { get; set; } // 2 + Diagnostic(ErrorCode.ERR_FileTypeDisallowedInSignature, "property").WithArguments("C", "E").WithLocation(9, 7), + // (10,12): error CS9051: File-local type 'C' cannot be used in a member signature in non-file-local type 'E'. + // object this[C c] { get => c; set { } } // 3 + Diagnostic(ErrorCode.ERR_FileTypeDisallowedInSignature, "this").WithArguments("C", "E").WithLocation(10, 12), + // (11,13): error CS9051: File-local type 'D' cannot be used in a member signature in non-file-local type 'E'. + // event D @event; // 4 + Diagnostic(ErrorCode.ERR_FileTypeDisallowedInSignature, "@event").WithArguments("D", "E").WithLocation(11, 13), + // (11,13): warning CS0067: The event 'E.event' is never used + // event D @event; // 4 + Diagnostic(ErrorCode.WRN_UnreferencedEvent, "@event").WithArguments("E.event").WithLocation(11, 13)); + } + + [Fact] + public void SignatureUsage_04() + { + var source = """ + file class C + { + public class Inner { } + public delegate void InnerDelegate(); + } + + public class E + { + C.Inner field; // 1 + C.Inner property { get; set; } // 2 + object this[C.Inner inner] { get => inner; set { } } // 3 + event C.InnerDelegate @event; // 4 + } + """; + + var comp = CreateCompilation(source); + comp.VerifyDiagnostics( + // (9,13): error CS9051: File-local type 'C.Inner' cannot be used in a member signature in non-file-local type 'E'. + // C.Inner field; // 1 + Diagnostic(ErrorCode.ERR_FileTypeDisallowedInSignature, "field").WithArguments("C.Inner", "E").WithLocation(9, 13), + // (9,13): warning CS0169: The field 'E.field' is never used + // C.Inner field; // 1 + Diagnostic(ErrorCode.WRN_UnreferencedField, "field").WithArguments("E.field").WithLocation(9, 13), + // (10,13): error CS9051: File-local type 'C.Inner' cannot be used in a member signature in non-file-local type 'E'. + // C.Inner property { get; set; } // 2 + Diagnostic(ErrorCode.ERR_FileTypeDisallowedInSignature, "property").WithArguments("C.Inner", "E").WithLocation(10, 13), + // (11,12): error CS9051: File-local type 'C.Inner' cannot be used in a member signature in non-file-local type 'E'. + // object this[C.Inner inner] { get => inner; set { } } // 3 + Diagnostic(ErrorCode.ERR_FileTypeDisallowedInSignature, "this").WithArguments("C.Inner", "E").WithLocation(11, 12), + // (12,27): error CS9051: File-local type 'C.InnerDelegate' cannot be used in a member signature in non-file-local type 'E'. + // event C.InnerDelegate @event; // 4 + Diagnostic(ErrorCode.ERR_FileTypeDisallowedInSignature, "@event").WithArguments("C.InnerDelegate", "E").WithLocation(12, 27), + // (12,27): warning CS0067: The event 'E.event' is never used + // event C.InnerDelegate @event; // 4 + Diagnostic(ErrorCode.WRN_UnreferencedEvent, "@event").WithArguments("E.event").WithLocation(12, 27)); + } + + [Fact] + public void SignatureUsage_05() + { + var source = """ + #pragma warning disable 67, 169 // unused event, field + + file class C + { + public class Inner { } + public delegate void InnerDelegate(); + } + + file class D + { + public class Inner + { + C.Inner field; + C.Inner property { get; set; } + object this[C.Inner inner] { get => inner; set { } } + event C.InnerDelegate @event; + } + } + + class E + { + public class Inner + { + C.Inner field; // 1 + C.Inner property { get; set; } // 2 + object this[C.Inner inner] { get => inner; set { } } // 3 + event C.InnerDelegate @event; // 4 + } + } + """; + + var comp = CreateCompilation(source); + comp.VerifyDiagnostics( + // (24,17): error CS9051: File-local type 'C.Inner' cannot be used in a member signature in non-file-local type 'E.Inner'. + // C.Inner field; // 1 + Diagnostic(ErrorCode.ERR_FileTypeDisallowedInSignature, "field").WithArguments("C.Inner", "E.Inner").WithLocation(24, 17), + // (25,17): error CS9051: File-local type 'C.Inner' cannot be used in a member signature in non-file-local type 'E.Inner'. + // C.Inner property { get; set; } // 2 + Diagnostic(ErrorCode.ERR_FileTypeDisallowedInSignature, "property").WithArguments("C.Inner", "E.Inner").WithLocation(25, 17), + // (26,16): error CS9051: File-local type 'C.Inner' cannot be used in a member signature in non-file-local type 'E.Inner'. + // object this[C.Inner inner] { get => inner; set { } } // 3 + Diagnostic(ErrorCode.ERR_FileTypeDisallowedInSignature, "this").WithArguments("C.Inner", "E.Inner").WithLocation(26, 16), + // (27,31): error CS9051: File-local type 'C.InnerDelegate' cannot be used in a member signature in non-file-local type 'E.Inner'. + // event C.InnerDelegate @event; // 4 + Diagnostic(ErrorCode.ERR_FileTypeDisallowedInSignature, "@event").WithArguments("C.InnerDelegate", "E.Inner").WithLocation(27, 31)); + } + + [Fact] + public void SignatureUsage_06() + { + var source = """ + file class C + { + } + + delegate void Del1(C c); // 1 + delegate C Del2(); // 2 + """; + + var comp = CreateCompilation(source); + comp.VerifyDiagnostics( + // (5,15): error CS9051: File-local type 'C' cannot be used in a member signature in non-file-local type 'Del1'. + // delegate void Del1(C c); // 1 + Diagnostic(ErrorCode.ERR_FileTypeDisallowedInSignature, "Del1").WithArguments("C", "Del1").WithLocation(5, 15), + // (6,12): error CS9051: File-local type 'C' cannot be used in a member signature in non-file-local type 'Del2'. + // delegate C Del2(); // 2 + Diagnostic(ErrorCode.ERR_FileTypeDisallowedInSignature, "Del2").WithArguments("C", "Del2").WithLocation(6, 12)); + } + + [Fact] + public void SignatureUsage_07() + { + var source = """ + file class C + { + } + + class D + { + public static D operator +(D d, C c) => d; // 1 + public static C operator -(D d1, D d2) => new C(); // 2 + } + """; + + var comp = CreateCompilation(source); + comp.VerifyDiagnostics( + // (7,30): error CS9051: File-local type 'C' cannot be used in a member signature in non-file-local type 'D'. + // public static D operator +(D d, C c) => d; // 1 + Diagnostic(ErrorCode.ERR_FileTypeDisallowedInSignature, "+").WithArguments("C", "D").WithLocation(7, 30), + // (8,30): error CS9051: File-local type 'C' cannot be used in a member signature in non-file-local type 'D'. + // public static C operator -(D d1, D d2) => new C(); // 2 + Diagnostic(ErrorCode.ERR_FileTypeDisallowedInSignature, "-").WithArguments("C", "D").WithLocation(8, 30)); + } + + [Fact] + public void SignatureUsage_08() + { + var source = """ + file class C + { + } + + class D + { + public D(C c) { } // 1 + } + """; + + var comp = CreateCompilation(source); + comp.VerifyDiagnostics( + // (7,12): error CS9051: File-local type 'C' cannot be used in a member signature in non-file-local type 'D'. + // public D(C c) { } // 1 + Diagnostic(ErrorCode.ERR_FileTypeDisallowedInSignature, "D").WithArguments("C", "D").WithLocation(7, 12)); + } + + [Fact] + public void SignatureUsage_09() + { + var source = """ + file class C + { + } + + class D + { + public C M(C c1, C c2) => c1; // 1, 2, 3 + } + """; + + var comp = CreateCompilation(source); + comp.VerifyDiagnostics( + // (7,14): error CS9051: File-local type 'C' cannot be used in a member signature in non-file-local type 'D'. + // public C M(C c1, C c2) => c1; // 1, 2, 3 + Diagnostic(ErrorCode.ERR_FileTypeDisallowedInSignature, "M").WithArguments("C", "D").WithLocation(7, 14), + // (7,14): error CS9051: File-local type 'C' cannot be used in a member signature in non-file-local type 'D'. + // public C M(C c1, C c2) => c1; // 1, 2, 3 + Diagnostic(ErrorCode.ERR_FileTypeDisallowedInSignature, "M").WithArguments("C", "D").WithLocation(7, 14), + // (7,14): error CS9051: File-local type 'C' cannot be used in a member signature in non-file-local type 'D'. + // public C M(C c1, C c2) => c1; // 1, 2, 3 + Diagnostic(ErrorCode.ERR_FileTypeDisallowedInSignature, "M").WithArguments("C", "D").WithLocation(7, 14)); + } + + [Fact] + public void AccessModifiers_01() + { + var source = """ + public file class C { } // 1 + file internal class D { } // 2 + private file class E { } // 3, 4 + file class F { } // ok + """; + + var comp = CreateCompilation(source); + comp.VerifyDiagnostics( + // (1,19): error CS9052: File-local type 'C' cannot use accessibility modifiers. + // public file class C { } // 1 + Diagnostic(ErrorCode.ERR_FileTypeNoExplicitAccessibility, "C").WithArguments("C").WithLocation(1, 19), + // (2,21): error CS9052: File-local type 'D' cannot use accessibility modifiers. + // file internal class D { } // 2 + Diagnostic(ErrorCode.ERR_FileTypeNoExplicitAccessibility, "D").WithArguments("D").WithLocation(2, 21), + // (3,20): error CS9052: File-local type 'E' cannot use accessibility modifiers. + // private file class E { } // 3, 4 + Diagnostic(ErrorCode.ERR_FileTypeNoExplicitAccessibility, "E").WithArguments("E").WithLocation(3, 20), + // (3,20): error CS1527: Elements defined in a namespace cannot be explicitly declared as private, protected, protected internal, or private protected + // private file class E { } // 3, 4 + Diagnostic(ErrorCode.ERR_NoNamespacePrivate, "E").WithLocation(3, 20)); + } + + [Fact] + public void DuplicateModifiers_01() + { + var source = """ + file file class C { } // 1 + file readonly file struct D { } // 2 + """; + + var comp = CreateCompilation(source); + comp.VerifyDiagnostics( + // (1,6): error CS1004: Duplicate 'file' modifier + // file file class C { } // 1 + Diagnostic(ErrorCode.ERR_DuplicateModifier, "file").WithArguments("file").WithLocation(1, 6), + // (2,15): error CS1004: Duplicate 'file' modifier + // file readonly file struct D { } // 2 + Diagnostic(ErrorCode.ERR_DuplicateModifier, "file").WithArguments("file").WithLocation(2, 15)); + } + + [Fact] + public void BaseClause_01() + { + var source = """ + file class Base { } + class Derived1 : Base { } // 1 + public class Derived2 : Base { } // 2, 3 + file class Derived3 : Base { } // ok + """; + + var comp = CreateCompilation(source); + comp.VerifyDiagnostics( + // (2,7): error CS9053: File-local type 'Base' cannot be used as a base type of non-file-local type 'Derived1'. + // class Derived1 : Base { } // 1 + Diagnostic(ErrorCode.ERR_FileTypeBase, "Derived1").WithArguments("Base", "Derived1").WithLocation(2, 7), + // (3,14): error CS0060: Inconsistent accessibility: base class 'Base' is less accessible than class 'Derived2' + // public class Derived2 : Base { } // 2, 3 + Diagnostic(ErrorCode.ERR_BadVisBaseClass, "Derived2").WithArguments("Derived2", "Base").WithLocation(3, 14), + // (3,14): error CS9053: File-local type 'Base' cannot be used as a base type of non-file-local type 'Derived2'. + // public class Derived2 : Base { } // 2, 3 + Diagnostic(ErrorCode.ERR_FileTypeBase, "Derived2").WithArguments("Base", "Derived2").WithLocation(3, 14)); + } + + [Fact] + public void BaseClause_02() + { + var source = """ + file interface Interface { } + + class Derived1 : Interface { } // ok + file class Derived2 : Interface { } // ok + + interface Derived3 : Interface { } // 1 + file interface Derived4 : Interface { } // ok + """; + + var comp = CreateCompilation(source); + comp.VerifyDiagnostics( + // (6,11): error CS9053: File-local type 'Interface' cannot be used as a base type of non-file-local type 'Derived3'. + // interface Derived3 : Interface { } // 1 + Diagnostic(ErrorCode.ERR_FileTypeBase, "Derived3").WithArguments("Interface", "Derived3").WithLocation(6, 11)); + } + + [Fact] + public void BaseClause_03() + { + var source1 = """ + using System; + class Base + { + public static void M0() + { + Console.Write(1); + } + } + """; + var source2 = """ + using System; + + file class Base + { + public static void M0() + { + Console.Write(2); + } + } + file class Program : Base + { + static void Main() + { + M0(); + } + } + """; + + var verifier = CompileAndVerify(new[] { source1, source2 }, expectedOutput: "2"); + verifier.VerifyDiagnostics(); + var comp = (CSharpCompilation)verifier.Compilation; + + var tree = comp.SyntaxTrees[1]; + var model = comp.GetSemanticModel(tree); + + var fileClassBase = (NamedTypeSymbol)comp.GetMembers("Base")[1]; + var expectedSymbol = fileClassBase.GetMember("M0"); + + var node = tree.GetRoot().DescendantNodes().OfType().Last(); + var symbolInfo = model.GetSymbolInfo(node.Expression); + Assert.Equal(expectedSymbol.GetPublicSymbol(), symbolInfo.Symbol); + Assert.Empty(symbolInfo.CandidateSymbols); + Assert.Equal(CandidateReason.None, symbolInfo.CandidateReason); + } + + [Fact] + public void BaseClause_04() + { + var source1 = """ + using System; + class Base + { + public static void M0() + { + Console.Write(1); + } + } + """; + var source2 = """ + file class Program : Base + { + static void Main() + { + M0(); + } + } + """; + + var verifier = CompileAndVerify(new[] { source1, source2 }, expectedOutput: "1"); + verifier.VerifyDiagnostics(); + var comp = (CSharpCompilation)verifier.Compilation; + + var tree = comp.SyntaxTrees[1]; + var model = comp.GetSemanticModel(tree); + + var expectedSymbol = comp.GetMember("Base.M0"); + + var node = tree.GetRoot().DescendantNodes().OfType().Last(); + var symbolInfo = model.GetSymbolInfo(node.Expression); + Assert.Equal(expectedSymbol.GetPublicSymbol(), symbolInfo.Symbol); + Assert.Empty(symbolInfo.CandidateSymbols); + Assert.Equal(CandidateReason.None, symbolInfo.CandidateReason); + } + + [Fact] + public void BaseClause_05() + { + var source = """ + interface I2 { } + file interface I1 { } + partial interface Derived : I1 { } // 1 + partial interface Derived : I2 { } + """; + + var comp = CreateCompilation(source); + comp.VerifyDiagnostics( + // (3,19): error CS9053: File-local type 'I1' cannot be used as a base type of non-file-local type 'Derived'. + // partial interface Derived : I1 { } // 1 + Diagnostic(ErrorCode.ERR_FileTypeBase, "Derived").WithArguments("I1", "Derived").WithLocation(3, 19)); + } + + [Fact] + public void InterfaceImplementation_01() + { + var source = """ + file interface I + { + void F(); + } + class C : I + { + public void F() { } + } + """; + + var comp = CreateCompilation(source); + comp.VerifyDiagnostics(); + } + + [Fact] + public void InterfaceImplementation_02() + { + var source = """ + file interface I + { + void F(I i); + } + class C : I + { + public void F(I i) { } // 1 + } + """; + + var comp = CreateCompilation(source); + comp.VerifyDiagnostics( + // (7,17): error CS9051: File-local type 'I' cannot be used in a member signature in non-file-local type 'C'. + // public void F(I i) { } // 1 + Diagnostic(ErrorCode.ERR_FileTypeDisallowedInSignature, "F").WithArguments("I", "C").WithLocation(7, 17)); + } + + [Fact] + public void InterfaceImplementation_03() + { + var source = """ + file interface I + { + void F(I i); + } + class C : I + { + void I.F(I i) { } + } + """; + + var comp = CreateCompilation(source); + comp.VerifyDiagnostics( + // (7,12): error CS9051: File-local type 'I' cannot be used in a member signature in non-file-local type 'C'. + // void I.F(I i) { } + Diagnostic(ErrorCode.ERR_FileTypeDisallowedInSignature, "F").WithArguments("I", "C").WithLocation(7, 12)); + } + + [Fact] + public void InterfaceImplementation_04() + { + var source1 = """ + file interface I + { + void F(); + } + partial class C : I + { + } + """; + + var source2 = """ + partial class C + { + public void F() { } + } + """; + + // This is similar to how a base class may not have access to an interface (by being from another assembly, etc.), + // but a derived class might add that interface to its list, and a base member implicitly implements an interface member. + var comp = CreateCompilation(new[] { source1, source2 }); + comp.VerifyDiagnostics(); + } + + [Fact] + public void InterfaceImplementation_05() + { + var source1 = """ + file interface I + { + void F(); + } + partial class C : I // 1 + { + } + """; + + var source2 = """ + partial class C + { + void I.F() { } // 2, 3 + } + """; + + var comp = CreateCompilation(new[] { source1, source2 }); + comp.VerifyDiagnostics( + // (3,10): error CS0246: The type or namespace name 'I' could not be found (are you missing a using directive or an assembly reference?) + // void I.F() { } // 2, 3 + Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "I").WithArguments("I").WithLocation(3, 10), + // (3,10): error CS0538: 'I' in explicit interface declaration is not an interface + // void I.F() { } // 2, 3 + Diagnostic(ErrorCode.ERR_ExplicitInterfaceImplementationNotInterface, "I").WithArguments("I").WithLocation(3, 10), + // (5,19): error CS0535: 'C' does not implement interface member 'I.F()' + // partial class C : I // 1 + Diagnostic(ErrorCode.ERR_UnimplementedInterfaceMember, "I").WithArguments("C", "I.F()").WithLocation(5, 19)); + } + + [Fact] + public void TypeArguments_01() + { + var source = """ + file struct S { public int X; } + class Container { } + unsafe class Program + { + Container M1() => new Container(); // 1 + S[] M2() => new S[0]; // 2 + (S, S) M3() => (new S(), new S()); // 3 + S* M4() => null; // 4 + delegate* M5() => null; // 5 + } + """; + + var comp = CreateCompilation(source, options: TestOptions.UnsafeDebugDll); + comp.VerifyDiagnostics( + // (1,28): warning CS0649: Field 'S.X' is never assigned to, and will always have its default value 0 + // file struct S { public int X; } + Diagnostic(ErrorCode.WRN_UnassignedInternalField, "X").WithArguments("S.X", "0").WithLocation(1, 28), + // (5,18): error CS9051: File-local type 'Container' cannot be used in a member signature in non-file-local type 'Program'. + // Container M1() => new Container(); // 1 + Diagnostic(ErrorCode.ERR_FileTypeDisallowedInSignature, "M1").WithArguments("Container", "Program").WithLocation(5, 18), + // (6,9): error CS9051: File-local type 'S[]' cannot be used in a member signature in non-file-local type 'Program'. + // S[] M2() => new S[0]; // 2 + Diagnostic(ErrorCode.ERR_FileTypeDisallowedInSignature, "M2").WithArguments("S[]", "Program").WithLocation(6, 9), + // (7,12): error CS9051: File-local type '(S, S)' cannot be used in a member signature in non-file-local type 'Program'. + // (S, S) M3() => (new S(), new S()); // 3 + Diagnostic(ErrorCode.ERR_FileTypeDisallowedInSignature, "M3").WithArguments("(S, S)", "Program").WithLocation(7, 12), + // (8,8): error CS9051: File-local type 'S*' cannot be used in a member signature in non-file-local type 'Program'. + // S* M4() => null; // 4 + Diagnostic(ErrorCode.ERR_FileTypeDisallowedInSignature, "M4").WithArguments("S*", "Program").WithLocation(8, 8), + // (9,24): error CS9051: File-local type 'delegate*' cannot be used in a member signature in non-file-local type 'Program'. + // delegate* M5() => null; // 5 + Diagnostic(ErrorCode.ERR_FileTypeDisallowedInSignature, "M5").WithArguments("delegate*", "Program").WithLocation(9, 24)); + } + + [Fact] + public void Constraints_01() + { + var source = """ + file class C { } + + file class D + { + void M(T t) where T : C { } // ok + } + + class E + { + void M(T t) where T : C { } // 1 + } + """; + + var comp = CreateCompilation(source); + comp.VerifyDiagnostics( + // (10,30): error CS9051: File-local type 'C' cannot be used in a member signature in non-file-local type 'E.M(T)'. + // void M(T t) where T : C { } // 1 + Diagnostic(ErrorCode.ERR_FileTypeDisallowedInSignature, "C").WithArguments("C", "E.M(T)").WithLocation(10, 30)); + } + + [Theory, WorkItem(62435, "https://github.com/dotnet/roslyn/issues/62435")] + [InlineData("class")] + [InlineData("struct")] + [InlineData("interface")] + [InlineData("record")] + [InlineData("record struct")] + public void Constraints_02(string typeKind) + { + var source = $$""" + file class C { } + + file {{typeKind}} D where T : C // ok + { + } + + {{typeKind}} E where T : C // 1 + { + } + """; + + var comp = CreateCompilation(source); + comp.VerifyDiagnostics( + // (7,{{17 + typeKind.Length}}): error CS9051: File-local type 'C' cannot be used in a member signature in non-file-local type 'E'. + // {{typeKind}} E where T : C // 1 + Diagnostic(ErrorCode.ERR_FileTypeDisallowedInSignature, "C").WithArguments("C", "E").WithLocation(7, 17 + typeKind.Length)); + } + + [Fact] + public void Constraints_03() + { + var source = """ + file class C { } + + file class D + { + void M() + { + local(new C()); + void local(T t) where T : C { } // ok + } + } + + class E + { + void M() + { + local(new C()); + void local(T t) where T : C { } // ok + } + } + """; + + // Local functions aren't members, so we don't give any diagnostics when their signatures contain file types. + var comp = CreateCompilation(source); + comp.VerifyDiagnostics(); + } + + [Fact] + public void Constraints_04() + { + var source = """ + file class C { } + + file delegate void D1(T t) where T : C; // ok + + delegate void D2(T t) where T : C; // 1 + """; + + var comp = CreateCompilation(source); + comp.VerifyDiagnostics( + // (5,36): error CS9051: File-local type 'C' cannot be used in a member signature in non-file-local type 'D2'. + // delegate void D2(T t) where T : C; // 1 + Diagnostic(ErrorCode.ERR_FileTypeDisallowedInSignature, "C").WithArguments("C", "D2").WithLocation(5, 36)); + } + + [Fact] + public void PrimaryConstructor_01() + { + var source = """ + file class C { } + + record R1(C c); // 1 + record struct R2(C c); // 2 + + file record R3(C c); + file record struct R4(C c); + """; + + var comp = CreateCompilation(new[] { source, IsExternalInitTypeDefinition }); + comp.VerifyDiagnostics( + // (3,8): error CS9051: File-local type 'C' cannot be used in a member signature in non-file-local type 'R1'. + // record R1(C c); // 1 + Diagnostic(ErrorCode.ERR_FileTypeDisallowedInSignature, "R1").WithArguments("C", "R1").WithLocation(3, 8), + // (3,8): error CS9051: File-local type 'C' cannot be used in a member signature in non-file-local type 'R1'. + // record R1(C c); // 1 + Diagnostic(ErrorCode.ERR_FileTypeDisallowedInSignature, "R1").WithArguments("C", "R1").WithLocation(3, 8), + // (4,15): error CS9051: File-local type 'C' cannot be used in a member signature in non-file-local type 'R2'. + // record struct R2(C c); // 2 + Diagnostic(ErrorCode.ERR_FileTypeDisallowedInSignature, "R2").WithArguments("C", "R2").WithLocation(4, 15), + // (4,15): error CS9051: File-local type 'C' cannot be used in a member signature in non-file-local type 'R2'. + // record struct R2(C c); // 2 + Diagnostic(ErrorCode.ERR_FileTypeDisallowedInSignature, "R2").WithArguments("C", "R2").WithLocation(4, 15) + ); + } + + [Fact] + public void Lambda_01() + { + var source = """ + file class C { } + + class Program + { + void M() + { + var lambda = C (C c) => c; // ok + } + } + """; + + var comp = CreateCompilation(source); + comp.VerifyDiagnostics(); + } + + [Fact] + public void LocalFunction_01() + { + var source = """ + file class C { } + + class Program + { + void M() + { + local(null!); + C local(C c) => c; // ok + } + } + """; + + var comp = CreateCompilation(source); + comp.VerifyDiagnostics(); + } + + [Fact] + public void AccessThroughNamespace_01() + { + var source = """ + using System; + + namespace NS + { + file class C + { + public static void M() => Console.Write(1); + } + } + + class Program + { + public static void Main() + { + NS.C.M(); + } + } + """; + + var verifier = CompileAndVerify(source, expectedOutput: "1"); + verifier.VerifyDiagnostics(); + } + + [Fact] + public void AccessThroughNamespace_02() + { + var source1 = """ + using System; + + namespace NS + { + file class C + { + public static void M() + { + Console.Write(1); + } + } + } + """; + + var source2 = """ + class Program + { + static void Main() + { + NS.C.M(); // 1 + } + } + """; + + var comp = CreateCompilation(new[] { source1, source2 }); + comp.VerifyDiagnostics( + // (5,9): error CS0234: The type or namespace name 'C' does not exist in the namespace 'NS' (are you missing an assembly reference?) + // NS.C.M(); // 1 + Diagnostic(ErrorCode.ERR_DottedTypeNameNotFoundInNS, "NS.C").WithArguments("C", "NS").WithLocation(5, 9)); + } + + [Fact] + public void AccessThroughType_01() + { + var source = """ + using System; + + class Outer + { + file class C // 1 + { + public static void M() => Console.Write(1); + } + } + + class Program + { + public static void Main() + { + Outer.C.M(); // 2 + } + } + """; + + var comp = CreateCompilation(source); + comp.VerifyDiagnostics( + // (5,16): error CS9054: File-local type 'Outer.C' must be defined in a top level type; 'Outer.C' is a nested type. + // file class C // 1 + Diagnostic(ErrorCode.ERR_FileTypeNested, "C").WithArguments("Outer.C").WithLocation(5, 16), + // (15,15): error CS0122: 'Outer.C' is inaccessible due to its protection level + // Outer.C.M(); // 2 + Diagnostic(ErrorCode.ERR_BadAccess, "C").WithArguments("Outer.C").WithLocation(15, 15)); + } + + [Fact] + public void AccessThroughType_02() + { + var source1 = """ + using System; + + class Outer + { + file class C + { + public static void M() + { + Console.Write(1); + } + } + } + """; + + var source2 = """ + class Program + { + static void Main() + { + Outer.C.M(); // 1 + } + } + """; + + var comp = CreateCompilation(new[] { source1, source2 }); + comp.VerifyDiagnostics( + // (5,15): error CS0117: 'Outer' does not contain a definition for 'C' + // Outer.C.M(); // 1 + Diagnostic(ErrorCode.ERR_NoSuchMember, "C").WithArguments("Outer", "C").WithLocation(5, 15), + // (5,16): error CS9054: File-local type 'Outer.C' must be defined in a top level type; 'Outer.C' is a nested type. + // file class C + Diagnostic(ErrorCode.ERR_FileTypeNested, "C").WithArguments("Outer.C").WithLocation(5, 16)); + } + + [Fact] + public void AccessThroughGlobalUsing_01() + { + var usings = """ + global using NS; + """; + + var source = """ + using System; + + namespace NS + { + file class C + { + public static void M() => Console.Write(1); + } + } + + class Program + { + public static void Main() + { + C.M(); + } + } + """; + + var verifier = CompileAndVerify(new[] { usings, source, IsExternalInitTypeDefinition }, expectedOutput: "1"); + verifier.VerifyDiagnostics(); + } + + [Theory] + [InlineData("file ")] + [InlineData("")] + public void AccessThroughGlobalUsing_02(string fileModifier) + { + var source = $$""" + using System; + + namespace NS + { + {{fileModifier}}class C + { + public static void M() => Console.Write(1); + } + } + + class Program + { + public static void Main() + { + C.M(); // 1 + } + } + """; + + // note: 'Usings' is a legacy setting which only works in scripts. + // https://github.com/dotnet/roslyn/issues/61502 + var compilation = CreateCompilation(new[] { source, IsExternalInitTypeDefinition }, options: TestOptions.DebugExe.WithUsings("NS")); + compilation.VerifyDiagnostics( + // (15,9): error CS0103: The name 'C' does not exist in the current context + // C.M(); // 1 + Diagnostic(ErrorCode.ERR_NameNotInContext, "C").WithArguments("C").WithLocation(15, 9)); + } + + [Fact] + public void GlobalUsingStatic_01() + { + var source = """ + global using static C; + + file class C + { + public static void M() { } + } + """; + + var main = """ + class Program + { + public static void Main() + { + M(); + } + } + """; + + var compilation = CreateCompilation(new[] { source, main }); + compilation.VerifyDiagnostics( + // (1,1): hidden CS8019: Unnecessary using directive. + // global using static C; + Diagnostic(ErrorCode.HDN_UnusedUsingDirective, "global using static C;").WithLocation(1, 1), + // (1,21): error CS9055: File-local type 'C' cannot be used in a 'global using static' directive. + // global using static C; + Diagnostic(ErrorCode.ERR_GlobalUsingStaticFileType, "C").WithArguments("C").WithLocation(1, 21), + // (5,9): error CS0103: The name 'M' does not exist in the current context + // M(); + Diagnostic(ErrorCode.ERR_NameNotInContext, "M").WithArguments("M").WithLocation(5, 9)); + } + + [Fact] + public void GlobalUsingStatic_02() + { + var source = """ + global using static Container; + + public class Container + { + } + + file class C + { + public static void M() { } + } + """; + + var main = """ + class Program + { + public static void Main() + { + M(); + } + } + """; + + var compilation = CreateCompilation(new[] { source, main }); + compilation.VerifyDiagnostics( + // (1,1): hidden CS8019: Unnecessary using directive. + // global using static Container; + Diagnostic(ErrorCode.HDN_UnusedUsingDirective, "global using static Container;").WithLocation(1, 1), + // (1,21): error CS9055: File-local type 'Container' cannot be used in a 'global using static' directive. + // global using static Container; + Diagnostic(ErrorCode.ERR_GlobalUsingStaticFileType, "Container").WithArguments("Container").WithLocation(1, 21), + // (5,9): error CS0103: The name 'M' does not exist in the current context + // M(); + Diagnostic(ErrorCode.ERR_NameNotInContext, "M").WithArguments("M").WithLocation(5, 9)); + } + + [Fact] + public void UsingStatic_01() + { + var source = """ + using System; + using static C; + + file class C + { + public static void M() + { + Console.Write(1); + } + } + + class Program + { + public static void Main() + { + M(); + } + } + """; + + var verifier = CompileAndVerify(source, expectedOutput: "1"); + verifier.VerifyDiagnostics(); + } + + [Fact] + public void UsingStatic_02() + { + var source1 = """ + using System; + using static C.D; + + M(); + + file class C + { + public class D + { + public static void M() { Console.Write(1); } + } + } + """; + + var source2 = """ + using System; + + class C + { + public class D + { + public static void M() { Console.Write(2); } + } + } + """; + + var verifier = CompileAndVerify(new[] { source1, source2 }, expectedOutput: "1"); + verifier.VerifyDiagnostics(); + var comp = (CSharpCompilation)verifier.Compilation; + + var tree = comp.SyntaxTrees[0]; + var model = comp.GetSemanticModel(tree); + + var members = comp.GetMembers("C"); + Assert.Equal(2, members.Length); + var expectedMember = ((NamedTypeSymbol)members[0]).GetMember("D.M"); + + var invocation = tree.GetRoot().DescendantNodes().OfType().First(); + var symbolInfo = model.GetSymbolInfo(invocation.Expression); + Assert.Equal(expectedMember.GetPublicSymbol(), symbolInfo.Symbol); + Assert.Equal(0, symbolInfo.CandidateSymbols.Length); + Assert.Equal(CandidateReason.None, symbolInfo.CandidateReason); + } + + [Theory] + [InlineData("file ")] + [InlineData("")] + public void UsingStatic_03(string fileModifier) + { + // note: the top-level `class D` "wins" the lookup in this scenario. + var source1 = $$""" + using System; + using static C; + + D.M(); + + {{fileModifier}}class C + { + public class D + { + public static void M() { Console.Write(1); } + } + } + """; + + var source2 = """ + using System; + + class D + { + public static void M() { Console.Write(2); } + } + """; + + var verifier = CompileAndVerify(new[] { source1, source2 }, expectedOutput: "2"); + verifier.VerifyDiagnostics( + // (2,1): hidden CS8019: Unnecessary using directive. + // using static C; + Diagnostic(ErrorCode.HDN_UnusedUsingDirective, "using static C;").WithLocation(2, 1)); + var comp = (CSharpCompilation)verifier.Compilation; + + var tree = comp.SyntaxTrees[0]; + var model = comp.GetSemanticModel(tree); + + var expectedMember = comp.GetMember("D.M"); + + var invocation = tree.GetRoot().DescendantNodes().OfType().First(); + var symbolInfo = model.GetSymbolInfo(invocation.Expression); + Assert.Equal(expectedMember.GetPublicSymbol(), symbolInfo.Symbol); + Assert.Equal(0, symbolInfo.CandidateSymbols.Length); + Assert.Equal(CandidateReason.None, symbolInfo.CandidateReason); + } + + [Fact] + public void TypeShadowing() + { + var source = """ + using System; + + class Base + { + internal class C + { + public static void M() + { + Console.Write(1); + } + } + } + + class Derived : Base + { + new file class C + { + } + } + """; + + var main = """ + class Program + { + public static void Main() + { + Derived.C.M(); + } + } + """; + + // 'Derived.C' is not actually accessible from 'Program', so we just bind to 'Base.C'. + var compilation = CreateCompilation(new[] { source, main }); + compilation.VerifyDiagnostics( + // (16,20): error CS9054: File-local type 'Derived.C' must be defined in a top level type; 'Derived.C' is a nested type. + // new file class C + Diagnostic(ErrorCode.ERR_FileTypeNested, "C").WithArguments("Derived.C").WithLocation(16, 20)); + + var expected = compilation.GetMember("Base.C.M"); + + var tree = compilation.SyntaxTrees[1]; + var model = compilation.GetSemanticModel(tree); + var invoked = tree.GetRoot().DescendantNodes().OfType().Single().Expression; + var symbolInfo = model.GetSymbolInfo(invoked); + Assert.Equal(expected, symbolInfo.Symbol.GetSymbol()); + } + + [Fact] + public void SemanticModel_01() + { + var source = """ + namespace NS; + + file class C + { + public static void M() { } + } + + class Program + { + public void M() + { + C.M(); + } + } + """; + + var compilation = CreateCompilation(source); + compilation.VerifyDiagnostics(); + + var tree = compilation.SyntaxTrees[0]; + var body = tree.GetRoot().DescendantNodes().OfType().Last().Body!; + + var model = compilation.GetSemanticModel(tree, ignoreAccessibility: false); + + var info = model.GetSymbolInfo(((ExpressionStatementSyntax)body.Statements.First()).Expression); + Assert.Equal("void NS.C@.M()", info.Symbol.ToTestDisplayString()); + + var classC = compilation.GetMember("NS.C").GetPublicSymbol(); + Assert.Equal("NS.C@", classC.ToTestDisplayString()); + + // lookup with no container + var symbols = model.LookupSymbols(body.OpenBraceToken.EndPosition, name: "C"); + Assert.Equal(new[] { classC }, symbols); + + symbols = model.LookupSymbols(body.OpenBraceToken.EndPosition); + Assert.Contains(classC, symbols); + + // lookup with a correct container + var nsSymbol = compilation.GetMember("NS").GetPublicSymbol(); + Assert.Equal("NS", nsSymbol.ToTestDisplayString()); + + symbols = model.LookupSymbols(body.OpenBraceToken.EndPosition, container: nsSymbol, name: "C"); + Assert.Equal(new[] { classC }, symbols); + + symbols = model.LookupSymbols(body.OpenBraceToken.EndPosition, container: nsSymbol); + Assert.Contains(classC, symbols); + + // lookup with an incorrect container + nsSymbol = compilation.GetMember("System").GetPublicSymbol(); + Assert.Equal("System", nsSymbol.ToTestDisplayString()); + + symbols = model.LookupSymbols(body.OpenBraceToken.EndPosition, container: nsSymbol, name: "C"); + Assert.Empty(symbols); + + symbols = model.LookupSymbols(body.OpenBraceToken.EndPosition, container: nsSymbol); + Assert.DoesNotContain(classC, symbols); + } + + [Fact] + public void SemanticModel_02() + { + var source = """ + namespace NS; + + file class C + { + public static void M() { } + } + """; + + var main = """ + namespace NS; + + class Program + { + public void M() + { + C.M(); // 1 + } + } + """; + + var compilation = CreateCompilation(new[] { source, main }); + compilation.VerifyDiagnostics( + // (7,9): error CS0103: The name 'C' does not exist in the current context + // C.M(); // 1 + Diagnostic(ErrorCode.ERR_NameNotInContext, "C").WithArguments("C").WithLocation(7, 9) + ); + + var tree = compilation.SyntaxTrees[1]; + var body = tree.GetRoot().DescendantNodes().OfType().Last().Body!; + + var model = compilation.GetSemanticModel(tree, ignoreAccessibility: false); + + var info = model.GetSymbolInfo(((ExpressionStatementSyntax)body.Statements.First()).Expression); + Assert.Null(info.Symbol); + Assert.Empty(info.CandidateSymbols); + Assert.Equal(CandidateReason.None, info.CandidateReason); + + var classC = compilation.GetMember("NS.C").GetPublicSymbol(); + Assert.Equal("NS.C@", classC.ToTestDisplayString()); + + // lookup with no container + var symbols = model.LookupSymbols(body.OpenBraceToken.EndPosition, name: "C"); + Assert.Empty(symbols); + + symbols = model.LookupSymbols(body.OpenBraceToken.EndPosition); + Assert.DoesNotContain(classC, symbols); + + // lookup with a correct container (still don't find the symbol due to lookup occurring in other file) + var nsSymbol = compilation.GetMember("NS").GetPublicSymbol(); + Assert.Equal("NS", nsSymbol.ToTestDisplayString()); + + symbols = model.LookupSymbols(body.OpenBraceToken.EndPosition, container: nsSymbol, name: "C"); + Assert.Empty(symbols); + + symbols = model.LookupSymbols(body.OpenBraceToken.EndPosition, container: nsSymbol); + Assert.DoesNotContain(classC, symbols); + + // lookup with an incorrect container + nsSymbol = compilation.GetMember("System").GetPublicSymbol(); + Assert.Equal("System", nsSymbol.ToTestDisplayString()); + + symbols = model.LookupSymbols(body.OpenBraceToken.EndPosition, container: nsSymbol, name: "C"); + Assert.Empty(symbols); + + symbols = model.LookupSymbols(body.OpenBraceToken.EndPosition, container: nsSymbol); + Assert.DoesNotContain(classC, symbols); + } + + [Fact] + public void Speculation_01() + { + var source = """ + file class C + { + public static void M() { } + } + + class Program + { + public void M() + { + + } + } + """; + + var compilation = CreateCompilation(source); + compilation.VerifyDiagnostics(); + + var tree = compilation.SyntaxTrees[0]; + var body = tree.GetRoot().DescendantNodes().OfType().Last().Body!; + + var model = compilation.GetSemanticModel(tree, ignoreAccessibility: false); + + var newBody = body.AddStatements(SyntaxFactory.ParseStatement("C.M();")); + Assert.True(model.TryGetSpeculativeSemanticModel(position: body.OpenBraceToken.EndPosition, newBody, out var speculativeModel)); + var info = speculativeModel!.GetSymbolInfo(((ExpressionStatementSyntax)newBody.Statements.First()).Expression); + Assert.Equal(compilation.GetMember("C.M").GetPublicSymbol(), info.Symbol); + + var classC = compilation.GetMember("C").GetPublicSymbol(); + var symbols = speculativeModel.LookupSymbols(newBody.OpenBraceToken.EndPosition, name: "C"); + Assert.Equal(new[] { classC }, symbols); + + symbols = speculativeModel.LookupSymbols(newBody.OpenBraceToken.EndPosition); + Assert.Contains(classC, symbols); + } + + [Fact] + public void Speculation_02() + { + var source = """ + file class C + { + public static void M() { } + } + """; + + var main = """ + class Program + { + public void M() + { + + } + } + """; + + var compilation = CreateCompilation(new[] { source, main }); + compilation.VerifyDiagnostics(); + + var tree = compilation.SyntaxTrees[1]; + var body = tree.GetRoot().DescendantNodes().OfType().Last().Body!; + + var model = compilation.GetSemanticModel(tree, ignoreAccessibility: false); + + var newBody = body.AddStatements(SyntaxFactory.ParseStatement("C.M();")); + Assert.True(model.TryGetSpeculativeSemanticModel(position: body.OpenBraceToken.EndPosition, newBody, out var speculativeModel)); + var info = speculativeModel!.GetSymbolInfo(((ExpressionStatementSyntax)newBody.Statements.First()).Expression); + Assert.Null(info.Symbol); + Assert.Empty(info.CandidateSymbols); + Assert.Equal(CandidateReason.None, info.CandidateReason); + + var symbols = speculativeModel.LookupSymbols(newBody.OpenBraceToken.EndPosition, name: "C"); + Assert.Empty(symbols); + + symbols = speculativeModel.LookupSymbols(newBody.OpenBraceToken.EndPosition); + Assert.DoesNotContain(compilation.GetMember("C").GetPublicSymbol(), symbols); + } + + [Fact] + public void Cref_01() + { + var source = """ + file class C + { + public static void M() { } + } + + class Program + { + /// + /// In the same file as . + /// + public static void M() + { + + } + } + """; + + var compilation = CreateCompilation(source, parseOptions: TestOptions.RegularPreview.WithDocumentationMode(DocumentationMode.Diagnose)); + compilation.VerifyDiagnostics(); + } + + [Fact] + public void Cref_02() + { + var source = """ + file class C + { + public static void M() { } + } + """; + + var main = """ + class Program + { + /// + /// In a different file than . + /// + public static void M() + { + + } + } + """; + + var compilation = CreateCompilation(new[] { source, main }, parseOptions: TestOptions.RegularPreview.WithDocumentationMode(DocumentationMode.Diagnose)); + compilation.VerifyDiagnostics( + // (4,45): warning CS1574: XML comment has cref attribute 'C' that could not be resolved + // /// In a different file than . + Diagnostic(ErrorCode.WRN_BadXMLRef, "C").WithArguments("C").WithLocation(4, 45) + ); + } + + [Fact] + public void TopLevelStatements() + { + var source = """ + using System; + + C.M(); + + file class C + { + public static void M() + { + Console.Write(1); + } + } + """; + + var verifier = CompileAndVerify(source, expectedOutput: "1"); + verifier.VerifyDiagnostics(); + } + + [Fact] + public void StaticFileClass() + { + var source = """ + using System; + + C.M(); + + static file class C + { + public static void M() + { + Console.Write(1); + } + } + """; + + var verifier = CompileAndVerify(source, expectedOutput: "1"); + verifier.VerifyDiagnostics(); + } + + [Fact] + public void ExtensionMethod_01() + { + var source = """ + using System; + + "a".M(); + + static file class C + { + public static void M(this string s) + { + Console.Write(1); + } + } + """; + + var verifier = CompileAndVerify(source, expectedOutput: "1"); + verifier.VerifyDiagnostics(); + } + + [Fact] + public void ExtensionMethod_02() + { + var source1 = """ + "a".M(); // 1 + """; + + var source2 = """ + using System; + + static file class C + { + public static void M(this string s) + { + Console.Write(1); + } + } + """; + + var comp = CreateCompilation(new[] { source1, source2 }); + comp.VerifyDiagnostics( + // (1,5): 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?) + // "a".M(); // 1 + Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "M").WithArguments("string", "M").WithLocation(1, 5)); + } + + [Fact] + public void ExtensionMethod_03() + { + var source1 = """ + "a".M(); // 1 + """; + + var source2 = """ + using System; + + file class C + { + static class D + { + public static void M(this string s) // 2 + { + Console.Write(1); + } + } + } + """; + + var comp = CreateCompilation(new[] { source1, source2 }); + comp.VerifyDiagnostics( + // (1,5): 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?) + // "a".M(); // 1 + Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "M").WithArguments("string", "M").WithLocation(1, 5), + // (7,28): error CS1109: Extension methods must be defined in a top level static class; D is a nested class + // public static void M(this string s) // 2 + Diagnostic(ErrorCode.ERR_ExtensionMethodsDecl, "M").WithArguments("D").WithLocation(7, 28)); + } + + [Fact] + public void Alias_01() + { + var source = """ + namespace NS; + using C1 = NS.C; + + file class C + { + } + + class D : C1 { } // 1 + """; + + var comp = CreateCompilation(source); + comp.VerifyDiagnostics( + // (8,7): error CS9053: File-local type 'C' cannot be used as a base type of non-file-local type 'D'. + // class D : C1 { } // 1 + Diagnostic(ErrorCode.ERR_FileTypeBase, "D").WithArguments("NS.C", "NS.D").WithLocation(8, 7)); + } + + [Fact] + public void SymbolDisplay() + { + var source1 = """ + file class C1 + { + public static void M() { } + } + """; + + var source2 = """ + file class C2 + { + public static void M() { } + } + """; + + var comp = CreateCompilation(new[] + { + SyntaxFactory.ParseSyntaxTree(source1, TestOptions.RegularPreview), + SyntaxFactory.ParseSyntaxTree(source2, TestOptions.RegularPreview, path: "path/to/FileB.cs") + }); + comp.VerifyDiagnostics(); + + var c1 = comp.GetMember("C1"); + var c2 = comp.GetMember("C2"); + Assert.Equal("C1@", c1.ToTestDisplayString()); + Assert.Equal("C2@FileB", c2.ToTestDisplayString()); + + Assert.Equal("void C1@.M()", c1.GetMember("M").ToTestDisplayString()); + Assert.Equal("void C2@FileB.M()", c2.GetMember("M").ToTestDisplayString()); + } + + [Fact] + public void Script_01() + { + var source1 = """ + using System; + + C1.M("a"); + + static file class C1 + { + public static void M(this string s) { } + } + """; + + var comp = CreateSubmission(source1, parseOptions: TestOptions.Script.WithLanguageVersion(LanguageVersion.Preview)); + comp.VerifyDiagnostics( + // (5,19): error CS9054: File-local type 'C1' must be defined in a top level type; 'C1' is a nested type. + // static file class C1 + Diagnostic(ErrorCode.ERR_FileTypeNested, "C1").WithArguments("C1").WithLocation(5, 19), + // (7,24): error CS1109: Extension methods must be defined in a top level static class; C1 is a nested class + // public static void M(this string s) { } + Diagnostic(ErrorCode.ERR_ExtensionMethodsDecl, "M").WithArguments("C1").WithLocation(7, 24)); + } + + [Fact] + public void SystemVoid_01() + { + var source1 = """ + using System; + + void M(Void v) { } + + namespace System + { + file class Void { } + } + """; + + // https://github.com/dotnet/roslyn/issues/62331 + // Ideally we would give an error about use of System.Void here. + var comp = CreateCompilation(source1); + comp.VerifyDiagnostics( + // (3,6): warning CS8321: The local function 'M' is declared but never used + // void M(Void v) { } + Diagnostic(ErrorCode.WRN_UnreferencedLocalFunction, "M").WithArguments("M").WithLocation(3, 6)); + + var tree = comp.SyntaxTrees[0]; + var model = comp.GetSemanticModel(tree); + + var voidTypeSyntax = tree.GetRoot().DescendantNodes().OfType().Single().Type!; + var typeInfo = model.GetTypeInfo(voidTypeSyntax); + Assert.Equal("System.Void@", typeInfo.Type!.ToDisplayString(SymbolDisplayFormat.TestFormat.WithCompilerInternalOptions(SymbolDisplayCompilerInternalOptions.IncludeContainingFileForFileTypes))); + } + + [Fact] + public void GetTypeByMetadataName_01() + { + var source1 = """ + file class C { } + """; + + // from source + var comp = CreateCompilation(source1); + comp.VerifyDiagnostics(); + var sourceMember = comp.GetMember("C"); + Assert.Equal("<>F0__C", sourceMember.MetadataName); + + var sourceType = comp.GetTypeByMetadataName("<>F0__C"); + Assert.Equal(sourceMember, sourceType); + + Assert.Null(comp.GetTypeByMetadataName("<>F0__D")); + Assert.Null(comp.GetTypeByMetadataName("<>F1__C")); + Assert.Null(comp.GetTypeByMetadataName("F0__C")); + Assert.Null(comp.GetTypeByMetadataName("F0__C")); + + // from metadata + var comp2 = CreateCompilation("", references: new[] { comp.EmitToImageReference() }); + comp2.VerifyDiagnostics(); + var metadataMember = comp2.GetMember("<>F0__C"); + Assert.Equal("<>F0__C", metadataMember.MetadataName); + + var metadataType = comp2.GetTypeByMetadataName("<>F0__C"); + Assert.Equal(metadataMember, metadataType); + } + + [Fact] + public void GetTypeByMetadataName_02() + { + var source1 = """ + file class C { } + """; + + // from source + var comp = CreateCompilation(source1); + comp.VerifyDiagnostics(); + var sourceMember = comp.GetMember("C"); + Assert.Equal("<>F0__C`1", sourceMember.MetadataName); + + var sourceType = comp.GetTypeByMetadataName("<>F0__C`1"); + Assert.Equal(sourceMember, sourceType); + Assert.Null(comp.GetTypeByMetadataName("<>F0__C")); + + // from metadata + var comp2 = CreateCompilation("", references: new[] { comp.EmitToImageReference() }); + comp2.VerifyDiagnostics(); + + var metadataMember = comp2.GetMember("<>F0__C"); + Assert.Equal("<>F0__C`1", metadataMember.MetadataName); + + var metadataType = comp2.GetTypeByMetadataName("<>F0__C`1"); + Assert.Equal(metadataMember, metadataType); + } + + [Fact] + public void GetTypeByMetadataName_03() + { + var source1 = """ + class Outer + { + file class C { } // 1 + } + """; + + // from source + var comp = CreateCompilation(source1); + comp.VerifyDiagnostics( + // (3,16): error CS9054: File-local type 'Outer.C' must be defined in a top level type; 'Outer.C' is a nested type. + // file class C { } // 1 + Diagnostic(ErrorCode.ERR_FileTypeNested, "C").WithArguments("Outer.C").WithLocation(3, 16)); + var sourceMember = comp.GetMember("Outer.C"); + Assert.Equal("<>F0__C", sourceMember.MetadataName); + + var sourceType = comp.GetTypeByMetadataName("Outer.<>F0__C"); + // Note: strictly speaking, it would be reasonable to return the (invalid) nested file-local type symbol here. + // However, since we don't actually support nested file types, we don't think we need the API to do the additional lookup + // when the requested type is nested, and so we end up giving a null here. + Assert.Null(sourceType); + } + + [Fact] + public void GetTypeByMetadataName_04() + { + var source1 = """ + file class C { } + """; + + var source2 = """ + class C { } + """; + + // from source + var comp = CreateCompilation(new[] { source1, source2 }); + comp.VerifyDiagnostics(); + var sourceMember = comp.GetMembers("C")[0]; + Assert.Equal("<>F0__C", sourceMember.MetadataName); + + var sourceType = comp.GetTypeByMetadataName("<>F0__C"); + Assert.Equal(sourceMember, sourceType); + + // from metadata + var comp2 = CreateCompilation("", references: new[] { comp.EmitToImageReference() }); + comp2.VerifyDiagnostics(); + + var metadataMember = comp2.GetMember("<>F0__C"); + Assert.Equal("<>F0__C", metadataMember.MetadataName); + + var metadataType = comp2.GetTypeByMetadataName("<>F0__C"); + Assert.Equal(metadataMember, metadataType); + } + + [CombinatorialData] + [Theory] + public void GetTypeByMetadataName_05(bool firstIsMetadataReference, bool secondIsMetadataReference) + { + var source1 = """ + file class C { } + """; + + // Create two references containing identically-named file types + var ref1 = CreateCompilation(source1, assemblyName: "ref1"); + var ref2 = CreateCompilation(source1, assemblyName: "ref2"); + + var comp = CreateCompilation("", references: new[] + { + firstIsMetadataReference ? ref1.ToMetadataReference() : ref1.EmitToImageReference(), + secondIsMetadataReference ? ref2.ToMetadataReference() : ref2.EmitToImageReference() + }); + comp.VerifyDiagnostics(); + + var sourceType = comp.GetTypeByMetadataName("<>F0__C"); + Assert.Null(sourceType); + + var types = comp.GetTypesByMetadataName("<>F0__C"); + Assert.Equal(2, types.Length); + Assert.Equal(firstIsMetadataReference ? "C@" : "<>F0__C", types[0].ToTestDisplayString()); + Assert.Equal(secondIsMetadataReference ? "C@" : "<>F0__C", types[1].ToTestDisplayString()); + Assert.NotEqual(types[0], types[1]); + } + + [Fact] + public void GetTypeByMetadataName_06() + { + var source1 = """ + file class C { } + file class C { } + """; + + var comp = CreateCompilation(source1); + comp.VerifyDiagnostics( + // (2,12): error CS0101: The namespace '' already contains a definition for 'C' + // file class C { } + Diagnostic(ErrorCode.ERR_DuplicateNameInNS, "C").WithArguments("C", "").WithLocation(2, 12)); + + var sourceType = ((Compilation)comp).GetTypeByMetadataName("<>F0__C"); + Assert.Equal("C@", sourceType.ToTestDisplayString()); + + var types = comp.GetTypesByMetadataName("<>F0__C"); + Assert.Equal(1, types.Length); + Assert.Same(sourceType, types[0]); + } + + [Fact] + public void GetTypeByMetadataName_07() + { + var source1 = """ + file class C { } + """; + + var comp = CreateCompilation(SyntaxFactory.ParseSyntaxTree(source1, options: TestOptions.RegularPreview, path: "path/to/SomeFile.cs")); + comp.VerifyDiagnostics(); + + Assert.Null(comp.GetTypeByMetadataName("<>F0__C")); + Assert.Empty(comp.GetTypesByMetadataName("<>F0__C")); + + Assert.Null(comp.GetTypeByMetadataName("F0__C")); + Assert.Empty(comp.GetTypesByMetadataName("F0__C")); + + var sourceType = ((Compilation)comp).GetTypeByMetadataName("F0__C"); + Assert.Equal("C@SomeFile", sourceType.ToTestDisplayString()); + + var types = comp.GetTypesByMetadataName("F0__C"); + Assert.Equal(1, types.Length); + Assert.Same(sourceType, types[0]); + } + + [Fact] + public void AssociatedSyntaxTree_01() + { + var source = """ + file class C + { + void M(C c) + { + } + } + """; + var comp = CreateCompilation(source); + comp.VerifyDiagnostics(); + + var tree = comp.SyntaxTrees[0]; + var model = comp.GetSemanticModel(tree); + var node = tree.GetRoot().DescendantNodes().OfType().Single(); + var type = (INamedTypeSymbol)model.GetTypeInfo(node.Type!).Type!; + Assert.Equal("C@", type.ToTestDisplayString()); + Assert.Equal(tree, type.GetSymbol()!.AssociatedSyntaxTree); + Assert.True(type.IsFileLocal); + + var referencingMetadataComp = CreateCompilation("", new[] { comp.ToMetadataReference() }); + type = ((Compilation)referencingMetadataComp).GetTypeByMetadataName("<>F0__C")!; + Assert.Equal("C@", type.ToTestDisplayString()); + Assert.Equal(tree, type.GetSymbol()!.AssociatedSyntaxTree); + Assert.True(type.IsFileLocal); + + var referencingImageComp = CreateCompilation("", new[] { comp.EmitToImageReference() }); + type = ((Compilation)referencingImageComp).GetTypeByMetadataName("<>F0__C")!; + Assert.Equal("<>F0__C", type.ToTestDisplayString()); + Assert.Null(type.GetSymbol()!.AssociatedSyntaxTree); + Assert.False(type.IsFileLocal); + } + + [Fact] + public void AssociatedSyntaxTree_02() + { + var source = """ + class C + { + void M(C c) + { + } + } + """; + var comp = CreateCompilation(source); + comp.VerifyDiagnostics(); + + var tree = comp.SyntaxTrees[0]; + var model = comp.GetSemanticModel(tree); + var node = tree.GetRoot().DescendantNodes().OfType().Single(); + var type = (INamedTypeSymbol)model.GetTypeInfo(node.Type!).Type!; + Assert.Equal("C", type.ToTestDisplayString()); + Assert.Null(type.GetSymbol()!.AssociatedSyntaxTree); + Assert.False(type.IsFileLocal); + } + + [Fact] + public void AssociatedSyntaxTree_03() + { + var source = """ + file class C + { + void M(C c) + { + } + } + """; + var comp = CreateCompilation(source); + comp.VerifyDiagnostics(); + + var tree = comp.SyntaxTrees[0]; + var model = comp.GetSemanticModel(tree); + var node = tree.GetRoot().DescendantNodes().OfType().Single(); + var type = (INamedTypeSymbol)model.GetTypeInfo(node.Type!).Type!; + Assert.Equal("C@", type.ToTestDisplayString()); + Assert.Equal(tree, type.GetSymbol()!.AssociatedSyntaxTree); + Assert.True(type.IsFileLocal); + } +} diff --git a/src/Compilers/CSharp/Test/Symbol/Symbols/StaticAbstractMembersInInterfacesTests.cs b/src/Compilers/CSharp/Test/Symbol/Symbols/StaticAbstractMembersInInterfacesTests.cs index f0fb8c8613e14..31fb1f7203af3 100644 --- a/src/Compilers/CSharp/Test/Symbol/Symbols/StaticAbstractMembersInInterfacesTests.cs +++ b/src/Compilers/CSharp/Test/Symbol/Symbols/StaticAbstractMembersInInterfacesTests.cs @@ -25,7 +25,7 @@ namespace Microsoft.CodeAnalysis.CSharp.UnitTests.Symbols { public class StaticAbstractMembersInInterfacesTests : CSharpTestBase { - private const TargetFramework _supportingFramework = TargetFramework.Net60; + internal const TargetFramework _supportingFramework = TargetFramework.Net60; [Fact] public void MethodModifiers_01() @@ -70,18 +70,18 @@ sealed override static void M10() targetFramework: _supportingFramework); compilation1.VerifyDiagnostics( - // (4,26): error CS8703: The modifier 'abstract' is not valid for this item in C# 10.0. Please use language version 'preview' or greater. + // (4,26): error CS8703: The modifier 'abstract' is not valid for this item in C# 10.0. Please use language version '11.0' or greater. // abstract static void M01() - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M01").WithArguments("abstract", "10.0", "preview").WithLocation(4, 26), - // (7,25): error CS8703: The modifier 'virtual' is not valid for this item in C# 10.0. Please use language version 'preview' or greater. + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M01").WithArguments("abstract", "10.0", "11.0").WithLocation(4, 26), + // (7,25): error CS8703: The modifier 'virtual' is not valid for this item in C# 10.0. Please use language version '11.0' or greater. // virtual static void M02() - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M02").WithArguments("virtual", "10.0", "preview").WithLocation(7, 25), + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M02").WithArguments("virtual", "10.0", "11.0").WithLocation(7, 25), // (7,25): error CS0501: 'I1.M02()' must declare a body because it is not marked abstract, extern, or partial // virtual static void M02() Diagnostic(ErrorCode.ERR_ConcreteMissingBody, "M02").WithArguments("I1.M02()").WithLocation(7, 25), - // (10,24): error CS8703: The modifier 'sealed' is not valid for this item in C# 10.0. Please use language version 'preview' or greater. + // (10,24): error CS8703: The modifier 'sealed' is not valid for this item in C# 10.0. Please use language version '11.0' or greater. // sealed static void M03() - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M03").WithArguments("sealed", "10.0", "preview").WithLocation(10, 24), + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M03").WithArguments("sealed", "10.0", "11.0").WithLocation(10, 24), // (10,24): error CS0501: 'I1.M03()' must declare a body because it is not marked abstract, extern, or partial // sealed static void M03() Diagnostic(ErrorCode.ERR_ConcreteMissingBody, "M03").WithArguments("I1.M03()").WithLocation(10, 24), @@ -91,51 +91,51 @@ sealed override static void M10() // (13,26): error CS0501: 'I1.M04()' must declare a body because it is not marked abstract, extern, or partial // override static void M04() Diagnostic(ErrorCode.ERR_ConcreteMissingBody, "M04").WithArguments("I1.M04()").WithLocation(13, 26), - // (16,34): error CS8703: The modifier 'virtual' is not valid for this item in C# 10.0. Please use language version 'preview' or greater. + // (16,34): error CS8703: The modifier 'abstract' is not valid for this item in C# 10.0. Please use language version '11.0' or greater. // abstract virtual static void M05() - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M05").WithArguments("virtual", "10.0", "preview").WithLocation(16, 34), - // (16,34): error CS8703: The modifier 'abstract' is not valid for this item in C# 10.0. Please use language version 'preview' or greater. + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M05").WithArguments("abstract", "10.0", "11.0").WithLocation(16, 34), + // (16,34): error CS8703: The modifier 'virtual' is not valid for this item in C# 10.0. Please use language version '11.0' or greater. // abstract virtual static void M05() - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M05").WithArguments("abstract", "10.0", "preview").WithLocation(16, 34), + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M05").WithArguments("virtual", "10.0", "11.0").WithLocation(16, 34), // (16,34): error CS0503: The abstract method 'I1.M05()' cannot be marked virtual // abstract virtual static void M05() Diagnostic(ErrorCode.ERR_AbstractNotVirtual, "M05").WithArguments("method", "I1.M05()").WithLocation(16, 34), // (19,33): error CS0106: The modifier 'sealed' is not valid for this item // abstract sealed static void M06() Diagnostic(ErrorCode.ERR_BadMemberFlag, "M06").WithArguments("sealed").WithLocation(19, 33), - // (19,33): error CS8703: The modifier 'abstract' is not valid for this item in C# 10.0. Please use language version 'preview' or greater. + // (19,33): error CS8703: The modifier 'abstract' is not valid for this item in C# 10.0. Please use language version '11.0' or greater. // abstract sealed static void M06() - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M06").WithArguments("abstract", "10.0", "preview").WithLocation(19, 33), + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M06").WithArguments("abstract", "10.0", "11.0").WithLocation(19, 33), // (22,35): error CS0106: The modifier 'override' is not valid for this item // abstract override static void M07() Diagnostic(ErrorCode.ERR_BadMemberFlag, "M07").WithArguments("override").WithLocation(22, 35), - // (22,35): error CS8703: The modifier 'abstract' is not valid for this item in C# 10.0. Please use language version 'preview' or greater. + // (22,35): error CS8703: The modifier 'abstract' is not valid for this item in C# 10.0. Please use language version '11.0' or greater. // abstract override static void M07() - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M07").WithArguments("abstract", "10.0", "preview").WithLocation(22, 35), + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M07").WithArguments("abstract", "10.0", "11.0").WithLocation(22, 35), // (25,32): error CS0106: The modifier 'sealed' is not valid for this item // virtual sealed static void M08() Diagnostic(ErrorCode.ERR_BadMemberFlag, "M08").WithArguments("sealed").WithLocation(25, 32), - // (25,32): error CS8703: The modifier 'virtual' is not valid for this item in C# 10.0. Please use language version 'preview' or greater. + // (25,32): error CS8703: The modifier 'virtual' is not valid for this item in C# 10.0. Please use language version '11.0' or greater. // virtual sealed static void M08() - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M08").WithArguments("virtual", "10.0", "preview").WithLocation(25, 32), + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M08").WithArguments("virtual", "10.0", "11.0").WithLocation(25, 32), // (25,32): error CS0501: 'I1.M08()' must declare a body because it is not marked abstract, extern, or partial // virtual sealed static void M08() Diagnostic(ErrorCode.ERR_ConcreteMissingBody, "M08").WithArguments("I1.M08()").WithLocation(25, 32), - // (28,34): error CS8703: The modifier 'virtual' is not valid for this item in C# 10.0. Please use language version 'preview' or greater. - // virtual override static void M09() - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M09").WithArguments("virtual", "10.0", "preview").WithLocation(28, 34), // (28,34): error CS0106: The modifier 'override' is not valid for this item // virtual override static void M09() Diagnostic(ErrorCode.ERR_BadMemberFlag, "M09").WithArguments("override").WithLocation(28, 34), + // (28,34): error CS8703: The modifier 'virtual' is not valid for this item in C# 10.0. Please use language version '11.0' or greater. + // virtual override static void M09() + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M09").WithArguments("virtual", "10.0", "11.0").WithLocation(28, 34), // (28,34): error CS0501: 'I1.M09()' must declare a body because it is not marked abstract, extern, or partial // virtual override static void M09() Diagnostic(ErrorCode.ERR_ConcreteMissingBody, "M09").WithArguments("I1.M09()").WithLocation(28, 34), // (31,33): error CS0106: The modifier 'override' is not valid for this item // sealed override static void M10() Diagnostic(ErrorCode.ERR_BadMemberFlag, "M10").WithArguments("override").WithLocation(31, 33), - // (31,33): error CS8703: The modifier 'sealed' is not valid for this item in C# 10.0. Please use language version 'preview' or greater. + // (31,33): error CS8703: The modifier 'sealed' is not valid for this item in C# 10.0. Please use language version '11.0' or greater. // sealed override static void M10() - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M10").WithArguments("sealed", "10.0", "preview").WithLocation(31, 33), + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M10").WithArguments("sealed", "10.0", "11.0").WithLocation(31, 33), // (31,33): error CS0501: 'I1.M10()' must declare a body because it is not marked abstract, extern, or partial // sealed override static void M10() Diagnostic(ErrorCode.ERR_ConcreteMissingBody, "M10").WithArguments("I1.M10()").WithLocation(31, 33) @@ -311,27 +311,27 @@ sealed override static void M10() targetFramework: _supportingFramework); compilation1.VerifyDiagnostics( - // (4,26): error CS8703: The modifier 'abstract' is not valid for this item in C# 10.0. Please use language version 'preview' or greater. + // (4,26): error CS8703: The modifier 'abstract' is not valid for this item in C# 10.0. Please use language version '11.0' or greater. // abstract static void M01() - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M01").WithArguments("abstract", "10.0", "preview").WithLocation(4, 26), + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M01").WithArguments("abstract", "10.0", "11.0").WithLocation(4, 26), // (4,26): error CS0500: 'I1.M01()' cannot declare a body because it is marked abstract // abstract static void M01() Diagnostic(ErrorCode.ERR_AbstractHasBody, "M01").WithArguments("I1.M01()").WithLocation(4, 26), - // (7,25): error CS8703: The modifier 'virtual' is not valid for this item in C# 10.0. Please use language version 'preview' or greater. + // (7,25): error CS8703: The modifier 'virtual' is not valid for this item in C# 10.0. Please use language version '11.0' or greater. // virtual static void M02() - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M02").WithArguments("virtual", "10.0", "preview").WithLocation(7, 25), - // (10,24): error CS8703: The modifier 'sealed' is not valid for this item in C# 10.0. Please use language version 'preview' or greater. + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M02").WithArguments("virtual", "10.0", "11.0").WithLocation(7, 25), + // (10,24): error CS8703: The modifier 'sealed' is not valid for this item in C# 10.0. Please use language version '11.0' or greater. // sealed static void M03() - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M03").WithArguments("sealed", "10.0", "preview").WithLocation(10, 24), + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M03").WithArguments("sealed", "10.0", "11.0").WithLocation(10, 24), // (13,26): error CS0106: The modifier 'override' is not valid for this item // override static void M04() Diagnostic(ErrorCode.ERR_BadMemberFlag, "M04").WithArguments("override").WithLocation(13, 26), - // (16,34): error CS8703: The modifier 'virtual' is not valid for this item in C# 10.0. Please use language version 'preview' or greater. + // (16,34): error CS8703: The modifier 'abstract' is not valid for this item in C# 10.0. Please use language version '11.0' or greater. // abstract virtual static void M05() - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M05").WithArguments("virtual", "10.0", "preview").WithLocation(16, 34), - // (16,34): error CS8703: The modifier 'abstract' is not valid for this item in C# 10.0. Please use language version 'preview' or greater. + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M05").WithArguments("abstract", "10.0", "11.0").WithLocation(16, 34), + // (16,34): error CS8703: The modifier 'virtual' is not valid for this item in C# 10.0. Please use language version '11.0' or greater. // abstract virtual static void M05() - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M05").WithArguments("abstract", "10.0", "preview").WithLocation(16, 34), + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M05").WithArguments("virtual", "10.0", "11.0").WithLocation(16, 34), // (16,34): error CS0500: 'I1.M05()' cannot declare a body because it is marked abstract // abstract virtual static void M05() Diagnostic(ErrorCode.ERR_AbstractHasBody, "M05").WithArguments("I1.M05()").WithLocation(16, 34), @@ -341,39 +341,39 @@ sealed override static void M10() // (19,33): error CS0106: The modifier 'sealed' is not valid for this item // abstract sealed static void M06() Diagnostic(ErrorCode.ERR_BadMemberFlag, "M06").WithArguments("sealed").WithLocation(19, 33), - // (19,33): error CS8703: The modifier 'abstract' is not valid for this item in C# 10.0. Please use language version 'preview' or greater. + // (19,33): error CS8703: The modifier 'abstract' is not valid for this item in C# 10.0. Please use language version '11.0' or greater. // abstract sealed static void M06() - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M06").WithArguments("abstract", "10.0", "preview").WithLocation(19, 33), + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M06").WithArguments("abstract", "10.0", "11.0").WithLocation(19, 33), // (19,33): error CS0500: 'I1.M06()' cannot declare a body because it is marked abstract // abstract sealed static void M06() Diagnostic(ErrorCode.ERR_AbstractHasBody, "M06").WithArguments("I1.M06()").WithLocation(19, 33), // (22,35): error CS0106: The modifier 'override' is not valid for this item // abstract override static void M07() Diagnostic(ErrorCode.ERR_BadMemberFlag, "M07").WithArguments("override").WithLocation(22, 35), - // (22,35): error CS8703: The modifier 'abstract' is not valid for this item in C# 10.0. Please use language version 'preview' or greater. + // (22,35): error CS8703: The modifier 'abstract' is not valid for this item in C# 10.0. Please use language version '11.0' or greater. // abstract override static void M07() - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M07").WithArguments("abstract", "10.0", "preview").WithLocation(22, 35), + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M07").WithArguments("abstract", "10.0", "11.0").WithLocation(22, 35), // (22,35): error CS0500: 'I1.M07()' cannot declare a body because it is marked abstract // abstract override static void M07() Diagnostic(ErrorCode.ERR_AbstractHasBody, "M07").WithArguments("I1.M07()").WithLocation(22, 35), // (25,32): error CS0106: The modifier 'sealed' is not valid for this item // virtual sealed static void M08() Diagnostic(ErrorCode.ERR_BadMemberFlag, "M08").WithArguments("sealed").WithLocation(25, 32), - // (25,32): error CS8703: The modifier 'virtual' is not valid for this item in C# 10.0. Please use language version 'preview' or greater. + // (25,32): error CS8703: The modifier 'virtual' is not valid for this item in C# 10.0. Please use language version '11.0' or greater. // virtual sealed static void M08() - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M08").WithArguments("virtual", "10.0", "preview").WithLocation(25, 32), - // (28,34): error CS8703: The modifier 'virtual' is not valid for this item in C# 10.0. Please use language version 'preview' or greater. - // virtual override static void M09() - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M09").WithArguments("virtual", "10.0", "preview").WithLocation(28, 34), + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M08").WithArguments("virtual", "10.0", "11.0").WithLocation(25, 32), // (28,34): error CS0106: The modifier 'override' is not valid for this item // virtual override static void M09() Diagnostic(ErrorCode.ERR_BadMemberFlag, "M09").WithArguments("override").WithLocation(28, 34), + // (28,34): error CS8703: The modifier 'virtual' is not valid for this item in C# 10.0. Please use language version '11.0' or greater. + // virtual override static void M09() + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M09").WithArguments("virtual", "10.0", "11.0").WithLocation(28, 34), // (31,33): error CS0106: The modifier 'override' is not valid for this item // sealed override static void M10() Diagnostic(ErrorCode.ERR_BadMemberFlag, "M10").WithArguments("override").WithLocation(31, 33), - // (31,33): error CS8703: The modifier 'sealed' is not valid for this item in C# 10.0. Please use language version 'preview' or greater. + // (31,33): error CS8703: The modifier 'sealed' is not valid for this item in C# 10.0. Please use language version '11.0' or greater. // sealed override static void M10() - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M10").WithArguments("sealed", "10.0", "preview").WithLocation(31, 33) + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M10").WithArguments("sealed", "10.0", "11.0").WithLocation(31, 33) ); ValidateMethodModifiers_01(compilation1); @@ -590,18 +590,18 @@ sealed override static void M10() targetFramework: _supportingFramework); compilation1.VerifyDiagnostics( - // (4,26): error CS8703: The modifier 'abstract' is not valid for this item in C# 7.3. Please use language version 'preview' or greater. + // (4,26): error CS8703: The modifier 'abstract' is not valid for this item in C# 7.3. Please use language version '11.0' or greater. // abstract static void M01() - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M01").WithArguments("abstract", "7.3", "preview").WithLocation(4, 26), - // (7,25): error CS8703: The modifier 'virtual' is not valid for this item in C# 7.3. Please use language version 'preview' or greater. + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M01").WithArguments("abstract", "7.3", "11.0").WithLocation(4, 26), + // (7,25): error CS8703: The modifier 'virtual' is not valid for this item in C# 7.3. Please use language version '11.0' or greater. // virtual static void M02() - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M02").WithArguments("virtual", "7.3", "preview").WithLocation(7, 25), + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M02").WithArguments("virtual", "7.3", "11.0").WithLocation(7, 25), // (7,25): error CS0501: 'I1.M02()' must declare a body because it is not marked abstract, extern, or partial // virtual static void M02() Diagnostic(ErrorCode.ERR_ConcreteMissingBody, "M02").WithArguments("I1.M02()").WithLocation(7, 25), - // (10,24): error CS8703: The modifier 'sealed' is not valid for this item in C# 7.3. Please use language version 'preview' or greater. + // (10,24): error CS8703: The modifier 'sealed' is not valid for this item in C# 7.3. Please use language version '11.0' or greater. // sealed static void M03() - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M03").WithArguments("sealed", "7.3", "preview").WithLocation(10, 24), + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M03").WithArguments("sealed", "7.3", "11.0").WithLocation(10, 24), // (10,24): error CS0501: 'I1.M03()' must declare a body because it is not marked abstract, extern, or partial // sealed static void M03() Diagnostic(ErrorCode.ERR_ConcreteMissingBody, "M03").WithArguments("I1.M03()").WithLocation(10, 24), @@ -614,51 +614,51 @@ sealed override static void M10() // (13,26): error CS0501: 'I1.M04()' must declare a body because it is not marked abstract, extern, or partial // override static void M04() Diagnostic(ErrorCode.ERR_ConcreteMissingBody, "M04").WithArguments("I1.M04()").WithLocation(13, 26), - // (16,34): error CS0503: The abstract method 'I1.M05()' cannot be marked virtual + // (16,34): error CS8703: The modifier 'abstract' is not valid for this item in C# 7.3. Please use language version '11.0' or greater. // abstract virtual static void M05() - Diagnostic(ErrorCode.ERR_AbstractNotVirtual, "M05").WithArguments("method", "I1.M05()").WithLocation(16, 34), - // (16,34): error CS8703: The modifier 'abstract' is not valid for this item in C# 7.3. Please use language version 'preview' or greater. + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M05").WithArguments("abstract", "7.3", "11.0").WithLocation(16, 34), + // (16,34): error CS8703: The modifier 'virtual' is not valid for this item in C# 7.3. Please use language version '11.0' or greater. // abstract virtual static void M05() - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M05").WithArguments("abstract", "7.3", "preview").WithLocation(16, 34), - // (16,34): error CS8703: The modifier 'virtual' is not valid for this item in C# 7.3. Please use language version 'preview' or greater. + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M05").WithArguments("virtual", "7.3", "11.0").WithLocation(16, 34), + // (16,34): error CS0503: The abstract method 'I1.M05()' cannot be marked virtual // abstract virtual static void M05() - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M05").WithArguments("virtual", "7.3", "preview").WithLocation(16, 34), + Diagnostic(ErrorCode.ERR_AbstractNotVirtual, "M05").WithArguments("method", "I1.M05()").WithLocation(16, 34), // (19,33): error CS0106: The modifier 'sealed' is not valid for this item // abstract sealed static void M06() Diagnostic(ErrorCode.ERR_BadMemberFlag, "M06").WithArguments("sealed").WithLocation(19, 33), - // (19,33): error CS8703: The modifier 'abstract' is not valid for this item in C# 7.3. Please use language version 'preview' or greater. + // (19,33): error CS8703: The modifier 'abstract' is not valid for this item in C# 7.3. Please use language version '11.0' or greater. // abstract sealed static void M06() - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M06").WithArguments("abstract", "7.3", "preview").WithLocation(19, 33), + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M06").WithArguments("abstract", "7.3", "11.0").WithLocation(19, 33), // (22,35): error CS0106: The modifier 'override' is not valid for this item // abstract override static void M07() Diagnostic(ErrorCode.ERR_BadMemberFlag, "M07").WithArguments("override").WithLocation(22, 35), - // (22,35): error CS8703: The modifier 'abstract' is not valid for this item in C# 7.3. Please use language version 'preview' or greater. + // (22,35): error CS8703: The modifier 'abstract' is not valid for this item in C# 7.3. Please use language version '11.0' or greater. // abstract override static void M07() - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M07").WithArguments("abstract", "7.3", "preview").WithLocation(22, 35), + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M07").WithArguments("abstract", "7.3", "11.0").WithLocation(22, 35), // (25,32): error CS0106: The modifier 'sealed' is not valid for this item // virtual sealed static void M08() Diagnostic(ErrorCode.ERR_BadMemberFlag, "M08").WithArguments("sealed").WithLocation(25, 32), - // (25,32): error CS8703: The modifier 'virtual' is not valid for this item in C# 7.3. Please use language version 'preview' or greater. + // (25,32): error CS8703: The modifier 'virtual' is not valid for this item in C# 7.3. Please use language version '11.0' or greater. // virtual sealed static void M08() - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M08").WithArguments("virtual", "7.3", "preview").WithLocation(25, 32), + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M08").WithArguments("virtual", "7.3", "11.0").WithLocation(25, 32), // (25,32): error CS0501: 'I1.M08()' must declare a body because it is not marked abstract, extern, or partial // virtual sealed static void M08() Diagnostic(ErrorCode.ERR_ConcreteMissingBody, "M08").WithArguments("I1.M08()").WithLocation(25, 32), // (28,34): error CS0106: The modifier 'override' is not valid for this item // virtual override static void M09() Diagnostic(ErrorCode.ERR_BadMemberFlag, "M09").WithArguments("override").WithLocation(28, 34), - // (28,34): error CS8703: The modifier 'virtual' is not valid for this item in C# 7.3. Please use language version 'preview' or greater. + // (28,34): error CS8703: The modifier 'virtual' is not valid for this item in C# 7.3. Please use language version '11.0' or greater. // virtual override static void M09() - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M09").WithArguments("virtual", "7.3", "preview").WithLocation(28, 34), + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M09").WithArguments("virtual", "7.3", "11.0").WithLocation(28, 34), // (28,34): error CS0501: 'I1.M09()' must declare a body because it is not marked abstract, extern, or partial // virtual override static void M09() Diagnostic(ErrorCode.ERR_ConcreteMissingBody, "M09").WithArguments("I1.M09()").WithLocation(28, 34), // (31,33): error CS0106: The modifier 'override' is not valid for this item // sealed override static void M10() Diagnostic(ErrorCode.ERR_BadMemberFlag, "M10").WithArguments("override").WithLocation(31, 33), - // (31,33): error CS8703: The modifier 'sealed' is not valid for this item in C# 7.3. Please use language version 'preview' or greater. + // (31,33): error CS8703: The modifier 'sealed' is not valid for this item in C# 7.3. Please use language version '11.0' or greater. // sealed override static void M10() - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M10").WithArguments("sealed", "7.3", "preview").WithLocation(31, 33), + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M10").WithArguments("sealed", "7.3", "11.0").WithLocation(31, 33), // (31,33): error CS0501: 'I1.M10()' must declare a body because it is not marked abstract, extern, or partial // sealed override static void M10() Diagnostic(ErrorCode.ERR_ConcreteMissingBody, "M10").WithArguments("I1.M10()").WithLocation(31, 33) @@ -710,30 +710,30 @@ sealed override static void M10() targetFramework: _supportingFramework); compilation1.VerifyDiagnostics( - // (4,26): error CS8703: The modifier 'abstract' is not valid for this item in C# 7.3. Please use language version 'preview' or greater. + // (4,26): error CS8703: The modifier 'abstract' is not valid for this item in C# 7.3. Please use language version '11.0' or greater. // abstract static void M01() - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M01").WithArguments("abstract", "7.3", "preview").WithLocation(4, 26), + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M01").WithArguments("abstract", "7.3", "11.0").WithLocation(4, 26), // (4,26): error CS0500: 'I1.M01()' cannot declare a body because it is marked abstract // abstract static void M01() Diagnostic(ErrorCode.ERR_AbstractHasBody, "M01").WithArguments("I1.M01()").WithLocation(4, 26), - // (7,25): error CS8703: The modifier 'virtual' is not valid for this item in C# 7.3. Please use language version 'preview' or greater. + // (7,25): error CS8703: The modifier 'virtual' is not valid for this item in C# 7.3. Please use language version '11.0' or greater. // virtual static void M02() - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M02").WithArguments("virtual", "7.3", "preview").WithLocation(7, 25), - // (10,24): error CS8703: The modifier 'sealed' is not valid for this item in C# 7.3. Please use language version 'preview' or greater. + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M02").WithArguments("virtual", "7.3", "11.0").WithLocation(7, 25), + // (10,24): error CS8703: The modifier 'sealed' is not valid for this item in C# 7.3. Please use language version '11.0' or greater. // sealed static void M03() - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M03").WithArguments("sealed", "7.3", "preview").WithLocation(10, 24), + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M03").WithArguments("sealed", "7.3", "11.0").WithLocation(10, 24), // (13,26): error CS0106: The modifier 'override' is not valid for this item // override static void M04() Diagnostic(ErrorCode.ERR_BadMemberFlag, "M04").WithArguments("override").WithLocation(13, 26), // (13,26): error CS8370: Feature 'default interface implementation' is not available in C# 7.3. Please use language version 8.0 or greater. // override static void M04() Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7_3, "M04").WithArguments("default interface implementation", "8.0").WithLocation(13, 26), - // (16,34): error CS8703: The modifier 'virtual' is not valid for this item in C# 7.3. Please use language version 'preview' or greater. + // (16,34): error CS8703: The modifier 'abstract' is not valid for this item in C# 7.3. Please use language version '11.0' or greater. // abstract virtual static void M05() - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M05").WithArguments("virtual", "7.3", "preview").WithLocation(16, 34), - // (16,34): error CS8703: The modifier 'abstract' is not valid for this item in C# 7.3. Please use language version 'preview' or greater. + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M05").WithArguments("abstract", "7.3", "11.0").WithLocation(16, 34), + // (16,34): error CS8703: The modifier 'virtual' is not valid for this item in C# 7.3. Please use language version '11.0' or greater. // abstract virtual static void M05() - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M05").WithArguments("abstract", "7.3", "preview").WithLocation(16, 34), + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M05").WithArguments("virtual", "7.3", "11.0").WithLocation(16, 34), // (16,34): error CS0500: 'I1.M05()' cannot declare a body because it is marked abstract // abstract virtual static void M05() Diagnostic(ErrorCode.ERR_AbstractHasBody, "M05").WithArguments("I1.M05()").WithLocation(16, 34), @@ -743,39 +743,39 @@ sealed override static void M10() // (19,33): error CS0106: The modifier 'sealed' is not valid for this item // abstract sealed static void M06() Diagnostic(ErrorCode.ERR_BadMemberFlag, "M06").WithArguments("sealed").WithLocation(19, 33), - // (19,33): error CS8703: The modifier 'abstract' is not valid for this item in C# 7.3. Please use language version 'preview' or greater. + // (19,33): error CS8703: The modifier 'abstract' is not valid for this item in C# 7.3. Please use language version '11.0' or greater. // abstract sealed static void M06() - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M06").WithArguments("abstract", "7.3", "preview").WithLocation(19, 33), + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M06").WithArguments("abstract", "7.3", "11.0").WithLocation(19, 33), // (19,33): error CS0500: 'I1.M06()' cannot declare a body because it is marked abstract // abstract sealed static void M06() Diagnostic(ErrorCode.ERR_AbstractHasBody, "M06").WithArguments("I1.M06()").WithLocation(19, 33), // (22,35): error CS0106: The modifier 'override' is not valid for this item // abstract override static void M07() Diagnostic(ErrorCode.ERR_BadMemberFlag, "M07").WithArguments("override").WithLocation(22, 35), - // (22,35): error CS8703: The modifier 'abstract' is not valid for this item in C# 7.3. Please use language version 'preview' or greater. + // (22,35): error CS8703: The modifier 'abstract' is not valid for this item in C# 7.3. Please use language version '11.0' or greater. // abstract override static void M07() - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M07").WithArguments("abstract", "7.3", "preview").WithLocation(22, 35), + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M07").WithArguments("abstract", "7.3", "11.0").WithLocation(22, 35), // (22,35): error CS0500: 'I1.M07()' cannot declare a body because it is marked abstract // abstract override static void M07() Diagnostic(ErrorCode.ERR_AbstractHasBody, "M07").WithArguments("I1.M07()").WithLocation(22, 35), // (25,32): error CS0106: The modifier 'sealed' is not valid for this item // virtual sealed static void M08() Diagnostic(ErrorCode.ERR_BadMemberFlag, "M08").WithArguments("sealed").WithLocation(25, 32), - // (25,32): error CS8703: The modifier 'virtual' is not valid for this item in C# 7.3. Please use language version 'preview' or greater. + // (25,32): error CS8703: The modifier 'virtual' is not valid for this item in C# 7.3. Please use language version '11.0' or greater. // virtual sealed static void M08() - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M08").WithArguments("virtual", "7.3", "preview").WithLocation(25, 32), - // (28,34): error CS8703: The modifier 'virtual' is not valid for this item in C# 7.3. Please use language version 'preview' or greater. - // virtual override static void M09() - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M09").WithArguments("virtual", "7.3", "preview").WithLocation(28, 34), + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M08").WithArguments("virtual", "7.3", "11.0").WithLocation(25, 32), // (28,34): error CS0106: The modifier 'override' is not valid for this item // virtual override static void M09() Diagnostic(ErrorCode.ERR_BadMemberFlag, "M09").WithArguments("override").WithLocation(28, 34), + // (28,34): error CS8703: The modifier 'virtual' is not valid for this item in C# 7.3. Please use language version '11.0' or greater. + // virtual override static void M09() + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M09").WithArguments("virtual", "7.3", "11.0").WithLocation(28, 34), // (31,33): error CS0106: The modifier 'override' is not valid for this item // sealed override static void M10() Diagnostic(ErrorCode.ERR_BadMemberFlag, "M10").WithArguments("override").WithLocation(31, 33), - // (31,33): error CS8703: The modifier 'sealed' is not valid for this item in C# 7.3. Please use language version 'preview' or greater. + // (31,33): error CS8703: The modifier 'sealed' is not valid for this item in C# 7.3. Please use language version '11.0' or greater. // sealed override static void M10() - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M10").WithArguments("sealed", "7.3", "preview").WithLocation(31, 33) + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M10").WithArguments("sealed", "7.3", "11.0").WithLocation(31, 33) ); ValidateMethodModifiers_01(compilation1); @@ -1670,57 +1670,57 @@ sealed override static bool M10 { get targetFramework: _supportingFramework); compilation1.VerifyDiagnostics( - // (4,26): error CS8703: The modifier 'abstract' is not valid for this item in C# 10.0. Please use language version 'preview' or greater. + // (4,26): error CS8703: The modifier 'abstract' is not valid for this item in C# 10.0. Please use language version '11.0' or greater. // abstract static bool M01 { get - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M01").WithArguments("abstract", "10.0", "preview").WithLocation(4, 26), - // (7,25): error CS8703: The modifier 'virtual' is not valid for this item in C# 10.0. Please use language version 'preview' or greater. + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M01").WithArguments("abstract", "10.0", "11.0").WithLocation(4, 26), + // (7,25): error CS8703: The modifier 'virtual' is not valid for this item in C# 10.0. Please use language version '11.0' or greater. // virtual static bool M02 { get - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M02").WithArguments("virtual", "10.0", "preview").WithLocation(7, 25), - // (10,24): error CS8703: The modifier 'sealed' is not valid for this item in C# 10.0. Please use language version 'preview' or greater. + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M02").WithArguments("virtual", "10.0", "11.0").WithLocation(7, 25), + // (10,24): error CS8703: The modifier 'sealed' is not valid for this item in C# 10.0. Please use language version '11.0' or greater. // sealed static bool M03 { get - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M03").WithArguments("sealed", "10.0", "preview").WithLocation(10, 24), + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M03").WithArguments("sealed", "10.0", "11.0").WithLocation(10, 24), // (13,26): error CS0106: The modifier 'override' is not valid for this item // override static bool M04 { get Diagnostic(ErrorCode.ERR_BadMemberFlag, "M04").WithArguments("override").WithLocation(13, 26), - // (16,34): error CS8703: The modifier 'virtual' is not valid for this item in C# 10.0. Please use language version 'preview' or greater. + // (16,34): error CS8703: The modifier 'abstract' is not valid for this item in C# 10.0. Please use language version '11.0' or greater. // abstract virtual static bool M05 { get - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M05").WithArguments("virtual", "10.0", "preview").WithLocation(16, 34), + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M05").WithArguments("abstract", "10.0", "11.0").WithLocation(16, 34), + // (16,34): error CS8703: The modifier 'virtual' is not valid for this item in C# 10.0. Please use language version '11.0' or greater. + // abstract virtual static bool M05 { get + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M05").WithArguments("virtual", "10.0", "11.0").WithLocation(16, 34), // (16,34): error CS0503: The abstract property 'I1.M05' cannot be marked virtual // abstract virtual static bool M05 { get Diagnostic(ErrorCode.ERR_AbstractNotVirtual, "M05").WithArguments("property", "I1.M05").WithLocation(16, 34), - // (16,34): error CS8703: The modifier 'abstract' is not valid for this item in C# 10.0. Please use language version 'preview' or greater. - // abstract virtual static bool M05 { get - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M05").WithArguments("abstract", "10.0", "preview").WithLocation(16, 34), // (19,33): error CS0106: The modifier 'sealed' is not valid for this item // abstract sealed static bool M06 { get Diagnostic(ErrorCode.ERR_BadMemberFlag, "M06").WithArguments("sealed").WithLocation(19, 33), - // (19,33): error CS8703: The modifier 'abstract' is not valid for this item in C# 10.0. Please use language version 'preview' or greater. + // (19,33): error CS8703: The modifier 'abstract' is not valid for this item in C# 10.0. Please use language version '11.0' or greater. // abstract sealed static bool M06 { get - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M06").WithArguments("abstract", "10.0", "preview").WithLocation(19, 33), + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M06").WithArguments("abstract", "10.0", "11.0").WithLocation(19, 33), // (22,35): error CS0106: The modifier 'override' is not valid for this item // abstract override static bool M07 { get Diagnostic(ErrorCode.ERR_BadMemberFlag, "M07").WithArguments("override").WithLocation(22, 35), - // (22,35): error CS8703: The modifier 'abstract' is not valid for this item in C# 10.0. Please use language version 'preview' or greater. + // (22,35): error CS8703: The modifier 'abstract' is not valid for this item in C# 10.0. Please use language version '11.0' or greater. // abstract override static bool M07 { get - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M07").WithArguments("abstract", "10.0", "preview").WithLocation(22, 35), + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M07").WithArguments("abstract", "10.0", "11.0").WithLocation(22, 35), // (25,32): error CS0106: The modifier 'sealed' is not valid for this item // virtual sealed static bool M08 { get Diagnostic(ErrorCode.ERR_BadMemberFlag, "M08").WithArguments("sealed").WithLocation(25, 32), - // (25,32): error CS8703: The modifier 'virtual' is not valid for this item in C# 10.0. Please use language version 'preview' or greater. + // (25,32): error CS8703: The modifier 'virtual' is not valid for this item in C# 10.0. Please use language version '11.0' or greater. // virtual sealed static bool M08 { get - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M08").WithArguments("virtual", "10.0", "preview").WithLocation(25, 32), - // (28,34): error CS8703: The modifier 'virtual' is not valid for this item in C# 10.0. Please use language version 'preview' or greater. - // virtual override static bool M09 { get - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M09").WithArguments("virtual", "10.0", "preview").WithLocation(28, 34), + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M08").WithArguments("virtual", "10.0", "11.0").WithLocation(25, 32), // (28,34): error CS0106: The modifier 'override' is not valid for this item // virtual override static bool M09 { get Diagnostic(ErrorCode.ERR_BadMemberFlag, "M09").WithArguments("override").WithLocation(28, 34), + // (28,34): error CS8703: The modifier 'virtual' is not valid for this item in C# 10.0. Please use language version '11.0' or greater. + // virtual override static bool M09 { get + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M09").WithArguments("virtual", "10.0", "11.0").WithLocation(28, 34), // (31,33): error CS0106: The modifier 'override' is not valid for this item // sealed override static bool M10 { get Diagnostic(ErrorCode.ERR_BadMemberFlag, "M10").WithArguments("override").WithLocation(31, 33), - // (31,33): error CS8703: The modifier 'sealed' is not valid for this item in C# 10.0. Please use language version 'preview' or greater. + // (31,33): error CS8703: The modifier 'sealed' is not valid for this item in C# 10.0. Please use language version '11.0' or greater. // sealed override static bool M10 { get - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M10").WithArguments("sealed", "10.0", "preview").WithLocation(31, 33) + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M10").WithArguments("sealed", "10.0", "11.0").WithLocation(31, 33) ); ValidatePropertyModifiers_01(compilation1); @@ -1997,69 +1997,69 @@ sealed override static bool M10 { get targetFramework: _supportingFramework); compilation1.VerifyDiagnostics( - // (4,26): error CS8703: The modifier 'abstract' is not valid for this item in C# 10.0. Please use language version 'preview' or greater. + // (4,26): error CS8703: The modifier 'abstract' is not valid for this item in C# 10.0. Please use language version '11.0' or greater. // abstract static bool M01 { get - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M01").WithArguments("abstract", "10.0", "preview").WithLocation(4, 26), + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M01").WithArguments("abstract", "10.0", "11.0").WithLocation(4, 26), // (4,32): error CS0500: 'I1.M01.get' cannot declare a body because it is marked abstract // abstract static bool M01 { get Diagnostic(ErrorCode.ERR_AbstractHasBody, "get").WithArguments("I1.M01.get").WithLocation(4, 32), - // (7,25): error CS8703: The modifier 'virtual' is not valid for this item in C# 10.0. Please use language version 'preview' or greater. + // (7,25): error CS8703: The modifier 'virtual' is not valid for this item in C# 10.0. Please use language version '11.0' or greater. // virtual static bool M02 { get - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M02").WithArguments("virtual", "10.0", "preview").WithLocation(7, 25), - // (10,24): error CS8703: The modifier 'sealed' is not valid for this item in C# 10.0. Please use language version 'preview' or greater. + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M02").WithArguments("virtual", "10.0", "11.0").WithLocation(7, 25), + // (10,24): error CS8703: The modifier 'sealed' is not valid for this item in C# 10.0. Please use language version '11.0' or greater. // sealed static bool M03 { get - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M03").WithArguments("sealed", "10.0", "preview").WithLocation(10, 24), + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M03").WithArguments("sealed", "10.0", "11.0").WithLocation(10, 24), // (13,26): error CS0106: The modifier 'override' is not valid for this item // override static bool M04 { get Diagnostic(ErrorCode.ERR_BadMemberFlag, "M04").WithArguments("override").WithLocation(13, 26), - // (16,34): error CS8703: The modifier 'virtual' is not valid for this item in C# 10.0. Please use language version 'preview' or greater. + // (16,34): error CS8703: The modifier 'abstract' is not valid for this item in C# 10.0. Please use language version '11.0' or greater. + // abstract virtual static bool M05 { get + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M05").WithArguments("abstract", "10.0", "11.0").WithLocation(16, 34), + // (16,34): error CS8703: The modifier 'virtual' is not valid for this item in C# 10.0. Please use language version '11.0' or greater. // abstract virtual static bool M05 { get - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M05").WithArguments("virtual", "10.0", "preview").WithLocation(16, 34), + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M05").WithArguments("virtual", "10.0", "11.0").WithLocation(16, 34), // (16,34): error CS0503: The abstract property 'I1.M05' cannot be marked virtual // abstract virtual static bool M05 { get Diagnostic(ErrorCode.ERR_AbstractNotVirtual, "M05").WithArguments("property", "I1.M05").WithLocation(16, 34), - // (16,34): error CS8703: The modifier 'abstract' is not valid for this item in C# 10.0. Please use language version 'preview' or greater. - // abstract virtual static bool M05 { get - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M05").WithArguments("abstract", "10.0", "preview").WithLocation(16, 34), // (16,40): error CS0500: 'I1.M05.get' cannot declare a body because it is marked abstract // abstract virtual static bool M05 { get Diagnostic(ErrorCode.ERR_AbstractHasBody, "get").WithArguments("I1.M05.get").WithLocation(16, 40), // (19,33): error CS0106: The modifier 'sealed' is not valid for this item // abstract sealed static bool M06 { get Diagnostic(ErrorCode.ERR_BadMemberFlag, "M06").WithArguments("sealed").WithLocation(19, 33), - // (19,33): error CS8703: The modifier 'abstract' is not valid for this item in C# 10.0. Please use language version 'preview' or greater. + // (19,33): error CS8703: The modifier 'abstract' is not valid for this item in C# 10.0. Please use language version '11.0' or greater. // abstract sealed static bool M06 { get - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M06").WithArguments("abstract", "10.0", "preview").WithLocation(19, 33), + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M06").WithArguments("abstract", "10.0", "11.0").WithLocation(19, 33), // (19,39): error CS0500: 'I1.M06.get' cannot declare a body because it is marked abstract // abstract sealed static bool M06 { get Diagnostic(ErrorCode.ERR_AbstractHasBody, "get").WithArguments("I1.M06.get").WithLocation(19, 39), // (22,35): error CS0106: The modifier 'override' is not valid for this item // abstract override static bool M07 { get Diagnostic(ErrorCode.ERR_BadMemberFlag, "M07").WithArguments("override").WithLocation(22, 35), - // (22,35): error CS8703: The modifier 'abstract' is not valid for this item in C# 10.0. Please use language version 'preview' or greater. + // (22,35): error CS8703: The modifier 'abstract' is not valid for this item in C# 10.0. Please use language version '11.0' or greater. // abstract override static bool M07 { get - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M07").WithArguments("abstract", "10.0", "preview").WithLocation(22, 35), + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M07").WithArguments("abstract", "10.0", "11.0").WithLocation(22, 35), // (22,41): error CS0500: 'I1.M07.get' cannot declare a body because it is marked abstract // abstract override static bool M07 { get Diagnostic(ErrorCode.ERR_AbstractHasBody, "get").WithArguments("I1.M07.get").WithLocation(22, 41), // (25,32): error CS0106: The modifier 'sealed' is not valid for this item // virtual sealed static bool M08 { get Diagnostic(ErrorCode.ERR_BadMemberFlag, "M08").WithArguments("sealed").WithLocation(25, 32), - // (25,32): error CS8703: The modifier 'virtual' is not valid for this item in C# 10.0. Please use language version 'preview' or greater. + // (25,32): error CS8703: The modifier 'virtual' is not valid for this item in C# 10.0. Please use language version '11.0' or greater. // virtual sealed static bool M08 { get - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M08").WithArguments("virtual", "10.0", "preview").WithLocation(25, 32), - // (28,34): error CS8703: The modifier 'virtual' is not valid for this item in C# 10.0. Please use language version 'preview' or greater. - // virtual override static bool M09 { get - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M09").WithArguments("virtual", "10.0", "preview").WithLocation(28, 34), + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M08").WithArguments("virtual", "10.0", "11.0").WithLocation(25, 32), // (28,34): error CS0106: The modifier 'override' is not valid for this item // virtual override static bool M09 { get Diagnostic(ErrorCode.ERR_BadMemberFlag, "M09").WithArguments("override").WithLocation(28, 34), + // (28,34): error CS8703: The modifier 'virtual' is not valid for this item in C# 10.0. Please use language version '11.0' or greater. + // virtual override static bool M09 { get + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M09").WithArguments("virtual", "10.0", "11.0").WithLocation(28, 34), // (31,33): error CS0106: The modifier 'override' is not valid for this item // sealed override static bool M10 { get Diagnostic(ErrorCode.ERR_BadMemberFlag, "M10").WithArguments("override").WithLocation(31, 33), - // (31,33): error CS8703: The modifier 'sealed' is not valid for this item in C# 10.0. Please use language version 'preview' or greater. + // (31,33): error CS8703: The modifier 'sealed' is not valid for this item in C# 10.0. Please use language version '11.0' or greater. // sealed override static bool M10 { get - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M10").WithArguments("sealed", "10.0", "preview").WithLocation(31, 33) + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M10").WithArguments("sealed", "10.0", "11.0").WithLocation(31, 33) ); ValidatePropertyModifiers_01(compilation1); @@ -2258,60 +2258,60 @@ sealed override static bool M10 { get targetFramework: _supportingFramework); compilation1.VerifyDiagnostics( - // (4,26): error CS8703: The modifier 'abstract' is not valid for this item in C# 7.3. Please use language version 'preview' or greater. + // (4,26): error CS8703: The modifier 'abstract' is not valid for this item in C# 7.3. Please use language version '11.0' or greater. // abstract static bool M01 { get - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M01").WithArguments("abstract", "7.3", "preview").WithLocation(4, 26), - // (7,25): error CS8703: The modifier 'virtual' is not valid for this item in C# 7.3. Please use language version 'preview' or greater. + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M01").WithArguments("abstract", "7.3", "11.0").WithLocation(4, 26), + // (7,25): error CS8703: The modifier 'virtual' is not valid for this item in C# 7.3. Please use language version '11.0' or greater. // virtual static bool M02 { get - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M02").WithArguments("virtual", "7.3", "preview").WithLocation(7, 25), - // (10,24): error CS8703: The modifier 'sealed' is not valid for this item in C# 7.3. Please use language version 'preview' or greater. + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M02").WithArguments("virtual", "7.3", "11.0").WithLocation(7, 25), + // (10,24): error CS8703: The modifier 'sealed' is not valid for this item in C# 7.3. Please use language version '11.0' or greater. // sealed static bool M03 { get - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M03").WithArguments("sealed", "7.3", "preview").WithLocation(10, 24), + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M03").WithArguments("sealed", "7.3", "11.0").WithLocation(10, 24), // (13,26): error CS0106: The modifier 'override' is not valid for this item // override static bool M04 { get Diagnostic(ErrorCode.ERR_BadMemberFlag, "M04").WithArguments("override").WithLocation(13, 26), // (13,26): error CS8703: The modifier 'static' is not valid for this item in C# 7.3. Please use language version '8.0' or greater. // override static bool M04 { get Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M04").WithArguments("static", "7.3", "8.0").WithLocation(13, 26), - // (16,34): error CS8703: The modifier 'virtual' is not valid for this item in C# 7.3. Please use language version 'preview' or greater. + // (16,34): error CS8703: The modifier 'abstract' is not valid for this item in C# 7.3. Please use language version '11.0' or greater. + // abstract virtual static bool M05 { get + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M05").WithArguments("abstract", "7.3", "11.0").WithLocation(16, 34), + // (16,34): error CS8703: The modifier 'virtual' is not valid for this item in C# 7.3. Please use language version '11.0' or greater. // abstract virtual static bool M05 { get - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M05").WithArguments("virtual", "7.3", "preview").WithLocation(16, 34), + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M05").WithArguments("virtual", "7.3", "11.0").WithLocation(16, 34), // (16,34): error CS0503: The abstract property 'I1.M05' cannot be marked virtual // abstract virtual static bool M05 { get Diagnostic(ErrorCode.ERR_AbstractNotVirtual, "M05").WithArguments("property", "I1.M05").WithLocation(16, 34), - // (16,34): error CS8703: The modifier 'abstract' is not valid for this item in C# 7.3. Please use language version 'preview' or greater. - // abstract virtual static bool M05 { get - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M05").WithArguments("abstract", "7.3", "preview").WithLocation(16, 34), // (19,33): error CS0106: The modifier 'sealed' is not valid for this item // abstract sealed static bool M06 { get Diagnostic(ErrorCode.ERR_BadMemberFlag, "M06").WithArguments("sealed").WithLocation(19, 33), - // (19,33): error CS8703: The modifier 'abstract' is not valid for this item in C# 7.3. Please use language version 'preview' or greater. + // (19,33): error CS8703: The modifier 'abstract' is not valid for this item in C# 7.3. Please use language version '11.0' or greater. // abstract sealed static bool M06 { get - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M06").WithArguments("abstract", "7.3", "preview").WithLocation(19, 33), + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M06").WithArguments("abstract", "7.3", "11.0").WithLocation(19, 33), // (22,35): error CS0106: The modifier 'override' is not valid for this item // abstract override static bool M07 { get Diagnostic(ErrorCode.ERR_BadMemberFlag, "M07").WithArguments("override").WithLocation(22, 35), - // (22,35): error CS8703: The modifier 'abstract' is not valid for this item in C# 7.3. Please use language version 'preview' or greater. + // (22,35): error CS8703: The modifier 'abstract' is not valid for this item in C# 7.3. Please use language version '11.0' or greater. // abstract override static bool M07 { get - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M07").WithArguments("abstract", "7.3", "preview").WithLocation(22, 35), + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M07").WithArguments("abstract", "7.3", "11.0").WithLocation(22, 35), // (25,32): error CS0106: The modifier 'sealed' is not valid for this item // virtual sealed static bool M08 { get Diagnostic(ErrorCode.ERR_BadMemberFlag, "M08").WithArguments("sealed").WithLocation(25, 32), - // (25,32): error CS8703: The modifier 'virtual' is not valid for this item in C# 7.3. Please use language version 'preview' or greater. + // (25,32): error CS8703: The modifier 'virtual' is not valid for this item in C# 7.3. Please use language version '11.0' or greater. // virtual sealed static bool M08 { get - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M08").WithArguments("virtual", "7.3", "preview").WithLocation(25, 32), + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M08").WithArguments("virtual", "7.3", "11.0").WithLocation(25, 32), // (28,34): error CS0106: The modifier 'override' is not valid for this item // virtual override static bool M09 { get Diagnostic(ErrorCode.ERR_BadMemberFlag, "M09").WithArguments("override").WithLocation(28, 34), - // (28,34): error CS8703: The modifier 'virtual' is not valid for this item in C# 7.3. Please use language version 'preview' or greater. + // (28,34): error CS8703: The modifier 'virtual' is not valid for this item in C# 7.3. Please use language version '11.0' or greater. // virtual override static bool M09 { get - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M09").WithArguments("virtual", "7.3", "preview").WithLocation(28, 34), + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M09").WithArguments("virtual", "7.3", "11.0").WithLocation(28, 34), // (31,33): error CS0106: The modifier 'override' is not valid for this item // sealed override static bool M10 { get Diagnostic(ErrorCode.ERR_BadMemberFlag, "M10").WithArguments("override").WithLocation(31, 33), - // (31,33): error CS8703: The modifier 'sealed' is not valid for this item in C# 7.3. Please use language version 'preview' or greater. + // (31,33): error CS8703: The modifier 'sealed' is not valid for this item in C# 7.3. Please use language version '11.0' or greater. // sealed override static bool M10 { get - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M10").WithArguments("sealed", "7.3", "preview").WithLocation(31, 33) + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M10").WithArguments("sealed", "7.3", "11.0").WithLocation(31, 33) ); ValidatePropertyModifiers_01(compilation1); @@ -2360,72 +2360,72 @@ sealed override static bool M10 { get targetFramework: _supportingFramework); compilation1.VerifyDiagnostics( - // (4,26): error CS8703: The modifier 'abstract' is not valid for this item in C# 7.3. Please use language version 'preview' or greater. + // (4,26): error CS8703: The modifier 'abstract' is not valid for this item in C# 7.3. Please use language version '11.0' or greater. // abstract static bool M01 { get - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M01").WithArguments("abstract", "7.3", "preview").WithLocation(4, 26), + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M01").WithArguments("abstract", "7.3", "11.0").WithLocation(4, 26), // (4,32): error CS0500: 'I1.M01.get' cannot declare a body because it is marked abstract // abstract static bool M01 { get Diagnostic(ErrorCode.ERR_AbstractHasBody, "get").WithArguments("I1.M01.get").WithLocation(4, 32), - // (7,25): error CS8703: The modifier 'virtual' is not valid for this item in C# 7.3. Please use language version 'preview' or greater. + // (7,25): error CS8703: The modifier 'virtual' is not valid for this item in C# 7.3. Please use language version '11.0' or greater. // virtual static bool M02 { get - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M02").WithArguments("virtual", "7.3", "preview").WithLocation(7, 25), - // (10,24): error CS8703: The modifier 'sealed' is not valid for this item in C# 7.3. Please use language version 'preview' or greater. + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M02").WithArguments("virtual", "7.3", "11.0").WithLocation(7, 25), + // (10,24): error CS8703: The modifier 'sealed' is not valid for this item in C# 7.3. Please use language version '11.0' or greater. // sealed static bool M03 { get - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M03").WithArguments("sealed", "7.3", "preview").WithLocation(10, 24), + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M03").WithArguments("sealed", "7.3", "11.0").WithLocation(10, 24), // (13,26): error CS0106: The modifier 'override' is not valid for this item // override static bool M04 { get Diagnostic(ErrorCode.ERR_BadMemberFlag, "M04").WithArguments("override").WithLocation(13, 26), // (13,26): error CS8370: Feature 'default interface implementation' is not available in C# 7.3. Please use language version 8.0 or greater. // override static bool M04 { get Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7_3, "M04").WithArguments("default interface implementation", "8.0").WithLocation(13, 26), - // (16,34): error CS8703: The modifier 'virtual' is not valid for this item in C# 7.3. Please use language version 'preview' or greater. + // (16,34): error CS8703: The modifier 'abstract' is not valid for this item in C# 7.3. Please use language version '11.0' or greater. + // abstract virtual static bool M05 { get + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M05").WithArguments("abstract", "7.3", "11.0").WithLocation(16, 34), + // (16,34): error CS8703: The modifier 'virtual' is not valid for this item in C# 7.3. Please use language version '11.0' or greater. // abstract virtual static bool M05 { get - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M05").WithArguments("virtual", "7.3", "preview").WithLocation(16, 34), + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M05").WithArguments("virtual", "7.3", "11.0").WithLocation(16, 34), // (16,34): error CS0503: The abstract property 'I1.M05' cannot be marked virtual // abstract virtual static bool M05 { get Diagnostic(ErrorCode.ERR_AbstractNotVirtual, "M05").WithArguments("property", "I1.M05").WithLocation(16, 34), - // (16,34): error CS8703: The modifier 'abstract' is not valid for this item in C# 7.3. Please use language version 'preview' or greater. - // abstract virtual static bool M05 { get - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M05").WithArguments("abstract", "7.3", "preview").WithLocation(16, 34), // (16,40): error CS0500: 'I1.M05.get' cannot declare a body because it is marked abstract // abstract virtual static bool M05 { get Diagnostic(ErrorCode.ERR_AbstractHasBody, "get").WithArguments("I1.M05.get").WithLocation(16, 40), // (19,33): error CS0106: The modifier 'sealed' is not valid for this item // abstract sealed static bool M06 { get Diagnostic(ErrorCode.ERR_BadMemberFlag, "M06").WithArguments("sealed").WithLocation(19, 33), - // (19,33): error CS8703: The modifier 'abstract' is not valid for this item in C# 7.3. Please use language version 'preview' or greater. + // (19,33): error CS8703: The modifier 'abstract' is not valid for this item in C# 7.3. Please use language version '11.0' or greater. // abstract sealed static bool M06 { get - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M06").WithArguments("abstract", "7.3", "preview").WithLocation(19, 33), + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M06").WithArguments("abstract", "7.3", "11.0").WithLocation(19, 33), // (19,39): error CS0500: 'I1.M06.get' cannot declare a body because it is marked abstract // abstract sealed static bool M06 { get Diagnostic(ErrorCode.ERR_AbstractHasBody, "get").WithArguments("I1.M06.get").WithLocation(19, 39), // (22,35): error CS0106: The modifier 'override' is not valid for this item // abstract override static bool M07 { get Diagnostic(ErrorCode.ERR_BadMemberFlag, "M07").WithArguments("override").WithLocation(22, 35), - // (22,35): error CS8703: The modifier 'abstract' is not valid for this item in C# 7.3. Please use language version 'preview' or greater. + // (22,35): error CS8703: The modifier 'abstract' is not valid for this item in C# 7.3. Please use language version '11.0' or greater. // abstract override static bool M07 { get - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M07").WithArguments("abstract", "7.3", "preview").WithLocation(22, 35), + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M07").WithArguments("abstract", "7.3", "11.0").WithLocation(22, 35), // (22,41): error CS0500: 'I1.M07.get' cannot declare a body because it is marked abstract // abstract override static bool M07 { get Diagnostic(ErrorCode.ERR_AbstractHasBody, "get").WithArguments("I1.M07.get").WithLocation(22, 41), // (25,32): error CS0106: The modifier 'sealed' is not valid for this item // virtual sealed static bool M08 { get Diagnostic(ErrorCode.ERR_BadMemberFlag, "M08").WithArguments("sealed").WithLocation(25, 32), - // (25,32): error CS8703: The modifier 'virtual' is not valid for this item in C# 7.3. Please use language version 'preview' or greater. + // (25,32): error CS8703: The modifier 'virtual' is not valid for this item in C# 7.3. Please use language version '11.0' or greater. // virtual sealed static bool M08 { get - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M08").WithArguments("virtual", "7.3", "preview").WithLocation(25, 32), + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M08").WithArguments("virtual", "7.3", "11.0").WithLocation(25, 32), // (28,34): error CS0106: The modifier 'override' is not valid for this item // virtual override static bool M09 { get Diagnostic(ErrorCode.ERR_BadMemberFlag, "M09").WithArguments("override").WithLocation(28, 34), - // (28,34): error CS8703: The modifier 'virtual' is not valid for this item in C# 7.3. Please use language version 'preview' or greater. + // (28,34): error CS8703: The modifier 'virtual' is not valid for this item in C# 7.3. Please use language version '11.0' or greater. // virtual override static bool M09 { get - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M09").WithArguments("virtual", "7.3", "preview").WithLocation(28, 34), + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M09").WithArguments("virtual", "7.3", "11.0").WithLocation(28, 34), // (31,33): error CS0106: The modifier 'override' is not valid for this item // sealed override static bool M10 { get Diagnostic(ErrorCode.ERR_BadMemberFlag, "M10").WithArguments("override").WithLocation(31, 33), - // (31,33): error CS8703: The modifier 'sealed' is not valid for this item in C# 7.3. Please use language version 'preview' or greater. + // (31,33): error CS8703: The modifier 'sealed' is not valid for this item in C# 7.3. Please use language version '11.0' or greater. // sealed override static bool M10 { get - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M10").WithArguments("sealed", "7.3", "preview").WithLocation(31, 33) + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M10").WithArguments("sealed", "7.3", "11.0").WithLocation(31, 33) ); ValidatePropertyModifiers_01(compilation1); @@ -2476,57 +2476,57 @@ sealed override static event D M10 targetFramework: _supportingFramework); compilation1.VerifyDiagnostics( - // (4,29): error CS8703: The modifier 'abstract' is not valid for this item in C# 10.0. Please use language version 'preview' or greater. + // (4,29): error CS8703: The modifier 'abstract' is not valid for this item in C# 10.0. Please use language version '11.0' or greater. // abstract static event D M01 - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M01").WithArguments("abstract", "10.0", "preview").WithLocation(4, 29), - // (7,28): error CS8703: The modifier 'virtual' is not valid for this item in C# 10.0. Please use language version 'preview' or greater. + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M01").WithArguments("abstract", "10.0", "11.0").WithLocation(4, 29), + // (7,28): error CS8703: The modifier 'virtual' is not valid for this item in C# 10.0. Please use language version '11.0' or greater. // virtual static event D M02 - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M02").WithArguments("virtual", "10.0", "preview").WithLocation(7, 28), - // (10,27): error CS8703: The modifier 'sealed' is not valid for this item in C# 10.0. Please use language version 'preview' or greater. + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M02").WithArguments("virtual", "10.0", "11.0").WithLocation(7, 28), + // (10,27): error CS8703: The modifier 'sealed' is not valid for this item in C# 10.0. Please use language version '11.0' or greater. // sealed static event D M03 - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M03").WithArguments("sealed", "10.0", "preview").WithLocation(10, 27), + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M03").WithArguments("sealed", "10.0", "11.0").WithLocation(10, 27), // (13,29): error CS0106: The modifier 'override' is not valid for this item // override static event D M04 Diagnostic(ErrorCode.ERR_BadMemberFlag, "M04").WithArguments("override").WithLocation(13, 29), - // (16,37): error CS8703: The modifier 'abstract' is not valid for this item in C# 10.0. Please use language version 'preview' or greater. + // (16,37): error CS8703: The modifier 'abstract' is not valid for this item in C# 10.0. Please use language version '11.0' or greater. // abstract virtual static event D M05 - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M05").WithArguments("abstract", "10.0", "preview").WithLocation(16, 37), - // (16,37): error CS8703: The modifier 'virtual' is not valid for this item in C# 10.0. Please use language version 'preview' or greater. + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M05").WithArguments("abstract", "10.0", "11.0").WithLocation(16, 37), + // (16,37): error CS8703: The modifier 'virtual' is not valid for this item in C# 10.0. Please use language version '11.0' or greater. // abstract virtual static event D M05 - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M05").WithArguments("virtual", "10.0", "preview").WithLocation(16, 37), + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M05").WithArguments("virtual", "10.0", "11.0").WithLocation(16, 37), // (16,37): error CS0503: The abstract event 'I1.M05' cannot be marked virtual // abstract virtual static event D M05 Diagnostic(ErrorCode.ERR_AbstractNotVirtual, "M05").WithArguments("event", "I1.M05").WithLocation(16, 37), // (19,36): error CS0106: The modifier 'sealed' is not valid for this item // abstract sealed static event D M06 Diagnostic(ErrorCode.ERR_BadMemberFlag, "M06").WithArguments("sealed").WithLocation(19, 36), - // (19,36): error CS8703: The modifier 'abstract' is not valid for this item in C# 10.0. Please use language version 'preview' or greater. + // (19,36): error CS8703: The modifier 'abstract' is not valid for this item in C# 10.0. Please use language version '11.0' or greater. // abstract sealed static event D M06 - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M06").WithArguments("abstract", "10.0", "preview").WithLocation(19, 36), + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M06").WithArguments("abstract", "10.0", "11.0").WithLocation(19, 36), // (22,38): error CS0106: The modifier 'override' is not valid for this item // abstract override static event D M07 Diagnostic(ErrorCode.ERR_BadMemberFlag, "M07").WithArguments("override").WithLocation(22, 38), - // (22,38): error CS8703: The modifier 'abstract' is not valid for this item in C# 10.0. Please use language version 'preview' or greater. + // (22,38): error CS8703: The modifier 'abstract' is not valid for this item in C# 10.0. Please use language version '11.0' or greater. // abstract override static event D M07 - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M07").WithArguments("abstract", "10.0", "preview").WithLocation(22, 38), + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M07").WithArguments("abstract", "10.0", "11.0").WithLocation(22, 38), // (25,35): error CS0106: The modifier 'sealed' is not valid for this item // virtual sealed static event D M08 Diagnostic(ErrorCode.ERR_BadMemberFlag, "M08").WithArguments("sealed").WithLocation(25, 35), - // (25,35): error CS8703: The modifier 'virtual' is not valid for this item in C# 10.0. Please use language version 'preview' or greater. + // (25,35): error CS8703: The modifier 'virtual' is not valid for this item in C# 10.0. Please use language version '11.0' or greater. // virtual sealed static event D M08 - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M08").WithArguments("virtual", "10.0", "preview").WithLocation(25, 35), + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M08").WithArguments("virtual", "10.0", "11.0").WithLocation(25, 35), // (28,37): error CS0106: The modifier 'override' is not valid for this item // virtual override static event D M09 Diagnostic(ErrorCode.ERR_BadMemberFlag, "M09").WithArguments("override").WithLocation(28, 37), - // (28,37): error CS8703: The modifier 'virtual' is not valid for this item in C# 10.0. Please use language version 'preview' or greater. + // (28,37): error CS8703: The modifier 'virtual' is not valid for this item in C# 10.0. Please use language version '11.0' or greater. // virtual override static event D M09 - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M09").WithArguments("virtual", "10.0", "preview").WithLocation(28, 37), + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M09").WithArguments("virtual", "10.0", "11.0").WithLocation(28, 37), // (31,36): error CS0106: The modifier 'override' is not valid for this item // sealed override static event D M10 Diagnostic(ErrorCode.ERR_BadMemberFlag, "M10").WithArguments("override").WithLocation(31, 36), - // (31,36): error CS8703: The modifier 'sealed' is not valid for this item in C# 10.0. Please use language version 'preview' or greater. + // (31,36): error CS8703: The modifier 'sealed' is not valid for this item in C# 10.0. Please use language version '11.0' or greater. // sealed override static event D M10 - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M10").WithArguments("sealed", "10.0", "preview").WithLocation(31, 36) + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M10").WithArguments("sealed", "10.0", "11.0").WithLocation(31, 36) ); ValidateEventModifiers_01(compilation1); @@ -2811,27 +2811,27 @@ sealed override static event D M10 { add {} remove {} } targetFramework: _supportingFramework); compilation1.VerifyDiagnostics( - // (4,29): error CS8703: The modifier 'abstract' is not valid for this item in C# 10.0. Please use language version 'preview' or greater. + // (4,29): error CS8703: The modifier 'abstract' is not valid for this item in C# 10.0. Please use language version '11.0' or greater. // abstract static event D M01 { add {} remove {} } - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M01").WithArguments("abstract", "10.0", "preview").WithLocation(4, 29), + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M01").WithArguments("abstract", "10.0", "11.0").WithLocation(4, 29), // (4,33): error CS8712: 'I1.M01': abstract event cannot use event accessor syntax // abstract static event D M01 { add {} remove {} } Diagnostic(ErrorCode.ERR_AbstractEventHasAccessors, "{").WithArguments("I1.M01").WithLocation(4, 33), - // (7,28): error CS8703: The modifier 'virtual' is not valid for this item in C# 10.0. Please use language version 'preview' or greater. + // (7,28): error CS8703: The modifier 'virtual' is not valid for this item in C# 10.0. Please use language version '11.0' or greater. // virtual static event D M02 { add {} remove {} } - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M02").WithArguments("virtual", "10.0", "preview").WithLocation(7, 28), - // (10,27): error CS8703: The modifier 'sealed' is not valid for this item in C# 10.0. Please use language version 'preview' or greater. + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M02").WithArguments("virtual", "10.0", "11.0").WithLocation(7, 28), + // (10,27): error CS8703: The modifier 'sealed' is not valid for this item in C# 10.0. Please use language version '11.0' or greater. // sealed static event D M03 { add {} remove {} } - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M03").WithArguments("sealed", "10.0", "preview").WithLocation(10, 27), + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M03").WithArguments("sealed", "10.0", "11.0").WithLocation(10, 27), // (13,29): error CS0106: The modifier 'override' is not valid for this item // override static event D M04 { add {} remove {} } Diagnostic(ErrorCode.ERR_BadMemberFlag, "M04").WithArguments("override").WithLocation(13, 29), - // (16,37): error CS8703: The modifier 'abstract' is not valid for this item in C# 10.0. Please use language version 'preview' or greater. + // (16,37): error CS8703: The modifier 'abstract' is not valid for this item in C# 10.0. Please use language version '11.0' or greater. // abstract virtual static event D M05 { add {} remove {} } - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M05").WithArguments("abstract", "10.0", "preview").WithLocation(16, 37), - // (16,37): error CS8703: The modifier 'virtual' is not valid for this item in C# 10.0. Please use language version 'preview' or greater. + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M05").WithArguments("abstract", "10.0", "11.0").WithLocation(16, 37), + // (16,37): error CS8703: The modifier 'virtual' is not valid for this item in C# 10.0. Please use language version '11.0' or greater. // abstract virtual static event D M05 { add {} remove {} } - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M05").WithArguments("virtual", "10.0", "preview").WithLocation(16, 37), + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M05").WithArguments("virtual", "10.0", "11.0").WithLocation(16, 37), // (16,37): error CS0503: The abstract event 'I1.M05' cannot be marked virtual // abstract virtual static event D M05 { add {} remove {} } Diagnostic(ErrorCode.ERR_AbstractNotVirtual, "M05").WithArguments("event", "I1.M05").WithLocation(16, 37), @@ -2841,39 +2841,39 @@ sealed override static event D M10 { add {} remove {} } // (19,36): error CS0106: The modifier 'sealed' is not valid for this item // abstract sealed static event D M06 { add {} remove {} } Diagnostic(ErrorCode.ERR_BadMemberFlag, "M06").WithArguments("sealed").WithLocation(19, 36), - // (19,36): error CS8703: The modifier 'abstract' is not valid for this item in C# 10.0. Please use language version 'preview' or greater. + // (19,36): error CS8703: The modifier 'abstract' is not valid for this item in C# 10.0. Please use language version '11.0' or greater. // abstract sealed static event D M06 { add {} remove {} } - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M06").WithArguments("abstract", "10.0", "preview").WithLocation(19, 36), + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M06").WithArguments("abstract", "10.0", "11.0").WithLocation(19, 36), // (19,40): error CS8712: 'I1.M06': abstract event cannot use event accessor syntax // abstract sealed static event D M06 { add {} remove {} } Diagnostic(ErrorCode.ERR_AbstractEventHasAccessors, "{").WithArguments("I1.M06").WithLocation(19, 40), // (22,38): error CS0106: The modifier 'override' is not valid for this item // abstract override static event D M07 { add {} remove {} } Diagnostic(ErrorCode.ERR_BadMemberFlag, "M07").WithArguments("override").WithLocation(22, 38), - // (22,38): error CS8703: The modifier 'abstract' is not valid for this item in C# 10.0. Please use language version 'preview' or greater. + // (22,38): error CS8703: The modifier 'abstract' is not valid for this item in C# 10.0. Please use language version '11.0' or greater. // abstract override static event D M07 { add {} remove {} } - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M07").WithArguments("abstract", "10.0", "preview").WithLocation(22, 38), + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M07").WithArguments("abstract", "10.0", "11.0").WithLocation(22, 38), // (22,42): error CS8712: 'I1.M07': abstract event cannot use event accessor syntax // abstract override static event D M07 { add {} remove {} } Diagnostic(ErrorCode.ERR_AbstractEventHasAccessors, "{").WithArguments("I1.M07").WithLocation(22, 42), // (25,35): error CS0106: The modifier 'sealed' is not valid for this item // virtual sealed static event D M08 { add {} remove {} } Diagnostic(ErrorCode.ERR_BadMemberFlag, "M08").WithArguments("sealed").WithLocation(25, 35), - // (25,35): error CS8703: The modifier 'virtual' is not valid for this item in C# 10.0. Please use language version 'preview' or greater. + // (25,35): error CS8703: The modifier 'virtual' is not valid for this item in C# 10.0. Please use language version '11.0' or greater. // virtual sealed static event D M08 { add {} remove {} } - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M08").WithArguments("virtual", "10.0", "preview").WithLocation(25, 35), + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M08").WithArguments("virtual", "10.0", "11.0").WithLocation(25, 35), // (28,37): error CS0106: The modifier 'override' is not valid for this item // virtual override static event D M09 { add {} remove {} } Diagnostic(ErrorCode.ERR_BadMemberFlag, "M09").WithArguments("override").WithLocation(28, 37), - // (28,37): error CS8703: The modifier 'virtual' is not valid for this item in C# 10.0. Please use language version 'preview' or greater. + // (28,37): error CS8703: The modifier 'virtual' is not valid for this item in C# 10.0. Please use language version '11.0' or greater. // virtual override static event D M09 { add {} remove {} } - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M09").WithArguments("virtual", "10.0", "preview").WithLocation(28, 37), + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M09").WithArguments("virtual", "10.0", "11.0").WithLocation(28, 37), // (31,36): error CS0106: The modifier 'override' is not valid for this item // sealed override static event D M10 { add {} remove {} } Diagnostic(ErrorCode.ERR_BadMemberFlag, "M10").WithArguments("override").WithLocation(31, 36), - // (31,36): error CS8703: The modifier 'sealed' is not valid for this item in C# 10.0. Please use language version 'preview' or greater. + // (31,36): error CS8703: The modifier 'sealed' is not valid for this item in C# 10.0. Please use language version '11.0' or greater. // sealed override static event D M10 { add {} remove {} } - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M10").WithArguments("sealed", "10.0", "preview").WithLocation(31, 36) + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M10").WithArguments("sealed", "10.0", "11.0").WithLocation(31, 36) ); ValidateEventModifiers_01(compilation1); @@ -3077,60 +3077,60 @@ sealed override static event D M10 targetFramework: _supportingFramework); compilation1.VerifyDiagnostics( - // (4,29): error CS8703: The modifier 'abstract' is not valid for this item in C# 7.3. Please use language version 'preview' or greater. + // (4,29): error CS8703: The modifier 'abstract' is not valid for this item in C# 7.3. Please use language version '11.0' or greater. // abstract static event D M01 - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M01").WithArguments("abstract", "7.3", "preview").WithLocation(4, 29), - // (7,28): error CS8703: The modifier 'virtual' is not valid for this item in C# 7.3. Please use language version 'preview' or greater. + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M01").WithArguments("abstract", "7.3", "11.0").WithLocation(4, 29), + // (7,28): error CS8703: The modifier 'virtual' is not valid for this item in C# 7.3. Please use language version '11.0' or greater. // virtual static event D M02 - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M02").WithArguments("virtual", "7.3", "preview").WithLocation(7, 28), - // (10,27): error CS8703: The modifier 'sealed' is not valid for this item in C# 7.3. Please use language version 'preview' or greater. + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M02").WithArguments("virtual", "7.3", "11.0").WithLocation(7, 28), + // (10,27): error CS8703: The modifier 'sealed' is not valid for this item in C# 7.3. Please use language version '11.0' or greater. // sealed static event D M03 - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M03").WithArguments("sealed", "7.3", "preview").WithLocation(10, 27), + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M03").WithArguments("sealed", "7.3", "11.0").WithLocation(10, 27), // (13,29): error CS0106: The modifier 'override' is not valid for this item // override static event D M04 Diagnostic(ErrorCode.ERR_BadMemberFlag, "M04").WithArguments("override").WithLocation(13, 29), // (13,29): error CS8703: The modifier 'static' is not valid for this item in C# 7.3. Please use language version '8.0' or greater. // override static event D M04 Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M04").WithArguments("static", "7.3", "8.0").WithLocation(13, 29), - // (16,37): error CS8703: The modifier 'abstract' is not valid for this item in C# 7.3. Please use language version 'preview' or greater. + // (16,37): error CS8703: The modifier 'abstract' is not valid for this item in C# 7.3. Please use language version '11.0' or greater. // abstract virtual static event D M05 - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M05").WithArguments("abstract", "7.3", "preview").WithLocation(16, 37), - // (16,37): error CS8703: The modifier 'virtual' is not valid for this item in C# 7.3. Please use language version 'preview' or greater. + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M05").WithArguments("abstract", "7.3", "11.0").WithLocation(16, 37), + // (16,37): error CS8703: The modifier 'virtual' is not valid for this item in C# 7.3. Please use language version '11.0' or greater. // abstract virtual static event D M05 - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M05").WithArguments("virtual", "7.3", "preview").WithLocation(16, 37), + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M05").WithArguments("virtual", "7.3", "11.0").WithLocation(16, 37), // (16,37): error CS0503: The abstract event 'I1.M05' cannot be marked virtual // abstract virtual static event D M05 Diagnostic(ErrorCode.ERR_AbstractNotVirtual, "M05").WithArguments("event", "I1.M05").WithLocation(16, 37), // (19,36): error CS0106: The modifier 'sealed' is not valid for this item // abstract sealed static event D M06 Diagnostic(ErrorCode.ERR_BadMemberFlag, "M06").WithArguments("sealed").WithLocation(19, 36), - // (19,36): error CS8703: The modifier 'abstract' is not valid for this item in C# 7.3. Please use language version 'preview' or greater. + // (19,36): error CS8703: The modifier 'abstract' is not valid for this item in C# 7.3. Please use language version '11.0' or greater. // abstract sealed static event D M06 - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M06").WithArguments("abstract", "7.3", "preview").WithLocation(19, 36), + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M06").WithArguments("abstract", "7.3", "11.0").WithLocation(19, 36), // (22,38): error CS0106: The modifier 'override' is not valid for this item // abstract override static event D M07 Diagnostic(ErrorCode.ERR_BadMemberFlag, "M07").WithArguments("override").WithLocation(22, 38), - // (22,38): error CS8703: The modifier 'abstract' is not valid for this item in C# 7.3. Please use language version 'preview' or greater. + // (22,38): error CS8703: The modifier 'abstract' is not valid for this item in C# 7.3. Please use language version '11.0' or greater. // abstract override static event D M07 - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M07").WithArguments("abstract", "7.3", "preview").WithLocation(22, 38), + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M07").WithArguments("abstract", "7.3", "11.0").WithLocation(22, 38), // (25,35): error CS0106: The modifier 'sealed' is not valid for this item // virtual sealed static event D M08 Diagnostic(ErrorCode.ERR_BadMemberFlag, "M08").WithArguments("sealed").WithLocation(25, 35), - // (25,35): error CS8703: The modifier 'virtual' is not valid for this item in C# 7.3. Please use language version 'preview' or greater. + // (25,35): error CS8703: The modifier 'virtual' is not valid for this item in C# 7.3. Please use language version '11.0' or greater. // virtual sealed static event D M08 - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M08").WithArguments("virtual", "7.3", "preview").WithLocation(25, 35), + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M08").WithArguments("virtual", "7.3", "11.0").WithLocation(25, 35), // (28,37): error CS0106: The modifier 'override' is not valid for this item // virtual override static event D M09 Diagnostic(ErrorCode.ERR_BadMemberFlag, "M09").WithArguments("override").WithLocation(28, 37), - // (28,37): error CS8703: The modifier 'virtual' is not valid for this item in C# 7.3. Please use language version 'preview' or greater. + // (28,37): error CS8703: The modifier 'virtual' is not valid for this item in C# 7.3. Please use language version '11.0' or greater. // virtual override static event D M09 - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M09").WithArguments("virtual", "7.3", "preview").WithLocation(28, 37), + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M09").WithArguments("virtual", "7.3", "11.0").WithLocation(28, 37), // (31,36): error CS0106: The modifier 'override' is not valid for this item // sealed override static event D M10 Diagnostic(ErrorCode.ERR_BadMemberFlag, "M10").WithArguments("override").WithLocation(31, 36), - // (31,36): error CS8703: The modifier 'sealed' is not valid for this item in C# 7.3. Please use language version 'preview' or greater. + // (31,36): error CS8703: The modifier 'sealed' is not valid for this item in C# 7.3. Please use language version '11.0' or greater. // sealed override static event D M10 - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M10").WithArguments("sealed", "7.3", "preview").WithLocation(31, 36) + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M10").WithArguments("sealed", "7.3", "11.0").WithLocation(31, 36) ); ValidateEventModifiers_01(compilation1); @@ -3180,30 +3180,30 @@ sealed override static event D M10 { add {} remove {} } targetFramework: _supportingFramework); compilation1.VerifyDiagnostics( - // (4,29): error CS8703: The modifier 'abstract' is not valid for this item in C# 7.3. Please use language version 'preview' or greater. + // (4,29): error CS8703: The modifier 'abstract' is not valid for this item in C# 7.3. Please use language version '11.0' or greater. // abstract static event D M01 { add {} remove {} } - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M01").WithArguments("abstract", "7.3", "preview").WithLocation(4, 29), + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M01").WithArguments("abstract", "7.3", "11.0").WithLocation(4, 29), // (4,33): error CS8712: 'I1.M01': abstract event cannot use event accessor syntax // abstract static event D M01 { add {} remove {} } Diagnostic(ErrorCode.ERR_AbstractEventHasAccessors, "{").WithArguments("I1.M01").WithLocation(4, 33), - // (7,28): error CS8703: The modifier 'virtual' is not valid for this item in C# 7.3. Please use language version 'preview' or greater. + // (7,28): error CS8703: The modifier 'virtual' is not valid for this item in C# 7.3. Please use language version '11.0' or greater. // virtual static event D M02 { add {} remove {} } - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M02").WithArguments("virtual", "7.3", "preview").WithLocation(7, 28), - // (10,27): error CS8703: The modifier 'sealed' is not valid for this item in C# 7.3. Please use language version 'preview' or greater. + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M02").WithArguments("virtual", "7.3", "11.0").WithLocation(7, 28), + // (10,27): error CS8703: The modifier 'sealed' is not valid for this item in C# 7.3. Please use language version '11.0' or greater. // sealed static event D M03 { add {} remove {} } - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M03").WithArguments("sealed", "7.3", "preview").WithLocation(10, 27), + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M03").WithArguments("sealed", "7.3", "11.0").WithLocation(10, 27), // (13,29): error CS0106: The modifier 'override' is not valid for this item // override static event D M04 { add {} remove {} } Diagnostic(ErrorCode.ERR_BadMemberFlag, "M04").WithArguments("override").WithLocation(13, 29), // (13,29): error CS8370: Feature 'default interface implementation' is not available in C# 7.3. Please use language version 8.0 or greater. // override static event D M04 { add {} remove {} } Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7_3, "M04").WithArguments("default interface implementation", "8.0").WithLocation(13, 29), - // (16,37): error CS8703: The modifier 'abstract' is not valid for this item in C# 7.3. Please use language version 'preview' or greater. + // (16,37): error CS8703: The modifier 'abstract' is not valid for this item in C# 7.3. Please use language version '11.0' or greater. // abstract virtual static event D M05 { add {} remove {} } - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M05").WithArguments("abstract", "7.3", "preview").WithLocation(16, 37), - // (16,37): error CS8703: The modifier 'virtual' is not valid for this item in C# 7.3. Please use language version 'preview' or greater. + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M05").WithArguments("abstract", "7.3", "11.0").WithLocation(16, 37), + // (16,37): error CS8703: The modifier 'virtual' is not valid for this item in C# 7.3. Please use language version '11.0' or greater. // abstract virtual static event D M05 { add {} remove {} } - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M05").WithArguments("virtual", "7.3", "preview").WithLocation(16, 37), + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M05").WithArguments("virtual", "7.3", "11.0").WithLocation(16, 37), // (16,37): error CS0503: The abstract event 'I1.M05' cannot be marked virtual // abstract virtual static event D M05 { add {} remove {} } Diagnostic(ErrorCode.ERR_AbstractNotVirtual, "M05").WithArguments("event", "I1.M05").WithLocation(16, 37), @@ -3213,39 +3213,39 @@ sealed override static event D M10 { add {} remove {} } // (19,36): error CS0106: The modifier 'sealed' is not valid for this item // abstract sealed static event D M06 { add {} remove {} } Diagnostic(ErrorCode.ERR_BadMemberFlag, "M06").WithArguments("sealed").WithLocation(19, 36), - // (19,36): error CS8703: The modifier 'abstract' is not valid for this item in C# 7.3. Please use language version 'preview' or greater. + // (19,36): error CS8703: The modifier 'abstract' is not valid for this item in C# 7.3. Please use language version '11.0' or greater. // abstract sealed static event D M06 { add {} remove {} } - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M06").WithArguments("abstract", "7.3", "preview").WithLocation(19, 36), + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M06").WithArguments("abstract", "7.3", "11.0").WithLocation(19, 36), // (19,40): error CS8712: 'I1.M06': abstract event cannot use event accessor syntax // abstract sealed static event D M06 { add {} remove {} } Diagnostic(ErrorCode.ERR_AbstractEventHasAccessors, "{").WithArguments("I1.M06").WithLocation(19, 40), // (22,38): error CS0106: The modifier 'override' is not valid for this item // abstract override static event D M07 { add {} remove {} } Diagnostic(ErrorCode.ERR_BadMemberFlag, "M07").WithArguments("override").WithLocation(22, 38), - // (22,38): error CS8703: The modifier 'abstract' is not valid for this item in C# 7.3. Please use language version 'preview' or greater. + // (22,38): error CS8703: The modifier 'abstract' is not valid for this item in C# 7.3. Please use language version '11.0' or greater. // abstract override static event D M07 { add {} remove {} } - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M07").WithArguments("abstract", "7.3", "preview").WithLocation(22, 38), + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M07").WithArguments("abstract", "7.3", "11.0").WithLocation(22, 38), // (22,42): error CS8712: 'I1.M07': abstract event cannot use event accessor syntax // abstract override static event D M07 { add {} remove {} } Diagnostic(ErrorCode.ERR_AbstractEventHasAccessors, "{").WithArguments("I1.M07").WithLocation(22, 42), // (25,35): error CS0106: The modifier 'sealed' is not valid for this item // virtual sealed static event D M08 { add {} remove {} } Diagnostic(ErrorCode.ERR_BadMemberFlag, "M08").WithArguments("sealed").WithLocation(25, 35), - // (25,35): error CS8703: The modifier 'virtual' is not valid for this item in C# 7.3. Please use language version 'preview' or greater. + // (25,35): error CS8703: The modifier 'virtual' is not valid for this item in C# 7.3. Please use language version '11.0' or greater. // virtual sealed static event D M08 { add {} remove {} } - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M08").WithArguments("virtual", "7.3", "preview").WithLocation(25, 35), + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M08").WithArguments("virtual", "7.3", "11.0").WithLocation(25, 35), // (28,37): error CS0106: The modifier 'override' is not valid for this item // virtual override static event D M09 { add {} remove {} } Diagnostic(ErrorCode.ERR_BadMemberFlag, "M09").WithArguments("override").WithLocation(28, 37), - // (28,37): error CS8703: The modifier 'virtual' is not valid for this item in C# 7.3. Please use language version 'preview' or greater. + // (28,37): error CS8703: The modifier 'virtual' is not valid for this item in C# 7.3. Please use language version '11.0' or greater. // virtual override static event D M09 { add {} remove {} } - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M09").WithArguments("virtual", "7.3", "preview").WithLocation(28, 37), + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M09").WithArguments("virtual", "7.3", "11.0").WithLocation(28, 37), // (31,36): error CS0106: The modifier 'override' is not valid for this item // sealed override static event D M10 { add {} remove {} } Diagnostic(ErrorCode.ERR_BadMemberFlag, "M10").WithArguments("override").WithLocation(31, 36), - // (31,36): error CS8703: The modifier 'sealed' is not valid for this item in C# 7.3. Please use language version 'preview' or greater. + // (31,36): error CS8703: The modifier 'sealed' is not valid for this item in C# 7.3. Please use language version '11.0' or greater. // sealed override static event D M10 { add {} remove {} } - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M10").WithArguments("sealed", "7.3", "preview").WithLocation(31, 36) + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M10").WithArguments("sealed", "7.3", "11.0").WithLocation(31, 36) ); ValidateEventModifiers_01(compilation1); @@ -3294,18 +3294,18 @@ public interface I1 targetFramework: _supportingFramework); compilation1.VerifyDiagnostics( - // (4,32): error CS8703: The modifier 'abstract' is not valid for this item in C# 10.0. Please use language version 'preview' or greater. + // (4,32): error CS8703: The modifier 'abstract' is not valid for this item in C# 10.0. Please use language version '11.0' or greater. // abstract static I1 operator+ (I1 x) - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "+").WithArguments("abstract", "10.0", "preview").WithLocation(4, 32), - // (7,31): error CS8703: The modifier 'virtual' is not valid for this item in C# 10.0. Please use language version 'preview' or greater. + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "+").WithArguments("abstract", "10.0", "11.0").WithLocation(4, 32), + // (7,31): error CS8703: The modifier 'virtual' is not valid for this item in C# 10.0. Please use language version '11.0' or greater. // virtual static I1 operator- (I1 x) - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "-").WithArguments("virtual", "10.0", "preview").WithLocation(7, 31), + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "-").WithArguments("virtual", "10.0", "11.0").WithLocation(7, 31), // (7,31): error CS0501: 'I1.operator -(I1)' must declare a body because it is not marked abstract, extern, or partial // virtual static I1 operator- (I1 x) Diagnostic(ErrorCode.ERR_ConcreteMissingBody, "-").WithArguments("I1.operator -(I1)").WithLocation(7, 31), - // (10,30): error CS8703: The modifier 'sealed' is not valid for this item in C# 10.0. Please use language version 'preview' or greater. + // (10,30): error CS8703: The modifier 'sealed' is not valid for this item in C# 10.0. Please use language version '11.0' or greater. // sealed static I1 operator++ (I1 x) - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "++").WithArguments("sealed", "10.0", "preview").WithLocation(10, 30), + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "++").WithArguments("sealed", "10.0", "11.0").WithLocation(10, 30), // (10,30): error CS0501: 'I1.operator ++(I1)' must declare a body because it is not marked abstract, extern, or partial // sealed static I1 operator++ (I1 x) Diagnostic(ErrorCode.ERR_ConcreteMissingBody, "++").WithArguments("I1.operator ++(I1)").WithLocation(10, 30), @@ -3315,48 +3315,48 @@ public interface I1 // (13,32): error CS0501: 'I1.operator --(I1)' must declare a body because it is not marked abstract, extern, or partial // override static I1 operator-- (I1 x) Diagnostic(ErrorCode.ERR_ConcreteMissingBody, "--").WithArguments("I1.operator --(I1)").WithLocation(13, 32), - // (16,40): error CS8703: The modifier 'abstract' is not valid for this item in C# 10.0. Please use language version 'preview' or greater. + // (16,40): error CS8703: The modifier 'abstract' is not valid for this item in C# 10.0. Please use language version '11.0' or greater. // abstract virtual static I1 operator! (I1 x) - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "!").WithArguments("abstract", "10.0", "preview").WithLocation(16, 40), + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "!").WithArguments("abstract", "10.0", "11.0").WithLocation(16, 40), // (16,40): error CS0503: The abstract method 'I1.operator !(I1)' cannot be marked virtual // abstract virtual static I1 operator! (I1 x) Diagnostic(ErrorCode.ERR_AbstractNotVirtual, "!").WithArguments("method", "I1.operator !(I1)").WithLocation(16, 40), // (19,39): error CS0106: The modifier 'sealed' is not valid for this item // abstract sealed static I1 operator~ (I1 x) Diagnostic(ErrorCode.ERR_BadMemberFlag, "~").WithArguments("sealed").WithLocation(19, 39), - // (19,39): error CS8703: The modifier 'abstract' is not valid for this item in C# 10.0. Please use language version 'preview' or greater. + // (19,39): error CS8703: The modifier 'abstract' is not valid for this item in C# 10.0. Please use language version '11.0' or greater. // abstract sealed static I1 operator~ (I1 x) - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "~").WithArguments("abstract", "10.0", "preview").WithLocation(19, 39), + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "~").WithArguments("abstract", "10.0", "11.0").WithLocation(19, 39), // (22,41): error CS0106: The modifier 'override' is not valid for this item // abstract override static I1 operator+ (I1 x, I1 y) Diagnostic(ErrorCode.ERR_BadMemberFlag, "+").WithArguments("override").WithLocation(22, 41), - // (22,41): error CS8703: The modifier 'abstract' is not valid for this item in C# 10.0. Please use language version 'preview' or greater. + // (22,41): error CS8703: The modifier 'abstract' is not valid for this item in C# 10.0. Please use language version '11.0' or greater. // abstract override static I1 operator+ (I1 x, I1 y) - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "+").WithArguments("abstract", "10.0", "preview").WithLocation(22, 41), + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "+").WithArguments("abstract", "10.0", "11.0").WithLocation(22, 41), // (25,38): error CS0106: The modifier 'sealed' is not valid for this item // virtual sealed static I1 operator- (I1 x, I1 y) Diagnostic(ErrorCode.ERR_BadMemberFlag, "-").WithArguments("sealed").WithLocation(25, 38), - // (25,38): error CS8703: The modifier 'virtual' is not valid for this item in C# 10.0. Please use language version 'preview' or greater. + // (25,38): error CS8703: The modifier 'virtual' is not valid for this item in C# 10.0. Please use language version '11.0' or greater. // virtual sealed static I1 operator- (I1 x, I1 y) - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "-").WithArguments("virtual", "10.0", "preview").WithLocation(25, 38), + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "-").WithArguments("virtual", "10.0", "11.0").WithLocation(25, 38), // (25,38): error CS0501: 'I1.operator -(I1, I1)' must declare a body because it is not marked abstract, extern, or partial // virtual sealed static I1 operator- (I1 x, I1 y) Diagnostic(ErrorCode.ERR_ConcreteMissingBody, "-").WithArguments("I1.operator -(I1, I1)").WithLocation(25, 38), // (28,40): error CS0106: The modifier 'override' is not valid for this item // virtual override static I1 operator* (I1 x, I1 y) Diagnostic(ErrorCode.ERR_BadMemberFlag, "*").WithArguments("override").WithLocation(28, 40), - // (28,40): error CS8703: The modifier 'virtual' is not valid for this item in C# 10.0. Please use language version 'preview' or greater. + // (28,40): error CS8703: The modifier 'virtual' is not valid for this item in C# 10.0. Please use language version '11.0' or greater. // virtual override static I1 operator* (I1 x, I1 y) - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "*").WithArguments("virtual", "10.0", "preview").WithLocation(28, 40), + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "*").WithArguments("virtual", "10.0", "11.0").WithLocation(28, 40), // (28,40): error CS0501: 'I1.operator *(I1, I1)' must declare a body because it is not marked abstract, extern, or partial // virtual override static I1 operator* (I1 x, I1 y) Diagnostic(ErrorCode.ERR_ConcreteMissingBody, "*").WithArguments("I1.operator *(I1, I1)").WithLocation(28, 40), // (31,39): error CS0106: The modifier 'override' is not valid for this item // sealed override static I1 operator/ (I1 x, I1 y) Diagnostic(ErrorCode.ERR_BadMemberFlag, "/").WithArguments("override").WithLocation(31, 39), - // (31,39): error CS8703: The modifier 'sealed' is not valid for this item in C# 10.0. Please use language version 'preview' or greater. + // (31,39): error CS8703: The modifier 'sealed' is not valid for this item in C# 10.0. Please use language version '11.0' or greater. // sealed override static I1 operator/ (I1 x, I1 y) - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "/").WithArguments("sealed", "10.0", "preview").WithLocation(31, 39), + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "/").WithArguments("sealed", "10.0", "11.0").WithLocation(31, 39), // (31,39): error CS0501: 'I1.operator /(I1, I1)' must declare a body because it is not marked abstract, extern, or partial // sealed override static I1 operator/ (I1 x, I1 y) Diagnostic(ErrorCode.ERR_ConcreteMissingBody, "/").WithArguments("I1.operator /(I1, I1)").WithLocation(31, 39) @@ -3532,63 +3532,63 @@ public interface I1 targetFramework: _supportingFramework); compilation1.VerifyDiagnostics( - // (4,32): error CS8703: The modifier 'abstract' is not valid for this item in C# 10.0. Please use language version 'preview' or greater. + // (4,32): error CS8703: The modifier 'abstract' is not valid for this item in C# 10.0. Please use language version '11.0' or greater. // abstract static I1 operator+ (I1 x) - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "+").WithArguments("abstract", "10.0", "preview").WithLocation(4, 32), + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "+").WithArguments("abstract", "10.0", "11.0").WithLocation(4, 32), // (4,32): error CS0500: 'I1.operator +(I1)' cannot declare a body because it is marked abstract // abstract static I1 operator+ (I1 x) Diagnostic(ErrorCode.ERR_AbstractHasBody, "+").WithArguments("I1.operator +(I1)").WithLocation(4, 32), - // (7,31): error CS8703: The modifier 'virtual' is not valid for this item in C# 10.0. Please use language version 'preview' or greater. + // (7,31): error CS8703: The modifier 'virtual' is not valid for this item in C# 10.0. Please use language version '11.0' or greater. // virtual static I1 operator- (I1 x) - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "-").WithArguments("virtual", "10.0", "preview").WithLocation(7, 31), - // (10,30): error CS8703: The modifier 'sealed' is not valid for this item in C# 10.0. Please use language version 'preview' or greater. + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "-").WithArguments("virtual", "10.0", "11.0").WithLocation(7, 31), + // (10,30): error CS8703: The modifier 'sealed' is not valid for this item in C# 10.0. Please use language version '11.0' or greater. // sealed static I1 operator++ (I1 x) - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "++").WithArguments("sealed", "10.0", "preview").WithLocation(10, 30), + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "++").WithArguments("sealed", "10.0", "11.0").WithLocation(10, 30), // (13,32): error CS0106: The modifier 'override' is not valid for this item // override static I1 operator-- (I1 x) Diagnostic(ErrorCode.ERR_BadMemberFlag, "--").WithArguments("override").WithLocation(13, 32), - // (16,40): error CS8703: The modifier 'abstract' is not valid for this item in C# 10.0. Please use language version 'preview' or greater. + // (16,40): error CS8703: The modifier 'abstract' is not valid for this item in C# 10.0. Please use language version '11.0' or greater. // abstract virtual static I1 operator! (I1 x) - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "!").WithArguments("abstract", "10.0", "preview").WithLocation(16, 40), + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "!").WithArguments("abstract", "10.0", "11.0").WithLocation(16, 40), // (16,40): error CS0503: The abstract method 'I1.operator !(I1)' cannot be marked virtual // abstract virtual static I1 operator! (I1 x) Diagnostic(ErrorCode.ERR_AbstractNotVirtual, "!").WithArguments("method", "I1.operator !(I1)").WithLocation(16, 40), // (19,39): error CS0106: The modifier 'sealed' is not valid for this item // abstract sealed static I1 operator~ (I1 x) Diagnostic(ErrorCode.ERR_BadMemberFlag, "~").WithArguments("sealed").WithLocation(19, 39), - // (19,39): error CS8703: The modifier 'abstract' is not valid for this item in C# 10.0. Please use language version 'preview' or greater. + // (19,39): error CS8703: The modifier 'abstract' is not valid for this item in C# 10.0. Please use language version '11.0' or greater. // abstract sealed static I1 operator~ (I1 x) - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "~").WithArguments("abstract", "10.0", "preview").WithLocation(19, 39), + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "~").WithArguments("abstract", "10.0", "11.0").WithLocation(19, 39), // (19,39): error CS0500: 'I1.operator ~(I1)' cannot declare a body because it is marked abstract // abstract sealed static I1 operator~ (I1 x) Diagnostic(ErrorCode.ERR_AbstractHasBody, "~").WithArguments("I1.operator ~(I1)").WithLocation(19, 39), // (22,41): error CS0106: The modifier 'override' is not valid for this item // abstract override static I1 operator+ (I1 x, I1 y) Diagnostic(ErrorCode.ERR_BadMemberFlag, "+").WithArguments("override").WithLocation(22, 41), - // (22,41): error CS8703: The modifier 'abstract' is not valid for this item in C# 10.0. Please use language version 'preview' or greater. + // (22,41): error CS8703: The modifier 'abstract' is not valid for this item in C# 10.0. Please use language version '11.0' or greater. // abstract override static I1 operator+ (I1 x, I1 y) - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "+").WithArguments("abstract", "10.0", "preview").WithLocation(22, 41), + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "+").WithArguments("abstract", "10.0", "11.0").WithLocation(22, 41), // (22,41): error CS0500: 'I1.operator +(I1, I1)' cannot declare a body because it is marked abstract // abstract override static I1 operator+ (I1 x, I1 y) Diagnostic(ErrorCode.ERR_AbstractHasBody, "+").WithArguments("I1.operator +(I1, I1)").WithLocation(22, 41), // (25,38): error CS0106: The modifier 'sealed' is not valid for this item // virtual sealed static I1 operator- (I1 x, I1 y) Diagnostic(ErrorCode.ERR_BadMemberFlag, "-").WithArguments("sealed").WithLocation(25, 38), - // (25,38): error CS8703: The modifier 'virtual' is not valid for this item in C# 10.0. Please use language version 'preview' or greater. + // (25,38): error CS8703: The modifier 'virtual' is not valid for this item in C# 10.0. Please use language version '11.0' or greater. // virtual sealed static I1 operator- (I1 x, I1 y) - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "-").WithArguments("virtual", "10.0", "preview").WithLocation(25, 38), + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "-").WithArguments("virtual", "10.0", "11.0").WithLocation(25, 38), // (28,40): error CS0106: The modifier 'override' is not valid for this item // virtual override static I1 operator* (I1 x, I1 y) Diagnostic(ErrorCode.ERR_BadMemberFlag, "*").WithArguments("override").WithLocation(28, 40), - // (28,40): error CS8703: The modifier 'virtual' is not valid for this item in C# 10.0. Please use language version 'preview' or greater. + // (28,40): error CS8703: The modifier 'virtual' is not valid for this item in C# 10.0. Please use language version '11.0' or greater. // virtual override static I1 operator* (I1 x, I1 y) - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "*").WithArguments("virtual", "10.0", "preview").WithLocation(28, 40), + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "*").WithArguments("virtual", "10.0", "11.0").WithLocation(28, 40), // (31,39): error CS0106: The modifier 'override' is not valid for this item // sealed override static I1 operator/ (I1 x, I1 y) Diagnostic(ErrorCode.ERR_BadMemberFlag, "/").WithArguments("override").WithLocation(31, 39), - // (31,39): error CS8703: The modifier 'sealed' is not valid for this item in C# 10.0. Please use language version 'preview' or greater. + // (31,39): error CS8703: The modifier 'sealed' is not valid for this item in C# 10.0. Please use language version '11.0' or greater. // sealed override static I1 operator/ (I1 x, I1 y) - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "/").WithArguments("sealed", "10.0", "preview").WithLocation(31, 39) + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "/").WithArguments("sealed", "10.0", "11.0").WithLocation(31, 39) ); ValidateOperatorModifiers_01(compilation1); @@ -3802,18 +3802,18 @@ public interface I1 targetFramework: _supportingFramework); compilation1.VerifyDiagnostics( - // (4,32): error CS8703: The modifier 'abstract' is not valid for this item in C# 7.3. Please use language version 'preview' or greater. + // (4,32): error CS8703: The modifier 'abstract' is not valid for this item in C# 7.3. Please use language version '11.0' or greater. // abstract static I1 operator+ (I1 x) - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "+").WithArguments("abstract", "7.3", "preview").WithLocation(4, 32), - // (7,31): error CS8703: The modifier 'virtual' is not valid for this item in C# 7.3. Please use language version 'preview' or greater. + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "+").WithArguments("abstract", "7.3", "11.0").WithLocation(4, 32), + // (7,31): error CS8703: The modifier 'virtual' is not valid for this item in C# 7.3. Please use language version '11.0' or greater. // virtual static I1 operator- (I1 x) - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "-").WithArguments("virtual", "7.3", "preview").WithLocation(7, 31), + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "-").WithArguments("virtual", "7.3", "11.0").WithLocation(7, 31), // (7,31): error CS0501: 'I1.operator -(I1)' must declare a body because it is not marked abstract, extern, or partial // virtual static I1 operator- (I1 x) Diagnostic(ErrorCode.ERR_ConcreteMissingBody, "-").WithArguments("I1.operator -(I1)").WithLocation(7, 31), - // (10,30): error CS8703: The modifier 'sealed' is not valid for this item in C# 7.3. Please use language version 'preview' or greater. + // (10,30): error CS8703: The modifier 'sealed' is not valid for this item in C# 7.3. Please use language version '11.0' or greater. // sealed static I1 operator++ (I1 x) - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "++").WithArguments("sealed", "7.3", "preview").WithLocation(10, 30), + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "++").WithArguments("sealed", "7.3", "11.0").WithLocation(10, 30), // (10,30): error CS0501: 'I1.operator ++(I1)' must declare a body because it is not marked abstract, extern, or partial // sealed static I1 operator++ (I1 x) Diagnostic(ErrorCode.ERR_ConcreteMissingBody, "++").WithArguments("I1.operator ++(I1)").WithLocation(10, 30), @@ -3826,48 +3826,48 @@ public interface I1 // (13,32): error CS0501: 'I1.operator --(I1)' must declare a body because it is not marked abstract, extern, or partial // override static I1 operator-- (I1 x) Diagnostic(ErrorCode.ERR_ConcreteMissingBody, "--").WithArguments("I1.operator --(I1)").WithLocation(13, 32), - // (16,40): error CS8703: The modifier 'abstract' is not valid for this item in C# 7.3. Please use language version 'preview' or greater. + // (16,40): error CS8703: The modifier 'abstract' is not valid for this item in C# 7.3. Please use language version '11.0' or greater. // abstract virtual static I1 operator! (I1 x) - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "!").WithArguments("abstract", "7.3", "preview").WithLocation(16, 40), + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "!").WithArguments("abstract", "7.3", "11.0").WithLocation(16, 40), // (16,40): error CS0503: The abstract method 'I1.operator !(I1)' cannot be marked virtual // abstract virtual static I1 operator! (I1 x) Diagnostic(ErrorCode.ERR_AbstractNotVirtual, "!").WithArguments("method", "I1.operator !(I1)").WithLocation(16, 40), // (19,39): error CS0106: The modifier 'sealed' is not valid for this item // abstract sealed static I1 operator~ (I1 x) Diagnostic(ErrorCode.ERR_BadMemberFlag, "~").WithArguments("sealed").WithLocation(19, 39), - // (19,39): error CS8703: The modifier 'abstract' is not valid for this item in C# 7.3. Please use language version 'preview' or greater. + // (19,39): error CS8703: The modifier 'abstract' is not valid for this item in C# 7.3. Please use language version '11.0' or greater. // abstract sealed static I1 operator~ (I1 x) - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "~").WithArguments("abstract", "7.3", "preview").WithLocation(19, 39), + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "~").WithArguments("abstract", "7.3", "11.0").WithLocation(19, 39), // (22,41): error CS0106: The modifier 'override' is not valid for this item // abstract override static I1 operator+ (I1 x, I1 y) Diagnostic(ErrorCode.ERR_BadMemberFlag, "+").WithArguments("override").WithLocation(22, 41), - // (22,41): error CS8703: The modifier 'abstract' is not valid for this item in C# 7.3. Please use language version 'preview' or greater. + // (22,41): error CS8703: The modifier 'abstract' is not valid for this item in C# 7.3. Please use language version '11.0' or greater. // abstract override static I1 operator+ (I1 x, I1 y) - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "+").WithArguments("abstract", "7.3", "preview").WithLocation(22, 41), + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "+").WithArguments("abstract", "7.3", "11.0").WithLocation(22, 41), // (25,38): error CS0106: The modifier 'sealed' is not valid for this item // virtual sealed static I1 operator- (I1 x, I1 y) Diagnostic(ErrorCode.ERR_BadMemberFlag, "-").WithArguments("sealed").WithLocation(25, 38), - // (25,38): error CS8703: The modifier 'virtual' is not valid for this item in C# 7.3. Please use language version 'preview' or greater. + // (25,38): error CS8703: The modifier 'virtual' is not valid for this item in C# 7.3. Please use language version '11.0' or greater. // virtual sealed static I1 operator- (I1 x, I1 y) - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "-").WithArguments("virtual", "7.3", "preview").WithLocation(25, 38), + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "-").WithArguments("virtual", "7.3", "11.0").WithLocation(25, 38), // (25,38): error CS0501: 'I1.operator -(I1, I1)' must declare a body because it is not marked abstract, extern, or partial // virtual sealed static I1 operator- (I1 x, I1 y) Diagnostic(ErrorCode.ERR_ConcreteMissingBody, "-").WithArguments("I1.operator -(I1, I1)").WithLocation(25, 38), // (28,40): error CS0106: The modifier 'override' is not valid for this item // virtual override static I1 operator* (I1 x, I1 y) Diagnostic(ErrorCode.ERR_BadMemberFlag, "*").WithArguments("override").WithLocation(28, 40), - // (28,40): error CS8703: The modifier 'virtual' is not valid for this item in C# 7.3. Please use language version 'preview' or greater. + // (28,40): error CS8703: The modifier 'virtual' is not valid for this item in C# 7.3. Please use language version '11.0' or greater. // virtual override static I1 operator* (I1 x, I1 y) - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "*").WithArguments("virtual", "7.3", "preview").WithLocation(28, 40), + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "*").WithArguments("virtual", "7.3", "11.0").WithLocation(28, 40), // (28,40): error CS0501: 'I1.operator *(I1, I1)' must declare a body because it is not marked abstract, extern, or partial // virtual override static I1 operator* (I1 x, I1 y) Diagnostic(ErrorCode.ERR_ConcreteMissingBody, "*").WithArguments("I1.operator *(I1, I1)").WithLocation(28, 40), // (31,39): error CS0106: The modifier 'override' is not valid for this item // sealed override static I1 operator/ (I1 x, I1 y) Diagnostic(ErrorCode.ERR_BadMemberFlag, "/").WithArguments("override").WithLocation(31, 39), - // (31,39): error CS8703: The modifier 'sealed' is not valid for this item in C# 7.3. Please use language version 'preview' or greater. + // (31,39): error CS8703: The modifier 'sealed' is not valid for this item in C# 7.3. Please use language version '11.0' or greater. // sealed override static I1 operator/ (I1 x, I1 y) - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "/").WithArguments("sealed", "7.3", "preview").WithLocation(31, 39), + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "/").WithArguments("sealed", "7.3", "11.0").WithLocation(31, 39), // (31,39): error CS0501: 'I1.operator /(I1, I1)' must declare a body because it is not marked abstract, extern, or partial // sealed override static I1 operator/ (I1 x, I1 y) Diagnostic(ErrorCode.ERR_ConcreteMissingBody, "/").WithArguments("I1.operator /(I1, I1)").WithLocation(31, 39) @@ -3919,66 +3919,66 @@ public interface I1 targetFramework: _supportingFramework); compilation1.VerifyDiagnostics( - // (4,32): error CS8703: The modifier 'abstract' is not valid for this item in C# 7.3. Please use language version 'preview' or greater. + // (4,32): error CS8703: The modifier 'abstract' is not valid for this item in C# 7.3. Please use language version '11.0' or greater. // abstract static I1 operator+ (I1 x) - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "+").WithArguments("abstract", "7.3", "preview").WithLocation(4, 32), + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "+").WithArguments("abstract", "7.3", "11.0").WithLocation(4, 32), // (4,32): error CS0500: 'I1.operator +(I1)' cannot declare a body because it is marked abstract // abstract static I1 operator+ (I1 x) Diagnostic(ErrorCode.ERR_AbstractHasBody, "+").WithArguments("I1.operator +(I1)").WithLocation(4, 32), - // (7,31): error CS8703: The modifier 'virtual' is not valid for this item in C# 7.3. Please use language version 'preview' or greater. + // (7,31): error CS8703: The modifier 'virtual' is not valid for this item in C# 7.3. Please use language version '11.0' or greater. // virtual static I1 operator- (I1 x) - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "-").WithArguments("virtual", "7.3", "preview").WithLocation(7, 31), - // (10,30): error CS8703: The modifier 'sealed' is not valid for this item in C# 7.3. Please use language version 'preview' or greater. + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "-").WithArguments("virtual", "7.3", "11.0").WithLocation(7, 31), + // (10,30): error CS8703: The modifier 'sealed' is not valid for this item in C# 7.3. Please use language version '11.0' or greater. // sealed static I1 operator++ (I1 x) - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "++").WithArguments("sealed", "7.3", "preview").WithLocation(10, 30), + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "++").WithArguments("sealed", "7.3", "11.0").WithLocation(10, 30), // (13,32): error CS0106: The modifier 'override' is not valid for this item // override static I1 operator-- (I1 x) Diagnostic(ErrorCode.ERR_BadMemberFlag, "--").WithArguments("override").WithLocation(13, 32), // (13,32): error CS8370: Feature 'default interface implementation' is not available in C# 7.3. Please use language version 8.0 or greater. // override static I1 operator-- (I1 x) Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7_3, "--").WithArguments("default interface implementation", "8.0").WithLocation(13, 32), - // (16,40): error CS8703: The modifier 'abstract' is not valid for this item in C# 7.3. Please use language version 'preview' or greater. + // (16,40): error CS8703: The modifier 'abstract' is not valid for this item in C# 7.3. Please use language version '11.0' or greater. // abstract virtual static I1 operator! (I1 x) - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "!").WithArguments("abstract", "7.3", "preview").WithLocation(16, 40), + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "!").WithArguments("abstract", "7.3", "11.0").WithLocation(16, 40), // (16,40): error CS0503: The abstract method 'I1.operator !(I1)' cannot be marked virtual // abstract virtual static I1 operator! (I1 x) Diagnostic(ErrorCode.ERR_AbstractNotVirtual, "!").WithArguments("method", "I1.operator !(I1)").WithLocation(16, 40), // (19,39): error CS0106: The modifier 'sealed' is not valid for this item // abstract sealed static I1 operator~ (I1 x) Diagnostic(ErrorCode.ERR_BadMemberFlag, "~").WithArguments("sealed").WithLocation(19, 39), - // (19,39): error CS8703: The modifier 'abstract' is not valid for this item in C# 7.3. Please use language version 'preview' or greater. + // (19,39): error CS8703: The modifier 'abstract' is not valid for this item in C# 7.3. Please use language version '11.0' or greater. // abstract sealed static I1 operator~ (I1 x) - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "~").WithArguments("abstract", "7.3", "preview").WithLocation(19, 39), + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "~").WithArguments("abstract", "7.3", "11.0").WithLocation(19, 39), // (19,39): error CS0500: 'I1.operator ~(I1)' cannot declare a body because it is marked abstract // abstract sealed static I1 operator~ (I1 x) Diagnostic(ErrorCode.ERR_AbstractHasBody, "~").WithArguments("I1.operator ~(I1)").WithLocation(19, 39), // (22,41): error CS0106: The modifier 'override' is not valid for this item // abstract override static I1 operator+ (I1 x, I1 y) Diagnostic(ErrorCode.ERR_BadMemberFlag, "+").WithArguments("override").WithLocation(22, 41), - // (22,41): error CS8703: The modifier 'abstract' is not valid for this item in C# 7.3. Please use language version 'preview' or greater. + // (22,41): error CS8703: The modifier 'abstract' is not valid for this item in C# 7.3. Please use language version '11.0' or greater. // abstract override static I1 operator+ (I1 x, I1 y) - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "+").WithArguments("abstract", "7.3", "preview").WithLocation(22, 41), + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "+").WithArguments("abstract", "7.3", "11.0").WithLocation(22, 41), // (22,41): error CS0500: 'I1.operator +(I1, I1)' cannot declare a body because it is marked abstract // abstract override static I1 operator+ (I1 x, I1 y) Diagnostic(ErrorCode.ERR_AbstractHasBody, "+").WithArguments("I1.operator +(I1, I1)").WithLocation(22, 41), // (25,38): error CS0106: The modifier 'sealed' is not valid for this item // virtual sealed static I1 operator- (I1 x, I1 y) Diagnostic(ErrorCode.ERR_BadMemberFlag, "-").WithArguments("sealed").WithLocation(25, 38), - // (25,38): error CS8703: The modifier 'virtual' is not valid for this item in C# 7.3. Please use language version 'preview' or greater. + // (25,38): error CS8703: The modifier 'virtual' is not valid for this item in C# 7.3. Please use language version '11.0' or greater. // virtual sealed static I1 operator- (I1 x, I1 y) - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "-").WithArguments("virtual", "7.3", "preview").WithLocation(25, 38), + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "-").WithArguments("virtual", "7.3", "11.0").WithLocation(25, 38), // (28,40): error CS0106: The modifier 'override' is not valid for this item // virtual override static I1 operator* (I1 x, I1 y) Diagnostic(ErrorCode.ERR_BadMemberFlag, "*").WithArguments("override").WithLocation(28, 40), - // (28,40): error CS8703: The modifier 'virtual' is not valid for this item in C# 7.3. Please use language version 'preview' or greater. + // (28,40): error CS8703: The modifier 'virtual' is not valid for this item in C# 7.3. Please use language version '11.0' or greater. // virtual override static I1 operator* (I1 x, I1 y) - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "*").WithArguments("virtual", "7.3", "preview").WithLocation(28, 40), + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "*").WithArguments("virtual", "7.3", "11.0").WithLocation(28, 40), // (31,39): error CS0106: The modifier 'override' is not valid for this item // sealed override static I1 operator/ (I1 x, I1 y) Diagnostic(ErrorCode.ERR_BadMemberFlag, "/").WithArguments("override").WithLocation(31, 39), - // (31,39): error CS8703: The modifier 'sealed' is not valid for this item in C# 7.3. Please use language version 'preview' or greater. + // (31,39): error CS8703: The modifier 'sealed' is not valid for this item in C# 7.3. Please use language version '11.0' or greater. // sealed override static I1 operator/ (I1 x, I1 y) - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "/").WithArguments("sealed", "7.3", "preview").WithLocation(31, 39) + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "/").WithArguments("sealed", "7.3", "11.0").WithLocation(31, 39) ); ValidateOperatorModifiers_01(compilation1); @@ -4015,12 +4015,12 @@ public interface I3 targetFramework: _supportingFramework); compilation1.GetDiagnostics().Where(d => d.Code is not (int)ErrorCode.ERR_BadAbstractEqualityOperatorSignature).Verify( - // (4,34): error CS8703: The modifier 'abstract' is not valid for this item in C# 7.3. Please use language version 'preview' or greater. + // (4,34): error CS8703: The modifier 'abstract' is not valid for this item in C# 7.3. Please use language version '11.0' or greater. // abstract static bool operator== (I1 x, I1 y); - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "==").WithArguments("abstract", "7.3", "preview").WithLocation(4, 34), - // (6,34): error CS8703: The modifier 'abstract' is not valid for this item in C# 7.3. Please use language version 'preview' or greater. + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "==").WithArguments("abstract", "7.3", "11.0").WithLocation(4, 34), + // (6,34): error CS8703: The modifier 'abstract' is not valid for this item in C# 7.3. Please use language version '11.0' or greater. // abstract static bool operator!= (I1 x, I1 y) {return false;} - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "!=").WithArguments("abstract", "7.3", "preview").WithLocation(6, 34), + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "!=").WithArguments("abstract", "7.3", "11.0").WithLocation(6, 34), // (6,34): error CS0500: 'I1.operator !=(I1, I1)' cannot declare a body because it is marked abstract // abstract static bool operator!= (I1 x, I1 y) {return false;} Diagnostic(ErrorCode.ERR_AbstractHasBody, "!=").WithArguments("I1.operator !=(I1, I1)").WithLocation(6, 34), @@ -4039,15 +4039,15 @@ public interface I3 // (18,41): error CS0106: The modifier 'sealed' is not valid for this item // abstract sealed static bool operator== (I3 x, I3 y); Diagnostic(ErrorCode.ERR_BadMemberFlag, "==").WithArguments("sealed").WithLocation(18, 41), - // (18,41): error CS8703: The modifier 'abstract' is not valid for this item in C# 7.3. Please use language version 'preview' or greater. + // (18,41): error CS8703: The modifier 'abstract' is not valid for this item in C# 7.3. Please use language version '11.0' or greater. // abstract sealed static bool operator== (I3 x, I3 y); - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "==").WithArguments("abstract", "7.3", "preview").WithLocation(18, 41), + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "==").WithArguments("abstract", "7.3", "11.0").WithLocation(18, 41), // (20,41): error CS0106: The modifier 'sealed' is not valid for this item // abstract sealed static bool operator!= (I3 x, I3 y) {return false;} Diagnostic(ErrorCode.ERR_BadMemberFlag, "!=").WithArguments("sealed").WithLocation(20, 41), - // (20,41): error CS8703: The modifier 'abstract' is not valid for this item in C# 7.3. Please use language version 'preview' or greater. + // (20,41): error CS8703: The modifier 'abstract' is not valid for this item in C# 7.3. Please use language version '11.0' or greater. // abstract sealed static bool operator!= (I3 x, I3 y) {return false;} - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "!=").WithArguments("abstract", "7.3", "preview").WithLocation(20, 41), + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "!=").WithArguments("abstract", "7.3", "11.0").WithLocation(20, 41), // (20,41): error CS0500: 'I3.operator !=(I3, I3)' cannot declare a body because it is marked abstract // abstract sealed static bool operator!= (I3 x, I3 y) {return false;} Diagnostic(ErrorCode.ERR_AbstractHasBody, "!=").WithArguments("I3.operator !=(I3, I3)").WithLocation(20, 41) @@ -4060,12 +4060,12 @@ public interface I3 targetFramework: _supportingFramework); compilation1.GetDiagnostics().Where(d => d.Code is not (int)ErrorCode.ERR_BadAbstractEqualityOperatorSignature).Verify( - // (4,34): error CS8703: The modifier 'abstract' is not valid for this item in C# 10.0. Please use language version 'preview' or greater. + // (4,34): error CS8703: The modifier 'abstract' is not valid for this item in C# 10.0. Please use language version '11.0' or greater. // abstract static bool operator== (I1 x, I1 y); - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "==").WithArguments("abstract", "10.0", "preview").WithLocation(4, 34), - // (6,34): error CS8703: The modifier 'abstract' is not valid for this item in C# 10.0. Please use language version 'preview' or greater. + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "==").WithArguments("abstract", "10.0", "11.0").WithLocation(4, 34), + // (6,34): error CS8703: The modifier 'abstract' is not valid for this item in C# 10.0. Please use language version '11.0' or greater. // abstract static bool operator!= (I1 x, I1 y) {return false;} - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "!=").WithArguments("abstract", "10.0", "preview").WithLocation(6, 34), + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "!=").WithArguments("abstract", "10.0", "11.0").WithLocation(6, 34), // (6,34): error CS0500: 'I1.operator !=(I1, I1)' cannot declare a body because it is marked abstract // abstract static bool operator!= (I1 x, I1 y) {return false;} Diagnostic(ErrorCode.ERR_AbstractHasBody, "!=").WithArguments("I1.operator !=(I1, I1)").WithLocation(6, 34), @@ -4084,15 +4084,15 @@ public interface I3 // (18,41): error CS0106: The modifier 'sealed' is not valid for this item // abstract sealed static bool operator== (I3 x, I3 y); Diagnostic(ErrorCode.ERR_BadMemberFlag, "==").WithArguments("sealed").WithLocation(18, 41), - // (18,41): error CS8703: The modifier 'abstract' is not valid for this item in C# 10.0. Please use language version 'preview' or greater. + // (18,41): error CS8703: The modifier 'abstract' is not valid for this item in C# 10.0. Please use language version '11.0' or greater. // abstract sealed static bool operator== (I3 x, I3 y); - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "==").WithArguments("abstract", "10.0", "preview").WithLocation(18, 41), + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "==").WithArguments("abstract", "10.0", "11.0").WithLocation(18, 41), // (20,41): error CS0106: The modifier 'sealed' is not valid for this item // abstract sealed static bool operator!= (I3 x, I3 y) {return false;} Diagnostic(ErrorCode.ERR_BadMemberFlag, "!=").WithArguments("sealed").WithLocation(20, 41), - // (20,41): error CS8703: The modifier 'abstract' is not valid for this item in C# 10.0. Please use language version 'preview' or greater. + // (20,41): error CS8703: The modifier 'abstract' is not valid for this item in C# 10.0. Please use language version '11.0' or greater. // abstract sealed static bool operator!= (I3 x, I3 y) {return false;} - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "!=").WithArguments("abstract", "10.0", "preview").WithLocation(20, 41), + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "!=").WithArguments("abstract", "10.0", "11.0").WithLocation(20, 41), // (20,41): error CS0500: 'I3.operator !=(I3, I3)' cannot declare a body because it is marked abstract // abstract sealed static bool operator!= (I3 x, I3 y) {return false;} Diagnostic(ErrorCode.ERR_AbstractHasBody, "!=").WithArguments("I3.operator !=(I3, I3)").WithLocation(20, 41) @@ -4207,15 +4207,15 @@ public interface I3 targetFramework: _supportingFramework); compilation1.VerifyDiagnostics( - // (4,39): error CS8703: The modifier 'abstract' is not valid for this item in C# 7.3. Please use language version 'preview' or greater. + // (4,39): error CS8703: The modifier 'abstract' is not valid for this item in C# 7.3. Please use language version '11.0' or greater. // abstract static implicit operator int(I1 x); - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "int").WithArguments("abstract", "7.3", "preview").WithLocation(4, 39), + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "int").WithArguments("abstract", "7.3", "11.0").WithLocation(4, 39), // (4,39): error CS0552: 'I1.implicit operator int(I1)': user-defined conversions to or from an interface are not allowed // abstract static implicit operator int(I1 x); Diagnostic(ErrorCode.ERR_ConversionWithInterface, "int").WithArguments("I1.implicit operator int(I1)").WithLocation(4, 39), - // (6,39): error CS8703: The modifier 'abstract' is not valid for this item in C# 7.3. Please use language version 'preview' or greater. + // (6,39): error CS8703: The modifier 'abstract' is not valid for this item in C# 7.3. Please use language version '11.0' or greater. // abstract static explicit operator I1(bool x) {return null;} - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "I1").WithArguments("abstract", "7.3", "preview").WithLocation(6, 39), + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "I1").WithArguments("abstract", "7.3", "11.0").WithLocation(6, 39), // (6,39): error CS0500: 'I1.explicit operator I1(bool)' cannot declare a body because it is marked abstract // abstract static explicit operator I1(bool x) {return null;} Diagnostic(ErrorCode.ERR_AbstractHasBody, "I1").WithArguments("I1.explicit operator I1(bool)").WithLocation(6, 39), @@ -4225,36 +4225,36 @@ public interface I3 // (11,37): error CS0106: The modifier 'sealed' is not valid for this item // sealed static implicit operator int(I2 x); Diagnostic(ErrorCode.ERR_BadMemberFlag, "int").WithArguments("sealed").WithLocation(11, 37), - // (11,37): error CS0552: 'I2.implicit operator int(I2)': user-defined conversions to or from an interface are not allowed - // sealed static implicit operator int(I2 x); - Diagnostic(ErrorCode.ERR_ConversionWithInterface, "int").WithArguments("I2.implicit operator int(I2)").WithLocation(11, 37), // (11,37): error CS0567: Conversion, equality, or inequality operators declared in interfaces must be abstract or virtual // sealed static implicit operator int(I2 x); Diagnostic(ErrorCode.ERR_InterfacesCantContainConversionOrEqualityOperators, "int").WithLocation(11, 37), + // (11,37): error CS0552: 'I2.implicit operator int(I2)': user-defined conversions to or from an interface are not allowed + // sealed static implicit operator int(I2 x); + Diagnostic(ErrorCode.ERR_ConversionWithInterface, "int").WithArguments("I2.implicit operator int(I2)").WithLocation(11, 37), // (13,37): error CS0106: The modifier 'sealed' is not valid for this item // sealed static explicit operator I2(bool x) {return null;} Diagnostic(ErrorCode.ERR_BadMemberFlag, "I2").WithArguments("sealed").WithLocation(13, 37), - // (13,37): error CS0552: 'I2.explicit operator I2(bool)': user-defined conversions to or from an interface are not allowed - // sealed static explicit operator I2(bool x) {return null;} - Diagnostic(ErrorCode.ERR_ConversionWithInterface, "I2").WithArguments("I2.explicit operator I2(bool)").WithLocation(13, 37), // (13,37): error CS0567: Conversion, equality, or inequality operators declared in interfaces must be abstract or virtual // sealed static explicit operator I2(bool x) {return null;} Diagnostic(ErrorCode.ERR_InterfacesCantContainConversionOrEqualityOperators, "I2").WithLocation(13, 37), + // (13,37): error CS0552: 'I2.explicit operator I2(bool)': user-defined conversions to or from an interface are not allowed + // sealed static explicit operator I2(bool x) {return null;} + Diagnostic(ErrorCode.ERR_ConversionWithInterface, "I2").WithArguments("I2.explicit operator I2(bool)").WithLocation(13, 37), // (18,46): error CS0106: The modifier 'sealed' is not valid for this item // abstract sealed static implicit operator int(I3 x); Diagnostic(ErrorCode.ERR_BadMemberFlag, "int").WithArguments("sealed").WithLocation(18, 46), - // (18,46): error CS8703: The modifier 'abstract' is not valid for this item in C# 7.3. Please use language version 'preview' or greater. + // (18,46): error CS8703: The modifier 'abstract' is not valid for this item in C# 7.3. Please use language version '11.0' or greater. // abstract sealed static implicit operator int(I3 x); - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "int").WithArguments("abstract", "7.3", "preview").WithLocation(18, 46), + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "int").WithArguments("abstract", "7.3", "11.0").WithLocation(18, 46), // (18,46): error CS0552: 'I3.implicit operator int(I3)': user-defined conversions to or from an interface are not allowed // abstract sealed static implicit operator int(I3 x); Diagnostic(ErrorCode.ERR_ConversionWithInterface, "int").WithArguments("I3.implicit operator int(I3)").WithLocation(18, 46), // (20,46): error CS0106: The modifier 'sealed' is not valid for this item // abstract sealed static explicit operator I3(bool x) {return null;} Diagnostic(ErrorCode.ERR_BadMemberFlag, "I3").WithArguments("sealed").WithLocation(20, 46), - // (20,46): error CS8703: The modifier 'abstract' is not valid for this item in C# 7.3. Please use language version 'preview' or greater. + // (20,46): error CS8703: The modifier 'abstract' is not valid for this item in C# 7.3. Please use language version '11.0' or greater. // abstract sealed static explicit operator I3(bool x) {return null;} - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "I3").WithArguments("abstract", "7.3", "preview").WithLocation(20, 46), + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "I3").WithArguments("abstract", "7.3", "11.0").WithLocation(20, 46), // (20,46): error CS0500: 'I3.explicit operator I3(bool)' cannot declare a body because it is marked abstract // abstract sealed static explicit operator I3(bool x) {return null;} Diagnostic(ErrorCode.ERR_AbstractHasBody, "I3").WithArguments("I3.explicit operator I3(bool)").WithLocation(20, 46), @@ -4270,15 +4270,15 @@ public interface I3 targetFramework: _supportingFramework); compilation1.VerifyDiagnostics( - // (4,39): error CS8703: The modifier 'abstract' is not valid for this item in C# 10.0. Please use language version 'preview' or greater. + // (4,39): error CS8703: The modifier 'abstract' is not valid for this item in C# 10.0. Please use language version '11.0' or greater. // abstract static implicit operator int(I1 x); - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "int").WithArguments("abstract", "10.0", "preview").WithLocation(4, 39), + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "int").WithArguments("abstract", "10.0", "11.0").WithLocation(4, 39), // (4,39): error CS0552: 'I1.implicit operator int(I1)': user-defined conversions to or from an interface are not allowed // abstract static implicit operator int(I1 x); Diagnostic(ErrorCode.ERR_ConversionWithInterface, "int").WithArguments("I1.implicit operator int(I1)").WithLocation(4, 39), - // (6,39): error CS8703: The modifier 'abstract' is not valid for this item in C# 10.0. Please use language version 'preview' or greater. + // (6,39): error CS8703: The modifier 'abstract' is not valid for this item in C# 10.0. Please use language version '11.0' or greater. // abstract static explicit operator I1(bool x) {return null;} - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "I1").WithArguments("abstract", "10.0", "preview").WithLocation(6, 39), + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "I1").WithArguments("abstract", "10.0", "11.0").WithLocation(6, 39), // (6,39): error CS0500: 'I1.explicit operator I1(bool)' cannot declare a body because it is marked abstract // abstract static explicit operator I1(bool x) {return null;} Diagnostic(ErrorCode.ERR_AbstractHasBody, "I1").WithArguments("I1.explicit operator I1(bool)").WithLocation(6, 39), @@ -4288,36 +4288,36 @@ public interface I3 // (11,37): error CS0106: The modifier 'sealed' is not valid for this item // sealed static implicit operator int(I2 x); Diagnostic(ErrorCode.ERR_BadMemberFlag, "int").WithArguments("sealed").WithLocation(11, 37), - // (11,37): error CS0552: 'I2.implicit operator int(I2)': user-defined conversions to or from an interface are not allowed - // sealed static implicit operator int(I2 x); - Diagnostic(ErrorCode.ERR_ConversionWithInterface, "int").WithArguments("I2.implicit operator int(I2)").WithLocation(11, 37), // (11,37): error CS0567: Conversion, equality, or inequality operators declared in interfaces must be abstract or virtual // sealed static implicit operator int(I2 x); Diagnostic(ErrorCode.ERR_InterfacesCantContainConversionOrEqualityOperators, "int").WithLocation(11, 37), + // (11,37): error CS0552: 'I2.implicit operator int(I2)': user-defined conversions to or from an interface are not allowed + // sealed static implicit operator int(I2 x); + Diagnostic(ErrorCode.ERR_ConversionWithInterface, "int").WithArguments("I2.implicit operator int(I2)").WithLocation(11, 37), // (13,37): error CS0106: The modifier 'sealed' is not valid for this item // sealed static explicit operator I2(bool x) {return null;} Diagnostic(ErrorCode.ERR_BadMemberFlag, "I2").WithArguments("sealed").WithLocation(13, 37), - // (13,37): error CS0552: 'I2.explicit operator I2(bool)': user-defined conversions to or from an interface are not allowed - // sealed static explicit operator I2(bool x) {return null;} - Diagnostic(ErrorCode.ERR_ConversionWithInterface, "I2").WithArguments("I2.explicit operator I2(bool)").WithLocation(13, 37), // (13,37): error CS0567: Conversion, equality, or inequality operators declared in interfaces must be abstract or virtual // sealed static explicit operator I2(bool x) {return null;} Diagnostic(ErrorCode.ERR_InterfacesCantContainConversionOrEqualityOperators, "I2").WithLocation(13, 37), + // (13,37): error CS0552: 'I2.explicit operator I2(bool)': user-defined conversions to or from an interface are not allowed + // sealed static explicit operator I2(bool x) {return null;} + Diagnostic(ErrorCode.ERR_ConversionWithInterface, "I2").WithArguments("I2.explicit operator I2(bool)").WithLocation(13, 37), // (18,46): error CS0106: The modifier 'sealed' is not valid for this item // abstract sealed static implicit operator int(I3 x); Diagnostic(ErrorCode.ERR_BadMemberFlag, "int").WithArguments("sealed").WithLocation(18, 46), - // (18,46): error CS8703: The modifier 'abstract' is not valid for this item in C# 10.0. Please use language version 'preview' or greater. + // (18,46): error CS8703: The modifier 'abstract' is not valid for this item in C# 10.0. Please use language version '11.0' or greater. // abstract sealed static implicit operator int(I3 x); - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "int").WithArguments("abstract", "10.0", "preview").WithLocation(18, 46), + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "int").WithArguments("abstract", "10.0", "11.0").WithLocation(18, 46), // (18,46): error CS0552: 'I3.implicit operator int(I3)': user-defined conversions to or from an interface are not allowed // abstract sealed static implicit operator int(I3 x); Diagnostic(ErrorCode.ERR_ConversionWithInterface, "int").WithArguments("I3.implicit operator int(I3)").WithLocation(18, 46), // (20,46): error CS0106: The modifier 'sealed' is not valid for this item // abstract sealed static explicit operator I3(bool x) {return null;} Diagnostic(ErrorCode.ERR_BadMemberFlag, "I3").WithArguments("sealed").WithLocation(20, 46), - // (20,46): error CS8703: The modifier 'abstract' is not valid for this item in C# 10.0. Please use language version 'preview' or greater. + // (20,46): error CS8703: The modifier 'abstract' is not valid for this item in C# 10.0. Please use language version '11.0' or greater. // abstract sealed static explicit operator I3(bool x) {return null;} - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "I3").WithArguments("abstract", "10.0", "preview").WithLocation(20, 46), + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "I3").WithArguments("abstract", "10.0", "11.0").WithLocation(20, 46), // (20,46): error CS0500: 'I3.explicit operator I3(bool)' cannot declare a body because it is marked abstract // abstract sealed static explicit operator I3(bool x) {return null;} Diagnostic(ErrorCode.ERR_AbstractHasBody, "I3").WithArguments("I3.explicit operator I3(bool)").WithLocation(20, 46), @@ -4453,39 +4453,39 @@ public interface I3 targetFramework: _supportingFramework); compilation1.GetDiagnostics().Where(d => d.Code is not (int)ErrorCode.ERR_BadAbstractEqualityOperatorSignature).Verify( - // (4,33): error CS8703: The modifier 'virtual' is not valid for this item in C# 7.3. Please use language version 'preview' or greater. + // (4,33): error CS8703: The modifier 'virtual' is not valid for this item in C# 7.3. Please use language version '11.0' or greater. // virtual static bool operator== (I1 x, I1 y); - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "==").WithArguments("virtual", "7.3", "preview").WithLocation(4, 33), + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "==").WithArguments("virtual", "7.3", "11.0").WithLocation(4, 33), // (4,33): error CS0501: 'I1.operator ==(I1, I1)' must declare a body because it is not marked abstract, extern, or partial // virtual static bool operator== (I1 x, I1 y); Diagnostic(ErrorCode.ERR_ConcreteMissingBody, "==").WithArguments("I1.operator ==(I1, I1)").WithLocation(4, 33), - // (6,33): error CS8703: The modifier 'virtual' is not valid for this item in C# 7.3. Please use language version 'preview' or greater. + // (6,33): error CS8703: The modifier 'virtual' is not valid for this item in C# 7.3. Please use language version '11.0' or greater. // virtual static bool operator!= (I1 x, I1 y) {return false;} - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "!=").WithArguments("virtual", "7.3", "preview").WithLocation(6, 33), + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "!=").WithArguments("virtual", "7.3", "11.0").WithLocation(6, 33), // (11,40): error CS0106: The modifier 'sealed' is not valid for this item // virtual sealed static bool operator== (I2 x, I2 y); Diagnostic(ErrorCode.ERR_BadMemberFlag, "==").WithArguments("sealed").WithLocation(11, 40), - // (11,40): error CS8703: The modifier 'virtual' is not valid for this item in C# 7.3. Please use language version 'preview' or greater. + // (11,40): error CS8703: The modifier 'virtual' is not valid for this item in C# 7.3. Please use language version '11.0' or greater. // virtual sealed static bool operator== (I2 x, I2 y); - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "==").WithArguments("virtual", "7.3", "preview").WithLocation(11, 40), + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "==").WithArguments("virtual", "7.3", "11.0").WithLocation(11, 40), // (11,40): error CS0501: 'I2.operator ==(I2, I2)' must declare a body because it is not marked abstract, extern, or partial // virtual sealed static bool operator== (I2 x, I2 y); Diagnostic(ErrorCode.ERR_ConcreteMissingBody, "==").WithArguments("I2.operator ==(I2, I2)").WithLocation(11, 40), // (13,40): error CS0106: The modifier 'sealed' is not valid for this item // virtual sealed static bool operator!= (I2 x, I2 y) {return false;} Diagnostic(ErrorCode.ERR_BadMemberFlag, "!=").WithArguments("sealed").WithLocation(13, 40), - // (13,40): error CS8703: The modifier 'virtual' is not valid for this item in C# 7.3. Please use language version 'preview' or greater. + // (13,40): error CS8703: The modifier 'virtual' is not valid for this item in C# 7.3. Please use language version '11.0' or greater. // virtual sealed static bool operator!= (I2 x, I2 y) {return false;} - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "!=").WithArguments("virtual", "7.3", "preview").WithLocation(13, 40), - // (18,42): error CS8703: The modifier 'abstract' is not valid for this item in C# 7.3. Please use language version 'preview' or greater. + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "!=").WithArguments("virtual", "7.3", "11.0").WithLocation(13, 40), + // (18,42): error CS8703: The modifier 'abstract' is not valid for this item in C# 7.3. Please use language version '11.0' or greater. // abstract virtual static bool operator== (I3 x, I3 y); - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "==").WithArguments("abstract", "7.3", "preview").WithLocation(18, 42), + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "==").WithArguments("abstract", "7.3", "11.0").WithLocation(18, 42), // (18,42): error CS0503: The abstract method 'I3.operator ==(I3, I3)' cannot be marked virtual // abstract virtual static bool operator== (I3 x, I3 y); Diagnostic(ErrorCode.ERR_AbstractNotVirtual, "==").WithArguments("method", "I3.operator ==(I3, I3)").WithLocation(18, 42), - // (20,42): error CS8703: The modifier 'abstract' is not valid for this item in C# 7.3. Please use language version 'preview' or greater. + // (20,42): error CS8703: The modifier 'abstract' is not valid for this item in C# 7.3. Please use language version '11.0' or greater. // abstract virtual static bool operator!= (I3 x, I3 y) {return false;} - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "!=").WithArguments("abstract", "7.3", "preview").WithLocation(20, 42), + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "!=").WithArguments("abstract", "7.3", "11.0").WithLocation(20, 42), // (20,42): error CS0503: The abstract method 'I3.operator !=(I3, I3)' cannot be marked virtual // abstract virtual static bool operator!= (I3 x, I3 y) {return false;} Diagnostic(ErrorCode.ERR_AbstractNotVirtual, "!=").WithArguments("method", "I3.operator !=(I3, I3)").WithLocation(20, 42) @@ -4498,39 +4498,39 @@ public interface I3 targetFramework: _supportingFramework); compilation1.GetDiagnostics().Where(d => d.Code is not (int)ErrorCode.ERR_BadAbstractEqualityOperatorSignature).Verify( - // (4,33): error CS8703: The modifier 'virtual' is not valid for this item in C# 10.0. Please use language version 'preview' or greater. + // (4,33): error CS8703: The modifier 'virtual' is not valid for this item in C# 10.0. Please use language version '11.0' or greater. // virtual static bool operator== (I1 x, I1 y); - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "==").WithArguments("virtual", "10.0", "preview").WithLocation(4, 33), + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "==").WithArguments("virtual", "10.0", "11.0").WithLocation(4, 33), // (4,33): error CS0501: 'I1.operator ==(I1, I1)' must declare a body because it is not marked abstract, extern, or partial // virtual static bool operator== (I1 x, I1 y); Diagnostic(ErrorCode.ERR_ConcreteMissingBody, "==").WithArguments("I1.operator ==(I1, I1)").WithLocation(4, 33), - // (6,33): error CS8703: The modifier 'virtual' is not valid for this item in C# 10.0. Please use language version 'preview' or greater. + // (6,33): error CS8703: The modifier 'virtual' is not valid for this item in C# 10.0. Please use language version '11.0' or greater. // virtual static bool operator!= (I1 x, I1 y) {return false;} - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "!=").WithArguments("virtual", "10.0", "preview").WithLocation(6, 33), + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "!=").WithArguments("virtual", "10.0", "11.0").WithLocation(6, 33), // (11,40): error CS0106: The modifier 'sealed' is not valid for this item // virtual sealed static bool operator== (I2 x, I2 y); Diagnostic(ErrorCode.ERR_BadMemberFlag, "==").WithArguments("sealed").WithLocation(11, 40), - // (11,40): error CS8703: The modifier 'virtual' is not valid for this item in C# 10.0. Please use language version 'preview' or greater. + // (11,40): error CS8703: The modifier 'virtual' is not valid for this item in C# 10.0. Please use language version '11.0' or greater. // virtual sealed static bool operator== (I2 x, I2 y); - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "==").WithArguments("virtual", "10.0", "preview").WithLocation(11, 40), + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "==").WithArguments("virtual", "10.0", "11.0").WithLocation(11, 40), // (11,40): error CS0501: 'I2.operator ==(I2, I2)' must declare a body because it is not marked abstract, extern, or partial // virtual sealed static bool operator== (I2 x, I2 y); Diagnostic(ErrorCode.ERR_ConcreteMissingBody, "==").WithArguments("I2.operator ==(I2, I2)").WithLocation(11, 40), // (13,40): error CS0106: The modifier 'sealed' is not valid for this item // virtual sealed static bool operator!= (I2 x, I2 y) {return false;} Diagnostic(ErrorCode.ERR_BadMemberFlag, "!=").WithArguments("sealed").WithLocation(13, 40), - // (13,40): error CS8703: The modifier 'virtual' is not valid for this item in C# 10.0. Please use language version 'preview' or greater. + // (13,40): error CS8703: The modifier 'virtual' is not valid for this item in C# 10.0. Please use language version '11.0' or greater. // virtual sealed static bool operator!= (I2 x, I2 y) {return false;} - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "!=").WithArguments("virtual", "10.0", "preview").WithLocation(13, 40), - // (18,42): error CS8703: The modifier 'abstract' is not valid for this item in C# 10.0. Please use language version 'preview' or greater. + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "!=").WithArguments("virtual", "10.0", "11.0").WithLocation(13, 40), + // (18,42): error CS8703: The modifier 'abstract' is not valid for this item in C# 10.0. Please use language version '11.0' or greater. // abstract virtual static bool operator== (I3 x, I3 y); - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "==").WithArguments("abstract", "10.0", "preview").WithLocation(18, 42), + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "==").WithArguments("abstract", "10.0", "11.0").WithLocation(18, 42), // (18,42): error CS0503: The abstract method 'I3.operator ==(I3, I3)' cannot be marked virtual // abstract virtual static bool operator== (I3 x, I3 y); Diagnostic(ErrorCode.ERR_AbstractNotVirtual, "==").WithArguments("method", "I3.operator ==(I3, I3)").WithLocation(18, 42), - // (20,42): error CS8703: The modifier 'abstract' is not valid for this item in C# 10.0. Please use language version 'preview' or greater. + // (20,42): error CS8703: The modifier 'abstract' is not valid for this item in C# 10.0. Please use language version '11.0' or greater. // abstract virtual static bool operator!= (I3 x, I3 y) {return false;} - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "!=").WithArguments("abstract", "10.0", "preview").WithLocation(20, 42), + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "!=").WithArguments("abstract", "10.0", "11.0").WithLocation(20, 42), // (20,42): error CS0503: The abstract method 'I3.operator !=(I3, I3)' cannot be marked virtual // abstract virtual static bool operator!= (I3 x, I3 y) {return false;} Diagnostic(ErrorCode.ERR_AbstractNotVirtual, "!=").WithArguments("method", "I3.operator !=(I3, I3)").WithLocation(20, 42) @@ -4639,27 +4639,27 @@ public interface I3 targetFramework: _supportingFramework); compilation1.VerifyDiagnostics( - // (4,38): error CS8703: The modifier 'virtual' is not valid for this item in C# 7.3. Please use language version 'preview' or greater. + // (4,38): error CS8703: The modifier 'virtual' is not valid for this item in C# 7.3. Please use language version '11.0' or greater. // virtual static implicit operator int(I1 x); - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "int").WithArguments("virtual", "7.3", "preview").WithLocation(4, 38), + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "int").WithArguments("virtual", "7.3", "11.0").WithLocation(4, 38), // (4,38): error CS0501: 'I1.implicit operator int(I1)' must declare a body because it is not marked abstract, extern, or partial // virtual static implicit operator int(I1 x); Diagnostic(ErrorCode.ERR_ConcreteMissingBody, "int").WithArguments("I1.implicit operator int(I1)").WithLocation(4, 38), // (4,38): error CS0552: 'I1.implicit operator int(I1)': user-defined conversions to or from an interface are not allowed // virtual static implicit operator int(I1 x); Diagnostic(ErrorCode.ERR_ConversionWithInterface, "int").WithArguments("I1.implicit operator int(I1)").WithLocation(4, 38), - // (6,38): error CS8703: The modifier 'virtual' is not valid for this item in C# 7.3. Please use language version 'preview' or greater. + // (6,38): error CS8703: The modifier 'virtual' is not valid for this item in C# 7.3. Please use language version '11.0' or greater. // virtual static explicit operator I1(bool x) {return null;} - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "I1").WithArguments("virtual", "7.3", "preview").WithLocation(6, 38), + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "I1").WithArguments("virtual", "7.3", "11.0").WithLocation(6, 38), // (6,38): error CS0552: 'I1.explicit operator I1(bool)': user-defined conversions to or from an interface are not allowed // virtual static explicit operator I1(bool x) {return null;} Diagnostic(ErrorCode.ERR_ConversionWithInterface, "I1").WithArguments("I1.explicit operator I1(bool)").WithLocation(6, 38), // (11,45): error CS0106: The modifier 'sealed' is not valid for this item // virtual sealed static implicit operator int(I2 x); Diagnostic(ErrorCode.ERR_BadMemberFlag, "int").WithArguments("sealed").WithLocation(11, 45), - // (11,45): error CS8703: The modifier 'virtual' is not valid for this item in C# 7.3. Please use language version 'preview' or greater. + // (11,45): error CS8703: The modifier 'virtual' is not valid for this item in C# 7.3. Please use language version '11.0' or greater. // virtual sealed static implicit operator int(I2 x); - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "int").WithArguments("virtual", "7.3", "preview").WithLocation(11, 45), + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "int").WithArguments("virtual", "7.3", "11.0").WithLocation(11, 45), // (11,45): error CS0501: 'I2.implicit operator int(I2)' must declare a body because it is not marked abstract, extern, or partial // virtual sealed static implicit operator int(I2 x); Diagnostic(ErrorCode.ERR_ConcreteMissingBody, "int").WithArguments("I2.implicit operator int(I2)").WithLocation(11, 45), @@ -4669,24 +4669,24 @@ public interface I3 // (13,45): error CS0106: The modifier 'sealed' is not valid for this item // virtual sealed static explicit operator I2(bool x) {return null;} Diagnostic(ErrorCode.ERR_BadMemberFlag, "I2").WithArguments("sealed").WithLocation(13, 45), - // (13,45): error CS8703: The modifier 'virtual' is not valid for this item in C# 7.3. Please use language version 'preview' or greater. + // (13,45): error CS8703: The modifier 'virtual' is not valid for this item in C# 7.3. Please use language version '11.0' or greater. // virtual sealed static explicit operator I2(bool x) {return null;} - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "I2").WithArguments("virtual", "7.3", "preview").WithLocation(13, 45), + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "I2").WithArguments("virtual", "7.3", "11.0").WithLocation(13, 45), // (13,45): error CS0552: 'I2.explicit operator I2(bool)': user-defined conversions to or from an interface are not allowed // virtual sealed static explicit operator I2(bool x) {return null;} Diagnostic(ErrorCode.ERR_ConversionWithInterface, "I2").WithArguments("I2.explicit operator I2(bool)").WithLocation(13, 45), - // (18,47): error CS8703: The modifier 'abstract' is not valid for this item in C# 7.3. Please use language version 'preview' or greater. + // (18,47): error CS8703: The modifier 'abstract' is not valid for this item in C# 7.3. Please use language version '11.0' or greater. // abstract virtual static implicit operator int(I3 x); - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "int").WithArguments("abstract", "7.3", "preview").WithLocation(18, 47), + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "int").WithArguments("abstract", "7.3", "11.0").WithLocation(18, 47), // (18,47): error CS0503: The abstract method 'I3.implicit operator int(I3)' cannot be marked virtual // abstract virtual static implicit operator int(I3 x); Diagnostic(ErrorCode.ERR_AbstractNotVirtual, "int").WithArguments("method", "I3.implicit operator int(I3)").WithLocation(18, 47), // (18,47): error CS0552: 'I3.implicit operator int(I3)': user-defined conversions to or from an interface are not allowed // abstract virtual static implicit operator int(I3 x); Diagnostic(ErrorCode.ERR_ConversionWithInterface, "int").WithArguments("I3.implicit operator int(I3)").WithLocation(18, 47), - // (20,47): error CS8703: The modifier 'abstract' is not valid for this item in C# 7.3. Please use language version 'preview' or greater. + // (20,47): error CS8703: The modifier 'abstract' is not valid for this item in C# 7.3. Please use language version '11.0' or greater. // abstract virtual static explicit operator I3(bool x) {return null;} - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "I3").WithArguments("abstract", "7.3", "preview").WithLocation(20, 47), + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "I3").WithArguments("abstract", "7.3", "11.0").WithLocation(20, 47), // (20,47): error CS0503: The abstract method 'I3.explicit operator I3(bool)' cannot be marked virtual // abstract virtual static explicit operator I3(bool x) {return null;} Diagnostic(ErrorCode.ERR_AbstractNotVirtual, "I3").WithArguments("method", "I3.explicit operator I3(bool)").WithLocation(20, 47), @@ -4702,27 +4702,27 @@ public interface I3 targetFramework: _supportingFramework); compilation1.VerifyDiagnostics( - // (4,38): error CS8703: The modifier 'virtual' is not valid for this item in C# 10.0. Please use language version 'preview' or greater. + // (4,38): error CS8703: The modifier 'virtual' is not valid for this item in C# 10.0. Please use language version '11.0' or greater. // virtual static implicit operator int(I1 x); - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "int").WithArguments("virtual", "10.0", "preview").WithLocation(4, 38), + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "int").WithArguments("virtual", "10.0", "11.0").WithLocation(4, 38), // (4,38): error CS0501: 'I1.implicit operator int(I1)' must declare a body because it is not marked abstract, extern, or partial // virtual static implicit operator int(I1 x); Diagnostic(ErrorCode.ERR_ConcreteMissingBody, "int").WithArguments("I1.implicit operator int(I1)").WithLocation(4, 38), // (4,38): error CS0552: 'I1.implicit operator int(I1)': user-defined conversions to or from an interface are not allowed // virtual static implicit operator int(I1 x); Diagnostic(ErrorCode.ERR_ConversionWithInterface, "int").WithArguments("I1.implicit operator int(I1)").WithLocation(4, 38), - // (6,38): error CS8703: The modifier 'virtual' is not valid for this item in C# 10.0. Please use language version 'preview' or greater. + // (6,38): error CS8703: The modifier 'virtual' is not valid for this item in C# 10.0. Please use language version '11.0' or greater. // virtual static explicit operator I1(bool x) {return null;} - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "I1").WithArguments("virtual", "10.0", "preview").WithLocation(6, 38), + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "I1").WithArguments("virtual", "10.0", "11.0").WithLocation(6, 38), // (6,38): error CS0552: 'I1.explicit operator I1(bool)': user-defined conversions to or from an interface are not allowed // virtual static explicit operator I1(bool x) {return null;} Diagnostic(ErrorCode.ERR_ConversionWithInterface, "I1").WithArguments("I1.explicit operator I1(bool)").WithLocation(6, 38), // (11,45): error CS0106: The modifier 'sealed' is not valid for this item // virtual sealed static implicit operator int(I2 x); Diagnostic(ErrorCode.ERR_BadMemberFlag, "int").WithArguments("sealed").WithLocation(11, 45), - // (11,45): error CS8703: The modifier 'virtual' is not valid for this item in C# 10.0. Please use language version 'preview' or greater. + // (11,45): error CS8703: The modifier 'virtual' is not valid for this item in C# 10.0. Please use language version '11.0' or greater. // virtual sealed static implicit operator int(I2 x); - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "int").WithArguments("virtual", "10.0", "preview").WithLocation(11, 45), + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "int").WithArguments("virtual", "10.0", "11.0").WithLocation(11, 45), // (11,45): error CS0501: 'I2.implicit operator int(I2)' must declare a body because it is not marked abstract, extern, or partial // virtual sealed static implicit operator int(I2 x); Diagnostic(ErrorCode.ERR_ConcreteMissingBody, "int").WithArguments("I2.implicit operator int(I2)").WithLocation(11, 45), @@ -4732,24 +4732,24 @@ public interface I3 // (13,45): error CS0106: The modifier 'sealed' is not valid for this item // virtual sealed static explicit operator I2(bool x) {return null;} Diagnostic(ErrorCode.ERR_BadMemberFlag, "I2").WithArguments("sealed").WithLocation(13, 45), - // (13,45): error CS8703: The modifier 'virtual' is not valid for this item in C# 10.0. Please use language version 'preview' or greater. + // (13,45): error CS8703: The modifier 'virtual' is not valid for this item in C# 10.0. Please use language version '11.0' or greater. // virtual sealed static explicit operator I2(bool x) {return null;} - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "I2").WithArguments("virtual", "10.0", "preview").WithLocation(13, 45), + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "I2").WithArguments("virtual", "10.0", "11.0").WithLocation(13, 45), // (13,45): error CS0552: 'I2.explicit operator I2(bool)': user-defined conversions to or from an interface are not allowed // virtual sealed static explicit operator I2(bool x) {return null;} Diagnostic(ErrorCode.ERR_ConversionWithInterface, "I2").WithArguments("I2.explicit operator I2(bool)").WithLocation(13, 45), - // (18,47): error CS8703: The modifier 'abstract' is not valid for this item in C# 10.0. Please use language version 'preview' or greater. + // (18,47): error CS8703: The modifier 'abstract' is not valid for this item in C# 10.0. Please use language version '11.0' or greater. // abstract virtual static implicit operator int(I3 x); - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "int").WithArguments("abstract", "10.0", "preview").WithLocation(18, 47), + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "int").WithArguments("abstract", "10.0", "11.0").WithLocation(18, 47), // (18,47): error CS0503: The abstract method 'I3.implicit operator int(I3)' cannot be marked virtual // abstract virtual static implicit operator int(I3 x); Diagnostic(ErrorCode.ERR_AbstractNotVirtual, "int").WithArguments("method", "I3.implicit operator int(I3)").WithLocation(18, 47), // (18,47): error CS0552: 'I3.implicit operator int(I3)': user-defined conversions to or from an interface are not allowed // abstract virtual static implicit operator int(I3 x); Diagnostic(ErrorCode.ERR_ConversionWithInterface, "int").WithArguments("I3.implicit operator int(I3)").WithLocation(18, 47), - // (20,47): error CS8703: The modifier 'abstract' is not valid for this item in C# 10.0. Please use language version 'preview' or greater. + // (20,47): error CS8703: The modifier 'abstract' is not valid for this item in C# 10.0. Please use language version '11.0' or greater. // abstract virtual static explicit operator I3(bool x) {return null;} - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "I3").WithArguments("abstract", "10.0", "preview").WithLocation(20, 47), + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "I3").WithArguments("abstract", "10.0", "11.0").WithLocation(20, 47), // (20,47): error CS0503: The abstract method 'I3.explicit operator I3(bool)' cannot be marked virtual // abstract virtual static explicit operator I3(bool x) {return null;} Diagnostic(ErrorCode.ERR_AbstractNotVirtual, "I3").WithArguments("method", "I3.explicit operator I3(bool)").WithLocation(20, 47), @@ -8582,9 +8582,9 @@ static void M02() where T : I1 references: new[] { compilation1.ToMetadataReference() }); compilation2.VerifyDiagnostics( - // (6,9): error CS8652: The feature 'static abstract members in interfaces' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // (6,9): error CS8936: Feature 'static abstract members in interfaces' is not available in C# 10.0. Please use language version 11.0 or greater. // T.M01(); - Diagnostic(ErrorCode.ERR_FeatureInPreview, "T").WithArguments("static abstract members in interfaces").WithLocation(6, 9) + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "T").WithArguments("static abstract members in interfaces", "11.0").WithLocation(6, 9) ); var compilation3 = CreateCompilation(source2 + source1, options: TestOptions.DebugDll, @@ -8592,12 +8592,12 @@ static void M02() where T : I1 targetFramework: _supportingFramework); compilation3.VerifyDiagnostics( - // (6,9): error CS8652: The feature 'static abstract members in interfaces' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // (6,9): error CS8936: Feature 'static abstract members in interfaces' is not available in C# 10.0. Please use language version 11.0 or greater. // T.M01(); - Diagnostic(ErrorCode.ERR_FeatureInPreview, "T").WithArguments("static abstract members in interfaces").WithLocation(6, 9), - // (12,26): error CS8703: The modifier 'abstract' is not valid for this item in C# 10.0. Please use language version 'preview' or greater. - // abstract static void M01(); - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M01").WithArguments(modifier.Trim(), "10.0", "preview").WithLocation(12, 26) + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "T").WithArguments("static abstract members in interfaces", "11.0").WithLocation(6, 9), + // (12,26): error CS8703: The modifier 'virtual' is not valid for this item in C# 10.0. Please use language version '11.0' or greater. + // virtual static void M01() => throw null; + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M01").WithArguments(modifier.Trim(), "10.0", "11.0").WithLocation(12, 26) ); } @@ -9177,20 +9177,20 @@ static void M02(T x) where T : I1 if (isChecked) { compilation2.VerifyDiagnostics( - // (6,13): error CS8652: The feature 'static abstract members in interfaces' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. - // _ = -x; - Diagnostic(ErrorCode.ERR_FeatureInPreview, prefixOp + "x" + postfixOp).WithArguments("static abstract members in interfaces").WithLocation(6, 13), - // (6,13): error CS8652: The feature 'checked user-defined operators' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. - // _ = -x; - Diagnostic(ErrorCode.ERR_FeatureInPreview, prefixOp + "x" + postfixOp).WithArguments("checked user-defined operators").WithLocation(6, 13) + // (6,13): error CS8936: Feature 'static abstract members in interfaces' is not available in C# 10.0. Please use language version 11.0 or greater. + // _ = ++x; + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, prefixOp + "x" + postfixOp).WithArguments("static abstract members in interfaces", "11.0").WithLocation(6, 13), + // (6,13): error CS8936: Feature 'checked user-defined operators' is not available in C# 10.0. Please use language version 11.0 or greater. + // _ = ++x; + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, prefixOp + "x" + postfixOp).WithArguments("checked user-defined operators", "11.0").WithLocation(6, 13) ); } else { compilation2.VerifyDiagnostics( - // (6,13): error CS8652: The feature 'static abstract members in interfaces' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. - // _ = -x; - Diagnostic(ErrorCode.ERR_FeatureInPreview, prefixOp + "x" + postfixOp).WithArguments("static abstract members in interfaces").WithLocation(6, 13) + // (6,13): error CS8936: Feature 'static abstract members in interfaces' is not available in C# 10.0. Please use language version 11.0 or greater. + // _ = ++x; + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, prefixOp + "x" + postfixOp).WithArguments("static abstract members in interfaces", "11.0").WithLocation(6, 13) ); } @@ -9201,20 +9201,20 @@ static void M02(T x) where T : I1 if (isChecked) { compilation3.GetDiagnostics().Where(d => d.Code is not (int)ErrorCode.ERR_CheckedOperatorNeedsMatch).Verify( - // (12,32): error CS8652: The feature 'checked user-defined operators' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. - // abstract static T operator checked - (T x); - Diagnostic(ErrorCode.ERR_FeatureInPreview, "checked").WithArguments("checked user-defined operators").WithLocation(12, 32), - // (12,40): error CS8703: The modifier 'abstract' is not valid for this item in C# 10.0. Please use language version 'preview' or greater. - // abstract static T operator checked - (T x); - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, prefixOp + postfixOp).WithArguments(modifier.Trim(), "10.0", "preview").WithLocation(12, 40) + // (12,32): error CS8936: Feature 'checked user-defined operators' is not available in C# 10.0. Please use language version 11.0 or greater. + // abstract static T operator checked ++ (T x); + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "checked").WithArguments("checked user-defined operators", "11.0").WithLocation(12, 32), + // (12,40): error CS8703: The modifier 'abstract' is not valid for this item in C# 10.0. Please use language version '11.0' or greater. + // abstract static T operator checked ++ (T x); + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, prefixOp + postfixOp).WithArguments(modifier.Trim(), "10.0", "11.0").WithLocation(12, 40) ); } else { compilation3.VerifyDiagnostics( - // (12,31): error CS8703: The modifier 'abstract' is not valid for this item in C# 10.0. Please use language version 'preview' or greater. - // abstract static T operator- (T x); - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, prefixOp + postfixOp).WithArguments(modifier.Trim(), "10.0", "preview").WithLocation(12, 31) + // (12,31): error CS8703: The modifier 'abstract' is not valid for this item in C# 10.0. Please use language version '11.0' or greater. + // abstract static T operator+ (T x); + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, prefixOp + postfixOp).WithArguments(modifier.Trim(), "10.0", "11.0").WithLocation(12, 31) ); } } @@ -9445,9 +9445,9 @@ static void M02(T x) where T : I1 references: new[] { compilation1.ToMetadataReference() }); compilation2.VerifyDiagnostics( - // (6,13): error CS8652: The feature 'static abstract members in interfaces' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // (6,13): error CS8936: Feature 'static abstract members in interfaces' is not available in C# 10.0. Please use language version 11.0 or greater. // _ = x ? true : false; - Diagnostic(ErrorCode.ERR_FeatureInPreview, "x").WithArguments("static abstract members in interfaces").WithLocation(6, 13) + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "x").WithArguments("static abstract members in interfaces", "11.0").WithLocation(6, 13) ); var compilation3 = CreateCompilation(source2 + source1, options: TestOptions.DebugDll, @@ -9455,12 +9455,12 @@ static void M02(T x) where T : I1 targetFramework: _supportingFramework); compilation3.VerifyDiagnostics( - // (12,35): error CS8703: The modifier 'abstract' is not valid for this item in C# 10.0. Please use language version 'preview' or greater. - // abstract static bool operator true (I1 x); - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "true").WithArguments(modifier.Trim(), "10.0", "preview").WithLocation(12, 35), - // (13,35): error CS8703: The modifier 'abstract' is not valid for this item in C# 10.0. Please use language version 'preview' or greater. - // abstract static bool operator false (I1 x); - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "false").WithArguments(modifier.Trim(), "10.0", "preview").WithLocation(13, 35) + // (12,35): error CS8703: The modifier 'virtual' is not valid for this item in C# 10.0. Please use language version '11.0' or greater. + // virtual static bool operator true (I1 x) => throw null; + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "true").WithArguments(modifier.Trim(), "10.0", "11.0").WithLocation(12, 35), + // (13,35): error CS8703: The modifier 'virtual' is not valid for this item in C# 10.0. Please use language version '11.0' or greater. + // virtual static bool operator false (I1 x) => throw null; + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "false").WithArguments(modifier.Trim(), "10.0", "11.0").WithLocation(13, 35) ); } @@ -9860,9 +9860,9 @@ class C references: new[] { compilation1.ToMetadataReference() }); compilation2.VerifyDiagnostics( - // (6,13): error CS8652: The feature 'static abstract members in interfaces' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // (6,13): error CS8936: Feature 'static abstract members in interfaces' is not available in C# 10.0. Please use language version 11.0 or greater. // _ = x == x; - Diagnostic(ErrorCode.ERR_FeatureInPreview, "x " + op + " x").WithArguments("static abstract members in interfaces").WithLocation(6, 13) + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "x " + op + " x").WithArguments("static abstract members in interfaces", "11.0").WithLocation(6, 13) ); var compilation3 = CreateCompilation(source2 + source1, options: TestOptions.DebugDll, @@ -9870,12 +9870,12 @@ class C targetFramework: _supportingFramework); compilation3.VerifyDiagnostics( - // (21,35): error CS8703: The modifier 'abstract' is not valid for this item in C# 10.0. Please use language version 'preview' or greater. - // abstract static bool operator true (I1 x); - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "true").WithArguments(modifier.Trim(), "10.0", "preview").WithLocation(21, 35), - // (22,35): error CS8703: The modifier 'abstract' is not valid for this item in C# 10.0. Please use language version 'preview' or greater. - // abstract static bool operator false (I1 x); - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "false").WithArguments(modifier.Trim(), "10.0", "preview").WithLocation(22, 35) + // (21,35): error CS8703: The modifier 'virtual' is not valid for this item in C# 10.0. Please use language version '11.0' or greater. + // virtual static bool operator true (I1 x) => throw null; + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "true").WithArguments(modifier.Trim(), "10.0", "11.0").WithLocation(21, 35), + // (22,35): error CS8703: The modifier 'virtual' is not valid for this item in C# 10.0. Please use language version '11.0' or greater. + // virtual static bool operator false (I1 x) => throw null; + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "false").WithArguments(modifier.Trim(), "10.0", "11.0").WithLocation(22, 35) ); } @@ -12437,31 +12437,31 @@ static void M02(T x, int y) where T : I1 if (isChecked) { compilation2.VerifyDiagnostics( - // (6,13): error CS8652: The feature 'static abstract members in interfaces' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. - // _ = x - y; - Diagnostic(ErrorCode.ERR_FeatureInPreview, "x " + op + " y").WithArguments("static abstract members in interfaces").WithLocation(6, 13), - // (6,13): error CS8652: The feature 'checked user-defined operators' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. - // _ = x - y; - Diagnostic(ErrorCode.ERR_FeatureInPreview, "x " + op + " y").WithArguments("checked user-defined operators").WithLocation(6, 13) + // (6,13): error CS8936: Feature 'static abstract members in interfaces' is not available in C# 10.0. Please use language version 11.0 or greater. + // _ = x + y; + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "x " + op + " y").WithArguments("static abstract members in interfaces", "11.0").WithLocation(6, 13), + // (6,13): error CS8936: Feature 'checked user-defined operators' is not available in C# 10.0. Please use language version 11.0 or greater. + // _ = x + y; + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "x " + op + " y").WithArguments("checked user-defined operators", "11.0").WithLocation(6, 13) ); } else if (op != ">>>") { compilation2.VerifyDiagnostics( - // (6,13): error CS8652: The feature 'static abstract members in interfaces' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. - // _ = x - y; - Diagnostic(ErrorCode.ERR_FeatureInPreview, "x " + op + " y").WithArguments("static abstract members in interfaces").WithLocation(6, 13) + // (6,13): error CS8936: Feature 'static abstract members in interfaces' is not available in C# 10.0. Please use language version 11.0 or greater. + // _ = x >> y; + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "x " + op + " y").WithArguments("static abstract members in interfaces", "11.0").WithLocation(6, 13) ); } else { compilation2.VerifyDiagnostics( - // (6,13): error CS8652: The feature 'static abstract members in interfaces' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // (6,13): error CS8936: Feature 'static abstract members in interfaces' is not available in C# 10.0. Please use language version 11.0 or greater. // _ = x >>> y; - Diagnostic(ErrorCode.ERR_FeatureInPreview, "x >>> y").WithArguments("static abstract members in interfaces").WithLocation(6, 13), - // (6,13): error CS8652: The feature 'unsigned right shift' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "x >>> y").WithArguments("static abstract members in interfaces", "11.0").WithLocation(6, 13), + // (6,13): error CS8936: Feature 'unsigned right shift' is not available in C# 10.0. Please use language version 11.0 or greater. // _ = x >>> y; - Diagnostic(ErrorCode.ERR_FeatureInPreview, "x >>> y").WithArguments("unsigned right shift").WithLocation(6, 13) + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "x >>> y").WithArguments("unsigned right shift", "11.0").WithLocation(6, 13) ); } @@ -12472,31 +12472,31 @@ static void M02(T x, int y) where T : I1 if (isChecked) { compilation3.GetDiagnostics().Where(d => d.Code is not (int)ErrorCode.ERR_CheckedOperatorNeedsMatch).Verify( - // (12,33): error CS8652: The feature 'checked user-defined operators' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. - // abstract static I1 operator checked - (I1 x, int y); - Diagnostic(ErrorCode.ERR_FeatureInPreview, "checked").WithArguments("checked user-defined operators").WithLocation(12, 33), - // (12,41): error CS8703: The modifier 'abstract' is not valid for this item in C# 10.0. Please use language version 'preview' or greater. - // abstract static I1 operator checked - (I1 x, int y); - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, op).WithArguments(modifier.Trim(), "10.0", "preview").WithLocation(12, 41) + // (12,33): error CS8936: Feature 'checked user-defined operators' is not available in C# 10.0. Please use language version 11.0 or greater. + // virtual static I1 operator checked + (I1 x, int y) => throw null; + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "checked").WithArguments("checked user-defined operators", "11.0").WithLocation(12, 33), + // (12,41): error CS8703: The modifier 'virtual' is not valid for this item in C# 10.0. Please use language version '11.0' or greater. + // virtual static I1 operator checked + (I1 x, int y) => throw null; + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, op).WithArguments(modifier.Trim(), "10.0", "11.0").WithLocation(12, 41) ); } else if (op != ">>>") { compilation3.GetDiagnostics().Where(d => d.Code is not ((int)ErrorCode.ERR_OperatorNeedsMatch or (int)ErrorCode.ERR_BadAbstractEqualityOperatorSignature)).Verify( - // (12,33): error CS8703: The modifier 'abstract' is not valid for this item in C# 10.0. Please use language version 'preview' or greater. - // abstract static I1 operator - (I1 x, int y); - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, op).WithArguments(modifier.Trim(), "10.0", "preview").WithLocation(12, 33) + // (12,33): error CS8703: The modifier 'virtual' is not valid for this item in C# 10.0. Please use language version '11.0' or greater. + // virtual static I1 operator >= (I1 x, int y) => throw null; + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, op).WithArguments(modifier.Trim(), "10.0", "11.0").WithLocation(12, 33) ); } else { compilation3.VerifyDiagnostics( - // (12,33): error CS8652: The feature 'unsigned right shift' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. - // abstract static I1 operator >>> (I1 x, int y); - Diagnostic(ErrorCode.ERR_FeatureInPreview, ">>>").WithArguments("unsigned right shift").WithLocation(12, 33), - // (12,33): error CS8703: The modifier 'abstract' is not valid for this item in C# 10.0. Please use language version 'preview' or greater. - // abstract static I1 operator >>> (I1 x, int y); - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, ">>>").WithArguments(modifier.Trim(), "10.0", "preview").WithLocation(12, 33) + // (12,33): error CS8936: Feature 'unsigned right shift' is not available in C# 10.0. Please use language version 11.0 or greater. + // virtual static I1 operator >>> (I1 x, int y) => throw null; + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, ">>>").WithArguments("unsigned right shift", "11.0").WithLocation(12, 33), + // (12,33): error CS8703: The modifier 'virtual' is not valid for this item in C# 10.0. Please use language version '11.0' or greater. + // virtual static I1 operator >>> (I1 x, int y) => throw null; + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, ">>>").WithArguments(modifier.Trim(), "10.0", "11.0").WithLocation(12, 33) ); } } @@ -12554,9 +12554,9 @@ static void M02(T x, T y) where T : I1 else { compilation2.VerifyDiagnostics( - // (6,13): error CS8652: The feature 'static abstract members in interfaces' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. - // _ = x && y; - Diagnostic(ErrorCode.ERR_FeatureInPreview, "x " + op + op + " y").WithArguments("static abstract members in interfaces").WithLocation(6, 13) + // (6,13): error CS8936: Feature 'static abstract members in interfaces' is not available in C# 10.0. Please use language version 11.0 or greater. + // _ = x || y; + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "x " + op + op + " y").WithArguments("static abstract members in interfaces", "11.0").WithLocation(6, 13) ); } @@ -12569,27 +12569,27 @@ static void M02(T x, T y) where T : I1 if (binaryIsAbstract) { builder.Add( - // (12,32): error CS8703: The modifier 'abstract' is not valid for this item in C# 10.0. Please use language version 'preview' or greater. + // (12,32): error CS8703: The modifier 'abstract' is not valid for this item in C# 10.0. Please use language version '11.0' or greater. // abstract static I1 operator& (I1 x, I1 y); - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, op).WithArguments(modifier.Trim(), "10.0", "preview").WithLocation(12, 32) + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, op).WithArguments(modifier.Trim(), "10.0", "11.0").WithLocation(12, 32) ); } if (trueIsAbstract) { builder.Add( - // (13,35): error CS8703: The modifier 'abstract' is not valid for this item in C# 10.0. Please use language version 'preview' or greater. + // (13,35): error CS8703: The modifier 'abstract' is not valid for this item in C# 10.0. Please use language version '11.0' or greater. // abstract static bool operator true (I1 x); - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "true").WithArguments(modifier.Trim(), "10.0", "preview").WithLocation(13, 35) + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "true").WithArguments(modifier.Trim(), "10.0", "11.0").WithLocation(13, 35) ); } if (falseIsAbstract) { builder.Add( - // (14,35): error CS8703: The modifier 'abstract' is not valid for this item in C# 10.0. Please use language version 'preview' or greater. + // (14,35): error CS8703: The modifier 'abstract' is not valid for this item in C# 10.0. Please use language version '11.0' or greater. // abstract static bool operator false (I1 x); - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "false").WithArguments(modifier.Trim(), "10.0", "preview").WithLocation(14, 35) + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "false").WithArguments(modifier.Trim(), "10.0", "11.0").WithLocation(14, 35) ); } @@ -12637,31 +12637,31 @@ static void M02(T x, int y) where T : I1 if (isChecked) { compilation2.GetDiagnostics().Where(d => d.Code is not (int)ErrorCode.ERR_CheckedOperatorNeedsMatch).Verify( - // (6,9): error CS8652: The feature 'static abstract members in interfaces' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. - // x -= y; - Diagnostic(ErrorCode.ERR_FeatureInPreview, "x " + op + "= y").WithArguments("static abstract members in interfaces").WithLocation(6, 9), - // (6,9): error CS8652: The feature 'checked user-defined operators' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. - // x -= y; - Diagnostic(ErrorCode.ERR_FeatureInPreview, "x " + op + "= y").WithArguments("checked user-defined operators").WithLocation(6, 9) + // (6,9): error CS8936: Feature 'static abstract members in interfaces' is not available in C# 10.0. Please use language version 11.0 or greater. + // x += y; + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "x " + op + "= y").WithArguments("static abstract members in interfaces", "11.0").WithLocation(6, 9), + // (6,9): error CS8936: Feature 'checked user-defined operators' is not available in C# 10.0. Please use language version 11.0 or greater. + // x += y; + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "x " + op + "= y").WithArguments("checked user-defined operators", "11.0").WithLocation(6, 9) ); } else if (op != ">>>") { compilation2.VerifyDiagnostics( - // (6,9): error CS8652: The feature 'static abstract members in interfaces' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. - // x <<= y; - Diagnostic(ErrorCode.ERR_FeatureInPreview, "x " + op + "= y").WithArguments("static abstract members in interfaces").WithLocation(6, 9) + // (6,9): error CS8936: Feature 'static abstract members in interfaces' is not available in C# 10.0. Please use language version 11.0 or greater. + // x >>>= y; + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "x " + op + "= y").WithArguments("static abstract members in interfaces", "11.0").WithLocation(6, 9) ); } else { compilation2.VerifyDiagnostics( - // (6,9): error CS8652: The feature 'static abstract members in interfaces' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // (6,9): error CS8936: Feature 'static abstract members in interfaces' is not available in C# 10.0. Please use language version 11.0 or greater. // x >>>= y; - Diagnostic(ErrorCode.ERR_FeatureInPreview, "x >>>= y").WithArguments("static abstract members in interfaces").WithLocation(6, 9), - // (6,9): error CS8652: The feature 'unsigned right shift' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "x >>>= y").WithArguments("static abstract members in interfaces", "11.0").WithLocation(6, 9), + // (6,9): error CS8936: Feature 'unsigned right shift' is not available in C# 10.0. Please use language version 11.0 or greater. // x >>>= y; - Diagnostic(ErrorCode.ERR_FeatureInPreview, "x >>>= y").WithArguments("unsigned right shift").WithLocation(6, 9) + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "x >>>= y").WithArguments("unsigned right shift", "11.0").WithLocation(6, 9) ); } @@ -12672,31 +12672,31 @@ static void M02(T x, int y) where T : I1 if (isChecked) { compilation3.GetDiagnostics().Where(d => d.Code is not (int)ErrorCode.ERR_CheckedOperatorNeedsMatch).Verify( - // (12,32): error CS8652: The feature 'checked user-defined operators' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. - // abstract static T operator checked - (T x, int y); - Diagnostic(ErrorCode.ERR_FeatureInPreview, "checked").WithArguments("checked user-defined operators").WithLocation(12, 32), - // (12,40): error CS8703: The modifier 'abstract' is not valid for this item in C# 10.0. Please use language version 'preview' or greater. - // abstract static T operator checked - (T x, int y); - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, op).WithArguments(modifier.Trim(), "10.0", "preview").WithLocation(12, 40) + // (12,32): error CS8936: Feature 'checked user-defined operators' is not available in C# 10.0. Please use language version 11.0 or greater. + // virtual static T operator checked + (T x, int y) => throw null; + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "checked").WithArguments("checked user-defined operators", "11.0").WithLocation(12, 32), + // (12,40): error CS8703: The modifier 'virtual' is not valid for this item in C# 10.0. Please use language version '11.0' or greater. + // virtual static T operator checked + (T x, int y) => throw null; + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, op).WithArguments(modifier.Trim(), "10.0", "11.0").WithLocation(12, 40) ); } else if (op != ">>>") { compilation3.VerifyDiagnostics( - // (12,32): error CS8703: The modifier 'abstract' is not valid for this item in C# 10.0. Please use language version 'preview' or greater. + // (12,32): error CS8703: The modifier 'abstract' is not valid for this item in C# 10.0. Please use language version '11.0' or greater. // abstract static T operator << (T x, int y); - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, op).WithArguments(modifier.Trim(), "10.0", "preview").WithLocation(12, 32) + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, op).WithArguments(modifier.Trim(), "10.0", "11.0").WithLocation(12, 32) ); } else { compilation3.VerifyDiagnostics( - // (12,32): error CS8652: The feature 'unsigned right shift' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. - // abstract static T operator >>> (T x, int y); - Diagnostic(ErrorCode.ERR_FeatureInPreview, ">>>").WithArguments("unsigned right shift").WithLocation(12, 32), - // (12,32): error CS8703: The modifier 'abstract' is not valid for this item in C# 10.0. Please use language version 'preview' or greater. - // abstract static T operator >>> (T x, int y); - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, ">>>").WithArguments(modifier.Trim(), "10.0", "preview").WithLocation(12, 32) + // (12,32): error CS8936: Feature 'unsigned right shift' is not available in C# 10.0. Please use language version 11.0 or greater. + // virtual static T operator >>> (T x, int y) => throw null; + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, ">>>").WithArguments("unsigned right shift", "11.0").WithLocation(12, 32), + // (12,32): error CS8703: The modifier 'virtual' is not valid for this item in C# 10.0. Please use language version '11.0' or greater. + // virtual static T operator >>> (T x, int y) => throw null; + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, ">>>").WithArguments(modifier.Trim(), "10.0", "11.0").WithLocation(12, 32) ); } } @@ -12735,9 +12735,9 @@ static void M02((int, T) x) where T : I1 references: new[] { compilation1.ToMetadataReference() }); compilation2.VerifyDiagnostics( - // (6,13): error CS8652: The feature 'static abstract members in interfaces' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // (6,13): error CS8936: Feature 'static abstract members in interfaces' is not available in C# 10.0. Please use language version 11.0 or greater. // _ = x == x; - Diagnostic(ErrorCode.ERR_FeatureInPreview, "x " + op + " x").WithArguments("static abstract members in interfaces").WithLocation(6, 13) + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "x " + op + " x").WithArguments("static abstract members in interfaces", "11.0").WithLocation(6, 13) ); var compilation3 = CreateCompilation(source2 + source1, options: TestOptions.DebugDll, @@ -12745,12 +12745,12 @@ static void M02((int, T) x) where T : I1 targetFramework: _supportingFramework); compilation3.VerifyDiagnostics( - // (12,35): error CS8703: The modifier 'abstract' is not valid for this item in C# 10.0. Please use language version 'preview' or greater. - // abstract static bool operator == (T x, T y); - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "==").WithArguments(modifier.Trim(), "10.0", "preview").WithLocation(12, 35), - // (13,35): error CS8703: The modifier 'abstract' is not valid for this item in C# 10.0. Please use language version 'preview' or greater. - // abstract static bool operator != (T x, T y); - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "!=").WithArguments(modifier.Trim(), "10.0", "preview").WithLocation(13, 35) + // (12,35): error CS8703: The modifier 'virtual' is not valid for this item in C# 10.0. Please use language version '11.0' or greater. + // virtual static bool operator == (T x, T y) => throw null; + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "==").WithArguments(modifier.Trim(), "10.0", "11.0").WithLocation(12, 35), + // (13,35): error CS8703: The modifier 'virtual' is not valid for this item in C# 10.0. Please use language version '11.0' or greater. + // virtual static bool operator != (T x, T y) => throw null; + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "!=").WithArguments(modifier.Trim(), "10.0", "11.0").WithLocation(13, 35) ); } @@ -13604,9 +13604,9 @@ static void M02() where T : I1 references: new[] { compilation1.ToMetadataReference() }); compilation2.VerifyDiagnostics( - // (6,13): error CS8652: The feature 'static abstract members in interfaces' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // (6,13): error CS8936: Feature 'static abstract members in interfaces' is not available in C# 10.0. Please use language version 11.0 or greater. // _ = T.P01; - Diagnostic(ErrorCode.ERR_FeatureInPreview, "T").WithArguments("static abstract members in interfaces").WithLocation(6, 13) + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "T").WithArguments("static abstract members in interfaces", "11.0").WithLocation(6, 13) ); var compilation3 = CreateCompilation(source2 + source1, options: TestOptions.DebugDll, @@ -13614,12 +13614,12 @@ static void M02() where T : I1 targetFramework: _supportingFramework); compilation3.VerifyDiagnostics( - // (6,13): error CS8652: The feature 'static abstract members in interfaces' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // (6,13): error CS8936: Feature 'static abstract members in interfaces' is not available in C# 10.0. Please use language version 11.0 or greater. // _ = T.P01; - Diagnostic(ErrorCode.ERR_FeatureInPreview, "T").WithArguments("static abstract members in interfaces").WithLocation(6, 13), - // (12,25): error CS8703: The modifier 'abstract' is not valid for this item in C# 10.0. Please use language version 'preview' or greater. - // abstract static int P01 { get; set; } - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "P01").WithArguments(modifier.Trim(), "10.0", "preview").WithLocation(12, 25) + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "T").WithArguments("static abstract members in interfaces", "11.0").WithLocation(6, 13), + // (12,25): error CS8703: The modifier 'virtual' is not valid for this item in C# 10.0. Please use language version '11.0' or greater. + // virtual static int P01 { get; set; } + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "P01").WithArguments(modifier.Trim(), "10.0", "11.0").WithLocation(12, 25) ); } @@ -13656,9 +13656,9 @@ static void M02() where T : I1 references: new[] { compilation1.ToMetadataReference() }); compilation2.VerifyDiagnostics( - // (6,9): error CS8652: The feature 'static abstract members in interfaces' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // (6,9): error CS8936: Feature 'static abstract members in interfaces' is not available in C# 10.0. Please use language version 11.0 or greater. // T.P01 = 1; - Diagnostic(ErrorCode.ERR_FeatureInPreview, "T").WithArguments("static abstract members in interfaces").WithLocation(6, 9) + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "T").WithArguments("static abstract members in interfaces", "11.0").WithLocation(6, 9) ); var compilation3 = CreateCompilation(source2 + source1, options: TestOptions.DebugDll, @@ -13666,12 +13666,12 @@ static void M02() where T : I1 targetFramework: _supportingFramework); compilation3.VerifyDiagnostics( - // (6,9): error CS8652: The feature 'static abstract members in interfaces' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // (6,9): error CS8936: Feature 'static abstract members in interfaces' is not available in C# 10.0. Please use language version 11.0 or greater. // T.P01 = 1; - Diagnostic(ErrorCode.ERR_FeatureInPreview, "T").WithArguments("static abstract members in interfaces").WithLocation(6, 9), - // (12,25): error CS8703: The modifier 'abstract' is not valid for this item in C# 10.0. Please use language version 'preview' or greater. - // abstract static int P01 { get; set; } - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "P01").WithArguments(modifier.Trim(), "10.0", "preview").WithLocation(12, 25) + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "T").WithArguments("static abstract members in interfaces", "11.0").WithLocation(6, 9), + // (12,25): error CS8703: The modifier 'virtual' is not valid for this item in C# 10.0. Please use language version '11.0' or greater. + // virtual static int P01 { get; set; } + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "P01").WithArguments(modifier.Trim(), "10.0", "11.0").WithLocation(12, 25) ); } @@ -13708,9 +13708,9 @@ static void M02() where T : I1 references: new[] { compilation1.ToMetadataReference() }); compilation2.VerifyDiagnostics( - // (6,9): error CS8652: The feature 'static abstract members in interfaces' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // (6,9): error CS8936: Feature 'static abstract members in interfaces' is not available in C# 10.0. Please use language version 11.0 or greater. // T.P01 += 1; - Diagnostic(ErrorCode.ERR_FeatureInPreview, "T").WithArguments("static abstract members in interfaces").WithLocation(6, 9) + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "T").WithArguments("static abstract members in interfaces", "11.0").WithLocation(6, 9) ); var compilation3 = CreateCompilation(source2 + source1, options: TestOptions.DebugDll, @@ -13718,12 +13718,12 @@ static void M02() where T : I1 targetFramework: _supportingFramework); compilation3.VerifyDiagnostics( - // (6,9): error CS8652: The feature 'static abstract members in interfaces' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // (6,9): error CS8936: Feature 'static abstract members in interfaces' is not available in C# 10.0. Please use language version 11.0 or greater. // T.P01 += 1; - Diagnostic(ErrorCode.ERR_FeatureInPreview, "T").WithArguments("static abstract members in interfaces").WithLocation(6, 9), - // (12,25): error CS8703: The modifier 'abstract' is not valid for this item in C# 10.0. Please use language version 'preview' or greater. - // abstract static int P01 { get; set; } - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "P01").WithArguments(modifier.Trim(), "10.0", "preview").WithLocation(12, 25) + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "T").WithArguments("static abstract members in interfaces", "11.0").WithLocation(6, 9), + // (12,25): error CS8703: The modifier 'virtual' is not valid for this item in C# 10.0. Please use language version '11.0' or greater. + // virtual static int P01 { get; set; } + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "P01").WithArguments(modifier.Trim(), "10.0", "11.0").WithLocation(12, 25) ); } @@ -14265,9 +14265,9 @@ static void M02() where T : I1 references: new[] { compilation1.ToMetadataReference() }); compilation2.VerifyDiagnostics( - // (6,9): error CS8652: The feature 'static abstract members in interfaces' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // (6,9): error CS8936: Feature 'static abstract members in interfaces' is not available in C# 10.0. Please use language version 11.0 or greater. // T.P01 += null; - Diagnostic(ErrorCode.ERR_FeatureInPreview, "T").WithArguments("static abstract members in interfaces").WithLocation(6, 9) + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "T").WithArguments("static abstract members in interfaces", "11.0").WithLocation(6, 9) ); var compilation3 = CreateCompilation(source2 + source1, options: TestOptions.DebugDll, @@ -14275,12 +14275,12 @@ static void M02() where T : I1 targetFramework: _supportingFramework); compilation3.VerifyDiagnostics( - // (6,9): error CS8652: The feature 'static abstract members in interfaces' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // (6,9): error CS8936: Feature 'static abstract members in interfaces' is not available in C# 10.0. Please use language version 11.0 or greater. // T.P01 += null; - Diagnostic(ErrorCode.ERR_FeatureInPreview, "T").WithArguments("static abstract members in interfaces").WithLocation(6, 9), - // (12,41): error CS8703: The modifier 'abstract' is not valid for this item in C# 10.0. Please use language version 'preview' or greater. - // abstract static event System.Action P01; - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "P01").WithArguments(modifier.Trim(), "10.0", "preview").WithLocation(12, 41) + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "T").WithArguments("static abstract members in interfaces", "11.0").WithLocation(6, 9), + // (12,41): error CS8703: The modifier 'virtual' is not valid for this item in C# 10.0. Please use language version '11.0' or greater. + // virtual static event System.Action P01; + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "P01").WithArguments(modifier.Trim(), "10.0", "11.0").WithLocation(12, 41) ); } @@ -14317,9 +14317,9 @@ static void M02() where T : I1 references: new[] { compilation1.ToMetadataReference() }); compilation2.VerifyDiagnostics( - // (6,9): error CS8652: The feature 'static abstract members in interfaces' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // (6,9): error CS8936: Feature 'static abstract members in interfaces' is not available in C# 10.0. Please use language version 11.0 or greater. // T.P01 -= null; - Diagnostic(ErrorCode.ERR_FeatureInPreview, "T").WithArguments("static abstract members in interfaces").WithLocation(6, 9) + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "T").WithArguments("static abstract members in interfaces", "11.0").WithLocation(6, 9) ); var compilation3 = CreateCompilation(source2 + source1, options: TestOptions.DebugDll, @@ -14327,12 +14327,12 @@ static void M02() where T : I1 targetFramework: _supportingFramework); compilation3.VerifyDiagnostics( - // (6,9): error CS8652: The feature 'static abstract members in interfaces' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // (6,9): error CS8936: Feature 'static abstract members in interfaces' is not available in C# 10.0. Please use language version 11.0 or greater. // T.P01 -= null; - Diagnostic(ErrorCode.ERR_FeatureInPreview, "T").WithArguments("static abstract members in interfaces").WithLocation(6, 9), - // (12,41): error CS8703: The modifier 'abstract' is not valid for this item in C# 10.0. Please use language version 'preview' or greater. - // abstract static event System.Action P01; - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "P01").WithArguments(modifier.Trim(), "10.0", "preview").WithLocation(12, 41) + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "T").WithArguments("static abstract members in interfaces", "11.0").WithLocation(6, 9), + // (12,41): error CS8703: The modifier 'virtual' is not valid for this item in C# 10.0. Please use language version '11.0' or greater. + // virtual static event System.Action P01; + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "P01").WithArguments(modifier.Trim(), "10.0", "11.0").WithLocation(12, 41) ); } @@ -14818,9 +14818,9 @@ static void M02() where T : I1 references: new[] { compilation1.ToMetadataReference() }); compilation2.VerifyDiagnostics( - // (6,28): error CS8652: The feature 'static abstract members in interfaces' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // (6,28): error CS8936: Feature 'static abstract members in interfaces' is not available in C# 10.0. Please use language version 11.0 or greater. // _ = (System.Action)T.M01; - Diagnostic(ErrorCode.ERR_FeatureInPreview, "T").WithArguments("static abstract members in interfaces").WithLocation(6, 28) + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "T").WithArguments("static abstract members in interfaces", "11.0").WithLocation(6, 28) ); var compilation3 = CreateCompilation(source2 + source1, options: TestOptions.DebugDll, @@ -14828,12 +14828,12 @@ static void M02() where T : I1 targetFramework: _supportingFramework); compilation3.VerifyDiagnostics( - // (6,28): error CS8652: The feature 'static abstract members in interfaces' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // (6,28): error CS8936: Feature 'static abstract members in interfaces' is not available in C# 10.0. Please use language version 11.0 or greater. // _ = (System.Action)T.M01; - Diagnostic(ErrorCode.ERR_FeatureInPreview, "T").WithArguments("static abstract members in interfaces").WithLocation(6, 28), - // (12,26): error CS8703: The modifier 'abstract' is not valid for this item in C# 10.0. Please use language version 'preview' or greater. - // abstract static void M01(); - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M01").WithArguments(modifier.Trim(), "10.0", "preview").WithLocation(12, 26) + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "T").WithArguments("static abstract members in interfaces", "11.0").WithLocation(6, 28), + // (12,26): error CS8703: The modifier 'virtual' is not valid for this item in C# 10.0. Please use language version '11.0' or greater. + // virtual static void M01() => throw null; + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M01").WithArguments(modifier.Trim(), "10.0", "11.0").WithLocation(12, 26) ); } @@ -15231,9 +15231,9 @@ static void M02() where T : I1 references: new[] { compilation1.ToMetadataReference() }); compilation2.VerifyDiagnostics( - // (6,31): error CS8652: The feature 'static abstract members in interfaces' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // (6,31): error CS8936: Feature 'static abstract members in interfaces' is not available in C# 10.0. Please use language version 11.0 or greater. // _ = new System.Action(T.M01); - Diagnostic(ErrorCode.ERR_FeatureInPreview, "T").WithArguments("static abstract members in interfaces").WithLocation(6, 31) + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "T").WithArguments("static abstract members in interfaces", "11.0").WithLocation(6, 31) ); var compilation3 = CreateCompilation(source2 + source1, options: TestOptions.DebugDll, @@ -15241,12 +15241,12 @@ static void M02() where T : I1 targetFramework: _supportingFramework); compilation3.VerifyDiagnostics( - // (6,31): error CS8652: The feature 'static abstract members in interfaces' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // (6,31): error CS8936: Feature 'static abstract members in interfaces' is not available in C# 10.0. Please use language version 11.0 or greater. // _ = new System.Action(T.M01); - Diagnostic(ErrorCode.ERR_FeatureInPreview, "T").WithArguments("static abstract members in interfaces").WithLocation(6, 31), - // (12,26): error CS8703: The modifier 'abstract' is not valid for this item in C# 10.0. Please use language version 'preview' or greater. - // abstract static void M01(); - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M01").WithArguments(modifier.Trim(), "10.0", "preview").WithLocation(12, 26) + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "T").WithArguments("static abstract members in interfaces", "11.0").WithLocation(6, 31), + // (12,26): error CS8703: The modifier 'virtual' is not valid for this item in C# 10.0. Please use language version '11.0' or greater. + // virtual static void M01() => throw null; + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M01").WithArguments(modifier.Trim(), "10.0", "11.0").WithLocation(12, 26) ); } @@ -15499,9 +15499,9 @@ static void M02() where T : I1 references: new[] { compilation1.ToMetadataReference() }); compilation2.VerifyDiagnostics( - // (6,31): error CS8652: The feature 'static abstract members in interfaces' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // (6,31): error CS8936: Feature 'static abstract members in interfaces' is not available in C# 10.0. Please use language version 11.0 or greater. // _ = (delegate*)&T.M01; - Diagnostic(ErrorCode.ERR_FeatureInPreview, "T").WithArguments("static abstract members in interfaces").WithLocation(6, 31) + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "T").WithArguments("static abstract members in interfaces", "11.0").WithLocation(6, 31) ); var compilation3 = CreateCompilation(source2 + source1, options: TestOptions.DebugDll.WithAllowUnsafe(true), @@ -15509,12 +15509,12 @@ static void M02() where T : I1 targetFramework: _supportingFramework); compilation3.VerifyDiagnostics( - // (6,31): error CS8652: The feature 'static abstract members in interfaces' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // (6,31): error CS8936: Feature 'static abstract members in interfaces' is not available in C# 10.0. Please use language version 11.0 or greater. // _ = (delegate*)&T.M01; - Diagnostic(ErrorCode.ERR_FeatureInPreview, "T").WithArguments("static abstract members in interfaces").WithLocation(6, 31), - // (12,26): error CS8703: The modifier 'abstract' is not valid for this item in C# 10.0. Please use language version 'preview' or greater. - // abstract static void M01(); - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M01").WithArguments(modifier.Trim(), "10.0", "preview").WithLocation(12, 26) + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "T").WithArguments("static abstract members in interfaces", "11.0").WithLocation(6, 31), + // (12,26): error CS8703: The modifier 'virtual' is not valid for this item in C# 10.0. Please use language version '11.0' or greater. + // virtual static void M01() => throw null; + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M01").WithArguments(modifier.Trim(), "10.0", "11.0").WithLocation(12, 26) ); } @@ -15932,12 +15932,12 @@ public static void M02() {} references: new[] { compilation1.ToMetadataReference() }); compilation2.VerifyDiagnostics( - // (4,20): error CS8703: The modifier 'static' is not valid for this item in C# 10.0. Please use language version 'preview' or greater. + // (4,20): error CS8703: The modifier 'static' is not valid for this item in C# 10.0. Please use language version '11.0' or greater. // static void I1.M01() {} - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M01").WithArguments("static", "10.0", "preview").WithLocation(4, 20), - // (5,24): error CS8706: 'Test.M02()' cannot implement interface member 'I1.M02()' in type 'Test' because feature 'static abstract members in interfaces' is not available in C# 10.0. Please use language version 'preview' or greater. + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M01").WithArguments("static", "10.0", "11.0").WithLocation(4, 20), + // (5,24): error CS8706: 'Test.M02()' cannot implement interface member 'I1.M02()' in type 'Test' because feature 'static abstract members in interfaces' is not available in C# 10.0. Please use language version '11.0' or greater. // public static void M02() {} - Diagnostic(ErrorCode.ERR_LanguageVersionDoesNotSupportInterfaceImplementationForMember, "M02").WithArguments("Test.M02()", "I1.M02()", "Test", "static abstract members in interfaces", "10.0", "preview").WithLocation(5, 24) + Diagnostic(ErrorCode.ERR_LanguageVersionDoesNotSupportInterfaceImplementationForMember, "M02").WithArguments("Test.M02()", "I1.M02()", "Test", "static abstract members in interfaces", "10.0", "11.0").WithLocation(5, 24) ); var compilation3 = CreateCompilation(source2 + source1, options: TestOptions.DebugDll, @@ -15945,15 +15945,15 @@ public static void M02() {} targetFramework: _supportingFramework); compilation3.VerifyDiagnostics( - // (4,20): error CS8703: The modifier 'static' is not valid for this item in C# 10.0. Please use language version 'preview' or greater. + // (4,20): error CS8703: The modifier 'static' is not valid for this item in C# 10.0. Please use language version '11.0' or greater. // static void I1.M01() {} - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M01").WithArguments("static", "10.0", "preview").WithLocation(4, 20), - // (10,26): error CS8703: The modifier 'abstract' is not valid for this item in C# 10.0. Please use language version 'preview' or greater. - // abstract static void M01(); - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M01").WithArguments(modifier.Trim(), "10.0", "preview").WithLocation(10, 26), - // (11,26): error CS8703: The modifier 'abstract' is not valid for this item in C# 10.0. Please use language version 'preview' or greater. - // abstract static void M02(); - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M02").WithArguments(modifier.Trim(), "10.0", "preview").WithLocation(11, 26) + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M01").WithArguments("static", "10.0", "11.0").WithLocation(4, 20), + // (10,26): error CS8703: The modifier 'virtual' is not valid for this item in C# 10.0. Please use language version '11.0' or greater. + // virtual static void M01() => throw null; + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M01").WithArguments(modifier.Trim(), "10.0", "11.0").WithLocation(10, 26), + // (11,26): error CS8703: The modifier 'virtual' is not valid for this item in C# 10.0. Please use language version '11.0' or greater. + // virtual static void M02() => throw null; + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M02").WithArguments(modifier.Trim(), "10.0", "11.0").WithLocation(11, 26) ); } @@ -16343,9 +16343,9 @@ public class C5 : C2, I1 targetFramework: _supportingFramework); compilation1.VerifyDiagnostics( - // (10,23): error CS8706: 'C2.M01()' cannot implement interface member 'I1.M01()' in type 'C5' because feature 'static abstract members in interfaces' is not available in C# 10.0. Please use language version 'preview' or greater. + // (10,23): error CS8706: 'C2.M01()' cannot implement interface member 'I1.M01()' in type 'C5' because feature 'static abstract members in interfaces' is not available in C# 10.0. Please use language version '11.0' or greater. // public class C5 : C2, I1 - Diagnostic(ErrorCode.ERR_LanguageVersionDoesNotSupportInterfaceImplementationForMember, "I1").WithArguments("C2.M01()", "I1.M01()", "C5", "static abstract members in interfaces", "10.0", "preview").WithLocation(10, 23) + Diagnostic(ErrorCode.ERR_LanguageVersionDoesNotSupportInterfaceImplementationForMember, "I1").WithArguments("C2.M01()", "I1.M01()", "C5", "static abstract members in interfaces", "10.0", "11.0").WithLocation(10, 23) ); } @@ -16390,9 +16390,9 @@ public class C1 : I1 targetFramework: _supportingFramework); compilation1.VerifyEmitDiagnostics( - // (2,19): error CS8706: 'I1.M01()' cannot implement interface member 'I1.M01()' in type 'C1' because feature 'static abstract members in interfaces' is not available in C# 10.0. Please use language version 'preview' or greater. + // (2,19): error CS8706: 'I1.M01()' cannot implement interface member 'I1.M01()' in type 'C1' because feature 'static abstract members in interfaces' is not available in C# 10.0. Please use language version '11.0' or greater. // public class C1 : I1 - Diagnostic(ErrorCode.ERR_LanguageVersionDoesNotSupportInterfaceImplementationForMember, "I1").WithArguments("I1.M01()", "I1.M01()", "C1", "static abstract members in interfaces", "10.0", "preview").WithLocation(2, 19) + Diagnostic(ErrorCode.ERR_LanguageVersionDoesNotSupportInterfaceImplementationForMember, "I1").WithArguments("I1.M01()", "I1.M01()", "C1", "static abstract members in interfaces", "10.0", "11.0").WithLocation(2, 19) ); var source2 = @@ -18805,29 +18805,29 @@ public interface I2 where T : I2 if (isChecked) { expected2 = new[] { - // (4,15): error CS8652: The feature 'static abstract members in interfaces' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. - // static I1 I1.operator +(I1 x) => default; - Diagnostic(ErrorCode.ERR_FeatureInPreview, "I1.").WithArguments("static abstract members in interfaces").WithLocation(4, 15), - // (4,27): error CS8652: The feature 'checked user-defined operators' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. - // static I1 I1.operator checked -(I1 x) => default; - Diagnostic(ErrorCode.ERR_FeatureInPreview, "checked").WithArguments("checked user-defined operators").WithLocation(4, 27), - // (9,34): error CS8652: The feature 'checked user-defined operators' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. - // public static Test2 operator checked -(Test2 x) => default; - Diagnostic(ErrorCode.ERR_FeatureInPreview, "checked").WithArguments("checked user-defined operators").WithLocation(9, 34), - // (9,42): error CS8706: 'Test2.operator checked -(Test2)' cannot implement interface member 'I2.operator checked -(Test2)' in type 'Test2' because feature 'static abstract members in interfaces' is not available in C# 10.0. Please use language version 'preview' or greater. - // public static Test2 operator checked -(Test2 x) => default; - Diagnostic(ErrorCode.ERR_LanguageVersionDoesNotSupportInterfaceImplementationForMember, op).WithArguments("Test2.operator checked " + op + "(Test2)", "I2.operator checked " + op + "(Test2)", "Test2", "static abstract members in interfaces", "10.0", "preview").WithLocation(9, 42) + // (4,15): error CS8936: Feature 'static abstract members in interfaces' is not available in C# 10.0. Please use language version 11.0 or greater. + // static I1 I1.operator checked ++(I1 x) => default; + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "I1.").WithArguments("static abstract members in interfaces", "11.0").WithLocation(4, 15), + // (4,27): error CS8936: Feature 'checked user-defined operators' is not available in C# 10.0. Please use language version 11.0 or greater. + // static I1 I1.operator checked ++(I1 x) => default; + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "checked").WithArguments("checked user-defined operators", "11.0").WithLocation(4, 27), + // (9,34): error CS8936: Feature 'checked user-defined operators' is not available in C# 10.0. Please use language version 11.0 or greater. + // public static Test2 operator checked ++(Test2 x) => default; + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "checked").WithArguments("checked user-defined operators", "11.0").WithLocation(9, 34), + // (9,42): error CS8706: 'Test2.operator checked ++(Test2)' cannot implement interface member 'I2.operator checked ++(Test2)' in type 'Test2' because feature 'static abstract members in interfaces' is not available in C# 10.0. Please use language version '11.0' or greater. + // public static Test2 operator checked ++(Test2 x) => default; + Diagnostic(ErrorCode.ERR_LanguageVersionDoesNotSupportInterfaceImplementationForMember, op).WithArguments("Test2.operator checked " + op + "(Test2)", "I2.operator checked " + op + "(Test2)", "Test2", "static abstract members in interfaces", "10.0", "11.0").WithLocation(9, 42) }; } else { expected2 = new[] { - // (4,15): error CS8652: The feature 'static abstract members in interfaces' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. - // static I1 I1.operator +(I1 x) => default; - Diagnostic(ErrorCode.ERR_FeatureInPreview, "I1.").WithArguments("static abstract members in interfaces").WithLocation(4, 15), - // (9,34): error CS8706: 'Test2.operator +(Test2)' cannot implement interface member 'I2.operator +(Test2)' in type 'Test2' because feature 'static abstract members in interfaces' is not available in C# 10.0. Please use language version 'preview' or greater. - // public static Test2 operator +(Test2 x) => default; - Diagnostic(ErrorCode.ERR_LanguageVersionDoesNotSupportInterfaceImplementationForMember, op).WithArguments("Test2.operator " + op + "(Test2)", "I2.operator " + op + "(Test2)", "Test2", "static abstract members in interfaces", "10.0", "preview").WithLocation(9, 34) + // (4,15): error CS8936: Feature 'static abstract members in interfaces' is not available in C# 10.0. Please use language version 11.0 or greater. + // static I1 I1.operator true(I1 x) => default; + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "I1.").WithArguments("static abstract members in interfaces", "11.0").WithLocation(4, 15), + // (9,34): error CS8706: 'Test2.operator true(Test2)' cannot implement interface member 'I2.operator true(Test2)' in type 'Test2' because feature 'static abstract members in interfaces' is not available in C# 10.0. Please use language version '11.0' or greater. + // public static Test2 operator true(Test2 x) => default; + Diagnostic(ErrorCode.ERR_LanguageVersionDoesNotSupportInterfaceImplementationForMember, op).WithArguments("Test2.operator " + op + "(Test2)", "I2.operator " + op + "(Test2)", "Test2", "static abstract members in interfaces", "10.0", "11.0").WithLocation(9, 34) }; } @@ -18842,41 +18842,41 @@ public interface I2 where T : I2 if (isChecked) { expected3 = new[] { - // (4,15): error CS8652: The feature 'static abstract members in interfaces' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. - // static I1 I1.operator checked --(I1 x) => default; - Diagnostic(ErrorCode.ERR_FeatureInPreview, "I1.").WithArguments("static abstract members in interfaces").WithLocation(4, 15), - // (4,27): error CS8652: The feature 'checked user-defined operators' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. - // static I1 I1.operator checked --(I1 x) => default; - Diagnostic(ErrorCode.ERR_FeatureInPreview, "checked").WithArguments("checked user-defined operators").WithLocation(4, 27), - // (9,34): error CS8652: The feature 'checked user-defined operators' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. - // public static Test2 operator checked --(Test2 x) => default; - Diagnostic(ErrorCode.ERR_FeatureInPreview, "checked").WithArguments("checked user-defined operators").WithLocation(9, 34), - // (14,33): error CS8652: The feature 'checked user-defined operators' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. - // abstract static I1 operator checked --(I1 x); - Diagnostic(ErrorCode.ERR_FeatureInPreview, "checked").WithArguments("checked user-defined operators").WithLocation(14, 33), - // (14,41): error CS8703: The modifier 'abstract' is not valid for this item in C# 10.0. Please use language version 'preview' or greater. - // abstract static I1 operator checked --(I1 x); - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, op).WithArguments(modifier.Trim(), "10.0", "preview").WithLocation(14, 41), - // (19,32): error CS8652: The feature 'checked user-defined operators' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. - // abstract static T operator checked --(T x); - Diagnostic(ErrorCode.ERR_FeatureInPreview, "checked").WithArguments("checked user-defined operators").WithLocation(19, 32), - // (19,40): error CS8703: The modifier 'abstract' is not valid for this item in C# 10.0. Please use language version 'preview' or greater. - // abstract static T operator checked --(T x); - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, op).WithArguments(modifier.Trim(), "10.0", "preview").WithLocation(19, 40) + // (4,15): error CS8936: Feature 'static abstract members in interfaces' is not available in C# 10.0. Please use language version 11.0 or greater. + // static I1 I1.operator checked ++(I1 x) => default; + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "I1.").WithArguments("static abstract members in interfaces", "11.0").WithLocation(4, 15), + // (4,27): error CS8936: Feature 'checked user-defined operators' is not available in C# 10.0. Please use language version 11.0 or greater. + // static I1 I1.operator checked ++(I1 x) => default; + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "checked").WithArguments("checked user-defined operators", "11.0").WithLocation(4, 27), + // (9,34): error CS8936: Feature 'checked user-defined operators' is not available in C# 10.0. Please use language version 11.0 or greater. + // public static Test2 operator checked ++(Test2 x) => default; + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "checked").WithArguments("checked user-defined operators", "11.0").WithLocation(9, 34), + // (14,33): error CS8936: Feature 'checked user-defined operators' is not available in C# 10.0. Please use language version 11.0 or greater. + // virtual static I1 operator checked ++(I1 x) => throw null; + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "checked").WithArguments("checked user-defined operators", "11.0").WithLocation(14, 33), + // (14,41): error CS8703: The modifier 'virtual' is not valid for this item in C# 10.0. Please use language version '11.0' or greater. + // virtual static I1 operator checked ++(I1 x) => throw null; + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, op).WithArguments(modifier.Trim(), "10.0", "11.0").WithLocation(14, 41), + // (19,32): error CS8936: Feature 'checked user-defined operators' is not available in C# 10.0. Please use language version 11.0 or greater. + // virtual static T operator checked ++(T x) => throw null; + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "checked").WithArguments("checked user-defined operators", "11.0").WithLocation(19, 32), + // (19,40): error CS8703: The modifier 'virtual' is not valid for this item in C# 10.0. Please use language version '11.0' or greater. + // virtual static T operator checked ++(T x) => throw null; + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, op).WithArguments(modifier.Trim(), "10.0", "11.0").WithLocation(19, 40) }; } else { expected3 = new[] { - // (4,15): error CS8652: The feature 'static abstract members in interfaces' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. - // static I1 I1.operator +(I1 x) => default; - Diagnostic(ErrorCode.ERR_FeatureInPreview, "I1.").WithArguments("static abstract members in interfaces").WithLocation(4, 15), - // (14,33): error CS8703: The modifier 'abstract' is not valid for this item in C# 10.0. Please use language version 'preview' or greater. - // abstract static I1 operator +(I1 x); - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, op).WithArguments(modifier.Trim(), "10.0", "preview").WithLocation(14, 33), - // (19,32): error CS8703: The modifier 'abstract' is not valid for this item in C# 10.0. Please use language version 'preview' or greater. - // abstract static T operator +(T x); - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, op).WithArguments(modifier.Trim(), "10.0", "preview").WithLocation(19, 32) + // (4,15): error CS8936: Feature 'static abstract members in interfaces' is not available in C# 10.0. Please use language version 11.0 or greater. + // static I1 I1.operator true(I1 x) => default; + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "I1.").WithArguments("static abstract members in interfaces", "11.0").WithLocation(4, 15), + // (14,33): error CS8703: The modifier 'virtual' is not valid for this item in C# 10.0. Please use language version '11.0' or greater. + // virtual static I1 operator true(I1 x) => throw null; + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, op).WithArguments(modifier.Trim(), "10.0", "11.0").WithLocation(14, 33), + // (19,32): error CS8703: The modifier 'virtual' is not valid for this item in C# 10.0. Please use language version '11.0' or greater. + // virtual static T operator true(T x) => throw null; + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, op).WithArguments(modifier.Trim(), "10.0", "11.0").WithLocation(19, 32) }; } @@ -18933,47 +18933,47 @@ public interface I2 where T : I2 if (op != ">>>") { compilation2.GetDiagnostics().Where(d => d.Code is not ((int)ErrorCode.ERR_OperatorNeedsMatch or (int)ErrorCode.WRN_EqualityOpWithoutEquals or (int)ErrorCode.WRN_EqualityOpWithoutGetHashCode)).Verify( - // (4,15): error CS8652: The feature 'static abstract members in interfaces' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. - // static I1 I1.operator +(I1 x, int y) => default; - Diagnostic(ErrorCode.ERR_FeatureInPreview, "I1.").WithArguments("static abstract members in interfaces").WithLocation(4, 15), - // (9,34): error CS8706: 'Test2.operator +(Test2, int)' cannot implement interface member 'I2.operator +(Test2, int)' in type 'Test2' because feature 'static abstract members in interfaces' is not available in C# 10.0. Please use language version 'preview' or greater. - // public static Test2 operator +(Test2 x, int y) => default; - Diagnostic(ErrorCode.ERR_LanguageVersionDoesNotSupportInterfaceImplementationForMember, op).WithArguments("Test2.operator " + op + "(Test2, int)", "I2.operator " + op + "(Test2, int)", "Test2", "static abstract members in interfaces", "10.0", "preview").WithLocation(9, 34) + // (4,15): error CS8936: Feature 'static abstract members in interfaces' is not available in C# 10.0. Please use language version 11.0 or greater. + // static I1 I1.operator >>(I1 x, int y) => default; + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "I1.").WithArguments("static abstract members in interfaces", "11.0").WithLocation(4, 15), + // (9,34): error CS8706: 'Test2.operator >>(Test2, int)' cannot implement interface member 'I2.operator >>(Test2, int)' in type 'Test2' because feature 'static abstract members in interfaces' is not available in C# 10.0. Please use language version '11.0' or greater. + // public static Test2 operator >>(Test2 x, int y) => default; + Diagnostic(ErrorCode.ERR_LanguageVersionDoesNotSupportInterfaceImplementationForMember, op).WithArguments("Test2.operator " + op + "(Test2, int)", "I2.operator " + op + "(Test2, int)", "Test2", "static abstract members in interfaces", "10.0", "11.0").WithLocation(9, 34) ); } else { compilation2.VerifyDiagnostics( - // (4,15): error CS8652: The feature 'static abstract members in interfaces' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // (4,15): error CS8936: Feature 'static abstract members in interfaces' is not available in C# 10.0. Please use language version 11.0 or greater. // static I1 I1.operator >>>(I1 x, int y) => default; - Diagnostic(ErrorCode.ERR_FeatureInPreview, "I1.").WithArguments("static abstract members in interfaces").WithLocation(4, 15), - // (4,27): error CS8652: The feature 'unsigned right shift' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "I1.").WithArguments("static abstract members in interfaces", "11.0").WithLocation(4, 15), + // (4,27): error CS8936: Feature 'unsigned right shift' is not available in C# 10.0. Please use language version 11.0 or greater. // static I1 I1.operator >>>(I1 x, int y) => default; - Diagnostic(ErrorCode.ERR_FeatureInPreview, ">>>").WithArguments("unsigned right shift").WithLocation(4, 27), - // (9,34): error CS8652: The feature 'unsigned right shift' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, ">>>").WithArguments("unsigned right shift", "11.0").WithLocation(4, 27), + // (9,34): error CS8936: Feature 'unsigned right shift' is not available in C# 10.0. Please use language version 11.0 or greater. // public static Test2 operator >>>(Test2 x, int y) => default; - Diagnostic(ErrorCode.ERR_FeatureInPreview, ">>>").WithArguments("unsigned right shift").WithLocation(9, 34), - // (9,34): error CS8706: 'Test2.operator >>>(Test2, int)' cannot implement interface member 'I2.operator >>>(Test2, int)' in type 'Test2' because feature 'static abstract members in interfaces' is not available in C# 10.0. Please use language version 'preview' or greater. + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, ">>>").WithArguments("unsigned right shift", "11.0").WithLocation(9, 34), + // (9,34): error CS8706: 'Test2.operator >>>(Test2, int)' cannot implement interface member 'I2.operator >>>(Test2, int)' in type 'Test2' because feature 'static abstract members in interfaces' is not available in C# 10.0. Please use language version '11.0' or greater. // public static Test2 operator >>>(Test2 x, int y) => default; - Diagnostic(ErrorCode.ERR_LanguageVersionDoesNotSupportInterfaceImplementationForMember, ">>>").WithArguments("Test2.operator >>>(Test2, int)", "I2.operator >>>(Test2, int)", "Test2", "static abstract members in interfaces", "10.0", "preview").WithLocation(9, 34) + Diagnostic(ErrorCode.ERR_LanguageVersionDoesNotSupportInterfaceImplementationForMember, ">>>").WithArguments("Test2.operator >>>(Test2, int)", "I2.operator >>>(Test2, int)", "Test2", "static abstract members in interfaces", "10.0", "11.0").WithLocation(9, 34) ); } } else { compilation2.GetDiagnostics().Where(d => d.Code is not ((int)ErrorCode.ERR_CheckedOperatorNeedsMatch or (int)ErrorCode.WRN_EqualityOpWithoutEquals or (int)ErrorCode.WRN_EqualityOpWithoutGetHashCode)).Verify( - // (4,15): error CS8652: The feature 'static abstract members in interfaces' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. - // static I1 I1.operator +(I1 x, int y) => default; - Diagnostic(ErrorCode.ERR_FeatureInPreview, "I1.").WithArguments("static abstract members in interfaces").WithLocation(4, 15), - // (4,27): error CS8652: The feature 'checked user-defined operators' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. - // static I1 I1.operator checked /(I1 x, int y) => default; - Diagnostic(ErrorCode.ERR_FeatureInPreview, "checked").WithArguments("checked user-defined operators").WithLocation(4, 27), - // (9,34): error CS8652: The feature 'checked user-defined operators' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. - // public static Test2 operator checked /(Test2 x, int y) => default; - Diagnostic(ErrorCode.ERR_FeatureInPreview, "checked").WithArguments("checked user-defined operators").WithLocation(9, 34), - // (9,42): error CS8706: 'Test2.operator checked /(Test2, int)' cannot implement interface member 'I2.operator checked /(Test2, int)' in type 'Test2' because feature 'static abstract members in interfaces' is not available in C# 10.0. Please use language version 'preview' or greater. - // public static Test2 operator checked /(Test2 x, int y) => default; - Diagnostic(ErrorCode.ERR_LanguageVersionDoesNotSupportInterfaceImplementationForMember, op).WithArguments("Test2.operator checked " + op + "(Test2, int)", "I2.operator checked " + op + "(Test2, int)", "Test2", "static abstract members in interfaces", "10.0", "preview").WithLocation(9, 42) + // (4,15): error CS8936: Feature 'static abstract members in interfaces' is not available in C# 10.0. Please use language version 11.0 or greater. + // static I1 I1.operator checked +(I1 x, int y) => default; + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "I1.").WithArguments("static abstract members in interfaces", "11.0").WithLocation(4, 15), + // (4,27): error CS8936: Feature 'checked user-defined operators' is not available in C# 10.0. Please use language version 11.0 or greater. + // static I1 I1.operator checked +(I1 x, int y) => default; + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "checked").WithArguments("checked user-defined operators", "11.0").WithLocation(4, 27), + // (9,34): error CS8936: Feature 'checked user-defined operators' is not available in C# 10.0. Please use language version 11.0 or greater. + // public static Test2 operator checked +(Test2 x, int y) => default; + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "checked").WithArguments("checked user-defined operators", "11.0").WithLocation(9, 34), + // (9,42): error CS8706: 'Test2.operator checked +(Test2, int)' cannot implement interface member 'I2.operator checked +(Test2, int)' in type 'Test2' because feature 'static abstract members in interfaces' is not available in C# 10.0. Please use language version '11.0' or greater. + // public static Test2 operator checked +(Test2 x, int y) => default; + Diagnostic(ErrorCode.ERR_LanguageVersionDoesNotSupportInterfaceImplementationForMember, op).WithArguments("Test2.operator checked " + op + "(Test2, int)", "I2.operator checked " + op + "(Test2, int)", "Test2", "static abstract members in interfaces", "10.0", "11.0").WithLocation(9, 42) ); } @@ -18987,68 +18987,68 @@ public interface I2 where T : I2 { compilation3.GetDiagnostics().Where(d => d.Code is not ((int)ErrorCode.ERR_OperatorNeedsMatch or (int)ErrorCode.WRN_EqualityOpWithoutEquals or (int)ErrorCode.WRN_EqualityOpWithoutGetHashCode or (int)ErrorCode.ERR_BadAbstractEqualityOperatorSignature)).Verify( - // (4,15): error CS8652: The feature 'static abstract members in interfaces' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // (4,15): error CS8936: Feature 'static abstract members in interfaces' is not available in C# 10.0. Please use language version 11.0 or greater. // static I1 I1.operator +(I1 x, int y) => default; - Diagnostic(ErrorCode.ERR_FeatureInPreview, "I1.").WithArguments("static abstract members in interfaces").WithLocation(4, 15), - // (14,33): error CS8703: The modifier 'abstract' is not valid for this item in C# 10.0. Please use language version 'preview' or greater. - // abstract static I1 operator +(I1 x, int y); - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, op).WithArguments(modifier.Trim(), "10.0", "preview").WithLocation(14, 33), - // (19,32): error CS8703: The modifier 'abstract' is not valid for this item in C# 10.0. Please use language version 'preview' or greater. - // abstract static T operator +(T x, int y); - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, op).WithArguments(modifier.Trim(), "10.0", "preview").WithLocation(19, 32) + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "I1.").WithArguments("static abstract members in interfaces", "11.0").WithLocation(4, 15), + // (14,33): error CS8703: The modifier 'virtual' is not valid for this item in C# 10.0. Please use language version '11.0' or greater. + // virtual static I1 operator +(I1 x, int y) => throw null; + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, op).WithArguments(modifier.Trim(), "10.0", "11.0").WithLocation(14, 33), + // (19,32): error CS8703: The modifier 'virtual' is not valid for this item in C# 10.0. Please use language version '11.0' or greater. + // virtual static T operator +(T x, int y) => throw null; + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, op).WithArguments(modifier.Trim(), "10.0", "11.0").WithLocation(19, 32) ); } else { compilation3.VerifyDiagnostics( - // (4,15): error CS8652: The feature 'static abstract members in interfaces' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // (4,15): error CS8936: Feature 'static abstract members in interfaces' is not available in C# 10.0. Please use language version 11.0 or greater. // static I1 I1.operator >>>(I1 x, int y) => default; - Diagnostic(ErrorCode.ERR_FeatureInPreview, "I1.").WithArguments("static abstract members in interfaces").WithLocation(4, 15), - // (4,27): error CS8652: The feature 'unsigned right shift' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "I1.").WithArguments("static abstract members in interfaces", "11.0").WithLocation(4, 15), + // (4,27): error CS8936: Feature 'unsigned right shift' is not available in C# 10.0. Please use language version 11.0 or greater. // static I1 I1.operator >>>(I1 x, int y) => default; - Diagnostic(ErrorCode.ERR_FeatureInPreview, ">>>").WithArguments("unsigned right shift").WithLocation(4, 27), - // (9,34): error CS8652: The feature 'unsigned right shift' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, ">>>").WithArguments("unsigned right shift", "11.0").WithLocation(4, 27), + // (9,34): error CS8936: Feature 'unsigned right shift' is not available in C# 10.0. Please use language version 11.0 or greater. // public static Test2 operator >>>(Test2 x, int y) => default; - Diagnostic(ErrorCode.ERR_FeatureInPreview, ">>>").WithArguments("unsigned right shift").WithLocation(9, 34), - // (14,33): error CS8652: The feature 'unsigned right shift' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. - // abstract static I1 operator >>>(I1 x, int y); - Diagnostic(ErrorCode.ERR_FeatureInPreview, ">>>").WithArguments("unsigned right shift").WithLocation(14, 33), - // (14,33): error CS8703: The modifier 'abstract' is not valid for this item in C# 10.0. Please use language version 'preview' or greater. - // abstract static I1 operator >>>(I1 x, int y); - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, ">>>").WithArguments(modifier.Trim(), "10.0", "preview").WithLocation(14, 33), - // (19,32): error CS8652: The feature 'unsigned right shift' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. - // abstract static T operator >>>(T x, int y); - Diagnostic(ErrorCode.ERR_FeatureInPreview, ">>>").WithArguments("unsigned right shift").WithLocation(19, 32), - // (19,32): error CS8703: The modifier 'abstract' is not valid for this item in C# 10.0. Please use language version 'preview' or greater. - // abstract static T operator >>>(T x, int y); - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, ">>>").WithArguments(modifier.Trim(), "10.0", "preview").WithLocation(19, 32) + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, ">>>").WithArguments("unsigned right shift", "11.0").WithLocation(9, 34), + // (14,33): error CS8936: Feature 'unsigned right shift' is not available in C# 10.0. Please use language version 11.0 or greater. + // virtual static I1 operator >>>(I1 x, int y) => throw null; + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, ">>>").WithArguments("unsigned right shift", "11.0").WithLocation(14, 33), + // (14,33): error CS8703: The modifier 'virtual' is not valid for this item in C# 10.0. Please use language version '11.0' or greater. + // virtual static I1 operator >>>(I1 x, int y) => throw null; + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, ">>>").WithArguments(modifier.Trim(), "10.0", "11.0").WithLocation(14, 33), + // (19,32): error CS8936: Feature 'unsigned right shift' is not available in C# 10.0. Please use language version 11.0 or greater. + // virtual static T operator >>>(T x, int y) => throw null; + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, ">>>").WithArguments("unsigned right shift", "11.0").WithLocation(19, 32), + // (19,32): error CS8703: The modifier 'virtual' is not valid for this item in C# 10.0. Please use language version '11.0' or greater. + // virtual static T operator >>>(T x, int y) => throw null; + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, ">>>").WithArguments(modifier.Trim(), "10.0", "11.0").WithLocation(19, 32) ); } } else { compilation3.GetDiagnostics().Where(d => d.Code is not ((int)ErrorCode.ERR_CheckedOperatorNeedsMatch or (int)ErrorCode.WRN_EqualityOpWithoutEquals or (int)ErrorCode.WRN_EqualityOpWithoutGetHashCode)).Verify( - // (4,15): error CS8652: The feature 'static abstract members in interfaces' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. - // static I1 I1.operator +(I1 x, int y) => default; - Diagnostic(ErrorCode.ERR_FeatureInPreview, "I1.").WithArguments("static abstract members in interfaces").WithLocation(4, 15), - // (14,33): error CS8703: The modifier 'abstract' is not valid for this item in C# 10.0. Please use language version 'preview' or greater. - // abstract static I1 operator +(I1 x, int y); - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, op).WithArguments(modifier.Trim(), "10.0", "preview").WithLocation(14, 33 + checkedKeyword.Length), - // (19,32): error CS8703: The modifier 'abstract' is not valid for this item in C# 10.0. Please use language version 'preview' or greater. - // abstract static T operator +(T x, int y); - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, op).WithArguments(modifier.Trim(), "10.0", "preview").WithLocation(19, 32 + checkedKeyword.Length), - // (4,27): error CS8652: The feature 'checked user-defined operators' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. - // static I1 I1.operator checked /(I1 x, int y) => default; - Diagnostic(ErrorCode.ERR_FeatureInPreview, "checked").WithArguments("checked user-defined operators").WithLocation(4, 27), - // (9,34): error CS8652: The feature 'checked user-defined operators' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. - // public static Test2 operator checked /(Test2 x, int y) => default; - Diagnostic(ErrorCode.ERR_FeatureInPreview, "checked").WithArguments("checked user-defined operators").WithLocation(9, 34), - // (14,33): error CS8652: The feature 'checked user-defined operators' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. - // abstract static I1 operator checked /(I1 x, int y); - Diagnostic(ErrorCode.ERR_FeatureInPreview, "checked").WithArguments("checked user-defined operators").WithLocation(14, 33), - // (19,32): error CS8652: The feature 'checked user-defined operators' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. - // abstract static T operator checked /(T x, int y); - Diagnostic(ErrorCode.ERR_FeatureInPreview, "checked").WithArguments("checked user-defined operators").WithLocation(19, 32) + // (4,15): error CS8936: Feature 'static abstract members in interfaces' is not available in C# 10.0. Please use language version 11.0 or greater. + // static I1 I1.operator checked +(I1 x, int y) => default; + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "I1.").WithArguments("static abstract members in interfaces", "11.0").WithLocation(4, 15), + // (14,33): error CS8936: Feature 'checked user-defined operators' is not available in C# 10.0. Please use language version 11.0 or greater. + // virtual static I1 operator checked +(I1 x, int y) => throw null; + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "checked").WithArguments("checked user-defined operators", "11.0").WithLocation(14, 33), + // (14,41): error CS8703: The modifier 'virtual' is not valid for this item in C# 10.0. Please use language version '11.0' or greater. + // virtual static I1 operator checked +(I1 x, int y) => throw null; + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, op).WithArguments(modifier.Trim(), "10.0", "11.0").WithLocation(14, 33 + checkedKeyword.Length), + // (4,27): error CS8936: Feature 'checked user-defined operators' is not available in C# 10.0. Please use language version 11.0 or greater. + // static I1 I1.operator checked +(I1 x, int y) => default; + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "checked").WithArguments("checked user-defined operators", "11.0").WithLocation(4, 27), + // (19,32): error CS8936: Feature 'checked user-defined operators' is not available in C# 10.0. Please use language version 11.0 or greater. + // virtual static T operator checked +(T x, int y) => throw null; + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "checked").WithArguments("checked user-defined operators", "11.0").WithLocation(19, 32), + // (19,40): error CS8703: The modifier 'virtual' is not valid for this item in C# 10.0. Please use language version '11.0' or greater. + // virtual static T operator checked +(T x, int y) => throw null; + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, op).WithArguments(modifier.Trim(), "10.0", "11.0").WithLocation(19, 32 + checkedKeyword.Length), + // (9,34): error CS8936: Feature 'checked user-defined operators' is not available in C# 10.0. Please use language version 11.0 or greater. + // public static Test2 operator checked +(Test2 x, int y) => default; + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "checked").WithArguments("checked user-defined operators", "11.0").WithLocation(9, 34) ); } } @@ -20330,9 +20330,9 @@ public class C5 : C2, I1 targetFramework: _supportingFramework); compilation1.VerifyDiagnostics( - // (10,23): error CS8706: 'C2.operator --(I1)' cannot implement interface member 'I1.operator --(I1)' in type 'C5' because feature 'static abstract members in interfaces' is not available in C# 10.0. Please use language version 'preview' or greater. + // (10,23): error CS8706: 'C2.operator true(I1)' cannot implement interface member 'I1.operator true(I1)' in type 'C5' because feature 'static abstract members in interfaces' is not available in C# 10.0. Please use language version '11.0' or greater. // public class C5 : C2, I1 - Diagnostic(ErrorCode.ERR_LanguageVersionDoesNotSupportInterfaceImplementationForMember, "I1").WithArguments("C2.operator " + checkedKeyword + op + "(I1)", "I1.operator " + checkedKeyword + op + "(I1)", "C5", "static abstract members in interfaces", "10.0", "preview").WithLocation(10, 23) + Diagnostic(ErrorCode.ERR_LanguageVersionDoesNotSupportInterfaceImplementationForMember, "I1").WithArguments("C2.operator " + checkedKeyword + op + "(I1)", "I1.operator " + checkedKeyword + op + "(I1)", "C5", "static abstract members in interfaces", "10.0", "11.0").WithLocation(10, 23) ); } @@ -20465,9 +20465,9 @@ public class C5 : C2, I1 targetFramework: _supportingFramework); compilation1.VerifyDiagnostics( - // (10,23): error CS8706: 'C2.operator checked *(I1, int)' cannot implement interface member 'I1.operator checked *(I1, int)' in type 'C5' because feature 'static abstract members in interfaces' is not available in C# 10.0. Please use language version 'preview' or greater. + // (10,23): error CS8706: 'C2.operator >>>(I1, int)' cannot implement interface member 'I1.operator >>>(I1, int)' in type 'C5' because feature 'static abstract members in interfaces' is not available in C# 10.0. Please use language version '11.0' or greater. // public class C5 : C2, I1 - Diagnostic(ErrorCode.ERR_LanguageVersionDoesNotSupportInterfaceImplementationForMember, "I1").WithArguments("C2.operator " + checkedKeyword + op + "(I1, int)", "I1.operator " + checkedKeyword + op + "(I1, int)", "C5", "static abstract members in interfaces", "10.0", "preview").WithLocation(10, 23) + Diagnostic(ErrorCode.ERR_LanguageVersionDoesNotSupportInterfaceImplementationForMember, "I1").WithArguments("C2.operator " + checkedKeyword + op + "(I1, int)", "I1.operator " + checkedKeyword + op + "(I1, int)", "C5", "static abstract members in interfaces", "10.0", "11.0").WithLocation(10, 23) ); } @@ -20524,9 +20524,9 @@ public class C1 : I1 targetFramework: _supportingFramework); compilation1.VerifyEmitDiagnostics( - // (2,19): error CS8706: 'I1.operator ~(I1)' cannot implement interface member 'I1.operator ~(I1)' in type 'C1' because feature 'static abstract members in interfaces' is not available in C# 10.0. Please use language version 'preview' or greater. + // (2,19): error CS8706: 'I1.operator true(I1)' cannot implement interface member 'I1.operator true(I1)' in type 'C1' because feature 'static abstract members in interfaces' is not available in C# 10.0. Please use language version '11.0' or greater. // public class C1 : I1 - Diagnostic(ErrorCode.ERR_LanguageVersionDoesNotSupportInterfaceImplementationForMember, "I1").WithArguments("I1.operator " + checkedKeyword + op + @"(I1)", "I1.operator " + checkedKeyword + op + @"(I1)", "C1", "static abstract members in interfaces", "10.0", "preview").WithLocation(2, 19) + Diagnostic(ErrorCode.ERR_LanguageVersionDoesNotSupportInterfaceImplementationForMember, "I1").WithArguments("I1.operator " + checkedKeyword + op + @"(I1)", "I1.operator " + checkedKeyword + op + @"(I1)", "C1", "static abstract members in interfaces", "10.0", "11.0").WithLocation(2, 19) ); var source2 = @@ -20604,9 +20604,9 @@ public class C1 : I1 targetFramework: _supportingFramework); compilation1.VerifyEmitDiagnostics( - // (2,19): error CS8706: 'I1.operator |(I1, int)' cannot implement interface member 'I1.operator |(I1, int)' in type 'C1' because feature 'static abstract members in interfaces' is not available in C# 10.0. Please use language version 'preview' or greater. + // (2,19): error CS8706: 'I1.operator >>>(I1, int)' cannot implement interface member 'I1.operator >>>(I1, int)' in type 'C1' because feature 'static abstract members in interfaces' is not available in C# 10.0. Please use language version '11.0' or greater. // public class C1 : I1 - Diagnostic(ErrorCode.ERR_LanguageVersionDoesNotSupportInterfaceImplementationForMember, "I1").WithArguments("I1.operator " + checkedKeyword + op + @"(I1, int)", "I1.operator " + checkedKeyword + op + @"(I1, int)", "C1", "static abstract members in interfaces", "10.0", "preview").WithLocation(2, 19) + Diagnostic(ErrorCode.ERR_LanguageVersionDoesNotSupportInterfaceImplementationForMember, "I1").WithArguments("I1.operator " + checkedKeyword + op + @"(I1, int)", "I1.operator " + checkedKeyword + op + @"(I1, int)", "C1", "static abstract members in interfaces", "10.0", "11.0").WithLocation(2, 19) ); var source2 = @@ -22781,18 +22781,18 @@ public interface I1 references: new[] { compilation1.ToMetadataReference() }); compilation2.VerifyDiagnostics( - // (4,19): error CS8703: The modifier 'static' is not valid for this item in C# 10.0. Please use language version 'preview' or greater. + // (4,19): error CS8703: The modifier 'static' is not valid for this item in C# 10.0. Please use language version '11.0' or greater. // static int I1.M01 { get; set; } - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M01").WithArguments("static", "10.0", "preview").WithLocation(4, 19), - // (5,23): error CS8706: 'Test.M02' cannot implement interface member 'I1.M02' in type 'Test' because feature 'static abstract members in interfaces' is not available in C# 10.0. Please use language version 'preview' or greater. + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M01").WithArguments("static", "10.0", "11.0").WithLocation(4, 19), + // (5,23): error CS8706: 'Test.M02' cannot implement interface member 'I1.M02' in type 'Test' because feature 'static abstract members in interfaces' is not available in C# 10.0. Please use language version '11.0' or greater. // public static int M02 { get; set; } - Diagnostic(ErrorCode.ERR_LanguageVersionDoesNotSupportInterfaceImplementationForMember, "M02").WithArguments("Test.M02", "I1.M02", "Test", "static abstract members in interfaces", "10.0", "preview").WithLocation(5, 23), - // (5,29): error CS8706: 'Test.M02.get' cannot implement interface member 'I1.M02.get' in type 'Test' because feature 'static abstract members in interfaces' is not available in C# 10.0. Please use language version 'preview' or greater. + Diagnostic(ErrorCode.ERR_LanguageVersionDoesNotSupportInterfaceImplementationForMember, "M02").WithArguments("Test.M02", "I1.M02", "Test", "static abstract members in interfaces", "10.0", "11.0").WithLocation(5, 23), + // (5,29): error CS8706: 'Test.M02.get' cannot implement interface member 'I1.M02.get' in type 'Test' because feature 'static abstract members in interfaces' is not available in C# 10.0. Please use language version '11.0' or greater. // public static int M02 { get; set; } - Diagnostic(ErrorCode.ERR_LanguageVersionDoesNotSupportInterfaceImplementationForMember, "get").WithArguments("Test.M02.get", "I1.M02.get", "Test", "static abstract members in interfaces", "10.0", "preview").WithLocation(5, 29), - // (5,34): error CS8706: 'Test.M02.set' cannot implement interface member 'I1.M02.set' in type 'Test' because feature 'static abstract members in interfaces' is not available in C# 10.0. Please use language version 'preview' or greater. + Diagnostic(ErrorCode.ERR_LanguageVersionDoesNotSupportInterfaceImplementationForMember, "get").WithArguments("Test.M02.get", "I1.M02.get", "Test", "static abstract members in interfaces", "10.0", "11.0").WithLocation(5, 29), + // (5,34): error CS8706: 'Test.M02.set' cannot implement interface member 'I1.M02.set' in type 'Test' because feature 'static abstract members in interfaces' is not available in C# 10.0. Please use language version '11.0' or greater. // public static int M02 { get; set; } - Diagnostic(ErrorCode.ERR_LanguageVersionDoesNotSupportInterfaceImplementationForMember, "set").WithArguments("Test.M02.set", "I1.M02.set", "Test", "static abstract members in interfaces", "10.0", "preview").WithLocation(5, 34) + Diagnostic(ErrorCode.ERR_LanguageVersionDoesNotSupportInterfaceImplementationForMember, "set").WithArguments("Test.M02.set", "I1.M02.set", "Test", "static abstract members in interfaces", "10.0", "11.0").WithLocation(5, 34) ); var compilation3 = CreateCompilation(source2 + source1, options: TestOptions.DebugDll, @@ -22800,15 +22800,15 @@ public interface I1 targetFramework: _supportingFramework); compilation3.VerifyDiagnostics( - // (4,19): error CS8703: The modifier 'static' is not valid for this item in C# 10.0. Please use language version 'preview' or greater. + // (4,19): error CS8703: The modifier 'static' is not valid for this item in C# 10.0. Please use language version '11.0' or greater. // static int I1.M01 { get; set; } - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M01").WithArguments("static", "10.0", "preview").WithLocation(4, 19), - // (10,25): error CS8703: The modifier 'abstract' is not valid for this item in C# 10.0. Please use language version 'preview' or greater. - // abstract static int M01 { get; set; } - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M01").WithArguments(modifier.Trim(), "10.0", "preview").WithLocation(10, 25), - // (11,25): error CS8703: The modifier 'abstract' is not valid for this item in C# 10.0. Please use language version 'preview' or greater. - // abstract static int M02 { get; set; } - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M02").WithArguments(modifier.Trim(), "10.0", "preview").WithLocation(11, 25) + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M01").WithArguments("static", "10.0", "11.0").WithLocation(4, 19), + // (10,25): error CS8703: The modifier 'virtual' is not valid for this item in C# 10.0. Please use language version '11.0' or greater. + // virtual static int M01 { get; set; } + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M01").WithArguments(modifier.Trim(), "10.0", "11.0").WithLocation(10, 25), + // (11,25): error CS8703: The modifier 'virtual' is not valid for this item in C# 10.0. Please use language version '11.0' or greater. + // virtual static int M02 { get; set; } + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M02").WithArguments(modifier.Trim(), "10.0", "11.0").WithLocation(11, 25) ); } @@ -23443,15 +23443,15 @@ public class C5 : C2, I1 targetFramework: _supportingFramework); compilation1.VerifyDiagnostics( - // (10,23): error CS8706: 'C2.M01.get' cannot implement interface member 'I1.M01.get' in type 'C5' because feature 'static abstract members in interfaces' is not available in C# 10.0. Please use language version 'preview' or greater. + // (10,23): error CS8706: 'C2.M01.get' cannot implement interface member 'I1.M01.get' in type 'C5' because feature 'static abstract members in interfaces' is not available in C# 10.0. Please use language version '11.0' or greater. // public class C5 : C2, I1 - Diagnostic(ErrorCode.ERR_LanguageVersionDoesNotSupportInterfaceImplementationForMember, "I1").WithArguments("C2.M01.get", "I1.M01.get", "C5", "static abstract members in interfaces", "10.0", "preview").WithLocation(10, 23), - // (10,23): error CS8706: 'C2.M01.set' cannot implement interface member 'I1.M01.set' in type 'C5' because feature 'static abstract members in interfaces' is not available in C# 10.0. Please use language version 'preview' or greater. + Diagnostic(ErrorCode.ERR_LanguageVersionDoesNotSupportInterfaceImplementationForMember, "I1").WithArguments("C2.M01.get", "I1.M01.get", "C5", "static abstract members in interfaces", "10.0", "11.0").WithLocation(10, 23), + // (10,23): error CS8706: 'C2.M01.set' cannot implement interface member 'I1.M01.set' in type 'C5' because feature 'static abstract members in interfaces' is not available in C# 10.0. Please use language version '11.0' or greater. // public class C5 : C2, I1 - Diagnostic(ErrorCode.ERR_LanguageVersionDoesNotSupportInterfaceImplementationForMember, "I1").WithArguments("C2.M01.set", "I1.M01.set", "C5", "static abstract members in interfaces", "10.0", "preview").WithLocation(10, 23), - // (10,23): error CS8706: 'C2.M01' cannot implement interface member 'I1.M01' in type 'C5' because feature 'static abstract members in interfaces' is not available in C# 10.0. Please use language version 'preview' or greater. + Diagnostic(ErrorCode.ERR_LanguageVersionDoesNotSupportInterfaceImplementationForMember, "I1").WithArguments("C2.M01.set", "I1.M01.set", "C5", "static abstract members in interfaces", "10.0", "11.0").WithLocation(10, 23), + // (10,23): error CS8706: 'C2.M01' cannot implement interface member 'I1.M01' in type 'C5' because feature 'static abstract members in interfaces' is not available in C# 10.0. Please use language version '11.0' or greater. // public class C5 : C2, I1 - Diagnostic(ErrorCode.ERR_LanguageVersionDoesNotSupportInterfaceImplementationForMember, "I1").WithArguments("C2.M01", "I1.M01", "C5", "static abstract members in interfaces", "10.0", "preview").WithLocation(10, 23) + Diagnostic(ErrorCode.ERR_LanguageVersionDoesNotSupportInterfaceImplementationForMember, "I1").WithArguments("C2.M01", "I1.M01", "C5", "static abstract members in interfaces", "10.0", "11.0").WithLocation(10, 23) ); } @@ -23520,12 +23520,12 @@ public class C1 : I1 targetFramework: _supportingFramework); compilation1.VerifyEmitDiagnostics( - // (2,19): error CS8706: 'I1.M01.get' cannot implement interface member 'I1.M01.get' in type 'C1' because feature 'static abstract members in interfaces' is not available in C# 10.0. Please use language version 'preview' or greater. + // (2,19): error CS8706: 'I1.M01.get' cannot implement interface member 'I1.M01.get' in type 'C1' because feature 'static abstract members in interfaces' is not available in C# 10.0. Please use language version '11.0' or greater. // public class C1 : I1 - Diagnostic(ErrorCode.ERR_LanguageVersionDoesNotSupportInterfaceImplementationForMember, "I1").WithArguments("I1.M01.get", "I1.M01.get", "C1", "static abstract members in interfaces", "10.0", "preview").WithLocation(2, 19), - // (2,19): error CS8706: 'I1.M01.set' cannot implement interface member 'I1.M01.set' in type 'C1' because feature 'static abstract members in interfaces' is not available in C# 10.0. Please use language version 'preview' or greater. + Diagnostic(ErrorCode.ERR_LanguageVersionDoesNotSupportInterfaceImplementationForMember, "I1").WithArguments("I1.M01.get", "I1.M01.get", "C1", "static abstract members in interfaces", "10.0", "11.0").WithLocation(2, 19), + // (2,19): error CS8706: 'I1.M01.set' cannot implement interface member 'I1.M01.set' in type 'C1' because feature 'static abstract members in interfaces' is not available in C# 10.0. Please use language version '11.0' or greater. // public class C1 : I1 - Diagnostic(ErrorCode.ERR_LanguageVersionDoesNotSupportInterfaceImplementationForMember, "I1").WithArguments("I1.M01.set", "I1.M01.set", "C1", "static abstract members in interfaces", "10.0", "preview").WithLocation(2, 19) + Diagnostic(ErrorCode.ERR_LanguageVersionDoesNotSupportInterfaceImplementationForMember, "I1").WithArguments("I1.M01.set", "I1.M01.set", "C1", "static abstract members in interfaces", "10.0", "11.0").WithLocation(2, 19) ); var source2 = @@ -25560,18 +25560,18 @@ public interface I1 references: new[] { compilation1.ToMetadataReference() }); compilation2.VerifyDiagnostics( - // (4,35): error CS8703: The modifier 'static' is not valid for this item in C# 10.0. Please use language version 'preview' or greater. + // (4,35): error CS8703: The modifier 'static' is not valid for this item in C# 10.0. Please use language version '11.0' or greater. // static event System.Action I1.M01 { add{} remove => throw null; } - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M01").WithArguments("static", "10.0", "preview").WithLocation(4, 35), - // (5,39): error CS8706: 'Test.M02.add' cannot implement interface member 'I1.M02.add' in type 'Test' because feature 'static abstract members in interfaces' is not available in C# 10.0. Please use language version 'preview' or greater. + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M01").WithArguments("static", "10.0", "11.0").WithLocation(4, 35), + // (5,39): error CS8706: 'Test.M02.add' cannot implement interface member 'I1.M02.add' in type 'Test' because feature 'static abstract members in interfaces' is not available in C# 10.0. Please use language version '11.0' or greater. // public static event System.Action M02; - Diagnostic(ErrorCode.ERR_LanguageVersionDoesNotSupportInterfaceImplementationForMember, "M02").WithArguments("Test.M02.add", "I1.M02.add", "Test", "static abstract members in interfaces", "10.0", "preview").WithLocation(5, 39), - // (5,39): error CS8706: 'Test.M02.remove' cannot implement interface member 'I1.M02.remove' in type 'Test' because feature 'static abstract members in interfaces' is not available in C# 10.0. Please use language version 'preview' or greater. + Diagnostic(ErrorCode.ERR_LanguageVersionDoesNotSupportInterfaceImplementationForMember, "M02").WithArguments("Test.M02.add", "I1.M02.add", "Test", "static abstract members in interfaces", "10.0", "11.0").WithLocation(5, 39), + // (5,39): error CS8706: 'Test.M02.remove' cannot implement interface member 'I1.M02.remove' in type 'Test' because feature 'static abstract members in interfaces' is not available in C# 10.0. Please use language version '11.0' or greater. // public static event System.Action M02; - Diagnostic(ErrorCode.ERR_LanguageVersionDoesNotSupportInterfaceImplementationForMember, "M02").WithArguments("Test.M02.remove", "I1.M02.remove", "Test", "static abstract members in interfaces", "10.0", "preview").WithLocation(5, 39), - // (5,39): error CS8706: 'Test.M02' cannot implement interface member 'I1.M02' in type 'Test' because feature 'static abstract members in interfaces' is not available in C# 10.0. Please use language version 'preview' or greater. + Diagnostic(ErrorCode.ERR_LanguageVersionDoesNotSupportInterfaceImplementationForMember, "M02").WithArguments("Test.M02.remove", "I1.M02.remove", "Test", "static abstract members in interfaces", "10.0", "11.0").WithLocation(5, 39), + // (5,39): error CS8706: 'Test.M02' cannot implement interface member 'I1.M02' in type 'Test' because feature 'static abstract members in interfaces' is not available in C# 10.0. Please use language version '11.0' or greater. // public static event System.Action M02; - Diagnostic(ErrorCode.ERR_LanguageVersionDoesNotSupportInterfaceImplementationForMember, "M02").WithArguments("Test.M02", "I1.M02", "Test", "static abstract members in interfaces", "10.0", "preview").WithLocation(5, 39), + Diagnostic(ErrorCode.ERR_LanguageVersionDoesNotSupportInterfaceImplementationForMember, "M02").WithArguments("Test.M02", "I1.M02", "Test", "static abstract members in interfaces", "10.0", "11.0").WithLocation(5, 39), // (5,39): warning CS0067: The event 'Test.M02' is never used // public static event System.Action M02; Diagnostic(ErrorCode.WRN_UnreferencedEvent, "M02").WithArguments("Test.M02").WithLocation(5, 39) @@ -25582,18 +25582,18 @@ public interface I1 targetFramework: _supportingFramework); compilation3.VerifyDiagnostics( - // (4,35): error CS8703: The modifier 'static' is not valid for this item in C# 10.0. Please use language version 'preview' or greater. + // (4,35): error CS8703: The modifier 'static' is not valid for this item in C# 10.0. Please use language version '11.0' or greater. // static event System.Action I1.M01 { add{} remove => throw null; } - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M01").WithArguments("static", "10.0", "preview").WithLocation(4, 35), + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M01").WithArguments("static", "10.0", "11.0").WithLocation(4, 35), // (5,39): warning CS0067: The event 'Test.M02' is never used // public static event System.Action M02; Diagnostic(ErrorCode.WRN_UnreferencedEvent, "M02").WithArguments("Test.M02").WithLocation(5, 39), - // (10,41): error CS8703: The modifier 'abstract' is not valid for this item in C# 10.0. Please use language version 'preview' or greater. - // abstract static event System.Action M01; - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M01").WithArguments(modifier.Trim(), "10.0", "preview").WithLocation(10, 41), - // (11,41): error CS8703: The modifier 'abstract' is not valid for this item in C# 10.0. Please use language version 'preview' or greater. - // abstract static event System.Action M02; - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M02").WithArguments(modifier.Trim(), "10.0", "preview").WithLocation(11, 41) + // (10,41): error CS8703: The modifier 'virtual' is not valid for this item in C# 10.0. Please use language version '11.0' or greater. + // virtual static event System.Action M01; + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M01").WithArguments(modifier.Trim(), "10.0", "11.0").WithLocation(10, 41), + // (11,41): error CS8703: The modifier 'virtual' is not valid for this item in C# 10.0. Please use language version '11.0' or greater. + // virtual static event System.Action M02; + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M02").WithArguments(modifier.Trim(), "10.0", "11.0").WithLocation(11, 41) ); } @@ -26136,15 +26136,15 @@ public class C5 : C2, I1 targetFramework: _supportingFramework); compilation1.VerifyDiagnostics( - // (10,23): error CS8706: 'C2.M01.add' cannot implement interface member 'I1.M01.add' in type 'C5' because feature 'static abstract members in interfaces' is not available in C# 10.0. Please use language version 'preview' or greater. + // (10,23): error CS8706: 'C2.M01.add' cannot implement interface member 'I1.M01.add' in type 'C5' because feature 'static abstract members in interfaces' is not available in C# 10.0. Please use language version '11.0' or greater. // public class C5 : C2, I1 - Diagnostic(ErrorCode.ERR_LanguageVersionDoesNotSupportInterfaceImplementationForMember, "I1").WithArguments("C2.M01.add", "I1.M01.add", "C5", "static abstract members in interfaces", "10.0", "preview").WithLocation(10, 23), - // (10,23): error CS8706: 'C2.M01.remove' cannot implement interface member 'I1.M01.remove' in type 'C5' because feature 'static abstract members in interfaces' is not available in C# 10.0. Please use language version 'preview' or greater. + Diagnostic(ErrorCode.ERR_LanguageVersionDoesNotSupportInterfaceImplementationForMember, "I1").WithArguments("C2.M01.add", "I1.M01.add", "C5", "static abstract members in interfaces", "10.0", "11.0").WithLocation(10, 23), + // (10,23): error CS8706: 'C2.M01.remove' cannot implement interface member 'I1.M01.remove' in type 'C5' because feature 'static abstract members in interfaces' is not available in C# 10.0. Please use language version '11.0' or greater. // public class C5 : C2, I1 - Diagnostic(ErrorCode.ERR_LanguageVersionDoesNotSupportInterfaceImplementationForMember, "I1").WithArguments("C2.M01.remove", "I1.M01.remove", "C5", "static abstract members in interfaces", "10.0", "preview").WithLocation(10, 23), - // (10,23): error CS8706: 'C2.M01' cannot implement interface member 'I1.M01' in type 'C5' because feature 'static abstract members in interfaces' is not available in C# 10.0. Please use language version 'preview' or greater. + Diagnostic(ErrorCode.ERR_LanguageVersionDoesNotSupportInterfaceImplementationForMember, "I1").WithArguments("C2.M01.remove", "I1.M01.remove", "C5", "static abstract members in interfaces", "10.0", "11.0").WithLocation(10, 23), + // (10,23): error CS8706: 'C2.M01' cannot implement interface member 'I1.M01' in type 'C5' because feature 'static abstract members in interfaces' is not available in C# 10.0. Please use language version '11.0' or greater. // public class C5 : C2, I1 - Diagnostic(ErrorCode.ERR_LanguageVersionDoesNotSupportInterfaceImplementationForMember, "I1").WithArguments("C2.M01", "I1.M01", "C5", "static abstract members in interfaces", "10.0", "preview").WithLocation(10, 23) + Diagnostic(ErrorCode.ERR_LanguageVersionDoesNotSupportInterfaceImplementationForMember, "I1").WithArguments("C2.M01", "I1.M01", "C5", "static abstract members in interfaces", "10.0", "11.0").WithLocation(10, 23) ); } @@ -26214,12 +26214,12 @@ public class C1 : I1 targetFramework: _supportingFramework); compilation1.VerifyEmitDiagnostics( - // (2,19): error CS8706: 'I1.M01.add' cannot implement interface member 'I1.M01.add' in type 'C1' because feature 'static abstract members in interfaces' is not available in C# 10.0. Please use language version 'preview' or greater. + // (2,19): error CS8706: 'I1.M01.add' cannot implement interface member 'I1.M01.add' in type 'C1' because feature 'static abstract members in interfaces' is not available in C# 10.0. Please use language version '11.0' or greater. // public class C1 : I1 - Diagnostic(ErrorCode.ERR_LanguageVersionDoesNotSupportInterfaceImplementationForMember, "I1").WithArguments("I1.M01.add", "I1.M01.add", "C1", "static abstract members in interfaces", "10.0", "preview").WithLocation(2, 19), - // (2,19): error CS8706: 'I1.M01.remove' cannot implement interface member 'I1.M01.remove' in type 'C1' because feature 'static abstract members in interfaces' is not available in C# 10.0. Please use language version 'preview' or greater. + Diagnostic(ErrorCode.ERR_LanguageVersionDoesNotSupportInterfaceImplementationForMember, "I1").WithArguments("I1.M01.add", "I1.M01.add", "C1", "static abstract members in interfaces", "10.0", "11.0").WithLocation(2, 19), + // (2,19): error CS8706: 'I1.M01.remove' cannot implement interface member 'I1.M01.remove' in type 'C1' because feature 'static abstract members in interfaces' is not available in C# 10.0. Please use language version '11.0' or greater. // public class C1 : I1 - Diagnostic(ErrorCode.ERR_LanguageVersionDoesNotSupportInterfaceImplementationForMember, "I1").WithArguments("I1.M01.remove", "I1.M01.remove", "C1", "static abstract members in interfaces", "10.0", "preview").WithLocation(2, 19) + Diagnostic(ErrorCode.ERR_LanguageVersionDoesNotSupportInterfaceImplementationForMember, "I1").WithArguments("I1.M01.remove", "I1.M01.remove", "C1", "static abstract members in interfaces", "10.0", "11.0").WithLocation(2, 19) ); var source2 = @@ -28454,29 +28454,29 @@ public interface I2 where T : I2 if (!isChecked) { compilation2.VerifyDiagnostics( - // (4,21): error CS8652: The feature 'static abstract members in interfaces' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. - // static explicit I2.operator int(Test1 x) => default; - Diagnostic(ErrorCode.ERR_FeatureInPreview, "I2.").WithArguments("static abstract members in interfaces").WithLocation(4, 21), - // (9,37): error CS8706: 'Test2.explicit operator int(Test2)' cannot implement interface member 'I2.explicit operator int(Test2)' in type 'Test2' because feature 'static abstract members in interfaces' is not available in C# 10.0. Please use language version 'preview' or greater. - // public static explicit operator int(Test2 x) => default; - Diagnostic(ErrorCode.ERR_LanguageVersionDoesNotSupportInterfaceImplementationForMember, "int").WithArguments("Test2." + op + " operator int(Test2)", "I2." + op + " operator int(Test2)", "Test2", "static abstract members in interfaces", "10.0", "preview").WithLocation(9, 37) + // (4,21): error CS8936: Feature 'static abstract members in interfaces' is not available in C# 10.0. Please use language version 11.0 or greater. + // static implicit I2.operator int(Test1 x) => default; + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "I2.").WithArguments("static abstract members in interfaces", "11.0").WithLocation(4, 21), + // (9,37): error CS8706: 'Test2.implicit operator int(Test2)' cannot implement interface member 'I2.implicit operator int(Test2)' in type 'Test2' because feature 'static abstract members in interfaces' is not available in C# 10.0. Please use language version '11.0' or greater. + // public static implicit operator int(Test2 x) => default; + Diagnostic(ErrorCode.ERR_LanguageVersionDoesNotSupportInterfaceImplementationForMember, "int").WithArguments("Test2." + op + " operator int(Test2)", "I2." + op + " operator int(Test2)", "Test2", "static abstract members in interfaces", "10.0", "11.0").WithLocation(9, 37) ); } else { compilation2.GetDiagnostics().Where(d => d.Code is not (int)ErrorCode.ERR_CheckedOperatorNeedsMatch).Verify( - // (4,21): error CS8652: The feature 'static abstract members in interfaces' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // (4,21): error CS8936: Feature 'static abstract members in interfaces' is not available in C# 10.0. Please use language version 11.0 or greater. // static explicit I2.operator checked int(Test1 x) => default; - Diagnostic(ErrorCode.ERR_FeatureInPreview, "I2.").WithArguments("static abstract members in interfaces").WithLocation(4, 21), - // (4,40): error CS8652: The feature 'checked user-defined operators' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "I2.").WithArguments("static abstract members in interfaces", "11.0").WithLocation(4, 21), + // (4,40): error CS8936: Feature 'checked user-defined operators' is not available in C# 10.0. Please use language version 11.0 or greater. // static explicit I2.operator checked int(Test1 x) => default; - Diagnostic(ErrorCode.ERR_FeatureInPreview, "checked").WithArguments("checked user-defined operators").WithLocation(4, 40), - // (9,37): error CS8652: The feature 'checked user-defined operators' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "checked").WithArguments("checked user-defined operators", "11.0").WithLocation(4, 40), + // (9,37): error CS8936: Feature 'checked user-defined operators' is not available in C# 10.0. Please use language version 11.0 or greater. // public static explicit operator checked int(Test2 x) => default; - Diagnostic(ErrorCode.ERR_FeatureInPreview, "checked").WithArguments("checked user-defined operators").WithLocation(9, 37), - // (9,45): error CS8706: 'Test2.explicit operator checked int(Test2)' cannot implement interface member 'I2.explicit operator checked int(Test2)' in type 'Test2' because feature 'static abstract members in interfaces' is not available in C# 10.0. Please use language version 'preview' or greater. + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "checked").WithArguments("checked user-defined operators", "11.0").WithLocation(9, 37), + // (9,45): error CS8706: 'Test2.explicit operator checked int(Test2)' cannot implement interface member 'I2.explicit operator checked int(Test2)' in type 'Test2' because feature 'static abstract members in interfaces' is not available in C# 10.0. Please use language version '11.0' or greater. // public static explicit operator checked int(Test2 x) => default; - Diagnostic(ErrorCode.ERR_LanguageVersionDoesNotSupportInterfaceImplementationForMember, "int").WithArguments("Test2." + op + " operator checked int(Test2)", "I2." + op + " operator checked int(Test2)", "Test2", "static abstract members in interfaces", "10.0", "preview").WithLocation(9, 45) + Diagnostic(ErrorCode.ERR_LanguageVersionDoesNotSupportInterfaceImplementationForMember, "int").WithArguments("Test2." + op + " operator checked int(Test2)", "I2." + op + " operator checked int(Test2)", "Test2", "static abstract members in interfaces", "10.0", "11.0").WithLocation(9, 45) ); } @@ -28487,32 +28487,32 @@ public interface I2 where T : I2 if (!isChecked) { compilation3.VerifyDiagnostics( - // (4,21): error CS8652: The feature 'static abstract members in interfaces' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. - // static explicit I2.operator int(Test1 x) => default; - Diagnostic(ErrorCode.ERR_FeatureInPreview, "I2.").WithArguments("static abstract members in interfaces").WithLocation(4, 21), - // (14,39): error CS8703: The modifier 'abstract' is not valid for this item in C# 10.0. Please use language version 'preview' or greater. - // abstract static explicit operator int(T x); - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "int").WithArguments(modifier.Trim(), "10.0", "preview").WithLocation(14, 39) + // (4,21): error CS8936: Feature 'static abstract members in interfaces' is not available in C# 10.0. Please use language version 11.0 or greater. + // static implicit I2.operator int(Test1 x) => default; + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "I2.").WithArguments("static abstract members in interfaces", "11.0").WithLocation(4, 21), + // (14,39): error CS8703: The modifier 'virtual' is not valid for this item in C# 10.0. Please use language version '11.0' or greater. + // virtual static implicit operator int(T x) => throw null; + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "int").WithArguments(modifier.Trim(), "10.0", "11.0").WithLocation(14, 39) ); } else { compilation3.GetDiagnostics().Where(d => d.Code is not (int)ErrorCode.ERR_CheckedOperatorNeedsMatch).Verify( - // (4,21): error CS8652: The feature 'static abstract members in interfaces' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // (4,21): error CS8936: Feature 'static abstract members in interfaces' is not available in C# 10.0. Please use language version 11.0 or greater. // static explicit I2.operator checked int(Test1 x) => default; - Diagnostic(ErrorCode.ERR_FeatureInPreview, "I2.").WithArguments("static abstract members in interfaces").WithLocation(4, 21), - // (4,40): error CS8652: The feature 'checked user-defined operators' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "I2.").WithArguments("static abstract members in interfaces", "11.0").WithLocation(4, 21), + // (4,40): error CS8936: Feature 'checked user-defined operators' is not available in C# 10.0. Please use language version 11.0 or greater. // static explicit I2.operator checked int(Test1 x) => default; - Diagnostic(ErrorCode.ERR_FeatureInPreview, "checked").WithArguments("checked user-defined operators").WithLocation(4, 40), - // (9,37): error CS8652: The feature 'checked user-defined operators' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "checked").WithArguments("checked user-defined operators", "11.0").WithLocation(4, 40), + // (9,37): error CS8936: Feature 'checked user-defined operators' is not available in C# 10.0. Please use language version 11.0 or greater. // public static explicit operator checked int(Test2 x) => default; - Diagnostic(ErrorCode.ERR_FeatureInPreview, "checked").WithArguments("checked user-defined operators").WithLocation(9, 37), - // (14,39): error CS8652: The feature 'checked user-defined operators' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "checked").WithArguments("checked user-defined operators", "11.0").WithLocation(9, 37), + // (14,39): error CS8936: Feature 'checked user-defined operators' is not available in C# 10.0. Please use language version 11.0 or greater. // abstract static explicit operator checked int(T x); - Diagnostic(ErrorCode.ERR_FeatureInPreview, "checked").WithArguments("checked user-defined operators").WithLocation(14, 39), - // (14,47): error CS8703: The modifier 'abstract' is not valid for this item in C# 10.0. Please use language version 'preview' or greater. + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "checked").WithArguments("checked user-defined operators", "11.0").WithLocation(14, 39), + // (14,47): error CS8703: The modifier 'abstract' is not valid for this item in C# 10.0. Please use language version '11.0' or greater. // abstract static explicit operator checked int(T x); - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "int").WithArguments(modifier.Trim(), "10.0", "preview").WithLocation(14, 47) + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "int").WithArguments(modifier.Trim(), "10.0", "11.0").WithLocation(14, 47) ); } } @@ -29071,9 +29071,9 @@ public class C5 : C2, I1 targetFramework: _supportingFramework); compilation1.VerifyDiagnostics( - // (10,23): error CS8706: 'C2.explicit operator int(C1)' cannot implement interface member 'I1.explicit operator int(C1)' in type 'C5' because feature 'static abstract members in interfaces' is not available in C# 10.0. Please use language version 'preview' or greater. + // (10,23): error CS8706: 'C2.implicit operator int(C1)' cannot implement interface member 'I1.implicit operator int(C1)' in type 'C5' because feature 'static abstract members in interfaces' is not available in C# 10.0. Please use language version '11.0' or greater. // public class C5 : C2, I1 - Diagnostic(ErrorCode.ERR_LanguageVersionDoesNotSupportInterfaceImplementationForMember, "I1").WithArguments("C2." + op + " operator " + checkedKeyword + "int(C1)", "I1." + op + " operator " + checkedKeyword + "int(C1)", "C5", "static abstract members in interfaces", "10.0", "preview").WithLocation(10, 23) + Diagnostic(ErrorCode.ERR_LanguageVersionDoesNotSupportInterfaceImplementationForMember, "I1").WithArguments("C2." + op + " operator " + checkedKeyword + "int(C1)", "I1." + op + " operator " + checkedKeyword + "int(C1)", "C5", "static abstract members in interfaces", "10.0", "11.0").WithLocation(10, 23) ); } @@ -29131,9 +29131,9 @@ public class C1 : I1 targetFramework: _supportingFramework); compilation1.VerifyEmitDiagnostics( - // (2,19): error CS8706: 'I1.explicit operator int(C1)' cannot implement interface member 'I1.explicit operator int(C1)' in type 'C1' because feature 'static abstract members in interfaces' is not available in C# 10.0. Please use language version 'preview' or greater. + // (2,19): error CS8706: 'I1.implicit operator int(C1)' cannot implement interface member 'I1.implicit operator int(C1)' in type 'C1' because feature 'static abstract members in interfaces' is not available in C# 10.0. Please use language version '11.0' or greater. // public class C1 : I1 - Diagnostic(ErrorCode.ERR_LanguageVersionDoesNotSupportInterfaceImplementationForMember, "I1").WithArguments("I1." + op + " operator " + checkedKeyword + "int(C1)", "I1." + op + " operator " + checkedKeyword + "int(C1)", "C1", "static abstract members in interfaces", "10.0", "preview").WithLocation(2, 19) + Diagnostic(ErrorCode.ERR_LanguageVersionDoesNotSupportInterfaceImplementationForMember, "I1").WithArguments("I1." + op + " operator " + checkedKeyword + "int(C1)", "I1." + op + " operator " + checkedKeyword + "int(C1)", "C1", "static abstract members in interfaces", "10.0", "11.0").WithLocation(2, 19) ); var source2 = @@ -30668,20 +30668,20 @@ static int M02(T x) where T : I1 if (isChecked) { compilation2.VerifyDiagnostics( - // (6,16): error CS8652: The feature 'static abstract members in interfaces' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. - // return x; - Diagnostic(ErrorCode.ERR_FeatureInPreview, (needCast ? "(int)" : "") + "x").WithArguments("static abstract members in interfaces").WithLocation(6, 16), - // (6,16): error CS8652: The feature 'checked user-defined operators' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // (6,16): error CS8936: Feature 'static abstract members in interfaces' is not available in C# 10.0. Please use language version 11.0 or greater. // return (int)x; - Diagnostic(ErrorCode.ERR_FeatureInPreview, "(int)x").WithArguments("checked user-defined operators").WithLocation(6, 16) + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, (needCast ? "(int)" : "") + "x").WithArguments("static abstract members in interfaces", "11.0").WithLocation(6, 16), + // (6,16): error CS8936: Feature 'checked user-defined operators' is not available in C# 10.0. Please use language version 11.0 or greater. + // return (int)x; + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "(int)x").WithArguments("checked user-defined operators", "11.0").WithLocation(6, 16) ); } else { compilation2.VerifyDiagnostics( - // (6,16): error CS8652: The feature 'static abstract members in interfaces' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // (6,16): error CS8936: Feature 'static abstract members in interfaces' is not available in C# 10.0. Please use language version 11.0 or greater. // return x; - Diagnostic(ErrorCode.ERR_FeatureInPreview, (needCast ? "(int)" : "") + "x").WithArguments("static abstract members in interfaces").WithLocation(6, 16) + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, (needCast ? "(int)" : "") + "x").WithArguments("static abstract members in interfaces", "11.0").WithLocation(6, 16) ); } @@ -30692,20 +30692,20 @@ static int M02(T x) where T : I1 if (isChecked) { compilation3.GetDiagnostics().Where(d => d.Code is not (int)ErrorCode.ERR_CheckedOperatorNeedsMatch).Verify( - // (12,40): error CS8652: The feature 'checked user-defined operators' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. - // abstract static explicit operator checked int(T x); - Diagnostic(ErrorCode.ERR_FeatureInPreview, "checked").WithArguments("checked user-defined operators").WithLocation(12, 40), - // (12,48): error CS8703: The modifier 'abstract' is not valid for this item in C# 10.0. Please use language version 'preview' or greater. - // abstract static explicit operator checked int(T x); - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "int").WithArguments(modifier.Trim(), "10.0", "preview").WithLocation(12, 48) + // (12,40): error CS8936: Feature 'checked user-defined operators' is not available in C# 10.0. Please use language version 11.0 or greater. + // virtual static explicit operator checked int(T x) => throw null; + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "checked").WithArguments("checked user-defined operators", "11.0").WithLocation(12, 40), + // (12,48): error CS8703: The modifier 'virtual' is not valid for this item in C# 10.0. Please use language version '11.0' or greater. + // virtual static explicit operator checked int(T x) => throw null; + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "int").WithArguments(modifier.Trim(), "10.0", "11.0").WithLocation(12, 48) ); } else { compilation3.VerifyDiagnostics( - // (12,39): error CS8703: The modifier 'abstract' is not valid for this item in C# 10.0. Please use language version 'preview' or greater. - // abstract static implicit operator int(T x); - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "int").WithArguments(modifier.Trim(), "10.0", "preview").WithLocation(12, 39) + // (12,39): error CS8703: The modifier 'virtual' is not valid for this item in C# 10.0. Please use language version '11.0' or greater. + // virtual static implicit operator int(T x) => throw null; + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "int").WithArguments(modifier.Trim(), "10.0", "11.0").WithLocation(12, 39) ); } } @@ -30752,9 +30752,9 @@ class C references: new[] { compilation1.ToMetadataReference() }); compilation2.VerifyDiagnostics( - // (6,13): error CS8652: The feature 'static abstract members in interfaces' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // (6,13): error CS8936: Feature 'static abstract members in interfaces' is not available in C# 10.0. Please use language version 11.0 or greater. // _ = x == x; - Diagnostic(ErrorCode.ERR_FeatureInPreview, "x " + op + " x").WithArguments("static abstract members in interfaces").WithLocation(6, 13) + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "x " + op + " x").WithArguments("static abstract members in interfaces", "11.0").WithLocation(6, 13) ); var compilation3 = CreateCompilation(source2 + source1, options: TestOptions.DebugDll, @@ -30762,9 +30762,9 @@ class C targetFramework: _supportingFramework); compilation3.VerifyDiagnostics( - // (21,39): error CS8703: The modifier 'abstract' is not valid for this item in C# 10.0. Please use language version 'preview' or greater. - // abstract static implicit operator bool(T x); - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "bool").WithArguments(modifier.Trim(), "10.0", "preview").WithLocation(21, 39) + // (21,39): error CS8703: The modifier 'virtual' is not valid for this item in C# 10.0. Please use language version '11.0' or greater. + // virtual static implicit operator bool(T x) => throw null; + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "bool").WithArguments(modifier.Trim(), "10.0", "11.0").WithLocation(21, 39) ); } diff --git a/src/Compilers/CSharp/Test/Symbol/Symbols/SymbolErrorTests.cs b/src/Compilers/CSharp/Test/Symbol/Symbols/SymbolErrorTests.cs index 11b3b08c47a4b..7278d0687bde6 100644 --- a/src/Compilers/CSharp/Test/Symbol/Symbols/SymbolErrorTests.cs +++ b/src/Compilers/CSharp/Test/Symbol/Symbols/SymbolErrorTests.cs @@ -10583,21 +10583,21 @@ class C2 comp = CreateCompilation(text, parseOptions: TestOptions.Regular10); comp.VerifyDiagnostics( - // (4,32): error CS8652: The feature 'relaxed shift operator' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // (4,32): error CS8936: Feature 'relaxed shift operator' is not available in C# 10.0. Please use language version 11.0 or greater. // public static int operator <<(C c1, C c2) // CS0564 - Diagnostic(ErrorCode.ERR_FeatureInPreview, "<<").WithArguments("relaxed shift operator").WithLocation(4, 32), + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "<<").WithArguments("relaxed shift operator", "11.0").WithLocation(4, 32), // (8,32): error CS0564: The first operand of an overloaded shift operator must have the same type as the containing type // public static int operator >>(int c1, int c2) // CS0564 Diagnostic(ErrorCode.ERR_BadShiftOperatorSignature, ">>").WithLocation(8, 32), - // (12,32): error CS8652: The feature 'unsigned right shift' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // (12,32): error CS8936: Feature 'unsigned right shift' is not available in C# 10.0. Please use language version 11.0 or greater. // public static int operator >>>(int c1, int c2) // CS0564 - Diagnostic(ErrorCode.ERR_FeatureInPreview, ">>>").WithArguments("unsigned right shift").WithLocation(12, 32), - // (12,32): error CS0564: The first operand of an overloaded shift operator must have the same type as the containing type, and the type of the second operand must be int + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, ">>>").WithArguments("unsigned right shift", "11.0").WithLocation(12, 32), + // (12,32): error CS0564: The first operand of an overloaded shift operator must have the same type as the containing type // public static int operator >>>(int c1, int c2) // CS0564 Diagnostic(ErrorCode.ERR_BadShiftOperatorSignature, ">>>").WithLocation(12, 32) ); - comp = CreateCompilation(text, parseOptions: TestOptions.RegularNext); + comp = CreateCompilation(text, parseOptions: TestOptions.Regular11); comp.VerifyDiagnostics( // (8,32): error CS0564: The first operand of an overloaded shift operator must have the same type as the containing type // public static int operator >>(int c1, int c2) // CS0564 @@ -12622,10 +12622,10 @@ public void CS0698ERR_GenericDerivingFromAttribute01() { } "; - CreateCompilation(text, parseOptions: TestOptions.Regular9).VerifyDiagnostics( - // (1,14): error CS8652: The feature 'generic attributes' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + CreateCompilation(text, parseOptions: TestOptions.Regular10).VerifyDiagnostics( + // (1,14): error CS8936: Feature 'generic attributes' is not available in C# 10.0. Please use language version 11.0 or greater. // class C : System.Attribute - Diagnostic(ErrorCode.ERR_FeatureInPreview, "System.Attribute").WithArguments("generic attributes").WithLocation(1, 14)); + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "System.Attribute").WithArguments("generic attributes", "11.0").WithLocation(1, 14)); } [Fact] @@ -12638,13 +12638,13 @@ class C { class B : A { } }"; - CreateCompilation(text, parseOptions: TestOptions.Regular9).VerifyDiagnostics( - // (2,14): error CS8652: The feature 'generic attributes' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + CreateCompilation(text, parseOptions: TestOptions.Regular10).VerifyDiagnostics( + // (2,14): error CS8936: Feature 'generic attributes' is not available in C# 10.0. Please use language version 11.0 or greater. // class B : A { } - Diagnostic(ErrorCode.ERR_FeatureInPreview, "A").WithArguments("generic attributes").WithLocation(2, 14), - // (5,15): error CS8652: The feature 'generic attributes' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "A").WithArguments("generic attributes", "11.0").WithLocation(2, 14), + // (5,15): error CS8936: Feature 'generic attributes' is not available in C# 10.0. Please use language version 11.0 or greater. // class B : A { } - Diagnostic(ErrorCode.ERR_FeatureInPreview, "A").WithArguments("generic attributes").WithLocation(5, 15)); + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "A").WithArguments("generic attributes", "11.0").WithLocation(5, 15)); } [Fact] @@ -21067,10 +21067,10 @@ class cédille { } var comp = CreateCompilation(text, parseOptions: TestOptions.Regular10); comp.VerifyDiagnostics(expected); - comp = CreateCompilation(text, parseOptions: TestOptions.RegularNext, options: TestOptions.DebugDll.WithWarningLevel(6)); + comp = CreateCompilation(text, parseOptions: TestOptions.Regular11, options: TestOptions.DebugDll.WithWarningLevel(6)); comp.VerifyDiagnostics(); - comp = CreateCompilation(text, parseOptions: TestOptions.RegularNext, options: TestOptions.DebugDll.WithWarningLevel(7)); + comp = CreateCompilation(text, parseOptions: TestOptions.Regular11, options: TestOptions.DebugDll.WithWarningLevel(7)); comp.VerifyDiagnostics(expected); } @@ -21128,10 +21128,10 @@ void local4() { } var comp = CreateCompilation(text, parseOptions: TestOptions.Regular10); comp.VerifyDiagnostics(expected); - comp = CreateCompilation(text, parseOptions: TestOptions.RegularNext, options: TestOptions.DebugDll.WithWarningLevel(6)); + comp = CreateCompilation(text, parseOptions: TestOptions.Regular11, options: TestOptions.DebugDll.WithWarningLevel(6)); comp.VerifyDiagnostics(); - comp = CreateCompilation(text, parseOptions: TestOptions.RegularNext, options: TestOptions.DebugDll.WithWarningLevel(7)); + comp = CreateCompilation(text, parseOptions: TestOptions.Regular11, options: TestOptions.DebugDll.WithWarningLevel(7)); comp.VerifyDiagnostics(expected); } @@ -21173,7 +21173,7 @@ public void DisallowLowerCaseTypeName_AsAlias() var comp = CreateCompilation(text, parseOptions: TestOptions.Regular10); comp.VerifyDiagnostics(expected); - comp = CreateCompilation(text, parseOptions: TestOptions.RegularNext, options: TestOptions.DebugDll.WithWarningLevel(6)); + comp = CreateCompilation(text, parseOptions: TestOptions.Regular11, options: TestOptions.DebugDll.WithWarningLevel(6)); comp.VerifyDiagnostics( // (2,1): hidden CS8019: Unnecessary using directive. // using one = System.Console; @@ -21192,7 +21192,7 @@ public void DisallowLowerCaseTypeName_AsAlias() Diagnostic(ErrorCode.HDN_UnusedUsingDirective, "using cédille = System.Console;").WithLocation(6, 1) ); - comp = CreateCompilation(text, parseOptions: TestOptions.RegularNext, options: TestOptions.DebugDll.WithWarningLevel(7)); + comp = CreateCompilation(text, parseOptions: TestOptions.Regular11, options: TestOptions.DebugDll.WithWarningLevel(7)); comp.VerifyDiagnostics(expected); } @@ -21215,7 +21215,7 @@ class \u00B5 { } class \u00c0 { } "; - var comp = CreateCompilation(text, parseOptions: TestOptions.RegularNext, options: TestOptions.DebugDll.WithWarningLevel(7)); + var comp = CreateCompilation(text, parseOptions: TestOptions.Regular11, options: TestOptions.DebugDll.WithWarningLevel(7)); comp.VerifyDiagnostics( // (2,7): warning CS8981: The type name 'a' only contains lower-cased ascii characters. Such names may become reserved for the language. // class a { } @@ -21233,7 +21233,7 @@ class \u00c0 { } class \u0060 { } "; - comp = CreateCompilation(text, parseOptions: TestOptions.RegularNext, options: TestOptions.DebugDll.WithWarningLevel(7)); + comp = CreateCompilation(text, parseOptions: TestOptions.Regular11, options: TestOptions.DebugDll.WithWarningLevel(7)); comp.VerifyDiagnostics( // (3,7): error CS1001: Identifier expected // class \u0060 { } @@ -21260,7 +21260,7 @@ class \u0060 { } class \u007c { } "; - comp = CreateCompilation(text, parseOptions: TestOptions.RegularNext, options: TestOptions.DebugDll.WithWarningLevel(7)); + comp = CreateCompilation(text, parseOptions: TestOptions.Regular11, options: TestOptions.DebugDll.WithWarningLevel(7)); comp.VerifyDiagnostics( // (3,7): error CS1001: Identifier expected // class \u007c { } @@ -21845,5 +21845,180 @@ string featureName Diagnostic(ErrorCode.ERR_UnsupportedCompilerFeature, "C1").WithArguments("C1", "SomeFeatureIsRequired").WithLocation(4, 35) ); } + + [Fact] + public void PartialConstructor() + { + CreateCompilation(new[] + { + """ + public class PartialCtor + { + partial PartialCtor() { } + } + """, + """ + public class PublicPartialCtor + { + public partial PublicPartialCtor() { } + } + """, + """ + public class PartialPublicCtor + { + 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. + // 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 + // 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 + // 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 + // 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 + // public partial PublicPartialCtor() { } + Diagnostic(ErrorCode.ERR_ReturnExpected, "PublicPartialCtor").WithArguments("PublicPartialCtor.PublicPartialCtor()").WithLocation(3, 20)); + } + + [Fact] + public void PartialStaticConstructor() + { + CreateCompilation(new[] + { + """ + public class PartialStaticCtor + { + partial static PartialStaticCtor() { } + } + """, + """ + public class StaticPartialCtor + { + static partial StaticPartialCtor() { } + } + """, + """ + public class PublicStaticPartialCtor + { + public static partial PublicStaticPartialCtor() { } + } + """, + """ + public class PublicPartialStaticCtor + { + public partial static PublicPartialStaticCtor() { } + } + """, + """ + public class StaticPublicPartialCtor + { + static public partial StaticPublicPartialCtor() { } + } + """, + """ + public class StaticPartialPublicCtor + { + static partial public StaticPartialPublicCtor() { } + } + """, + """ + public class PartialStaticPublicCtor + { + partial static public PartialStaticPublicCtor() { } + } + """, + """ + public class PartialPublicStaticCtor + { + 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. + // 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. + // 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. + // 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 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. + // 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. + // 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. + // 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. + // 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?) + // 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?) + // 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 + // 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 + // 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 + // 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 + // 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)); + } } } diff --git a/src/Compilers/CSharp/Test/Symbol/Symbols/UnsignedRightShiftTests.cs b/src/Compilers/CSharp/Test/Symbol/Symbols/UnsignedRightShiftTests.cs index d13cb91d68d30..65e7f13d86641 100644 --- a/src/Compilers/CSharp/Test/Symbol/Symbols/UnsignedRightShiftTests.cs +++ b/src/Compilers/CSharp/Test/Symbol/Symbols/UnsignedRightShiftTests.cs @@ -395,7 +395,7 @@ static void Main() compilation1.VerifyEmitDiagnostics(expected); compilation1 = CreateCompilation(source1, options: TestOptions.DebugDll, - parseOptions: TestOptions.RegularNext); + parseOptions: TestOptions.Regular11); compilation1.VerifyEmitDiagnostics(expected); } @@ -898,7 +898,7 @@ static void Main() compilation1.VerifyEmitDiagnostics(expected); compilation1 = CreateCompilation(source1, options: TestOptions.DebugDll, - parseOptions: TestOptions.RegularNext); + parseOptions: TestOptions.Regular11); compilation1.VerifyEmitDiagnostics(expected); } @@ -1013,7 +1013,7 @@ static void Main(dynamic x, int y) compilation1.VerifyEmitDiagnostics(expected); compilation1 = CreateCompilation(source1, options: TestOptions.DebugDll, - parseOptions: TestOptions.RegularNext); + parseOptions: TestOptions.Regular11); compilation1.VerifyEmitDiagnostics(expected); } @@ -1054,7 +1054,7 @@ static void Main(dynamic x, int y) compilation1.VerifyEmitDiagnostics(expected); compilation1 = CreateCompilation(source1, options: TestOptions.DebugDll, - parseOptions: TestOptions.RegularNext); + parseOptions: TestOptions.Regular11); compilation1.VerifyEmitDiagnostics(expected); } @@ -1452,7 +1452,7 @@ static void Main() compilation1.VerifyEmitDiagnostics(expected); compilation1 = CreateCompilation(source1, options: TestOptions.DebugDll, - parseOptions: TestOptions.RegularNext); + parseOptions: TestOptions.Regular11); compilation1.VerifyEmitDiagnostics(expected); } @@ -1860,7 +1860,7 @@ static void Main() compilation1.VerifyEmitDiagnostics(expected); compilation1 = CreateCompilation(source1, options: TestOptions.DebugDll, - parseOptions: TestOptions.RegularNext); + parseOptions: TestOptions.Regular11); compilation1.VerifyEmitDiagnostics(expected); } @@ -2715,12 +2715,12 @@ class C // (3,20): warning CS1584: XML comment has syntactically incorrect cref attribute 'operator >>>' // /// See . Diagnostic(ErrorCode.WRN_BadXMLRefSyntax, "operator >>>").WithArguments("operator >>>").WithLocation(3, 20), - // (3,29): warning CS1658: The feature 'unsigned right shift' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.. See also error CS8652. + // (3,29): warning CS1658: Feature 'unsigned right shift' is not available in C# 10.0. Please use language version 11.0 or greater.. See also error CS8936. // /// See . - Diagnostic(ErrorCode.WRN_ErrorOverride, ">>>").WithArguments("The feature 'unsigned right shift' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.", "8652").WithLocation(3, 29), - // (7,30): error CS8652: The feature 'unsigned right shift' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + Diagnostic(ErrorCode.WRN_ErrorOverride, ">>>").WithArguments("Feature 'unsigned right shift' is not available in C# 10.0. Please use language version 11.0 or greater.", "8936").WithLocation(3, 29), + // (7,30): error CS8936: Feature 'unsigned right shift' is not available in C# 10.0. Please use language version 11.0 or greater. // public static C operator >>>(C c, int y) - Diagnostic(ErrorCode.ERR_FeatureInPreview, ">>>").WithArguments("unsigned right shift").WithLocation(7, 30) + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, ">>>").WithArguments("unsigned right shift", "11.0").WithLocation(7, 30) ); crefSyntax = CrefTests.GetCrefSyntaxes(compilation).Single(); @@ -2728,7 +2728,7 @@ class C actualSymbol = CrefTests.GetReferencedSymbol(crefSyntax, compilation); Assert.Equal(expectedSymbol, actualSymbol); - compilation = CreateCompilationWithMscorlib40AndDocumentationComments(source, parseOptions: TestOptions.RegularNext.WithDocumentationMode(DocumentationMode.Diagnose)); + compilation = CreateCompilationWithMscorlib40AndDocumentationComments(source, parseOptions: TestOptions.Regular11.WithDocumentationMode(DocumentationMode.Diagnose)); compilation.VerifyDiagnostics(); crefSyntax = CrefTests.GetCrefSyntaxes(compilation).Single(); @@ -2887,12 +2887,12 @@ class C // (3,20): warning CS1584: XML comment has syntactically incorrect cref attribute 'operator >>>(C, int)' // /// See . Diagnostic(ErrorCode.WRN_BadXMLRefSyntax, "operator >>>(C, int)").WithArguments("operator >>>(C, int)").WithLocation(3, 20), - // (3,29): warning CS1658: The feature 'unsigned right shift' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.. See also error CS8652. + // (3,29): warning CS1658: Feature 'unsigned right shift' is not available in C# 10.0. Please use language version 11.0 or greater.. See also error CS8936. // /// See . - Diagnostic(ErrorCode.WRN_ErrorOverride, ">>>").WithArguments("The feature 'unsigned right shift' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.", "8652").WithLocation(3, 29), - // (7,30): error CS8652: The feature 'unsigned right shift' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + Diagnostic(ErrorCode.WRN_ErrorOverride, ">>>").WithArguments("Feature 'unsigned right shift' is not available in C# 10.0. Please use language version 11.0 or greater.", "8936").WithLocation(3, 29), + // (7,30): error CS8936: Feature 'unsigned right shift' is not available in C# 10.0. Please use language version 11.0 or greater. // public static C operator >>>(C c, int y) - Diagnostic(ErrorCode.ERR_FeatureInPreview, ">>>").WithArguments("unsigned right shift").WithLocation(7, 30) + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, ">>>").WithArguments("unsigned right shift", "11.0").WithLocation(7, 30) ); crefSyntax = CrefTests.GetCrefSyntaxes(compilation).Single(); @@ -2900,7 +2900,7 @@ class C actualSymbol = CrefTests.GetReferencedSymbol(crefSyntax, compilation); Assert.Equal(expectedSymbol, actualSymbol); - compilation = CreateCompilationWithMscorlib40AndDocumentationComments(source, parseOptions: TestOptions.RegularNext.WithDocumentationMode(DocumentationMode.Diagnose)); + compilation = CreateCompilationWithMscorlib40AndDocumentationComments(source, parseOptions: TestOptions.Regular11.WithDocumentationMode(DocumentationMode.Diagnose)); compilation.VerifyDiagnostics(); crefSyntax = CrefTests.GetCrefSyntaxes(compilation).Single(); @@ -3115,13 +3115,13 @@ static void Main() var compilation1 = CreateCompilation(source1, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular10); compilation1.VerifyDiagnostics( - // (8,13): error CS8652: The feature 'unsigned right shift' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // (8,13): error CS8936: Feature 'unsigned right shift' is not available in C# 10.0. Please use language version 11.0 or greater. // _ = x >>> y; - Diagnostic(ErrorCode.ERR_FeatureInPreview, "x >>> y").WithArguments("unsigned right shift").WithLocation(8, 13) + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "x >>> y").WithArguments("unsigned right shift", "11.0").WithLocation(8, 13) ); var compilation2 = CreateCompilation(source1, options: TestOptions.DebugExe, - parseOptions: TestOptions.RegularNext); + parseOptions: TestOptions.Regular11); compilation2.VerifyDiagnostics(); } @@ -3209,13 +3209,13 @@ static void Main() var compilation1 = CreateCompilation(source1, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular10); compilation1.VerifyDiagnostics( - // (8,9): error CS8652: The feature 'unsigned right shift' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // (8,9): error CS8936: Feature 'unsigned right shift' is not available in C# 10.0. Please use language version 11.0 or greater. // x >>>= y; - Diagnostic(ErrorCode.ERR_FeatureInPreview, "x >>>= y").WithArguments("unsigned right shift").WithLocation(8, 9) + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "x >>>= y").WithArguments("unsigned right shift", "11.0").WithLocation(8, 9) ); var compilation2 = CreateCompilation(source1, options: TestOptions.DebugExe, - parseOptions: TestOptions.RegularNext); + parseOptions: TestOptions.Regular11); compilation2.VerifyDiagnostics(); } @@ -3303,13 +3303,13 @@ static void Main() var compilation1 = CreateCompilation(source1, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular10); compilation1.VerifyDiagnostics( - // (8,13): error CS8652: The feature 'unsigned right shift' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // (8,13): error CS8936: Feature 'unsigned right shift' is not available in C# 10.0. Please use language version 11.0 or greater. // _ = x >>> y; - Diagnostic(ErrorCode.ERR_FeatureInPreview, "x >>> y").WithArguments("unsigned right shift").WithLocation(8, 13) + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "x >>> y").WithArguments("unsigned right shift", "11.0").WithLocation(8, 13) ); var compilation2 = CreateCompilation(source1, options: TestOptions.DebugExe, - parseOptions: TestOptions.RegularNext); + parseOptions: TestOptions.Regular11); compilation2.VerifyDiagnostics(); } @@ -3397,13 +3397,13 @@ static void Main() var compilation1 = CreateCompilation(source1, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular10); compilation1.VerifyDiagnostics( - // (8,9): error CS8652: The feature 'unsigned right shift' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // (8,9): error CS8936: Feature 'unsigned right shift' is not available in C# 10.0. Please use language version 11.0 or greater. // x >>>= y; - Diagnostic(ErrorCode.ERR_FeatureInPreview, "x >>>= y").WithArguments("unsigned right shift").WithLocation(8, 9) + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "x >>>= y").WithArguments("unsigned right shift", "11.0").WithLocation(8, 9) ); var compilation2 = CreateCompilation(source1, options: TestOptions.DebugExe, - parseOptions: TestOptions.RegularNext); + parseOptions: TestOptions.Regular11); compilation2.VerifyDiagnostics(); } @@ -3431,13 +3431,13 @@ class C var compilation1 = CreateCompilation(source0 + source1, options: TestOptions.DebugDll, parseOptions: TestOptions.Regular10); compilation1.VerifyDiagnostics( - // (4,31): error CS8652: The feature 'unsigned right shift' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // (4,31): error CS8936: Feature 'unsigned right shift' is not available in C# 10.0. Please use language version 11.0 or greater. // public static C1 operator >>>(C1 x, int y) - Diagnostic(ErrorCode.ERR_FeatureInPreview, ">>>").WithArguments("unsigned right shift").WithLocation(4, 31) + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, ">>>").WithArguments("unsigned right shift", "11.0").WithLocation(4, 31) ); compilation1 = CreateCompilation(source0 + source1, options: TestOptions.DebugDll, - parseOptions: TestOptions.RegularNext); + parseOptions: TestOptions.Regular11); compilation1.VerifyDiagnostics(); var compilation0 = CreateCompilation(source0, options: TestOptions.DebugDll, @@ -3448,13 +3448,13 @@ class C var compilation2 = CreateCompilation(source1, options: TestOptions.DebugDll, references: new[] { reference }, parseOptions: TestOptions.Regular10); compilation2.VerifyDiagnostics( - // (4,37): error CS8652: The feature 'unsigned right shift' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // (4,37): error CS8936: Feature 'unsigned right shift' is not available in C# 10.0. Please use language version 11.0 or greater. // static C1 Test1(C1 x, int y) => x >>> y; - Diagnostic(ErrorCode.ERR_FeatureInPreview, "x >>> y").WithArguments("unsigned right shift").WithLocation(4, 37) + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "x >>> y").WithArguments("unsigned right shift", "11.0").WithLocation(4, 37) ); compilation2 = CreateCompilation(source1, options: TestOptions.DebugDll, references: new[] { reference }, - parseOptions: TestOptions.RegularNext); + parseOptions: TestOptions.Regular11); compilation2.VerifyDiagnostics(); } } @@ -3483,13 +3483,13 @@ class C var compilation1 = CreateCompilation(source0 + source1, options: TestOptions.DebugDll, parseOptions: TestOptions.Regular10); compilation1.VerifyDiagnostics( - // (4,31): error CS8652: The feature 'unsigned right shift' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // (4,31): error CS8936: Feature 'unsigned right shift' is not available in C# 10.0. Please use language version 11.0 or greater. // public static C1 operator >>>(C1 x, int y) - Diagnostic(ErrorCode.ERR_FeatureInPreview, ">>>").WithArguments("unsigned right shift").WithLocation(4, 31) + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, ">>>").WithArguments("unsigned right shift", "11.0").WithLocation(4, 31) ); compilation1 = CreateCompilation(source0 + source1, options: TestOptions.DebugDll, - parseOptions: TestOptions.RegularNext); + parseOptions: TestOptions.Regular11); compilation1.VerifyDiagnostics(); var compilation0 = CreateCompilation(source0, options: TestOptions.DebugDll, @@ -3500,13 +3500,13 @@ class C var compilation2 = CreateCompilation(source1, options: TestOptions.DebugDll, references: new[] { reference }, parseOptions: TestOptions.Regular10); compilation2.VerifyDiagnostics( - // (4,37): error CS8652: The feature 'unsigned right shift' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // (4,37): error CS8936: Feature 'unsigned right shift' is not available in C# 10.0. Please use language version 11.0 or greater. // static C1 Test1(C1 x, int y) => x >>>= y; - Diagnostic(ErrorCode.ERR_FeatureInPreview, "x >>>= y").WithArguments("unsigned right shift").WithLocation(4, 37) + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "x >>>= y").WithArguments("unsigned right shift", "11.0").WithLocation(4, 37) ); compilation2 = CreateCompilation(source1, options: TestOptions.DebugDll, references: new[] { reference }, - parseOptions: TestOptions.RegularNext); + parseOptions: TestOptions.Regular11); compilation2.VerifyDiagnostics(); } } @@ -3535,13 +3535,13 @@ class C var compilation1 = CreateCompilation(source0 + source1, options: TestOptions.DebugDll, parseOptions: TestOptions.Regular10); compilation1.VerifyDiagnostics( - // (4,31): error CS8652: The feature 'unsigned right shift' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // (4,31): error CS8936: Feature 'unsigned right shift' is not available in C# 10.0. Please use language version 11.0 or greater. // public static C1 operator >>>(C1 x, int y) - Diagnostic(ErrorCode.ERR_FeatureInPreview, ">>>").WithArguments("unsigned right shift").WithLocation(4, 31) + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, ">>>").WithArguments("unsigned right shift", "11.0").WithLocation(4, 31) ); compilation1 = CreateCompilation(source0 + source1, options: TestOptions.DebugDll, - parseOptions: TestOptions.RegularNext); + parseOptions: TestOptions.Regular11); compilation1.VerifyDiagnostics(); var compilation0 = CreateCompilation(source0, options: TestOptions.DebugDll, @@ -3552,13 +3552,13 @@ class C var compilation2 = CreateCompilation(source1, options: TestOptions.DebugDll, references: new[] { reference }, parseOptions: TestOptions.Regular10); compilation2.VerifyDiagnostics( - // (4,40): error CS8652: The feature 'unsigned right shift' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // (4,40): error CS8936: Feature 'unsigned right shift' is not available in C# 10.0. Please use language version 11.0 or greater. // static C1? Test1(C1? x, int? y) => x >>> y; - Diagnostic(ErrorCode.ERR_FeatureInPreview, "x >>> y").WithArguments("unsigned right shift").WithLocation(4, 40) + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "x >>> y").WithArguments("unsigned right shift", "11.0").WithLocation(4, 40) ); compilation2 = CreateCompilation(source1, options: TestOptions.DebugDll, references: new[] { reference }, - parseOptions: TestOptions.RegularNext); + parseOptions: TestOptions.Regular11); compilation2.VerifyDiagnostics(); } } @@ -3587,13 +3587,13 @@ class C var compilation1 = CreateCompilation(source0 + source1, options: TestOptions.DebugDll, parseOptions: TestOptions.Regular10); compilation1.VerifyDiagnostics( - // (4,31): error CS8652: The feature 'unsigned right shift' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // (4,31): error CS8936: Feature 'unsigned right shift' is not available in C# 10.0. Please use language version 11.0 or greater. // public static C1 operator >>>(C1 x, int y) - Diagnostic(ErrorCode.ERR_FeatureInPreview, ">>>").WithArguments("unsigned right shift").WithLocation(4, 31) + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, ">>>").WithArguments("unsigned right shift", "11.0").WithLocation(4, 31) ); compilation1 = CreateCompilation(source0 + source1, options: TestOptions.DebugDll, - parseOptions: TestOptions.RegularNext); + parseOptions: TestOptions.Regular11); compilation1.VerifyDiagnostics(); var compilation0 = CreateCompilation(source0, options: TestOptions.DebugDll, @@ -3604,13 +3604,13 @@ class C var compilation2 = CreateCompilation(source1, options: TestOptions.DebugDll, references: new[] { reference }, parseOptions: TestOptions.Regular10); compilation2.VerifyDiagnostics( - // (4,40): error CS8652: The feature 'unsigned right shift' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // (4,40): error CS8936: Feature 'unsigned right shift' is not available in C# 10.0. Please use language version 11.0 or greater. // static C1? Test1(C1? x, int? y) => x >>>= y; - Diagnostic(ErrorCode.ERR_FeatureInPreview, "x >>>= y").WithArguments("unsigned right shift").WithLocation(4, 40) + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "x >>>= y").WithArguments("unsigned right shift", "11.0").WithLocation(4, 40) ); compilation2 = CreateCompilation(source1, options: TestOptions.DebugDll, references: new[] { reference }, - parseOptions: TestOptions.RegularNext); + parseOptions: TestOptions.Regular11); compilation2.VerifyDiagnostics(); } } @@ -3690,7 +3690,7 @@ public static void Main() } } "; - CompileAndVerify(source, expectedOutput: @"150150", parseOptions: TestOptions.RegularNext); + CompileAndVerify(source, expectedOutput: @"150150", parseOptions: TestOptions.Regular11); } } } diff --git a/src/Compilers/CSharp/Test/Syntax/Diagnostics/DiagnosticTest.cs b/src/Compilers/CSharp/Test/Syntax/Diagnostics/DiagnosticTest.cs index e49a82990b814..4db9910725ac4 100644 --- a/src/Compilers/CSharp/Test/Syntax/Diagnostics/DiagnosticTest.cs +++ b/src/Compilers/CSharp/Test/Syntax/Diagnostics/DiagnosticTest.cs @@ -2834,5 +2834,58 @@ CSharpCommandLineArguments parse(params string[] args) Assert.Equal(new KeyValuePair("/temp/", "/bar/"), doublemap[1]); } #endregion + + [Fact] + public void TestIsBuildOnlyDiagnostic() + { + foreach (ErrorCode errorCode in Enum.GetValues(typeof(ErrorCode))) + { + // ErrorFacts.IsBuildOnlyDiagnostic with throw if any new ErrorCode + // is added but not explicitly handled within it. + // Update ErrorFacts.IsBuildOnlyDiagnostic if the below call throws. + var isBuildOnly = ErrorFacts.IsBuildOnlyDiagnostic(errorCode); + + switch (errorCode) + { + case ErrorCode.WRN_ALinkWarn: + case ErrorCode.WRN_UnreferencedField: + case ErrorCode.WRN_UnreferencedFieldAssg: + case ErrorCode.WRN_UnreferencedEvent: + case ErrorCode.WRN_UnassignedInternalField: + case ErrorCode.ERR_MissingPredefinedMember: + case ErrorCode.ERR_PredefinedTypeNotFound: + case ErrorCode.ERR_NoEntryPoint: + case ErrorCode.WRN_InvalidMainSig: + case ErrorCode.ERR_MultipleEntryPoints: + case ErrorCode.WRN_MainIgnored: + case ErrorCode.ERR_MainClassNotClass: + case ErrorCode.WRN_MainCantBeGeneric: + case ErrorCode.ERR_NoMainInClass: + case ErrorCode.ERR_MainClassNotFound: + case ErrorCode.WRN_SyncAndAsyncEntryPoints: + case ErrorCode.ERR_BadDelegateConstructor: + case ErrorCode.ERR_InsufficientStack: + case ErrorCode.ERR_ModuleEmitFailure: + case ErrorCode.ERR_TooManyLocals: + case ErrorCode.ERR_BindToBogus: + case ErrorCode.ERR_ExportedTypeConflictsWithDeclaration: + case ErrorCode.ERR_ForwardedTypeConflictsWithDeclaration: + case ErrorCode.ERR_ExportedTypesConflict: + case ErrorCode.ERR_ForwardedTypeConflictsWithExportedType: + case ErrorCode.ERR_ByRefTypeAndAwait: + case ErrorCode.ERR_RefReturningCallAndAwait: + case ErrorCode.ERR_SpecialByRefInLambda: + case ErrorCode.ERR_DynamicRequiredTypesMissing: + case ErrorCode.ERR_EncUpdateFailedDelegateTypeChanged: + case ErrorCode.ERR_CannotBeConvertedToUtf8: + Assert.True(isBuildOnly, $"Check failed for ErrorCode.{errorCode}"); + break; + + default: + Assert.False(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 29bf359dfca36..195dbba9b5b19 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 @@ -65,7 +65,7 @@ private static Syntax.InternalSyntax.OmittedTypeArgumentSyntax GenerateOmittedTy => InternalSyntaxFactory.OmittedTypeArgument(InternalSyntaxFactory.Token(SyntaxKind.OmittedTypeArgumentToken)); private static Syntax.InternalSyntax.RefTypeSyntax GenerateRefType() - => InternalSyntaxFactory.RefType(InternalSyntaxFactory.Token(SyntaxKind.RefKeyword), null, null, GenerateIdentifierName()); + => InternalSyntaxFactory.RefType(InternalSyntaxFactory.Token(SyntaxKind.RefKeyword), null, GenerateIdentifierName()); private static Syntax.InternalSyntax.ParenthesizedExpressionSyntax GenerateParenthesizedExpression() => InternalSyntaxFactory.ParenthesizedExpression(InternalSyntaxFactory.Token(SyntaxKind.OpenParenToken), GenerateIdentifierName(), InternalSyntaxFactory.Token(SyntaxKind.CloseParenToken)); @@ -933,7 +933,6 @@ public void TestRefTypeFactoryAndProperties() Assert.Equal(SyntaxKind.RefKeyword, node.RefKeyword.Kind); Assert.Null(node.ReadOnlyKeyword); - Assert.Null(node.ScopedKeyword); Assert.NotNull(node.Type); AttachAndCheckDiagnostics(node); @@ -9998,7 +9997,7 @@ private static OmittedTypeArgumentSyntax GenerateOmittedTypeArgument() => SyntaxFactory.OmittedTypeArgument(SyntaxFactory.Token(SyntaxKind.OmittedTypeArgumentToken)); private static RefTypeSyntax GenerateRefType() - => SyntaxFactory.RefType(SyntaxFactory.Token(SyntaxKind.RefKeyword), default(SyntaxToken), default(SyntaxToken), GenerateIdentifierName()); + => SyntaxFactory.RefType(SyntaxFactory.Token(SyntaxKind.RefKeyword), default(SyntaxToken), GenerateIdentifierName()); private static ParenthesizedExpressionSyntax GenerateParenthesizedExpression() => SyntaxFactory.ParenthesizedExpression(SyntaxFactory.Token(SyntaxKind.OpenParenToken), GenerateIdentifierName(), SyntaxFactory.Token(SyntaxKind.CloseParenToken)); @@ -10866,9 +10865,8 @@ public void TestRefTypeFactoryAndProperties() Assert.Equal(SyntaxKind.RefKeyword, node.RefKeyword.Kind()); Assert.Equal(SyntaxKind.None, node.ReadOnlyKeyword.Kind()); - Assert.Equal(SyntaxKind.None, node.ScopedKeyword.Kind()); Assert.NotNull(node.Type); - var newNode = node.WithRefKeyword(node.RefKeyword).WithReadOnlyKeyword(node.ReadOnlyKeyword).WithScopedKeyword(node.ScopedKeyword).WithType(node.Type); + var newNode = node.WithRefKeyword(node.RefKeyword).WithReadOnlyKeyword(node.ReadOnlyKeyword).WithType(node.Type); Assert.Equal(node, newNode); } diff --git a/src/Compilers/CSharp/Test/Syntax/LexicalAndXml/LexicalErrorTests.cs b/src/Compilers/CSharp/Test/Syntax/LexicalAndXml/LexicalErrorTests.cs index cfde161c6bfc8..29bec0d98b7a7 100644 --- a/src/Compilers/CSharp/Test/Syntax/LexicalAndXml/LexicalErrorTests.cs +++ b/src/Compilers/CSharp/Test/Syntax/LexicalAndXml/LexicalErrorTests.cs @@ -459,7 +459,7 @@ public static void Main() ParserErrorMessageTests.ParseAndValidate(test); CreateCompilation(test, parseOptions: TestOptions.Regular10).VerifyDiagnostics(); - CreateCompilation(test, parseOptions: TestOptions.RegularNext).VerifyDiagnostics(); + CreateCompilation(test, parseOptions: TestOptions.Regular11).VerifyDiagnostics(); } [Fact] @@ -478,10 +478,10 @@ public static void Main() ParserErrorMessageTests.ParseAndValidate(test); CreateCompilation(test, parseOptions: TestOptions.Regular10).VerifyDiagnostics( - // (7,23): error CS8967: Newlines inside a non-verbatim interpolated string is not supported in C# 10.0. Please use language version preview or greater. + // (7,23): error CS8967: Newlines inside a non-verbatim interpolated string are not supported in C# 10.0. Please use language version 11.0 or greater. // } y"; - Diagnostic(ErrorCode.ERR_NewlinesAreNotAllowedInsideANonVerbatimInterpolatedString, "}").WithArguments("10.0", "preview").WithLocation(7, 23)); - CreateCompilation(test, parseOptions: TestOptions.RegularNext).VerifyDiagnostics(); + Diagnostic(ErrorCode.ERR_NewlinesAreNotAllowedInsideANonVerbatimInterpolatedString, "}").WithArguments("10.0", "11.0").WithLocation(7, 23)); + CreateCompilation(test, parseOptions: TestOptions.Regular11).VerifyDiagnostics(); } [Fact] @@ -500,10 +500,10 @@ public static void Main() ParserErrorMessageTests.ParseAndValidate(test); CreateCompilation(test, parseOptions: TestOptions.Regular10).VerifyDiagnostics( - // (7,28): error CS8967: Newlines inside a non-verbatim interpolated string is not supported in C# 10.0. Please use language version preview or greater. + // (7,28): error CS8967: Newlines inside a non-verbatim interpolated string are not supported in C# 10.0. Please use language version 11.0 or greater. // " } y"; - Diagnostic(ErrorCode.ERR_NewlinesAreNotAllowedInsideANonVerbatimInterpolatedString, "}").WithArguments("10.0", "preview").WithLocation(7, 28)); - CreateCompilation(test, parseOptions: TestOptions.RegularNext).VerifyDiagnostics(); + Diagnostic(ErrorCode.ERR_NewlinesAreNotAllowedInsideANonVerbatimInterpolatedString, "}").WithArguments("10.0", "11.0").WithLocation(7, 28)); + CreateCompilation(test, parseOptions: TestOptions.Regular11).VerifyDiagnostics(); } [Fact] @@ -523,10 +523,10 @@ public static void Main() ParserErrorMessageTests.ParseAndValidate(test); CreateCompilation(test, parseOptions: TestOptions.Regular10).VerifyDiagnostics( - // (8,23): error CS8967: Newlines inside a non-verbatim interpolated string is not supported in C# 10.0. Please use language version preview or greater. + // (8,23): error CS8967: Newlines inside a non-verbatim interpolated string are not supported in C# 10.0. Please use language version 11.0 or greater. // } y"; - Diagnostic(ErrorCode.ERR_NewlinesAreNotAllowedInsideANonVerbatimInterpolatedString, "}").WithArguments("10.0", "preview").WithLocation(8, 23)); - CreateCompilation(test, parseOptions: TestOptions.RegularNext).VerifyDiagnostics(); + Diagnostic(ErrorCode.ERR_NewlinesAreNotAllowedInsideANonVerbatimInterpolatedString, "}").WithArguments("10.0", "11.0").WithLocation(8, 23)); + CreateCompilation(test, parseOptions: TestOptions.Regular11).VerifyDiagnostics(); } [Fact] @@ -545,10 +545,10 @@ public static void Main() ParserErrorMessageTests.ParseAndValidate(test); CreateCompilation(test, parseOptions: TestOptions.Regular10).VerifyDiagnostics( - // (7,30): error CS8967: Newlines inside a non-verbatim interpolated string is not supported in C# 10.0. Please use language version preview or greater. + // (7,30): error CS8967: Newlines inside a non-verbatim interpolated string are not supported in C# 10.0. Please use language version 11.0 or greater. // @" " } y"; - Diagnostic(ErrorCode.ERR_NewlinesAreNotAllowedInsideANonVerbatimInterpolatedString, "}").WithArguments("10.0", "preview").WithLocation(7, 30)); - CreateCompilation(test, parseOptions: TestOptions.RegularNext).VerifyDiagnostics(); + Diagnostic(ErrorCode.ERR_NewlinesAreNotAllowedInsideANonVerbatimInterpolatedString, "}").WithArguments("10.0", "11.0").WithLocation(7, 30)); + CreateCompilation(test, parseOptions: TestOptions.Regular11).VerifyDiagnostics(); } [Fact] @@ -568,10 +568,10 @@ public static void Main() ParserErrorMessageTests.ParseAndValidate(test); CreateCompilation(test, parseOptions: TestOptions.Regular10).VerifyDiagnostics( - // (8,28): error CS8967: Newlines inside a non-verbatim interpolated string is not supported in C# 10.0. Please use language version preview or greater. + // (8,28): error CS8967: Newlines inside a non-verbatim interpolated string are not supported in C# 10.0. Please use language version 11.0 or greater. // " } y"; - Diagnostic(ErrorCode.ERR_NewlinesAreNotAllowedInsideANonVerbatimInterpolatedString, "}").WithArguments("10.0", "preview").WithLocation(8, 28)); - CreateCompilation(test, parseOptions: TestOptions.RegularNext).VerifyDiagnostics(); + Diagnostic(ErrorCode.ERR_NewlinesAreNotAllowedInsideANonVerbatimInterpolatedString, "}").WithArguments("10.0", "11.0").WithLocation(8, 28)); + CreateCompilation(test, parseOptions: TestOptions.Regular11).VerifyDiagnostics(); } [Fact] @@ -592,10 +592,10 @@ public static void Main() ParserErrorMessageTests.ParseAndValidate(test); CreateCompilation(test, parseOptions: TestOptions.Regular10).VerifyDiagnostics( - // (9,23): error CS8967: Newlines inside a non-verbatim interpolated string is not supported in C# 10.0. Please use language version preview or greater. + // (9,23): error CS8967: Newlines inside a non-verbatim interpolated string are not supported in C# 10.0. Please use language version 11.0 or greater. // } y"; - Diagnostic(ErrorCode.ERR_NewlinesAreNotAllowedInsideANonVerbatimInterpolatedString, "}").WithArguments("10.0", "preview").WithLocation(9, 23)); - CreateCompilation(test, parseOptions: TestOptions.RegularNext).VerifyDiagnostics(); + Diagnostic(ErrorCode.ERR_NewlinesAreNotAllowedInsideANonVerbatimInterpolatedString, "}").WithArguments("10.0", "11.0").WithLocation(9, 23)); + CreateCompilation(test, parseOptions: TestOptions.Regular11).VerifyDiagnostics(); } [Fact] @@ -615,10 +615,10 @@ public static void Main() ParserErrorMessageTests.ParseAndValidate(test); CreateCompilation(test, parseOptions: TestOptions.Regular10).VerifyDiagnostics( - // (8,28): error CS8967: Newlines inside a non-verbatim interpolated string is not supported in C# 10.0. Please use language version preview or greater. + // (8,28): error CS8967: Newlines inside a non-verbatim interpolated string are not supported in C# 10.0. Please use language version 11.0 or greater. // " } y"; - Diagnostic(ErrorCode.ERR_NewlinesAreNotAllowedInsideANonVerbatimInterpolatedString, "}").WithArguments("10.0", "preview").WithLocation(8, 28)); - CreateCompilation(test, parseOptions: TestOptions.RegularNext).VerifyDiagnostics(); + Diagnostic(ErrorCode.ERR_NewlinesAreNotAllowedInsideANonVerbatimInterpolatedString, "}").WithArguments("10.0", "11.0").WithLocation(8, 28)); + CreateCompilation(test, parseOptions: TestOptions.Regular11).VerifyDiagnostics(); } [Fact] @@ -638,10 +638,10 @@ public static void Main() ParserErrorMessageTests.ParseAndValidate(test); CreateCompilation(test, parseOptions: TestOptions.Regular10).VerifyDiagnostics( - // (8,28): error CS8967: Newlines inside a non-verbatim interpolated string is not supported in C# 10.0. Please use language version preview or greater. + // (8,28): error CS8967: Newlines inside a non-verbatim interpolated string are not supported in C# 10.0. Please use language version 11.0 or greater. // " } y"; - Diagnostic(ErrorCode.ERR_NewlinesAreNotAllowedInsideANonVerbatimInterpolatedString, "}").WithArguments("10.0", "preview").WithLocation(8, 28)); - CreateCompilation(test, parseOptions: TestOptions.RegularNext).VerifyDiagnostics(); + Diagnostic(ErrorCode.ERR_NewlinesAreNotAllowedInsideANonVerbatimInterpolatedString, "}").WithArguments("10.0", "11.0").WithLocation(8, 28)); + CreateCompilation(test, parseOptions: TestOptions.Regular11).VerifyDiagnostics(); } [Fact] @@ -661,10 +661,10 @@ public static void Main() ParserErrorMessageTests.ParseAndValidate(test); CreateCompilation(test, parseOptions: TestOptions.Regular10).VerifyDiagnostics( - // (8,39): error CS8967: Newlines inside a non-verbatim interpolated string is not supported in C# 10.0. Please use language version preview or greater. + // (8,39): error CS8967: Newlines inside a non-verbatim interpolated string are not supported in C# 10.0. Please use language version 11.0 or greater. // " } " } y"; - Diagnostic(ErrorCode.ERR_NewlinesAreNotAllowedInsideANonVerbatimInterpolatedString, "}").WithArguments("10.0", "preview").WithLocation(8, 39)); - CreateCompilation(test, parseOptions: TestOptions.RegularNext).VerifyDiagnostics(); + Diagnostic(ErrorCode.ERR_NewlinesAreNotAllowedInsideANonVerbatimInterpolatedString, "}").WithArguments("10.0", "11.0").WithLocation(8, 39)); + CreateCompilation(test, parseOptions: TestOptions.Regular11).VerifyDiagnostics(); } [Fact] @@ -688,7 +688,7 @@ public static void Main() // (6,38): error CS1733: Expected expression // string s = $"x { /* comment */ } y"; Diagnostic(ErrorCode.ERR_ExpressionExpected, "").WithLocation(6, 38)); - CreateCompilation(test, parseOptions: TestOptions.RegularNext).VerifyDiagnostics( + CreateCompilation(test, parseOptions: TestOptions.Regular11).VerifyDiagnostics( // (6,38): error CS1733: Expected expression // string s = $"x { /* comment */ } y"; Diagnostic(ErrorCode.ERR_ExpressionExpected, "").WithLocation(6, 38)); @@ -745,7 +745,7 @@ public static void Main() // (9,1): error CS1513: } expected // Diagnostic(ErrorCode.ERR_RbraceExpected, "").WithLocation(9, 1)); - CreateCompilation(test, parseOptions: TestOptions.RegularNext).VerifyDiagnostics( + CreateCompilation(test, parseOptions: TestOptions.Regular11).VerifyDiagnostics( // (6,21): error CS8076: Missing close delimiter '}' for interpolated expression started with '{'. // string s = $"x { /* comment } y"; Diagnostic(ErrorCode.ERR_UnclosedExpressionHole, " {").WithLocation(6, 21), @@ -818,7 +818,7 @@ public static void Main() // (10,1): error CS1513: } expected // Diagnostic(ErrorCode.ERR_RbraceExpected, "").WithLocation(10, 1)); - CreateCompilation(test, parseOptions: TestOptions.RegularNext).VerifyDiagnostics( + CreateCompilation(test, parseOptions: TestOptions.Regular11).VerifyDiagnostics( // (6,21): error CS8076: Missing close delimiter '}' for interpolated expression started with '{'. // string s = $"x { /* comment Diagnostic(ErrorCode.ERR_UnclosedExpressionHole, " {").WithLocation(6, 21), @@ -854,7 +854,7 @@ public static void Main() ParserErrorMessageTests.ParseAndValidate(test); CreateCompilation(test, parseOptions: TestOptions.Regular10).VerifyDiagnostics(); - CreateCompilation(test, parseOptions: TestOptions.RegularNext).VerifyDiagnostics(); + CreateCompilation(test, parseOptions: TestOptions.Regular11).VerifyDiagnostics(); } [Fact] @@ -873,10 +873,10 @@ public static void Main() ParserErrorMessageTests.ParseAndValidate(test); CreateCompilation(test, parseOptions: TestOptions.Regular10).VerifyDiagnostics( - // (7,27): error CS8967: Newlines inside a non-verbatim interpolated string is not supported in C# 10.0. Please use language version preview or greater. + // (7,27): error CS8967: Newlines inside a non-verbatim interpolated string are not supported in C# 10.0. Please use language version 11.0 or greater. // 0 } y"; - Diagnostic(ErrorCode.ERR_NewlinesAreNotAllowedInsideANonVerbatimInterpolatedString, "}").WithArguments("10.0", "preview").WithLocation(7, 27)); - CreateCompilation(test, parseOptions: TestOptions.RegularNext).VerifyDiagnostics(); + Diagnostic(ErrorCode.ERR_NewlinesAreNotAllowedInsideANonVerbatimInterpolatedString, "}").WithArguments("10.0", "11.0").WithLocation(7, 27)); + CreateCompilation(test, parseOptions: TestOptions.Regular11).VerifyDiagnostics(); } [Fact] @@ -902,7 +902,7 @@ public static void Main() // (8,29): error CS1733: Expected expression // */ } y"; Diagnostic(ErrorCode.ERR_ExpressionExpected, "").WithLocation(8, 29)); - CreateCompilation(test, parseOptions: TestOptions.RegularNext).VerifyDiagnostics( + CreateCompilation(test, parseOptions: TestOptions.Regular11).VerifyDiagnostics( // (8,29): error CS1733: Expected expression // */ } y"; Diagnostic(ErrorCode.ERR_ExpressionExpected, "").WithLocation(8, 29)); @@ -923,7 +923,7 @@ public static void Main() ParserErrorMessageTests.ParseAndValidate(test); CreateCompilation(test, parseOptions: TestOptions.Regular10).VerifyDiagnostics(); - CreateCompilation(test, parseOptions: TestOptions.RegularNext).VerifyDiagnostics(); + CreateCompilation(test, parseOptions: TestOptions.Regular11).VerifyDiagnostics(); } [Fact] @@ -942,10 +942,10 @@ public static void Main() ParserErrorMessageTests.ParseAndValidate(test); CreateCompilation(test, parseOptions: TestOptions.Regular10).VerifyDiagnostics( - // (7,27): error CS8967: Newlines inside a non-verbatim interpolated string is not supported in C# 10.0. Please use language version preview or greater. + // (7,27): error CS8967: Newlines inside a non-verbatim interpolated string are not supported in C# 10.0. Please use language version 11.0 or greater. // 0 } y"; - Diagnostic(ErrorCode.ERR_NewlinesAreNotAllowedInsideANonVerbatimInterpolatedString, "}").WithArguments("10.0", "preview").WithLocation(7, 27)); - CreateCompilation(test, parseOptions: TestOptions.RegularNext).VerifyDiagnostics(); + Diagnostic(ErrorCode.ERR_NewlinesAreNotAllowedInsideANonVerbatimInterpolatedString, "}").WithArguments("10.0", "11.0").WithLocation(7, 27)); + CreateCompilation(test, parseOptions: TestOptions.Regular11).VerifyDiagnostics(); } [Fact] @@ -970,7 +970,7 @@ public static void Main() // (7,23): error CS1733: Expected expression // } y"; Diagnostic(ErrorCode.ERR_ExpressionExpected, "").WithLocation(7, 23)); - CreateCompilation(test, parseOptions: TestOptions.RegularNext).VerifyDiagnostics( + CreateCompilation(test, parseOptions: TestOptions.Regular11).VerifyDiagnostics( // (7,23): error CS1733: Expected expression // } y"; Diagnostic(ErrorCode.ERR_ExpressionExpected, "").WithLocation(7, 23)); @@ -992,10 +992,10 @@ public static void Main() ParserErrorMessageTests.ParseAndValidate(test); CreateCompilation(test, parseOptions: TestOptions.Regular10).VerifyDiagnostics( - // (7,23): error CS8967: Newlines inside a non-verbatim interpolated string is not supported in C# 10.0. Please use language version preview or greater. + // (7,23): error CS8967: Newlines inside a non-verbatim interpolated string are not supported in C# 10.0. Please use language version 11.0 or greater. // } y"; - Diagnostic(ErrorCode.ERR_NewlinesAreNotAllowedInsideANonVerbatimInterpolatedString, "}").WithArguments("10.0", "preview").WithLocation(7, 23)); - CreateCompilation(test, parseOptions: TestOptions.RegularNext).VerifyDiagnostics(); + Diagnostic(ErrorCode.ERR_NewlinesAreNotAllowedInsideANonVerbatimInterpolatedString, "}").WithArguments("10.0", "11.0").WithLocation(7, 23)); + CreateCompilation(test, parseOptions: TestOptions.Regular11).VerifyDiagnostics(); } [Fact] @@ -1014,10 +1014,10 @@ public static void Main() ParserErrorMessageTests.ParseAndValidate(test); CreateCompilation(test, parseOptions: TestOptions.Regular10).VerifyDiagnostics( - // (7,27): error CS8967: Newlines inside a non-verbatim interpolated string is not supported in C# 10.0. Please use language version preview or greater. + // (7,27): error CS8967: Newlines inside a non-verbatim interpolated string are not supported in C# 10.0. Please use language version 11.0 or greater. // 0 } y"; - Diagnostic(ErrorCode.ERR_NewlinesAreNotAllowedInsideANonVerbatimInterpolatedString, "}").WithArguments("10.0", "preview").WithLocation(7, 27)); - CreateCompilation(test, parseOptions: TestOptions.RegularNext).VerifyDiagnostics(); + Diagnostic(ErrorCode.ERR_NewlinesAreNotAllowedInsideANonVerbatimInterpolatedString, "}").WithArguments("10.0", "11.0").WithLocation(7, 27)); + CreateCompilation(test, parseOptions: TestOptions.Regular11).VerifyDiagnostics(); } [Fact] @@ -1044,7 +1044,7 @@ public static void Main() // (9,23): error CS1733: Expected expression // } y"; Diagnostic(ErrorCode.ERR_ExpressionExpected, "").WithLocation(9, 23)); - CreateCompilation(test, parseOptions: TestOptions.RegularNext).VerifyDiagnostics( + CreateCompilation(test, parseOptions: TestOptions.Regular11).VerifyDiagnostics( // (9,23): error CS1733: Expected expression // } y"; Diagnostic(ErrorCode.ERR_ExpressionExpected, "").WithLocation(9, 23)); @@ -1068,10 +1068,10 @@ public static void Main() ParserErrorMessageTests.ParseAndValidate(test); CreateCompilation(test, parseOptions: TestOptions.Regular10).VerifyDiagnostics( - // (9,23): error CS8967: Newlines inside a non-verbatim interpolated string is not supported in C# 10.0. Please use language version preview or greater. + // (9,23): error CS8967: Newlines inside a non-verbatim interpolated string are not supported in C# 10.0. Please use language version 11.0 or greater. // } y"; - Diagnostic(ErrorCode.ERR_NewlinesAreNotAllowedInsideANonVerbatimInterpolatedString, "}").WithArguments("10.0", "preview").WithLocation(9, 23)); - CreateCompilation(test, parseOptions: TestOptions.RegularNext).VerifyDiagnostics(); + Diagnostic(ErrorCode.ERR_NewlinesAreNotAllowedInsideANonVerbatimInterpolatedString, "}").WithArguments("10.0", "11.0").WithLocation(9, 23)); + CreateCompilation(test, parseOptions: TestOptions.Regular11).VerifyDiagnostics(); } [Fact] @@ -1092,10 +1092,10 @@ public static void Main() ParserErrorMessageTests.ParseAndValidate(test); CreateCompilation(test, parseOptions: TestOptions.Regular10).VerifyDiagnostics( - // (9,27): error CS8967: Newlines inside a non-verbatim interpolated string is not supported in C# 10.0. Please use language version preview or greater. + // (9,27): error CS8967: Newlines inside a non-verbatim interpolated string are not supported in C# 10.0. Please use language version 11.0 or greater. // 0 } y"; - Diagnostic(ErrorCode.ERR_NewlinesAreNotAllowedInsideANonVerbatimInterpolatedString, "}").WithArguments("10.0", "preview").WithLocation(9, 27)); - CreateCompilation(test, parseOptions: TestOptions.RegularNext).VerifyDiagnostics(); + Diagnostic(ErrorCode.ERR_NewlinesAreNotAllowedInsideANonVerbatimInterpolatedString, "}").WithArguments("10.0", "11.0").WithLocation(9, 27)); + CreateCompilation(test, parseOptions: TestOptions.Regular11).VerifyDiagnostics(); } [Fact] @@ -1117,10 +1117,10 @@ public static void Main() ParserErrorMessageTests.ParseAndValidate(test); CreateCompilation(test, parseOptions: TestOptions.Regular10).VerifyDiagnostics( - // (10,23): error CS8967: Newlines inside a non-verbatim interpolated string is not supported in C# 10.0. Please use language version preview or greater. + // (10,23): error CS8967: Newlines inside a non-verbatim interpolated string are not supported in C# 10.0. Please use language version 11.0 or greater. // } y"; - Diagnostic(ErrorCode.ERR_NewlinesAreNotAllowedInsideANonVerbatimInterpolatedString, "}").WithArguments("10.0", "preview").WithLocation(10, 23)); - CreateCompilation(test, parseOptions: TestOptions.RegularNext).VerifyDiagnostics(); + Diagnostic(ErrorCode.ERR_NewlinesAreNotAllowedInsideANonVerbatimInterpolatedString, "}").WithArguments("10.0", "11.0").WithLocation(10, 23)); + CreateCompilation(test, parseOptions: TestOptions.Regular11).VerifyDiagnostics(); } [Fact] @@ -1145,7 +1145,7 @@ public static void Main() // (7,39): error CS1733: Expected expression // /* comment */ } y"; Diagnostic(ErrorCode.ERR_ExpressionExpected, "").WithLocation(7, 39)); - CreateCompilation(test, parseOptions: TestOptions.RegularNext).VerifyDiagnostics( + CreateCompilation(test, parseOptions: TestOptions.Regular11).VerifyDiagnostics( // (7,39): error CS1733: Expected expression // /* comment */ } y"; Diagnostic(ErrorCode.ERR_ExpressionExpected, "").WithLocation(7, 39)); @@ -1167,10 +1167,10 @@ public static void Main() ParserErrorMessageTests.ParseAndValidate(test); CreateCompilation(test, parseOptions: TestOptions.Regular10).VerifyDiagnostics( - // (7,41): error CS8967: Newlines inside a non-verbatim interpolated string is not supported in C# 10.0. Please use language version preview or greater. + // (7,41): error CS8967: Newlines inside a non-verbatim interpolated string are not supported in C# 10.0. Please use language version 11.0 or greater. // /* comment */ 0 } y"; - Diagnostic(ErrorCode.ERR_NewlinesAreNotAllowedInsideANonVerbatimInterpolatedString, "}").WithArguments("10.0", "preview").WithLocation(7, 41)); - CreateCompilation(test, parseOptions: TestOptions.RegularNext).VerifyDiagnostics(); + Diagnostic(ErrorCode.ERR_NewlinesAreNotAllowedInsideANonVerbatimInterpolatedString, "}").WithArguments("10.0", "11.0").WithLocation(7, 41)); + CreateCompilation(test, parseOptions: TestOptions.Regular11).VerifyDiagnostics(); } [Fact] @@ -1197,7 +1197,7 @@ public static void Main() // (9,29): error CS1733: Expected expression // */ } y"; Diagnostic(ErrorCode.ERR_ExpressionExpected, "").WithLocation(9, 29)); - CreateCompilation(test, parseOptions: TestOptions.RegularNext).VerifyDiagnostics( + CreateCompilation(test, parseOptions: TestOptions.Regular11).VerifyDiagnostics( // (9,29): error CS1733: Expected expression // */ } y"; Diagnostic(ErrorCode.ERR_ExpressionExpected, "").WithLocation(9, 29)); @@ -1221,10 +1221,10 @@ public static void Main() ParserErrorMessageTests.ParseAndValidate(test); CreateCompilation(test, parseOptions: TestOptions.Regular10).VerifyDiagnostics( - // (9,31): error CS8967: Newlines inside a non-verbatim interpolated string is not supported in C# 10.0. Please use language version preview or greater. + // (9,31): error CS8967: Newlines inside a non-verbatim interpolated string are not supported in C# 10.0. Please use language version 11.0 or greater. // */ 0 } y"; - Diagnostic(ErrorCode.ERR_NewlinesAreNotAllowedInsideANonVerbatimInterpolatedString, "}").WithArguments("10.0", "preview").WithLocation(9, 31)); - CreateCompilation(test, parseOptions: TestOptions.RegularNext).VerifyDiagnostics(); + Diagnostic(ErrorCode.ERR_NewlinesAreNotAllowedInsideANonVerbatimInterpolatedString, "}").WithArguments("10.0", "11.0").WithLocation(9, 31)); + CreateCompilation(test, parseOptions: TestOptions.Regular11).VerifyDiagnostics(); } [Fact] @@ -1246,10 +1246,10 @@ public static void Main() ParserErrorMessageTests.ParseAndValidate(test); CreateCompilation(test, parseOptions: TestOptions.Regular10).VerifyDiagnostics( - // (10,27): error CS8967: Newlines inside a non-verbatim interpolated string is not supported in C# 10.0. Please use language version preview or greater. + // (10,27): error CS8967: Newlines inside a non-verbatim interpolated string are not supported in C# 10.0. Please use language version 11.0 or greater. // 0 } y"; - Diagnostic(ErrorCode.ERR_NewlinesAreNotAllowedInsideANonVerbatimInterpolatedString, "}").WithArguments("10.0", "preview").WithLocation(10, 27)); - CreateCompilation(test, parseOptions: TestOptions.RegularNext).VerifyDiagnostics(); + Diagnostic(ErrorCode.ERR_NewlinesAreNotAllowedInsideANonVerbatimInterpolatedString, "}").WithArguments("10.0", "11.0").WithLocation(10, 27)); + CreateCompilation(test, parseOptions: TestOptions.Regular11).VerifyDiagnostics(); } [Fact] @@ -1277,7 +1277,7 @@ public static void Main() // (10,23): error CS1733: Expected expression // } y"; Diagnostic(ErrorCode.ERR_ExpressionExpected, "").WithLocation(10, 23)); - CreateCompilation(test, parseOptions: TestOptions.RegularNext).VerifyDiagnostics( + CreateCompilation(test, parseOptions: TestOptions.Regular11).VerifyDiagnostics( // (10,23): error CS1733: Expected expression // } y"; Diagnostic(ErrorCode.ERR_ExpressionExpected, "").WithLocation(10, 23)); @@ -1302,10 +1302,10 @@ public static void Main() ParserErrorMessageTests.ParseAndValidate(test); CreateCompilation(test, parseOptions: TestOptions.Regular10).VerifyDiagnostics( - // (10,23): error CS8967: Newlines inside a non-verbatim interpolated string is not supported in C# 10.0. Please use language version preview or greater. + // (10,23): error CS8967: Newlines inside a non-verbatim interpolated string are not supported in C# 10.0. Please use language version 11.0 or greater. // } y"; - Diagnostic(ErrorCode.ERR_NewlinesAreNotAllowedInsideANonVerbatimInterpolatedString, "}").WithArguments("10.0", "preview").WithLocation(10, 23)); - CreateCompilation(test, parseOptions: TestOptions.RegularNext).VerifyDiagnostics(); + Diagnostic(ErrorCode.ERR_NewlinesAreNotAllowedInsideANonVerbatimInterpolatedString, "}").WithArguments("10.0", "11.0").WithLocation(10, 23)); + CreateCompilation(test, parseOptions: TestOptions.Regular11).VerifyDiagnostics(); } [Fact] @@ -1328,10 +1328,10 @@ public static void Main() ParserErrorMessageTests.ParseAndValidate(test); CreateCompilation(test, parseOptions: TestOptions.Regular10).VerifyDiagnostics( - // (11,23): error CS8967: Newlines inside a non-verbatim interpolated string is not supported in C# 10.0. Please use language version preview or greater. + // (11,23): error CS8967: Newlines inside a non-verbatim interpolated string are not supported in C# 10.0. Please use language version 11.0 or greater. // } y"; - Diagnostic(ErrorCode.ERR_NewlinesAreNotAllowedInsideANonVerbatimInterpolatedString, "}").WithArguments("10.0", "preview").WithLocation(11, 23)); - CreateCompilation(test, parseOptions: TestOptions.RegularNext).VerifyDiagnostics(); + Diagnostic(ErrorCode.ERR_NewlinesAreNotAllowedInsideANonVerbatimInterpolatedString, "}").WithArguments("10.0", "11.0").WithLocation(11, 23)); + CreateCompilation(test, parseOptions: TestOptions.Regular11).VerifyDiagnostics(); } [Fact] @@ -1356,7 +1356,7 @@ public static void Main() // (7,23): error CS1733: Expected expression // } y"; Diagnostic(ErrorCode.ERR_ExpressionExpected, "").WithLocation(7, 23)); - CreateCompilation(test, parseOptions: TestOptions.RegularNext).VerifyDiagnostics( + CreateCompilation(test, parseOptions: TestOptions.Regular11).VerifyDiagnostics( // (7,23): error CS1733: Expected expression // } y"; Diagnostic(ErrorCode.ERR_ExpressionExpected, "").WithLocation(7, 23)); @@ -1384,7 +1384,7 @@ public static void Main() // (7,24): error CS1733: Expected expression // } y"; Diagnostic(ErrorCode.ERR_ExpressionExpected, "").WithLocation(7, 24)); - CreateCompilation(test, parseOptions: TestOptions.RegularNext).VerifyDiagnostics( + CreateCompilation(test, parseOptions: TestOptions.Regular11).VerifyDiagnostics( // (7,24): error CS1733: Expected expression // } y"; Diagnostic(ErrorCode.ERR_ExpressionExpected, "").WithLocation(7, 24)); @@ -1412,7 +1412,7 @@ public static void Main() // (7,30): error CS1733: Expected expression // } " } y"; Diagnostic(ErrorCode.ERR_ExpressionExpected, "").WithLocation(7, 30)); - CreateCompilation(test, parseOptions: TestOptions.RegularNext).VerifyDiagnostics( + CreateCompilation(test, parseOptions: TestOptions.Regular11).VerifyDiagnostics( // (7,30): error CS1733: Expected expression // } " } y"; Diagnostic(ErrorCode.ERR_ExpressionExpected, "").WithLocation(7, 30)); @@ -1435,10 +1435,10 @@ public static void Main() ParserErrorMessageTests.ParseAndValidate(test); CreateCompilation(test, parseOptions: TestOptions.Regular10).VerifyDiagnostics( - // (8,23): error CS8967: Newlines inside a non-verbatim interpolated string is not supported in C# 10.0. Please use language version preview or greater. + // (8,23): error CS8967: Newlines inside a non-verbatim interpolated string are not supported in C# 10.0. Please use language version 11.0 or greater. // } y"; - Diagnostic(ErrorCode.ERR_NewlinesAreNotAllowedInsideANonVerbatimInterpolatedString, "}").WithArguments("10.0", "preview").WithLocation(8, 23)); - CreateCompilation(test, parseOptions: TestOptions.RegularNext).VerifyDiagnostics(); + Diagnostic(ErrorCode.ERR_NewlinesAreNotAllowedInsideANonVerbatimInterpolatedString, "}").WithArguments("10.0", "11.0").WithLocation(8, 23)); + CreateCompilation(test, parseOptions: TestOptions.Regular11).VerifyDiagnostics(); } [Fact] @@ -1458,7 +1458,7 @@ public static void Main() ParserErrorMessageTests.ParseAndValidate(test); CreateCompilation(test, parseOptions: TestOptions.Regular10).VerifyDiagnostics(); - CreateCompilation(test, parseOptions: TestOptions.RegularNext).VerifyDiagnostics(); + CreateCompilation(test, parseOptions: TestOptions.Regular11).VerifyDiagnostics(); } [Fact] @@ -1478,10 +1478,10 @@ public static void Main() ParserErrorMessageTests.ParseAndValidate(test); CreateCompilation(test, parseOptions: TestOptions.Regular10).VerifyDiagnostics( - // (8,34): error CS8967: Newlines inside a non-verbatim interpolated string is not supported in C# 10.0. Please use language version preview or greater. + // (8,34): error CS8967: Newlines inside a non-verbatim interpolated string are not supported in C# 10.0. Please use language version 11.0 or greater. // } " } y"; - Diagnostic(ErrorCode.ERR_NewlinesAreNotAllowedInsideANonVerbatimInterpolatedString, "}").WithArguments("10.0", "preview").WithLocation(8, 34)); - CreateCompilation(test, parseOptions: TestOptions.RegularNext).VerifyDiagnostics(); + Diagnostic(ErrorCode.ERR_NewlinesAreNotAllowedInsideANonVerbatimInterpolatedString, "}").WithArguments("10.0", "11.0").WithLocation(8, 34)); + CreateCompilation(test, parseOptions: TestOptions.Regular11).VerifyDiagnostics(); } #endregion diff --git a/src/Compilers/CSharp/Test/Syntax/LexicalAndXml/LexicalTests.cs b/src/Compilers/CSharp/Test/Syntax/LexicalAndXml/LexicalTests.cs index 8b639a7788bcf..492afa93a2321 100644 --- a/src/Compilers/CSharp/Test/Syntax/LexicalAndXml/LexicalTests.cs +++ b/src/Compilers/CSharp/Test/Syntax/LexicalAndXml/LexicalTests.cs @@ -3742,5 +3742,424 @@ public void TestEqualsConflictMarker2() Assert.Equal(36, trivia4.Span.Start); Assert.Equal(24, trivia4.Span.Length); } + + [Fact] + public void TestEqualsConflictMarker3() + { + // second ======= is part of disabled text + var token = Lex(""" + ======= Trailing + disabled text 2 + ======= + more disabled text + >>>>>>> Actually the end + """).First(); + Assert.Equal(SyntaxKind.EndOfFileToken, token.Kind()); + Assert.True(token.HasLeadingTrivia); + Assert.Equal(4, token.LeadingTrivia.Count); + + var trivia = token.LeadingTrivia[0]; + Assert.True(trivia.Kind() == SyntaxKind.ConflictMarkerTrivia); + Assert.Equal("======= Trailing", trivia.ToFullString()); + Assert.True(trivia.ContainsDiagnostics); + Assert.Equal((int)ErrorCode.ERR_Merge_conflict_marker_encountered, trivia.Errors().Single().Code); + + trivia = token.LeadingTrivia[1]; + Assert.True(trivia.Kind() == SyntaxKind.EndOfLineTrivia); + + trivia = token.LeadingTrivia[2]; + Assert.True(trivia.Kind() == SyntaxKind.DisabledTextTrivia); + Assert.Equal(""" + disabled text 2 + ======= + more disabled text + + """, trivia.ToFullString()); + + trivia = token.LeadingTrivia[3]; + Assert.True(trivia.Kind() == SyntaxKind.ConflictMarkerTrivia); + Assert.Equal(">>>>>>> Actually the end", trivia.ToFullString()); + Assert.True(trivia.ContainsDiagnostics); + Assert.Equal((int)ErrorCode.ERR_Merge_conflict_marker_encountered, trivia.Errors().Single().Code); + } + + [Fact] + public void TestEqualsConflictMarker4() + { + // ||||||| is part of disabled text + var token = Lex(""" + ======= Trailing + disabled text 2 + ||||||| + more disabled text + >>>>>>> Actually the end + """).First(); + Assert.Equal(SyntaxKind.EndOfFileToken, token.Kind()); + Assert.True(token.HasLeadingTrivia); + Assert.Equal(4, token.LeadingTrivia.Count); + + var trivia = token.LeadingTrivia[0]; + Assert.True(trivia.Kind() == SyntaxKind.ConflictMarkerTrivia); + Assert.Equal("======= Trailing", trivia.ToFullString()); + Assert.True(trivia.ContainsDiagnostics); + Assert.Equal((int)ErrorCode.ERR_Merge_conflict_marker_encountered, trivia.Errors().Single().Code); + + trivia = token.LeadingTrivia[1]; + Assert.True(trivia.Kind() == SyntaxKind.EndOfLineTrivia); + + trivia = token.LeadingTrivia[2]; + Assert.True(trivia.Kind() == SyntaxKind.DisabledTextTrivia); + Assert.Equal(""" + disabled text 2 + ||||||| + more disabled text + + """, trivia.ToFullString()); + + trivia = token.LeadingTrivia[3]; + Assert.True(trivia.Kind() == SyntaxKind.ConflictMarkerTrivia); + Assert.Equal(">>>>>>> Actually the end", trivia.ToFullString()); + Assert.True(trivia.ContainsDiagnostics); + Assert.Equal((int)ErrorCode.ERR_Merge_conflict_marker_encountered, trivia.Errors().Single().Code); + } + + [Fact] + public void TestPipeConflictMarker1() + { + // Has to be the start of a line. + var token = Lex(" |||||||").First(); + Assert.Equal(SyntaxKind.BarBarToken, token.Kind()); + Assert.True(token.HasLeadingTrivia); + Assert.True(token.LeadingTrivia.Single().Kind() == SyntaxKind.WhitespaceTrivia); + + // Has to have at least seven characters. + token = Lex("|||||| ").First(); + Assert.Equal(SyntaxKind.BarBarToken, token.Kind()); + + // Start of line, seven characters + token = Lex("|||||||").First(); + Assert.Equal(SyntaxKind.EndOfFileToken, token.Kind()); + Assert.True(token.HasLeadingTrivia); + Assert.True(token.LeadingTrivia.Single().Kind() == SyntaxKind.ConflictMarkerTrivia); + + // Start of line, seven characters + token = Lex("||||||| trailing chars").First(); + Assert.Equal(SyntaxKind.EndOfFileToken, token.Kind()); + Assert.True(token.HasLeadingTrivia); + var trivia = token.LeadingTrivia.Single(); + Assert.True(trivia.Kind() == SyntaxKind.ConflictMarkerTrivia); + + Assert.True(trivia.ContainsDiagnostics); + var errors = trivia.Errors(); + Assert.Equal(1, errors.Length); + Assert.Equal((int)ErrorCode.ERR_Merge_conflict_marker_encountered, errors[0].Code); + + token = Lex(""" + ||||||| Trailing + disabled text + """).First(); + Assert.Equal(SyntaxKind.EndOfFileToken, token.Kind()); + Assert.True(token.HasLeadingTrivia); + Assert.Equal(3, token.LeadingTrivia.Count); + trivia = token.LeadingTrivia[0]; + Assert.True(trivia.Kind() == SyntaxKind.ConflictMarkerTrivia); + + Assert.True(trivia.ContainsDiagnostics); + errors = trivia.Errors(); + Assert.Equal(1, errors.Length); + Assert.Equal((int)ErrorCode.ERR_Merge_conflict_marker_encountered, errors[0].Code); + + trivia = token.LeadingTrivia[1]; + Assert.True(trivia.Kind() == SyntaxKind.EndOfLineTrivia); + + trivia = token.LeadingTrivia[2]; + Assert.True(trivia.Kind() == SyntaxKind.DisabledTextTrivia); + + token = Lex(""" + ||||||| Trailing + disabled text + >>>> still disabled + """).First(); + Assert.Equal(SyntaxKind.EndOfFileToken, token.Kind()); + Assert.True(token.HasLeadingTrivia); + Assert.Equal(3, token.LeadingTrivia.Count); + + trivia = token.LeadingTrivia[0]; + Assert.True(trivia.Kind() == SyntaxKind.ConflictMarkerTrivia); + + Assert.True(trivia.ContainsDiagnostics); + errors = trivia.Errors(); + Assert.Equal(1, errors.Length); + Assert.Equal((int)ErrorCode.ERR_Merge_conflict_marker_encountered, errors[0].Code); + + trivia = token.LeadingTrivia[1]; + Assert.True(trivia.Kind() == SyntaxKind.EndOfLineTrivia); + + trivia = token.LeadingTrivia[2]; + Assert.True(trivia.Kind() == SyntaxKind.DisabledTextTrivia); + + token = Lex(""" + ||||||| Trailing + disabled text + >>>>>>> Actually the end + """).First(); + Assert.Equal(SyntaxKind.EndOfFileToken, token.Kind()); + Assert.True(token.HasLeadingTrivia); + Assert.Equal(4, token.LeadingTrivia.Count); + var trivia1 = token.LeadingTrivia[0]; + Assert.True(trivia1.Kind() == SyntaxKind.ConflictMarkerTrivia); + + Assert.True(trivia1.ContainsDiagnostics); + errors = trivia1.Errors(); + Assert.Equal(1, errors.Length); + Assert.Equal((int)ErrorCode.ERR_Merge_conflict_marker_encountered, errors[0].Code); + + var trivia2 = token.LeadingTrivia[1]; + Assert.True(trivia2.Kind() == SyntaxKind.EndOfLineTrivia); + + var trivia3 = token.LeadingTrivia[2]; + Assert.True(trivia3.Kind() == SyntaxKind.DisabledTextTrivia); + + var trivia4 = token.LeadingTrivia[3]; + Assert.True(trivia4.Kind() == SyntaxKind.ConflictMarkerTrivia); + + Assert.True(trivia4.ContainsDiagnostics); + errors = trivia4.Errors(); + Assert.Equal(1, errors.Length); + Assert.Equal((int)ErrorCode.ERR_Merge_conflict_marker_encountered, errors[0].Code); + + + token = Lex(""" + ||||||| Trailing + >>>>>>> Actually the end + """).First(); + Assert.Equal(SyntaxKind.EndOfFileToken, token.Kind()); + Assert.True(token.HasLeadingTrivia); + Assert.Equal(3, token.LeadingTrivia.Count); + trivia1 = token.LeadingTrivia[0]; + Assert.True(trivia1.Kind() == SyntaxKind.ConflictMarkerTrivia); + + Assert.True(trivia1.ContainsDiagnostics); + errors = trivia1.Errors(); + Assert.Equal(1, errors.Length); + Assert.Equal((int)ErrorCode.ERR_Merge_conflict_marker_encountered, errors[0].Code); + + trivia2 = token.LeadingTrivia[1]; + Assert.True(trivia2.Kind() == SyntaxKind.EndOfLineTrivia); + + trivia3 = token.LeadingTrivia[2]; + Assert.True(trivia3.Kind() == SyntaxKind.ConflictMarkerTrivia); + + Assert.True(trivia3.ContainsDiagnostics); + errors = trivia3.Errors(); + Assert.Equal(1, errors.Length); + Assert.Equal((int)ErrorCode.ERR_Merge_conflict_marker_encountered, errors[0].Code); + } + + [Fact] + public void TestPipeConflictMarker2() + { + var token = Lex(""" + ||||||| Mid + ======= Trailing + >>>>>>> Actually the end + """).First(); + Assert.Equal(SyntaxKind.EndOfFileToken, token.Kind()); + Assert.True(token.HasLeadingTrivia); + Assert.Equal(5, token.LeadingTrivia.Count); + + var trivia = token.LeadingTrivia[0]; + Assert.True(trivia.Kind() == SyntaxKind.ConflictMarkerTrivia); + Assert.Equal("||||||| Mid", trivia.ToFullString()); + Assert.True(trivia.ContainsDiagnostics); + Assert.Equal((int)ErrorCode.ERR_Merge_conflict_marker_encountered, trivia.Errors().Single().Code); + + trivia = token.LeadingTrivia[1]; + Assert.True(trivia.Kind() == SyntaxKind.EndOfLineTrivia); + + trivia = token.LeadingTrivia[2]; + Assert.True(trivia.Kind() == SyntaxKind.ConflictMarkerTrivia); + Assert.Equal("======= Trailing", trivia.ToFullString()); + Assert.True(trivia.ContainsDiagnostics); + Assert.Equal((int)ErrorCode.ERR_Merge_conflict_marker_encountered, trivia.Errors().Single().Code); + + trivia = token.LeadingTrivia[3]; + Assert.True(trivia.Kind() == SyntaxKind.EndOfLineTrivia); + + trivia = token.LeadingTrivia[4]; + Assert.True(trivia.Kind() == SyntaxKind.ConflictMarkerTrivia); + Assert.Equal(">>>>>>> Actually the end", trivia.ToFullString()); + Assert.True(trivia.ContainsDiagnostics); + Assert.Equal((int)ErrorCode.ERR_Merge_conflict_marker_encountered, trivia.Errors().Single().Code); + } + + [Fact] + public void TestPipeConflictMarker3() + { + var token = Lex(""" + ||||||| Mid + disabled text 1 + ======= Trailing + disabled text 2 + >>>>>>> Actually the end + """).First(); + Assert.Equal(SyntaxKind.EndOfFileToken, token.Kind()); + Assert.True(token.HasLeadingTrivia); + Assert.Equal(7, token.LeadingTrivia.Count); + + var trivia = token.LeadingTrivia[0]; + Assert.True(trivia.Kind() == SyntaxKind.ConflictMarkerTrivia); + Assert.Equal("||||||| Mid", trivia.ToFullString()); + Assert.True(trivia.ContainsDiagnostics); + Assert.Equal((int)ErrorCode.ERR_Merge_conflict_marker_encountered, trivia.Errors().Single().Code); + + trivia = token.LeadingTrivia[1]; + Assert.True(trivia.Kind() == SyntaxKind.EndOfLineTrivia); + + trivia = token.LeadingTrivia[2]; + Assert.True(trivia.Kind() == SyntaxKind.DisabledTextTrivia); + Assert.Equal(""" + disabled text 1 + + """, trivia.ToFullString()); + + trivia = token.LeadingTrivia[3]; + Assert.True(trivia.Kind() == SyntaxKind.ConflictMarkerTrivia); + Assert.Equal("======= Trailing", trivia.ToFullString()); + Assert.True(trivia.ContainsDiagnostics); + Assert.Equal((int)ErrorCode.ERR_Merge_conflict_marker_encountered, trivia.Errors().Single().Code); + + trivia = token.LeadingTrivia[4]; + Assert.True(trivia.Kind() == SyntaxKind.EndOfLineTrivia); + + trivia = token.LeadingTrivia[5]; + Assert.True(trivia.Kind() == SyntaxKind.DisabledTextTrivia); + Assert.Equal(""" + disabled text 2 + + """, trivia.ToFullString()); + + trivia = token.LeadingTrivia[6]; + Assert.True(trivia.Kind() == SyntaxKind.ConflictMarkerTrivia); + Assert.Equal(">>>>>>> Actually the end", trivia.ToFullString()); + Assert.True(trivia.ContainsDiagnostics); + Assert.Equal((int)ErrorCode.ERR_Merge_conflict_marker_encountered, trivia.Errors().Single().Code); + } + + [Fact] + public void TestPipeConflictMarker4() + { + // second ======= is pat of disabled text + var token = Lex(""" + ||||||| Mid + disabled text 1 + ======= Trailing + disabled text 2 + ======= + more disabled text + >>>>>>> Actually the end + """).First(); + Assert.Equal(SyntaxKind.EndOfFileToken, token.Kind()); + Assert.True(token.HasLeadingTrivia); + Assert.Equal(7, token.LeadingTrivia.Count); + + var trivia = token.LeadingTrivia[0]; + Assert.True(trivia.Kind() == SyntaxKind.ConflictMarkerTrivia); + Assert.Equal("||||||| Mid", trivia.ToFullString()); + Assert.True(trivia.ContainsDiagnostics); + Assert.Equal((int)ErrorCode.ERR_Merge_conflict_marker_encountered, trivia.Errors().Single().Code); + + trivia = token.LeadingTrivia[1]; + Assert.True(trivia.Kind() == SyntaxKind.EndOfLineTrivia); + + trivia = token.LeadingTrivia[2]; + Assert.True(trivia.Kind() == SyntaxKind.DisabledTextTrivia); + Assert.Equal(""" + disabled text 1 + + """, trivia.ToFullString()); + + trivia = token.LeadingTrivia[3]; + Assert.True(trivia.Kind() == SyntaxKind.ConflictMarkerTrivia); + Assert.Equal("======= Trailing", trivia.ToFullString()); + Assert.True(trivia.ContainsDiagnostics); + Assert.Equal((int)ErrorCode.ERR_Merge_conflict_marker_encountered, trivia.Errors().Single().Code); + + trivia = token.LeadingTrivia[4]; + Assert.True(trivia.Kind() == SyntaxKind.EndOfLineTrivia); + + trivia = token.LeadingTrivia[5]; + Assert.True(trivia.Kind() == SyntaxKind.DisabledTextTrivia); + Assert.Equal(""" + disabled text 2 + ======= + more disabled text + + """, trivia.ToFullString()); + + trivia = token.LeadingTrivia[6]; + Assert.True(trivia.Kind() == SyntaxKind.ConflictMarkerTrivia); + Assert.Equal(">>>>>>> Actually the end", trivia.ToFullString()); + Assert.True(trivia.ContainsDiagnostics); + Assert.Equal((int)ErrorCode.ERR_Merge_conflict_marker_encountered, trivia.Errors().Single().Code); + } + + [Fact] + public void TestPipeConflictMarker5() + { + // second ||||||| is pat of disabled text + var token = Lex(""" + ||||||| Mid + disabled text 1 + ||||||| + more disabled text + ======= Trailing + disabled text 2 + >>>>>>> Actually the end + """).First(); + Assert.Equal(SyntaxKind.EndOfFileToken, token.Kind()); + Assert.True(token.HasLeadingTrivia); + Assert.Equal(7, token.LeadingTrivia.Count); + + var trivia = token.LeadingTrivia[0]; + Assert.True(trivia.Kind() == SyntaxKind.ConflictMarkerTrivia); + Assert.Equal("||||||| Mid", trivia.ToFullString()); + Assert.True(trivia.ContainsDiagnostics); + Assert.Equal((int)ErrorCode.ERR_Merge_conflict_marker_encountered, trivia.Errors().Single().Code); + + trivia = token.LeadingTrivia[1]; + Assert.True(trivia.Kind() == SyntaxKind.EndOfLineTrivia); + + trivia = token.LeadingTrivia[2]; + Assert.True(trivia.Kind() == SyntaxKind.DisabledTextTrivia); + Assert.Equal(""" + disabled text 1 + ||||||| + more disabled text + + """, trivia.ToFullString()); + + trivia = token.LeadingTrivia[3]; + Assert.True(trivia.Kind() == SyntaxKind.ConflictMarkerTrivia); + Assert.Equal("======= Trailing", trivia.ToFullString()); + Assert.True(trivia.ContainsDiagnostics); + Assert.Equal((int)ErrorCode.ERR_Merge_conflict_marker_encountered, trivia.Errors().Single().Code); + + trivia = token.LeadingTrivia[4]; + Assert.True(trivia.Kind() == SyntaxKind.EndOfLineTrivia); + + trivia = token.LeadingTrivia[5]; + Assert.True(trivia.Kind() == SyntaxKind.DisabledTextTrivia); + Assert.Equal(""" + disabled text 2 + + """, trivia.ToFullString()); + + trivia = token.LeadingTrivia[6]; + Assert.True(trivia.Kind() == SyntaxKind.ConflictMarkerTrivia); + Assert.Equal(">>>>>>> Actually the end", trivia.ToFullString()); + Assert.True(trivia.ContainsDiagnostics); + Assert.Equal((int)ErrorCode.ERR_Merge_conflict_marker_encountered, trivia.Errors().Single().Code); + } } } diff --git a/src/Compilers/CSharp/Test/Syntax/LexicalAndXml/PreprocessorTests.cs b/src/Compilers/CSharp/Test/Syntax/LexicalAndXml/PreprocessorTests.cs index 77b077c5328af..9d2ad9642482b 100644 --- a/src/Compilers/CSharp/Test/Syntax/LexicalAndXml/PreprocessorTests.cs +++ b/src/Compilers/CSharp/Test/Syntax/LexicalAndXml/PreprocessorTests.cs @@ -3223,9 +3223,9 @@ private void CheckDiagnosticStringFileName(string compilationFileName, string li [Theory] [InlineData(LanguageVersion.CSharp4, "4")] [InlineData(LanguageVersion.CSharp9, "9.0")] - [InlineData(LanguageVersion.Latest, "latest (10.0)")] - [InlineData(LanguageVersion.LatestMajor, "latestmajor (10.0)")] - [InlineData(LanguageVersion.Default, "default (10.0)")] + [InlineData(LanguageVersion.Latest, "latest (11.0)")] + [InlineData(LanguageVersion.LatestMajor, "latestmajor (11.0)")] + [InlineData(LanguageVersion.Default, "default (11.0)")] [InlineData(LanguageVersion.Preview, "preview")] public void TestErrorWithVersion(LanguageVersion version, string expectedLanguageVersion) { diff --git a/src/Compilers/CSharp/Test/Syntax/Parsing/AnonymousFunctionParsingTests.cs b/src/Compilers/CSharp/Test/Syntax/Parsing/AnonymousFunctionParsingTests.cs index 57c18f3c7fb05..51a5b3d40a6ac 100644 --- a/src/Compilers/CSharp/Test/Syntax/Parsing/AnonymousFunctionParsingTests.cs +++ b/src/Compilers/CSharp/Test/Syntax/Parsing/AnonymousFunctionParsingTests.cs @@ -2066,8 +2066,7 @@ static void Main() { } }"; - var tree = UsingTree(test); - tree.GetDiagnostics().Verify( + var tree = UsingTree(test, // (4,25): error CS1026: ) expected // [ObsoleteAttribute(x Diagnostic(ErrorCode.ERR_CloseParenExpected, "").WithLocation(4, 25), @@ -2144,8 +2143,7 @@ async static Task Main() { } }"; - var tree = UsingTree(test); - tree.GetDiagnostics().Verify( + var tree = UsingTree(test, // (4,25): error CS1003: Syntax error, ',' expected // [ObsoleteAttribute(x Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments(",").WithLocation(4, 25), diff --git a/src/Compilers/CSharp/Test/Syntax/Parsing/AsyncParsingTests.cs b/src/Compilers/CSharp/Test/Syntax/Parsing/AsyncParsingTests.cs index 78f0a99e054da..013e7a2862324 100644 --- a/src/Compilers/CSharp/Test/Syntax/Parsing/AsyncParsingTests.cs +++ b/src/Compilers/CSharp/Test/Syntax/Parsing/AsyncParsingTests.cs @@ -354,7 +354,13 @@ public void IncompleteAsync() class C { async -"); +", + // (4,10): error CS1513: } expected + // async + Diagnostic(ErrorCode.ERR_RbraceExpected, "").WithLocation(4, 10), + // (5,1): error CS1519: Invalid token '' in class, record, struct, or interface member declaration + // + Diagnostic(ErrorCode.ERR_InvalidMemberDecl, "").WithArguments("").WithLocation(5, 1)); N(SyntaxKind.CompilationUnit); { N(SyntaxKind.ClassDeclaration); @@ -382,7 +388,13 @@ public void IncompleteAsyncAsync() class C { async async -"); +", + // (4,16): error CS1513: } expected + // async async + Diagnostic(ErrorCode.ERR_RbraceExpected, "").WithLocation(4, 16), + // (5,1): error CS1519: Invalid token '' in class, record, struct, or interface member declaration + // + Diagnostic(ErrorCode.ERR_InvalidMemberDecl, "").WithArguments("").WithLocation(5, 1)); N(SyntaxKind.CompilationUnit); { N(SyntaxKind.ClassDeclaration); @@ -412,7 +424,10 @@ public void CompleteAsyncAsync1() class C { async async; -"); +", + // (4,17): error CS1513: } expected + // async async; + Diagnostic(ErrorCode.ERR_RbraceExpected, "").WithLocation(4, 17)); N(SyntaxKind.CompilationUnit); { N(SyntaxKind.ClassDeclaration); @@ -449,7 +464,10 @@ public void CompleteAsyncAsync2() class C { async async = 1; -"); +", + // (4,21): error CS1513: } expected + // async async = 1; + Diagnostic(ErrorCode.ERR_RbraceExpected, "").WithLocation(4, 21)); N(SyntaxKind.CompilationUnit); { N(SyntaxKind.ClassDeclaration); @@ -494,7 +512,13 @@ public void IncompleteAsyncAsyncAsync() class C { async async async -"); +", + // (4,22): error CS1513: } expected + // async async async + Diagnostic(ErrorCode.ERR_RbraceExpected, "").WithLocation(4, 22), + // (5,1): error CS1519: Invalid token '' in class, record, struct, or interface member declaration + // + Diagnostic(ErrorCode.ERR_InvalidMemberDecl, "").WithArguments("").WithLocation(5, 1)); N(SyntaxKind.CompilationUnit); { N(SyntaxKind.ClassDeclaration); @@ -525,7 +549,10 @@ public void CompleteAsyncAsyncAsync() class C { async async async; -"); +", + // (4,23): error CS1513: } expected + // async async async; + Diagnostic(ErrorCode.ERR_RbraceExpected, "").WithLocation(4, 23)); N(SyntaxKind.CompilationUnit); { N(SyntaxKind.ClassDeclaration); @@ -563,7 +590,13 @@ public void IncompleteAsyncAsyncAsyncAsync() class C { async async async async -"); +", + // (4,28): error CS1513: } expected + // async async async async + Diagnostic(ErrorCode.ERR_RbraceExpected, "").WithLocation(4, 28), + // (5,1): error CS1519: Invalid token '' in class, record, struct, or interface member declaration + // + Diagnostic(ErrorCode.ERR_InvalidMemberDecl, "").WithArguments("").WithLocation(5, 1)); N(SyntaxKind.CompilationUnit); { N(SyntaxKind.ClassDeclaration); @@ -595,7 +628,10 @@ public void CompleteAsyncAsyncAsyncAsync() class C { async async async async; -"); +", + // (4,29): error CS1513: } expected + // async async async async; + Diagnostic(ErrorCode.ERR_RbraceExpected, "").WithLocation(4, 29)); N(SyntaxKind.CompilationUnit); { N(SyntaxKind.ClassDeclaration); @@ -636,7 +672,13 @@ public void IncompleteAsyncMember01() class C { async Task< -}"); +}", + // (4,16): error CS1031: Type expected + // async Task< + Diagnostic(ErrorCode.ERR_TypeExpected, "").WithLocation(4, 16), + // (4,16): error CS1003: Syntax error, '>' expected + // async Task< + Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments(">").WithLocation(4, 16)); N(SyntaxKind.CompilationUnit); { N(SyntaxKind.ClassDeclaration); @@ -676,7 +718,13 @@ public void IncompleteAsyncMember02() class C { async Tasks.Task< -}"); +}", + // (4,22): error CS1031: Type expected + // async Tasks.Task< + Diagnostic(ErrorCode.ERR_TypeExpected, "").WithLocation(4, 22), + // (4,22): error CS1003: Syntax error, '>' expected + // async Tasks.Task< + Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments(">").WithLocation(4, 22)); N(SyntaxKind.CompilationUnit); { N(SyntaxKind.ClassDeclaration); @@ -724,7 +772,13 @@ public void IncompleteAsyncMember03() class C { static async Tasks.Task< -}"); +}", + // (4,29): error CS1031: Type expected + // static async Tasks.Task< + Diagnostic(ErrorCode.ERR_TypeExpected, "").WithLocation(4, 29), + // (4,29): error CS1003: Syntax error, '>' expected + // static async Tasks.Task< + Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments(">").WithLocation(4, 29)); N(SyntaxKind.CompilationUnit); { N(SyntaxKind.ClassDeclaration); @@ -774,7 +828,19 @@ public void IncompleteAsyncMember04() class C { async operator+ -}"); +}", + // (4,19): error CS1534: Overloaded binary operator '+' takes two parameters + // async operator+ + Diagnostic(ErrorCode.ERR_BadBinOpArgs, "+").WithArguments("+").WithLocation(4, 19), + // (4,20): error CS1003: Syntax error, '(' expected + // async operator+ + Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments("(").WithLocation(4, 20), + // (4,20): error CS1026: ) expected + // async operator+ + Diagnostic(ErrorCode.ERR_CloseParenExpected, "").WithLocation(4, 20), + // (4,20): error CS1002: ; expected + // async operator+ + Diagnostic(ErrorCode.ERR_SemicolonExpected, "").WithLocation(4, 20)); N(SyntaxKind.CompilationUnit); { N(SyntaxKind.ClassDeclaration); @@ -813,7 +879,10 @@ public void IncompleteAsyncMember05() class C { async Task -}"); +}", + // (5,1): error CS1519: Invalid token '}' in class, record, struct, or interface member declaration + // } + Diagnostic(ErrorCode.ERR_InvalidMemberDecl, "}").WithArguments("}").WithLocation(5, 1)); N(SyntaxKind.CompilationUnit); { N(SyntaxKind.ClassDeclaration); @@ -854,7 +923,10 @@ public void IncompleteAsyncMember06() class C { async Task f -}"); +}", + // (4,20): error CS1002: ; expected + // async Task f + Diagnostic(ErrorCode.ERR_SemicolonExpected, "").WithLocation(4, 20)); N(SyntaxKind.CompilationUnit); { N(SyntaxKind.ClassDeclaration); @@ -1030,7 +1102,16 @@ class C { event async async async; } -"); +", + // (4,23): error CS1002: ; expected + // event async async async; + Diagnostic(ErrorCode.ERR_SemicolonExpected, "async").WithLocation(4, 23), + // (4,28): error CS1519: Invalid token ';' in class, record, struct, or interface member declaration + // event async async async; + Diagnostic(ErrorCode.ERR_InvalidMemberDecl, ";").WithArguments(";").WithLocation(4, 28), + // (4,28): error CS1519: Invalid token ';' in class, record, struct, or interface member declaration + // event async async async; + Diagnostic(ErrorCode.ERR_InvalidMemberDecl, ";").WithArguments(";").WithLocation(4, 28)); N(SyntaxKind.CompilationUnit); { N(SyntaxKind.ClassDeclaration); @@ -1348,7 +1429,19 @@ public void AsyncInterface() class C { async interface -"); +", + // (4,20): error CS1001: Identifier expected + // async interface + Diagnostic(ErrorCode.ERR_IdentifierExpected, "").WithLocation(4, 20), + // (4,20): error CS1514: { expected + // async interface + Diagnostic(ErrorCode.ERR_LbraceExpected, "").WithLocation(4, 20), + // (4,20): error CS1513: } expected + // async interface + Diagnostic(ErrorCode.ERR_RbraceExpected, "").WithLocation(4, 20), + // (4,20): error CS1513: } expected + // async interface + Diagnostic(ErrorCode.ERR_RbraceExpected, "").WithLocation(4, 20)); N(SyntaxKind.CompilationUnit); { N(SyntaxKind.ClassDeclaration); @@ -1379,7 +1472,19 @@ public void AsyncPartialClass() class C { async partial class -"); +", + // (4,24): error CS1001: Identifier expected + // async partial class + Diagnostic(ErrorCode.ERR_IdentifierExpected, "").WithLocation(4, 24), + // (4,24): error CS1514: { expected + // async partial class + Diagnostic(ErrorCode.ERR_LbraceExpected, "").WithLocation(4, 24), + // (4,24): error CS1513: } expected + // async partial class + Diagnostic(ErrorCode.ERR_RbraceExpected, "").WithLocation(4, 24), + // (4,24): error CS1513: } expected + // async partial class + Diagnostic(ErrorCode.ERR_RbraceExpected, "").WithLocation(4, 24)); N(SyntaxKind.CompilationUnit); { N(SyntaxKind.ClassDeclaration); @@ -1411,7 +1516,19 @@ public void AsyncEvent() class C { async event -"); +", + // (4,16): error CS1031: Type expected + // async event + Diagnostic(ErrorCode.ERR_TypeExpected, "").WithLocation(4, 16), + // (4,16): error CS1514: { expected + // async event + Diagnostic(ErrorCode.ERR_LbraceExpected, "").WithLocation(4, 16), + // (4,16): error CS1513: } expected + // async event + Diagnostic(ErrorCode.ERR_RbraceExpected, "").WithLocation(4, 16), + // (4,16): error CS1513: } expected + // async event + Diagnostic(ErrorCode.ERR_RbraceExpected, "").WithLocation(4, 16)); N(SyntaxKind.CompilationUnit); { N(SyntaxKind.ClassDeclaration); @@ -1449,7 +1566,22 @@ public void AsyncPartialEvent() 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), + // (4,24): error CS1514: { expected + // async partial event + Diagnostic(ErrorCode.ERR_LbraceExpected, "").WithLocation(4, 24), + // (4,24): error CS1513: } expected + // async partial event + Diagnostic(ErrorCode.ERR_RbraceExpected, "").WithLocation(4, 24), + // (4,24): error CS1513: } expected + // async partial event + Diagnostic(ErrorCode.ERR_RbraceExpected, "").WithLocation(4, 24)); N(SyntaxKind.CompilationUnit); { N(SyntaxKind.ClassDeclaration); @@ -1494,7 +1626,22 @@ public void AsyncImplicitOperator() class C { async implicit operator -"); +", + // (4,28): error CS1031: Type expected + // async implicit operator + Diagnostic(ErrorCode.ERR_TypeExpected, "").WithLocation(4, 28), + // (4,28): error CS1003: Syntax error, '(' expected + // async implicit operator + Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments("(").WithLocation(4, 28), + // (4,28): error CS1026: ) expected + // async implicit operator + Diagnostic(ErrorCode.ERR_CloseParenExpected, "").WithLocation(4, 28), + // (4,28): error CS1002: ; expected + // async implicit operator + Diagnostic(ErrorCode.ERR_SemicolonExpected, "").WithLocation(4, 28), + // (4,28): error CS1513: } expected + // async implicit operator + Diagnostic(ErrorCode.ERR_RbraceExpected, "").WithLocation(4, 28)); N(SyntaxKind.CompilationUnit); { N(SyntaxKind.ClassDeclaration); @@ -1533,7 +1680,31 @@ public void AsyncPartialImplicitOperator() class C { async partial implicit operator -"); +", + // (4,11): error CS1553: Declaration is not valid; use '+ operator (...' instead + // async partial implicit operator + Diagnostic(ErrorCode.ERR_BadOperatorSyntax, "partial").WithArguments("+").WithLocation(4, 11), + // (4,19): error CS1003: Syntax error, 'operator' expected + // async partial implicit operator + Diagnostic(ErrorCode.ERR_SyntaxError, "implicit").WithArguments("operator").WithLocation(4, 19), + // (4,19): error CS1037: Overloadable operator expected + // async partial implicit operator + Diagnostic(ErrorCode.ERR_OvlOperatorExpected, "implicit").WithLocation(4, 19), + // (4,28): error CS1003: Syntax error, '(' expected + // async partial implicit operator + Diagnostic(ErrorCode.ERR_SyntaxError, "operator").WithArguments("(").WithLocation(4, 28), + // (4,28): error CS1041: Identifier expected; 'operator' is a keyword + // async partial implicit operator + Diagnostic(ErrorCode.ERR_IdentifierExpectedKW, "operator").WithArguments("", "operator").WithLocation(4, 28), + // (4,36): error CS1026: ) expected + // async partial implicit operator + Diagnostic(ErrorCode.ERR_CloseParenExpected, "").WithLocation(4, 36), + // (4,36): error CS1002: ; expected + // async partial implicit operator + Diagnostic(ErrorCode.ERR_SemicolonExpected, "").WithLocation(4, 36), + // (4,36): error CS1513: } expected + // async partial implicit operator + Diagnostic(ErrorCode.ERR_RbraceExpected, "").WithLocation(4, 36)); N(SyntaxKind.CompilationUnit); { N(SyntaxKind.ClassDeclaration); @@ -1572,7 +1743,22 @@ public void AsyncExplicitOperator() class C { async explicit operator -"); +", + // (4,28): error CS1031: Type expected + // async explicit operator + Diagnostic(ErrorCode.ERR_TypeExpected, "").WithLocation(4, 28), + // (4,28): error CS1003: Syntax error, '(' expected + // async explicit operator + Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments("(").WithLocation(4, 28), + // (4,28): error CS1026: ) expected + // async explicit operator + Diagnostic(ErrorCode.ERR_CloseParenExpected, "").WithLocation(4, 28), + // (4,28): error CS1002: ; expected + // async explicit operator + Diagnostic(ErrorCode.ERR_SemicolonExpected, "").WithLocation(4, 28), + // (4,28): error CS1513: } expected + // async explicit operator + Diagnostic(ErrorCode.ERR_RbraceExpected, "").WithLocation(4, 28)); N(SyntaxKind.CompilationUnit); { N(SyntaxKind.ClassDeclaration); @@ -1611,7 +1797,31 @@ public void AsyncPartialExplicitOperator() class C { async partial explicit operator -"); +", + // (4,11): error CS1553: Declaration is not valid; use '+ operator (...' instead + // async partial explicit operator + Diagnostic(ErrorCode.ERR_BadOperatorSyntax, "partial").WithArguments("+").WithLocation(4, 11), + // (4,19): error CS1003: Syntax error, 'operator' expected + // async partial explicit operator + Diagnostic(ErrorCode.ERR_SyntaxError, "explicit").WithArguments("operator").WithLocation(4, 19), + // (4,19): error CS1037: Overloadable operator expected + // async partial explicit operator + Diagnostic(ErrorCode.ERR_OvlOperatorExpected, "explicit").WithLocation(4, 19), + // (4,28): error CS1003: Syntax error, '(' expected + // async partial explicit operator + Diagnostic(ErrorCode.ERR_SyntaxError, "operator").WithArguments("(").WithLocation(4, 28), + // (4,28): error CS1041: Identifier expected; 'operator' is a keyword + // async partial explicit operator + Diagnostic(ErrorCode.ERR_IdentifierExpectedKW, "operator").WithArguments("", "operator").WithLocation(4, 28), + // (4,36): error CS1026: ) expected + // async partial explicit operator + Diagnostic(ErrorCode.ERR_CloseParenExpected, "").WithLocation(4, 36), + // (4,36): error CS1002: ; expected + // async partial explicit operator + Diagnostic(ErrorCode.ERR_SemicolonExpected, "").WithLocation(4, 36), + // (4,36): error CS1513: } expected + // async partial explicit operator + Diagnostic(ErrorCode.ERR_RbraceExpected, "").WithLocation(4, 36)); N(SyntaxKind.CompilationUnit); { N(SyntaxKind.ClassDeclaration); @@ -1650,7 +1860,22 @@ public void AsyncTypeOperator() class C { async C operator -"); +", + // (5,1): error CS1037: Overloadable operator expected + // + Diagnostic(ErrorCode.ERR_OvlOperatorExpected, "").WithLocation(5, 1), + // (5,1): error CS1003: Syntax error, '(' expected + // + Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments("(").WithLocation(5, 1), + // (5,1): error CS1026: ) expected + // + Diagnostic(ErrorCode.ERR_CloseParenExpected, "").WithLocation(5, 1), + // (5,1): error CS1002: ; expected + // + Diagnostic(ErrorCode.ERR_SemicolonExpected, "").WithLocation(5, 1), + // (5,1): error CS1513: } expected + // + Diagnostic(ErrorCode.ERR_RbraceExpected, "").WithLocation(5, 1)); N(SyntaxKind.CompilationUnit); { N(SyntaxKind.ClassDeclaration); @@ -1689,7 +1914,25 @@ public void AsyncPartialTypeOperator() class C { async partial int operator -"); +", + // (4,19): error CS1519: Invalid token 'int' in class, record, struct, or interface member declaration + // async partial int operator + Diagnostic(ErrorCode.ERR_InvalidMemberDecl, "int").WithArguments("int").WithLocation(4, 19), + // (5,1): error CS1037: Overloadable operator expected + // + Diagnostic(ErrorCode.ERR_OvlOperatorExpected, "").WithLocation(5, 1), + // (5,1): error CS1003: Syntax error, '(' expected + // + Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments("(").WithLocation(5, 1), + // (5,1): error CS1026: ) expected + // + Diagnostic(ErrorCode.ERR_CloseParenExpected, "").WithLocation(5, 1), + // (5,1): error CS1002: ; expected + // + Diagnostic(ErrorCode.ERR_SemicolonExpected, "").WithLocation(5, 1), + // (5,1): error CS1513: } expected + // + Diagnostic(ErrorCode.ERR_RbraceExpected, "").WithLocation(5, 1)); N(SyntaxKind.CompilationUnit); { N(SyntaxKind.ClassDeclaration); @@ -1735,7 +1978,13 @@ public void AsyncField() class C { async C C -"); +", + // (4,14): error CS1002: ; expected + // async C C + Diagnostic(ErrorCode.ERR_SemicolonExpected, "").WithLocation(4, 14), + // (4,14): error CS1513: } expected + // async C C + Diagnostic(ErrorCode.ERR_RbraceExpected, "").WithLocation(4, 14)); N(SyntaxKind.CompilationUnit); { N(SyntaxKind.ClassDeclaration); @@ -1774,7 +2023,22 @@ public void AsyncPartialIndexer() class C { async partial C this -"); +", + // (4,25): error CS1003: Syntax error, '[' expected + // async partial C this + Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments("[").WithLocation(4, 25), + // (4,25): error CS1003: Syntax error, ']' expected + // async partial C this + Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments("]").WithLocation(4, 25), + // (4,25): error CS1514: { expected + // async partial C this + Diagnostic(ErrorCode.ERR_LbraceExpected, "").WithLocation(4, 25), + // (4,25): error CS1513: } expected + // async partial C this + Diagnostic(ErrorCode.ERR_RbraceExpected, "").WithLocation(4, 25), + // (4,25): error CS1513: } expected + // async partial C this + Diagnostic(ErrorCode.ERR_RbraceExpected, "").WithLocation(4, 25)); N(SyntaxKind.CompilationUnit); { N(SyntaxKind.ClassDeclaration); @@ -1812,7 +2076,13 @@ async partial C this [Fact] public void AsyncTypeEndOfFile() { - UsingTree("class C { async T"); + UsingTree("class C { async T", + // (1,18): error CS1519: Invalid token '' in class, record, struct, or interface member declaration + // class C { async T + Diagnostic(ErrorCode.ERR_InvalidMemberDecl, "").WithArguments("").WithLocation(1, 18), + // (1,18): error CS1513: } expected + // class C { async T + Diagnostic(ErrorCode.ERR_RbraceExpected, "").WithLocation(1, 18)); N(SyntaxKind.CompilationUnit); { @@ -1839,7 +2109,10 @@ public void AsyncTypeEndOfFile() [Fact] public void AsyncTypeCloseCurly() { - UsingTree("class C { async T }"); + UsingTree("class C { async T }", + // (1,19): error CS1519: Invalid token '}' in class, record, struct, or interface member declaration + // class C { async T } + Diagnostic(ErrorCode.ERR_InvalidMemberDecl, "}").WithArguments("}").WithLocation(1, 19)); N(SyntaxKind.CompilationUnit); { @@ -1869,7 +2142,16 @@ public void AsyncTypePredefinedType() UsingTree( @"class C { async T - int"); + int", + // (3,5): error CS1519: Invalid token 'int' in class, record, struct, or interface member declaration + // int + Diagnostic(ErrorCode.ERR_InvalidMemberDecl, "int").WithArguments("int").WithLocation(3, 5), + // (3,8): error CS1519: Invalid token '' in class, record, struct, or interface member declaration + // int + Diagnostic(ErrorCode.ERR_InvalidMemberDecl, "").WithArguments("").WithLocation(3, 8), + // (3,8): error CS1513: } expected + // int + Diagnostic(ErrorCode.ERR_RbraceExpected, "").WithLocation(3, 8)); N(SyntaxKind.CompilationUnit); { @@ -1906,7 +2188,16 @@ public void AsyncTypeModifier() UsingTree( @"class C { async T - public"); + public", + // (3,5): error CS1585: Member modifier 'public' must precede the member type and name + // public + Diagnostic(ErrorCode.ERR_BadModifierLocation, "public").WithArguments("public").WithLocation(3, 5), + // (3,11): error CS1519: Invalid token '' in class, record, struct, or interface member declaration + // public + Diagnostic(ErrorCode.ERR_InvalidMemberDecl, "").WithArguments("").WithLocation(3, 11), + // (3,11): error CS1513: } expected + // public + Diagnostic(ErrorCode.ERR_RbraceExpected, "").WithLocation(3, 11)); N(SyntaxKind.CompilationUnit); { @@ -1940,7 +2231,22 @@ public void AsyncTypeFollowedByTypeDecl() UsingTree( @"class C { async T -class"); +class", + // (3,1): error CS1519: Invalid token 'class' in class, record, struct, or interface member declaration + // class + Diagnostic(ErrorCode.ERR_InvalidMemberDecl, "class").WithArguments("class").WithLocation(3, 1), + // (3,6): error CS1001: Identifier expected + // class + Diagnostic(ErrorCode.ERR_IdentifierExpected, "").WithLocation(3, 6), + // (3,6): error CS1514: { expected + // class + Diagnostic(ErrorCode.ERR_LbraceExpected, "").WithLocation(3, 6), + // (3,6): error CS1513: } expected + // class + Diagnostic(ErrorCode.ERR_RbraceExpected, "").WithLocation(3, 6), + // (3,6): error CS1513: } expected + // class + Diagnostic(ErrorCode.ERR_RbraceExpected, "").WithLocation(3, 6)); N(SyntaxKind.CompilationUnit); { @@ -1977,7 +2283,22 @@ public void AsyncTypeFollowedByNamespaceDecl() UsingTree( @"class C { async T -namespace"); +namespace", + // (2,12): error CS1513: } expected + // async T + Diagnostic(ErrorCode.ERR_RbraceExpected, "").WithLocation(2, 12), + // (3,1): error CS1519: Invalid token 'namespace' in class, record, struct, or interface member declaration + // namespace + Diagnostic(ErrorCode.ERR_InvalidMemberDecl, "namespace").WithArguments("namespace").WithLocation(3, 1), + // (3,10): error CS1001: Identifier expected + // namespace + Diagnostic(ErrorCode.ERR_IdentifierExpected, "").WithLocation(3, 10), + // (3,10): error CS1514: { expected + // namespace + Diagnostic(ErrorCode.ERR_LbraceExpected, "").WithLocation(3, 10), + // (3,10): error CS1513: } expected + // namespace + Diagnostic(ErrorCode.ERR_RbraceExpected, "").WithLocation(3, 10)); N(SyntaxKind.CompilationUnit); { @@ -2018,7 +2339,10 @@ public void AsyncGenericType() @"class Program { public async Task> -}"); +}", + // (4,1): error CS1519: Invalid token '}' in class, record, struct, or interface member declaration + // } + Diagnostic(ErrorCode.ERR_InvalidMemberDecl, "}").WithArguments("}").WithLocation(4, 1)); N(SyntaxKind.CompilationUnit); { @@ -2065,7 +2389,7 @@ public async Task> [WorkItem(16044, "https://github.com/dotnet/roslyn/issues/16044")] public void AsyncAsType_Property_ExpressionBody() { - UsingTree("class async { async async => null; }").GetDiagnostics().Verify( + UsingTree("class async { async async => null; }", // (1,27): error CS8026: Feature 'expression-bodied property' is not available in C# 5. Please use language version 6 or greater. // class async { async async => null; } Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion5, "=> null").WithArguments("expression-bodied property", "6").WithLocation(1, 27) @@ -2143,7 +2467,7 @@ public void AsyncAsType_Property() [WorkItem(16044, "https://github.com/dotnet/roslyn/issues/16044")] public void AsyncAsType_Indexer_ExpressionBody_ErrorCase() { - UsingTree("interface async { async this[async i] => null; }").GetDiagnostics().Verify( + UsingTree("interface async { async this[async i] => null; }", // (1,39): error CS8026: Feature 'expression-bodied indexer' is not available in C# 5. Please use language version 6 or greater. // interface async { async this[async i] => null; } Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion5, "=> null").WithArguments("expression-bodied indexer", "6").WithLocation(1, 39) @@ -2247,7 +2571,7 @@ public void AsyncAsType_Indexer() [WorkItem(16044, "https://github.com/dotnet/roslyn/issues/16044")] public void AsyncAsType_Property_ExplicitInterface() { - UsingTree("class async : async { async async.async => null; }").GetDiagnostics().Verify( + UsingTree("class async : async { async async.async => null; }", // (1,41): error CS8026: Feature 'expression-bodied property' is not available in C# 5. Please use language version 6 or greater. // class async : async { async async.async => null; } Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion5, "=> null").WithArguments("expression-bodied property", "6").WithLocation(1, 41) diff --git a/src/Compilers/CSharp/Test/Syntax/Parsing/AsyncStreamsParsingTests.cs b/src/Compilers/CSharp/Test/Syntax/Parsing/AsyncStreamsParsingTests.cs index 8aba0fc4800a5..b5c27199396f1 100644 --- a/src/Compilers/CSharp/Test/Syntax/Parsing/AsyncStreamsParsingTests.cs +++ b/src/Compilers/CSharp/Test/Syntax/Parsing/AsyncStreamsParsingTests.cs @@ -183,7 +183,25 @@ async void M() } } } -"); +", + // (6,15): error CS4003: 'await' cannot be used as an identifier within an async method or lambda expression + // using await (this) + Diagnostic(ErrorCode.ERR_BadAwaitAsIdentifier, "await").WithLocation(6, 15), + // (6,21): error CS1001: Identifier expected + // using await (this) + Diagnostic(ErrorCode.ERR_IdentifierExpected, "(").WithLocation(6, 21), + // (6,21): error CS1528: Expected ; or = (cannot specify constructor arguments in declaration) + // using await (this) + Diagnostic(ErrorCode.ERR_BadVarDecl, "(this").WithLocation(6, 21), + // (6,21): error CS1003: Syntax error, '[' expected + // using await (this) + Diagnostic(ErrorCode.ERR_SyntaxError, "(").WithArguments("[").WithLocation(6, 21), + // (6,26): error CS1003: Syntax error, ']' expected + // using await (this) + Diagnostic(ErrorCode.ERR_SyntaxError, ")").WithArguments("]").WithLocation(6, 26), + // (6,27): error CS1002: ; expected + // using await (this) + Diagnostic(ErrorCode.ERR_SemicolonExpected, "").WithLocation(6, 27)); N(SyntaxKind.CompilationUnit); { N(SyntaxKind.ClassDeclaration); @@ -334,7 +352,37 @@ async void M() } } } -"); +", + // (6,17): error CS1003: Syntax error, '(' expected + // foreach await (var i in collection) + Diagnostic(ErrorCode.ERR_SyntaxError, "await").WithArguments("(").WithLocation(6, 17), + // (6,28): error CS1026: ) expected + // foreach await (var i in collection) + Diagnostic(ErrorCode.ERR_CloseParenExpected, "i").WithLocation(6, 28), + // (6,28): error CS1515: 'in' expected + // foreach await (var i in collection) + Diagnostic(ErrorCode.ERR_InExpected, "i").WithLocation(6, 28), + // (6,28): error CS0230: Type and identifier are both required in a foreach statement + // foreach await (var i in collection) + Diagnostic(ErrorCode.ERR_BadForeachDecl, "i").WithLocation(6, 28), + // (6,30): error CS1026: ) expected + // foreach await (var i in collection) + Diagnostic(ErrorCode.ERR_CloseParenExpected, "in").WithLocation(6, 30), + // (6,30): error CS1525: Invalid expression term 'in' + // foreach await (var i in collection) + Diagnostic(ErrorCode.ERR_InvalidExprTerm, "in").WithArguments("in").WithLocation(6, 30), + // (6,30): error CS1002: ; expected + // foreach await (var i in collection) + Diagnostic(ErrorCode.ERR_SemicolonExpected, "in").WithLocation(6, 30), + // (6,30): error CS1513: } expected + // foreach await (var i in collection) + Diagnostic(ErrorCode.ERR_RbraceExpected, "in").WithLocation(6, 30), + // (6,43): error CS1002: ; expected + // foreach await (var i in collection) + Diagnostic(ErrorCode.ERR_SemicolonExpected, ")").WithLocation(6, 43), + // (6,43): error CS1513: } expected + // foreach await (var i in collection) + Diagnostic(ErrorCode.ERR_RbraceExpected, ")").WithLocation(6, 43)); N(SyntaxKind.CompilationUnit); { N(SyntaxKind.ClassDeclaration); diff --git a/src/Compilers/CSharp/Test/Syntax/Parsing/AwaitParsingTests.cs b/src/Compilers/CSharp/Test/Syntax/Parsing/AwaitParsingTests.cs index 4720d8418c1fe..56c40064345ad 100644 --- a/src/Compilers/CSharp/Test/Syntax/Parsing/AwaitParsingTests.cs +++ b/src/Compilers/CSharp/Test/Syntax/Parsing/AwaitParsingTests.cs @@ -225,7 +225,10 @@ void f() }; } } -"); +", + // (9,21): error CS4003: 'await' cannot be used as an identifier within an async method or lambda expression + // int await; + Diagnostic(ErrorCode.ERR_BadAwaitAsIdentifier, "await").WithLocation(9, 21)); N(SyntaxKind.CompilationUnit); { diff --git a/src/Compilers/CSharp/Test/Syntax/Parsing/CrefParsingTests.cs b/src/Compilers/CSharp/Test/Syntax/Parsing/CrefParsingTests.cs index ffa57fbff8d15..d7850d7a4095d 100644 --- a/src/Compilers/CSharp/Test/Syntax/Parsing/CrefParsingTests.cs +++ b/src/Compilers/CSharp/Test/Syntax/Parsing/CrefParsingTests.cs @@ -347,7 +347,7 @@ public void QualifiedIndexerMember2() [Fact] public void UnqualifiedUnsignedRightShift_01() { - foreach (var options in new[] { TestOptions.RegularPreview, TestOptions.Regular10, TestOptions.RegularNext }) + foreach (var options in new[] { TestOptions.RegularPreview, TestOptions.Regular10, TestOptions.Regular11 }) { UsingNode("operator >>>", options); @@ -362,7 +362,7 @@ public void UnqualifiedUnsignedRightShift_01() [Fact] public void UnqualifiedUnsignedRightShift_02() { - foreach (var options in new[] { TestOptions.RegularPreview, TestOptions.Regular10, TestOptions.RegularNext }) + foreach (var options in new[] { TestOptions.RegularPreview, TestOptions.Regular10, TestOptions.Regular11 }) { UsingNode("operator > >>", options); @@ -378,7 +378,7 @@ public void UnqualifiedUnsignedRightShift_02() [Fact] public void UnqualifiedUnsignedRightShift_03() { - foreach (var options in new[] { TestOptions.RegularPreview, TestOptions.Regular10, TestOptions.RegularNext }) + foreach (var options in new[] { TestOptions.RegularPreview, TestOptions.Regular10, TestOptions.Regular11 }) { UsingNode("operator >> >", options); @@ -394,7 +394,7 @@ public void UnqualifiedUnsignedRightShift_03() [Fact] public void UnqualifiedUnsignedRightShift_04() { - foreach (var options in new[] { TestOptions.RegularPreview, TestOptions.Regular10, TestOptions.RegularNext }) + foreach (var options in new[] { TestOptions.RegularPreview, TestOptions.Regular10, TestOptions.Regular11 }) { UsingNode("operator >>>=", options); diff --git a/src/Compilers/CSharp/Test/Syntax/Parsing/DeclarationParsingTests.cs b/src/Compilers/CSharp/Test/Syntax/Parsing/DeclarationParsingTests.cs index df1d098346a66..ea0b0e036738c 100644 --- a/src/Compilers/CSharp/Test/Syntax/Parsing/DeclarationParsingTests.cs +++ b/src/Compilers/CSharp/Test/Syntax/Parsing/DeclarationParsingTests.cs @@ -5757,9 +5757,6 @@ public void TestPartialEnum() { var text = @"partial enum E{}"; CreateCompilationWithMscorlib45(text).VerifyDiagnostics( - // (1,1): error CS0267: The 'partial' modifier can only appear immediately before 'class', 'record', 'struct', 'interface', or a method return type. - // partial enum E{} - Diagnostic(ErrorCode.ERR_PartialMisplaced, "partial").WithLocation(1, 1), // (1,14): error CS0267: The 'partial' modifier can only appear immediately before 'class', 'record', 'struct', 'interface', or a method return type. // partial enum E{} Diagnostic(ErrorCode.ERR_PartialMisplaced, "E").WithLocation(1, 14)); @@ -6122,7 +6119,13 @@ public interface I1 event System.Action I2. P10 } -"); +", + // (5,27): error CS0071: An explicit interface implementation of an event must use event accessor syntax + // event System.Action I2. + Diagnostic(ErrorCode.ERR_ExplicitEventFieldImpl, ".").WithLocation(5, 27), + // (7,1): error CS1519: Invalid token '}' in class, record, struct, or interface member declaration + // } + Diagnostic(ErrorCode.ERR_InvalidMemberDecl, "}").WithArguments("}").WithLocation(7, 1)); N(SyntaxKind.CompilationUnit); { N(SyntaxKind.InterfaceDeclaration); @@ -6192,7 +6195,10 @@ public interface I1 { event System.Action I2.P10 } -"); +", + // (5,27): error CS0071: An explicit interface implementation of an event must use event accessor syntax + // event System.Action I2.P10 + Diagnostic(ErrorCode.ERR_ExplicitEventFieldImpl, ".").WithLocation(5, 27)); N(SyntaxKind.CompilationUnit); { N(SyntaxKind.InterfaceDeclaration); @@ -6256,7 +6262,19 @@ class C int A { get { return this. public int B; } -"); +", + // (4,31): error CS1001: Identifier expected + // int A { get { return this. + Diagnostic(ErrorCode.ERR_IdentifierExpected, "").WithLocation(4, 31), + // (4,31): error CS1002: ; expected + // int A { get { return this. + Diagnostic(ErrorCode.ERR_SemicolonExpected, "").WithLocation(4, 31), + // (4,31): error CS1513: } expected + // int A { get { return this. + Diagnostic(ErrorCode.ERR_RbraceExpected, "").WithLocation(4, 31), + // (4,31): error CS1513: } expected + // int A { get { return this. + Diagnostic(ErrorCode.ERR_RbraceExpected, "").WithLocation(4, 31)); N(SyntaxKind.CompilationUnit); { @@ -6599,7 +6617,13 @@ public void TestPartiallyWrittenConstraintClauseInBaseList1() { var tree = UsingTree(@" class C : where -"); +", + // (2,19): error CS1514: { expected + // class C : where + Diagnostic(ErrorCode.ERR_LbraceExpected, "").WithLocation(2, 19), + // (2,19): error CS1513: } expected + // class C : where + Diagnostic(ErrorCode.ERR_RbraceExpected, "").WithLocation(2, 19)); N(SyntaxKind.CompilationUnit); { N(SyntaxKind.ClassDeclaration); @@ -6639,7 +6663,16 @@ public void TestPartiallyWrittenConstraintClauseInBaseList2() { var tree = UsingTree(@" class C : where T -"); +", + // (2,20): error CS1003: Syntax error, ',' expected + // class C : where T + Diagnostic(ErrorCode.ERR_SyntaxError, "T").WithArguments(",").WithLocation(2, 20), + // (2,21): error CS1514: { expected + // class C : where T + Diagnostic(ErrorCode.ERR_LbraceExpected, "").WithLocation(2, 21), + // (2,21): error CS1513: } expected + // class C : where T + Diagnostic(ErrorCode.ERR_RbraceExpected, "").WithLocation(2, 21)); N(SyntaxKind.CompilationUnit); { N(SyntaxKind.ClassDeclaration); @@ -6687,7 +6720,19 @@ public void TestPartiallyWrittenConstraintClauseInBaseList3() { var tree = UsingTree(@" class C : where T : -"); +", + // (2,14): error CS1031: Type expected + // class C : where T : + Diagnostic(ErrorCode.ERR_TypeExpected, "where").WithLocation(2, 14), + // (2,23): error CS1031: Type expected + // class C : where T : + Diagnostic(ErrorCode.ERR_TypeExpected, "").WithLocation(2, 23), + // (2,23): error CS1514: { expected + // class C : where T : + Diagnostic(ErrorCode.ERR_LbraceExpected, "").WithLocation(2, 23), + // (2,23): error CS1513: } expected + // class C : where T : + Diagnostic(ErrorCode.ERR_RbraceExpected, "").WithLocation(2, 23)); N(SyntaxKind.CompilationUnit); { N(SyntaxKind.ClassDeclaration); @@ -6743,7 +6788,16 @@ public void TestPartiallyWrittenConstraintClauseInBaseList4() { var tree = UsingTree(@" class C : where T : X -"); +", + // (2,14): error CS1031: Type expected + // class C : where T : X + Diagnostic(ErrorCode.ERR_TypeExpected, "where").WithLocation(2, 14), + // (2,25): error CS1514: { expected + // class C : where T : X + Diagnostic(ErrorCode.ERR_LbraceExpected, "").WithLocation(2, 25), + // (2,25): error CS1513: } expected + // class C : where T : X + Diagnostic(ErrorCode.ERR_RbraceExpected, "").WithLocation(2, 25)); N(SyntaxKind.CompilationUnit); { N(SyntaxKind.ClassDeclaration); @@ -8136,7 +8190,10 @@ public void TestNullCheckedMethod() class C { public void M(string x!!) { } -}", options: TestOptions.RegularPreview); +}", options: TestOptions.RegularPreview, + // (4,27): error CS8989: The 'parameter null-checking' feature is not supported. + // public void M(string x!!) { } + Diagnostic(ErrorCode.ERR_ParameterNullCheckingNotSupported, "!").WithLocation(4, 27)); N(SyntaxKind.CompilationUnit); { N(SyntaxKind.ClassDeclaration); @@ -8184,7 +8241,10 @@ public void TestNullCheckedConstructor() class C { public C(string x!!) { } -}", options: TestOptions.RegularPreview); +}", options: TestOptions.RegularPreview, + // (4,22): error CS8989: The 'parameter null-checking' feature is not supported. + // public C(string x!!) { } + Diagnostic(ErrorCode.ERR_ParameterNullCheckingNotSupported, "!").WithLocation(4, 22)); N(SyntaxKind.CompilationUnit); { N(SyntaxKind.ClassDeclaration); @@ -8232,7 +8292,10 @@ class Box { return 2; } -}", options: TestOptions.RegularPreview); +}", options: TestOptions.RegularPreview, + // (4,39): error CS8989: The 'parameter null-checking' feature is not supported. + // public static int operator+ (Box b!!, Box c) + Diagnostic(ErrorCode.ERR_ParameterNullCheckingNotSupported, "!").WithLocation(4, 39)); N(SyntaxKind.CompilationUnit); { @@ -8299,7 +8362,16 @@ public void TestAnonymousDelegateNullChecking() { UsingTree(@" delegate void Del(int x!!); -Del d = delegate(int k!!) { /* ... */ };", options: TestOptions.RegularPreview); +Del d = delegate(int k!!) { /* ... */ };", options: TestOptions.RegularPreview, + // (2,24): error CS8989: The 'parameter null-checking' feature is not supported. + // delegate void Del(int x!!); + Diagnostic(ErrorCode.ERR_ParameterNullCheckingNotSupported, "!").WithLocation(2, 24), + // (3,1): error CS8803: Top-level statements must precede namespace and type declarations. + // Del d = delegate(int k!!) { /* ... */ }; + Diagnostic(ErrorCode.ERR_TopLevelStatementAfterNamespaceOrType, "Del d = delegate(int k!!) { /* ... */ };").WithLocation(3, 1), + // (3,23): error CS8989: The 'parameter null-checking' feature is not supported. + // Del d = delegate(int k!!) { /* ... */ }; + Diagnostic(ErrorCode.ERR_ParameterNullCheckingNotSupported, "!").WithLocation(3, 23)); N(SyntaxKind.CompilationUnit); { N(SyntaxKind.DelegateDeclaration); diff --git a/src/Compilers/CSharp/Test/Syntax/Parsing/DeclarationScopeParsingTests.cs b/src/Compilers/CSharp/Test/Syntax/Parsing/DeclarationScopeParsingTests.cs index 63e6920d5edd1..a392cb0767971 100644 --- a/src/Compilers/CSharp/Test/Syntax/Parsing/DeclarationScopeParsingTests.cs +++ b/src/Compilers/CSharp/Test/Syntax/Parsing/DeclarationScopeParsingTests.cs @@ -3,6 +3,7 @@ // See the LICENSE file in the project root for more information. using Microsoft.CodeAnalysis.CSharp.Test.Utilities; +using Roslyn.Test.Utilities; using Xunit; using Xunit.Abstractions; @@ -16,7 +17,7 @@ public DeclarationScopeParsingTests(ITestOutputHelper output) : base(output) [Theory] [InlineData(LanguageVersion.CSharp10)] - [InlineData(LanguageVersionFacts.CSharpNext)] + [InlineData(LanguageVersion.CSharp11)] public void Method_01(LanguageVersion langVersion) { string source = "void F(scoped x, ref scoped y) { }"; @@ -63,7 +64,7 @@ public void Method_01(LanguageVersion langVersion) [Theory] [InlineData(LanguageVersion.CSharp10)] - [InlineData(LanguageVersionFacts.CSharpNext)] + [InlineData(LanguageVersion.CSharp11)] public void Method_02(LanguageVersion langVersion) { string source = "void F(scoped int a, scoped ref int b, scoped in int c, scoped out int d) { }"; @@ -134,7 +135,7 @@ public void Method_02(LanguageVersion langVersion) [Theory] [InlineData(LanguageVersion.CSharp10)] - [InlineData(LanguageVersionFacts.CSharpNext)] + [InlineData(LanguageVersion.CSharp11)] public void Method_03(LanguageVersion langVersion) { string source = "void F(ref scoped int b, in scoped int c, out scoped int d) { }"; @@ -197,7 +198,7 @@ public void Method_03(LanguageVersion langVersion) public void Method_04() { string source = "scoped R F() => default;"; - UsingDeclaration(source, TestOptions.RegularNext); + UsingDeclaration(source, TestOptions.Regular11); N(SyntaxKind.MethodDeclaration); { @@ -229,14 +230,17 @@ public void Method_04() public void Method_05() { string source = "ref scoped R F() => default;"; - UsingDeclaration(source, TestOptions.RegularNext); + UsingDeclaration(source, TestOptions.Regular11, + // (1,5): error CS9061: Unexpected contextual keyword 'scoped'. Did you mean 'scoped ref' or '@scoped'? + // ref scoped R F() => default; + Diagnostic(ErrorCode.ERR_MisplacedScoped, "scoped").WithLocation(1, 5) + ); N(SyntaxKind.MethodDeclaration); { N(SyntaxKind.RefType); { N(SyntaxKind.RefKeyword); - N(SyntaxKind.ScopedKeyword); N(SyntaxKind.IdentifierName); { N(SyntaxKind.IdentifierToken, "R"); @@ -263,7 +267,7 @@ public void Method_05() [Theory] [InlineData(LanguageVersion.CSharp10)] - [InlineData(LanguageVersionFacts.CSharpNext)] + [InlineData(LanguageVersion.CSharp11)] public void Method_06(LanguageVersion langVersion) { string source = @@ -271,7 +275,20 @@ public void Method_06(LanguageVersion langVersion) ref scoped F2() => default; scoped F3() { } ref scoped F4() { }"; - UsingCompilationRoot(source, TestOptions.Regular.WithLanguageVersion(langVersion)); + UsingTree(source, TestOptions.Regular.WithLanguageVersion(langVersion), + // (2,5): error CS9061: Unexpected contextual keyword 'scoped'. Did you mean 'scoped ref' or '@scoped'? + // ref scoped F2() => default; + Diagnostic(ErrorCode.ERR_MisplacedScoped, "scoped").WithLocation(2, 5), + // (4,5): error CS9061: Unexpected contextual keyword 'scoped'. Did you mean 'scoped ref' or '@scoped'? + // ref scoped F4() { } + Diagnostic(ErrorCode.ERR_MisplacedScoped, "scoped").WithLocation(4, 5), + // (4,15): error CS1525: Invalid expression term ')' + // ref scoped F4() { } + Diagnostic(ErrorCode.ERR_InvalidExprTerm, ")").WithArguments(")").WithLocation(4, 15), + // (4,17): error CS1002: ; expected + // ref scoped F4() { } + Diagnostic(ErrorCode.ERR_SemicolonExpected, "{").WithLocation(4, 17) + ); N(SyntaxKind.CompilationUnit); { @@ -300,26 +317,28 @@ scoped F3() { } N(SyntaxKind.SemicolonToken); } } + N(SyntaxKind.IncompleteMember); + { + N(SyntaxKind.RefType); + { + N(SyntaxKind.RefKeyword); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "F2"); + } + } + } N(SyntaxKind.GlobalStatement); { - N(SyntaxKind.LocalFunctionStatement); + N(SyntaxKind.ExpressionStatement); { - N(SyntaxKind.RefType); + N(SyntaxKind.ParenthesizedLambdaExpression); { - N(SyntaxKind.RefKeyword); - N(SyntaxKind.IdentifierName); + N(SyntaxKind.ParameterList); { - N(SyntaxKind.IdentifierToken, "scoped"); + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.CloseParenToken); } - } - N(SyntaxKind.IdentifierToken, "F2"); - N(SyntaxKind.ParameterList); - { - N(SyntaxKind.OpenParenToken); - N(SyntaxKind.CloseParenToken); - } - N(SyntaxKind.ArrowExpressionClause); - { N(SyntaxKind.EqualsGreaterThanToken); N(SyntaxKind.DefaultLiteralExpression); { @@ -350,6 +369,58 @@ scoped F3() { } } } } + N(SyntaxKind.IncompleteMember); + { + N(SyntaxKind.RefType); + { + N(SyntaxKind.RefKeyword); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "F4"); + } + } + } + N(SyntaxKind.GlobalStatement); + { + N(SyntaxKind.ExpressionStatement); + { + N(SyntaxKind.ParenthesizedExpression); + { + N(SyntaxKind.OpenParenToken); + M(SyntaxKind.IdentifierName); + { + M(SyntaxKind.IdentifierToken); + } + N(SyntaxKind.CloseParenToken); + } + M(SyntaxKind.SemicolonToken); + } + } + N(SyntaxKind.GlobalStatement); + { + N(SyntaxKind.Block); + { + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Theory] + [InlineData(LanguageVersion.CSharp10)] + [InlineData(LanguageVersion.CSharp11)] + public void Method_06_Escaped(LanguageVersion langVersion) + { + string source = @" +ref @scoped F2() => default; +ref @scoped F4() { }"; + UsingTree(source, TestOptions.Regular.WithLanguageVersion(langVersion)); + + N(SyntaxKind.CompilationUnit); + { N(SyntaxKind.GlobalStatement); { N(SyntaxKind.LocalFunctionStatement); @@ -359,7 +430,36 @@ scoped F3() { } N(SyntaxKind.RefKeyword); N(SyntaxKind.IdentifierName); { - N(SyntaxKind.IdentifierToken, "scoped"); + N(SyntaxKind.IdentifierToken, "@scoped"); + } + } + N(SyntaxKind.IdentifierToken, "F2"); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.ArrowExpressionClause); + { + N(SyntaxKind.EqualsGreaterThanToken); + N(SyntaxKind.DefaultLiteralExpression); + { + N(SyntaxKind.DefaultKeyword); + } + } + N(SyntaxKind.SemicolonToken); + } + } + N(SyntaxKind.GlobalStatement); + { + N(SyntaxKind.LocalFunctionStatement); + { + N(SyntaxKind.RefType); + { + N(SyntaxKind.RefKeyword); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "@scoped"); } } N(SyntaxKind.IdentifierToken, "F4"); @@ -384,7 +484,7 @@ scoped F3() { } public void Method_07() { string source = "void F(scoped scoped ref int i) { }"; - UsingDeclaration(source, TestOptions.RegularNext); + UsingDeclaration(source, TestOptions.Regular11); N(SyntaxKind.MethodDeclaration); { @@ -422,7 +522,7 @@ public void Method_07() public void Method_08() { string source = "void F(ref scoped scoped R r) { }"; - UsingDeclaration(source, TestOptions.RegularNext); + UsingDeclaration(source, TestOptions.Regular11); N(SyntaxKind.MethodDeclaration); { @@ -458,7 +558,7 @@ public void Method_08() [Theory] [InlineData(LanguageVersion.CSharp10)] - [InlineData(LanguageVersionFacts.CSharpNext)] + [InlineData(LanguageVersion.CSharp11)] public void Method_09(LanguageVersion langVersion) { string source = "void F(scoped scoped x, ref scoped y, ref scoped scoped z, scoped ref scoped w) { }"; @@ -528,7 +628,7 @@ public void Method_09(LanguageVersion langVersion) [Theory] [InlineData(LanguageVersion.CSharp10)] - [InlineData(LanguageVersionFacts.CSharpNext)] + [InlineData(LanguageVersion.CSharp11)] public void Method_10(LanguageVersion langVersion) { string source = "void F(scoped.nested x, ref scoped.nested y) { }"; @@ -591,7 +691,7 @@ public void Method_10(LanguageVersion langVersion) [Theory] [InlineData(LanguageVersion.CSharp10)] - [InlineData(LanguageVersionFacts.CSharpNext)] + [InlineData(LanguageVersion.CSharp11)] public void Lambda_01(LanguageVersion langVersion) { string source = "(scoped x, ref scoped y) => null"; @@ -633,7 +733,7 @@ public void Lambda_01(LanguageVersion langVersion) [Theory] [InlineData(LanguageVersion.CSharp10)] - [InlineData(LanguageVersionFacts.CSharpNext)] + [InlineData(LanguageVersion.CSharp11)] public void Lambda_02(LanguageVersion langVersion) { string source = "(scoped int a, scoped ref int b, scoped in int c, scoped out int d) => null"; @@ -699,7 +799,7 @@ public void Lambda_02(LanguageVersion langVersion) [Theory] [InlineData(LanguageVersion.CSharp10)] - [InlineData(LanguageVersionFacts.CSharpNext)] + [InlineData(LanguageVersion.CSharp11)] public void Lambda_03(LanguageVersion langVersion) { string source = "(ref scoped int a, out scoped int b, in scoped int c) => null"; @@ -755,7 +855,7 @@ public void Lambda_03(LanguageVersion langVersion) [Theory] [InlineData(LanguageVersion.CSharp10)] - [InlineData(LanguageVersionFacts.CSharpNext)] + [InlineData(LanguageVersion.CSharp11)] public void Lambda_04(LanguageVersion langVersion) { string source = "(scoped R a, scoped ref R b, ref scoped R c) => null"; @@ -812,7 +912,7 @@ public void Lambda_04(LanguageVersion langVersion) public void Lambda_05() { string source = "(scoped scoped ref int i) => null"; - UsingExpression(source, TestOptions.RegularNext); + UsingExpression(source, TestOptions.Regular11); N(SyntaxKind.ParenthesizedLambdaExpression); { @@ -845,7 +945,7 @@ public void Lambda_05() public void Lambda_06() { string source = "(ref scoped scoped R r) => { }"; - UsingExpression(source, TestOptions.RegularNext); + UsingExpression(source, TestOptions.Regular11); N(SyntaxKind.ParenthesizedLambdaExpression); { @@ -877,7 +977,7 @@ public void Lambda_06() [Theory] [InlineData(LanguageVersion.CSharp10)] - [InlineData(LanguageVersionFacts.CSharpNext)] + [InlineData(LanguageVersion.CSharp11)] public void Lambda_07(LanguageVersion langVersion) { string source = "([A] scoped R a, [B] scoped ref R b, [C] ref scoped R c) => null"; @@ -968,7 +1068,7 @@ public void Lambda_07(LanguageVersion langVersion) [Theory] [InlineData(LanguageVersion.CSharp10)] - [InlineData(LanguageVersionFacts.CSharpNext)] + [InlineData(LanguageVersion.CSharp11)] public void Lambda_08(LanguageVersion langVersion) { string source = $"scoped () => t"; @@ -998,7 +1098,7 @@ public void Lambda_08(LanguageVersion langVersion) public void Params_01() { string source = "void F(scoped params object[] args);"; - UsingDeclaration(source, TestOptions.RegularNext); + UsingDeclaration(source, TestOptions.Regular11); N(SyntaxKind.MethodDeclaration); { @@ -1043,7 +1143,7 @@ public void Params_01() public void Params_02() { string source = "void F(params scoped object[] args);"; - UsingDeclaration(source, TestOptions.RegularNext); + UsingDeclaration(source, TestOptions.Regular11); N(SyntaxKind.MethodDeclaration); { @@ -1086,7 +1186,7 @@ public void Params_02() [Theory] [InlineData(LanguageVersion.CSharp10)] - [InlineData(LanguageVersionFacts.CSharpNext)] + [InlineData(LanguageVersion.CSharp11)] public void Local_01(LanguageVersion langVersion) { string source = @@ -1097,9 +1197,26 @@ static void Main() scoped a; ref scoped b; ref readonly scoped c; + ref readonly scoped c c2; } }"; - UsingCompilationRoot(source, TestOptions.Regular.WithLanguageVersion(langVersion)); + UsingTree(source, TestOptions.Regular.WithLanguageVersion(langVersion), + // (6,13): error CS9061: Unexpected contextual keyword 'scoped'. Did you mean 'scoped ref' or '@scoped'? + // ref scoped b; + Diagnostic(ErrorCode.ERR_MisplacedScoped, "scoped").WithLocation(6, 13), + // (6,21): error CS1001: Identifier expected + // ref scoped b; + Diagnostic(ErrorCode.ERR_IdentifierExpected, ";").WithLocation(6, 21), + // (7,22): error CS9061: Unexpected contextual keyword 'scoped'. Did you mean 'scoped ref' or '@scoped'? + // ref readonly scoped c; + Diagnostic(ErrorCode.ERR_MisplacedScoped, "scoped").WithLocation(7, 22), + // (7,30): error CS1001: Identifier expected + // ref readonly scoped c; + Diagnostic(ErrorCode.ERR_IdentifierExpected, ";").WithLocation(7, 30), + // (8,22): error CS9061: Unexpected contextual keyword 'scoped'. Did you mean 'scoped ref' or '@scoped'? + // ref readonly scoped c c2; + Diagnostic(ErrorCode.ERR_MisplacedScoped, "scoped").WithLocation(8, 22) + ); N(SyntaxKind.CompilationUnit); { @@ -1148,16 +1265,104 @@ static void Main() N(SyntaxKind.RefKeyword); N(SyntaxKind.IdentifierName); { - N(SyntaxKind.IdentifierToken, "scoped"); + N(SyntaxKind.IdentifierToken, "b"); + } + } + M(SyntaxKind.VariableDeclarator); + { + M(SyntaxKind.IdentifierToken); + } + } + N(SyntaxKind.SemicolonToken); + } + N(SyntaxKind.LocalDeclarationStatement); + { + N(SyntaxKind.VariableDeclaration); + { + N(SyntaxKind.RefType); + { + N(SyntaxKind.RefKeyword); + N(SyntaxKind.ReadOnlyKeyword); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "c"); + } + } + M(SyntaxKind.VariableDeclarator); + { + M(SyntaxKind.IdentifierToken); + } + } + N(SyntaxKind.SemicolonToken); + } + N(SyntaxKind.LocalDeclarationStatement); + { + N(SyntaxKind.VariableDeclaration); + { + N(SyntaxKind.RefType); + { + N(SyntaxKind.RefKeyword); + N(SyntaxKind.ReadOnlyKeyword); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "c"); } } N(SyntaxKind.VariableDeclarator); { - N(SyntaxKind.IdentifierToken, "b"); + N(SyntaxKind.IdentifierToken, "c2"); } } N(SyntaxKind.SemicolonToken); } + N(SyntaxKind.CloseBraceToken); + } + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Theory] + [InlineData(LanguageVersion.CSharp10)] + [InlineData(LanguageVersion.CSharp11)] + public void Local_01_Escaped(LanguageVersion langVersion) + { + string source = +@"class Program +{ + static void Main() + { + ref readonly @scoped c; + } +}"; + UsingTree(source, TestOptions.Regular.WithLanguageVersion(langVersion)); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "Program"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.MethodDeclaration); + { + N(SyntaxKind.StaticKeyword); + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.VoidKeyword); + } + N(SyntaxKind.IdentifierToken, "Main"); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.Block); + { + N(SyntaxKind.OpenBraceToken); N(SyntaxKind.LocalDeclarationStatement); { N(SyntaxKind.VariableDeclaration); @@ -1168,7 +1373,7 @@ static void Main() N(SyntaxKind.ReadOnlyKeyword); N(SyntaxKind.IdentifierName); { - N(SyntaxKind.IdentifierToken, "scoped"); + N(SyntaxKind.IdentifierToken, "@scoped"); } } N(SyntaxKind.VariableDeclarator); @@ -1190,7 +1395,7 @@ static void Main() [Theory] [InlineData(LanguageVersion.CSharp10)] - [InlineData(LanguageVersionFacts.CSharpNext)] + [InlineData(LanguageVersion.CSharp11)] public void Local_02(LanguageVersion langVersion) { string source = @@ -1201,12 +1406,10 @@ static void Main() scoped int a; scoped ref int b; scoped ref readonly int c; - ref scoped int d; - ref readonly scoped int e; }} }} "; - UsingCompilationRoot(source, TestOptions.Regular.WithLanguageVersion(langVersion)); + UsingTree(source, TestOptions.Regular.WithLanguageVersion(langVersion)); N(SyntaxKind.CompilationUnit); { @@ -1288,6 +1491,63 @@ static void Main() } N(SyntaxKind.SemicolonToken); } + N(SyntaxKind.CloseBraceToken); + } + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Theory] + [InlineData(LanguageVersion.CSharp10)] + [InlineData(LanguageVersion.CSharp11)] + public void Local_02_RefScoped(LanguageVersion langVersion) + { + string source = """ +class Program +{ + static void Main() + { + ref scoped int d; + ref readonly scoped int e; + } +} +"""; + UsingTree(source, TestOptions.Regular.WithLanguageVersion(langVersion), + // (5,13): error CS9061: Unexpected contextual keyword 'scoped'. Did you mean 'scoped ref' or '@scoped'? + // ref scoped int d; + Diagnostic(ErrorCode.ERR_MisplacedScoped, "scoped").WithLocation(5, 13), + // (6,22): error CS9061: Unexpected contextual keyword 'scoped'. Did you mean 'scoped ref' or '@scoped'? + // ref readonly scoped int e; + Diagnostic(ErrorCode.ERR_MisplacedScoped, "scoped").WithLocation(6, 22) + ); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "Program"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.MethodDeclaration); + { + N(SyntaxKind.StaticKeyword); + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.VoidKeyword); + } + N(SyntaxKind.IdentifierToken, "Main"); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.Block); + { + N(SyntaxKind.OpenBraceToken); N(SyntaxKind.LocalDeclarationStatement); { N(SyntaxKind.VariableDeclaration); @@ -1295,7 +1555,6 @@ static void Main() N(SyntaxKind.RefType); { N(SyntaxKind.RefKeyword); - N(SyntaxKind.ScopedKeyword); N(SyntaxKind.PredefinedType); { N(SyntaxKind.IntKeyword); @@ -1316,7 +1575,6 @@ static void Main() { N(SyntaxKind.RefKeyword); N(SyntaxKind.ReadOnlyKeyword); - N(SyntaxKind.ScopedKeyword); N(SyntaxKind.PredefinedType); { N(SyntaxKind.IntKeyword); @@ -1341,15 +1599,14 @@ static void Main() [Theory] [InlineData(LanguageVersion.CSharp10)] - [InlineData(LanguageVersionFacts.CSharpNext)] + [InlineData(LanguageVersion.CSharp11)] public void Local_03(LanguageVersion langVersion) { string source = @"scoped int a; scoped ref int b; -ref scoped int c; "; - UsingCompilationRoot(source, TestOptions.Regular.WithLanguageVersion(langVersion)); + UsingTree(source, TestOptions.Regular.WithLanguageVersion(langVersion)); N(SyntaxKind.CompilationUnit); { @@ -1395,6 +1652,27 @@ public void Local_03(LanguageVersion langVersion) N(SyntaxKind.SemicolonToken); } } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Theory] + [InlineData(LanguageVersion.CSharp10)] + [InlineData(LanguageVersion.CSharp11)] + public void Local_03_RefScoped(LanguageVersion langVersion) + { + string source = @" +ref scoped int c; +"; + UsingTree(source, TestOptions.Regular.WithLanguageVersion(langVersion), + // (2,5): error CS9061: Unexpected contextual keyword 'scoped'. Did you mean 'scoped ref' or '@scoped'? + // ref scoped int c; + Diagnostic(ErrorCode.ERR_MisplacedScoped, "scoped").WithLocation(2, 5) + ); + + N(SyntaxKind.CompilationUnit); + { N(SyntaxKind.GlobalStatement); { N(SyntaxKind.LocalDeclarationStatement); @@ -1404,7 +1682,6 @@ public void Local_03(LanguageVersion langVersion) N(SyntaxKind.RefType); { N(SyntaxKind.RefKeyword); - N(SyntaxKind.ScopedKeyword); N(SyntaxKind.PredefinedType); { N(SyntaxKind.IntKeyword); @@ -1425,15 +1702,13 @@ public void Local_03(LanguageVersion langVersion) [Theory] [InlineData(LanguageVersion.CSharp10)] - [InlineData(LanguageVersionFacts.CSharpNext)] + [InlineData(LanguageVersion.CSharp11)] public void Local_04(LanguageVersion langVersion) { string source = @"scoped ref readonly S a; -ref readonly scoped S b; -scoped ref readonly scoped S c; "; - UsingCompilationRoot(source, TestOptions.Regular.WithLanguageVersion(langVersion)); + UsingTree(source, TestOptions.Regular.WithLanguageVersion(langVersion)); N(SyntaxKind.CompilationUnit); { @@ -1461,6 +1736,31 @@ public void Local_04(LanguageVersion langVersion) N(SyntaxKind.SemicolonToken); } } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Theory] + [InlineData(LanguageVersion.CSharp10)] + [InlineData(LanguageVersion.CSharp11)] + public void Local_04_RefScoped(LanguageVersion langVersion) + { + string source = @" +ref readonly scoped S b; +scoped ref readonly scoped S c; +"; + UsingTree(source, TestOptions.Regular.WithLanguageVersion(langVersion), + // (2,14): error CS9061: Unexpected contextual keyword 'scoped'. Did you mean 'scoped ref' or '@scoped'? + // ref readonly scoped S b; + Diagnostic(ErrorCode.ERR_MisplacedScoped, "scoped").WithLocation(2, 14), + // (3,21): error CS9061: Unexpected contextual keyword 'scoped'. Did you mean 'scoped ref' or '@scoped'? + // scoped ref readonly scoped S c; + Diagnostic(ErrorCode.ERR_MisplacedScoped, "scoped").WithLocation(3, 21) + ); + + N(SyntaxKind.CompilationUnit); + { N(SyntaxKind.GlobalStatement); { N(SyntaxKind.LocalDeclarationStatement); @@ -1471,7 +1771,6 @@ public void Local_04(LanguageVersion langVersion) { N(SyntaxKind.RefKeyword); N(SyntaxKind.ReadOnlyKeyword); - N(SyntaxKind.ScopedKeyword); N(SyntaxKind.IdentifierName); { N(SyntaxKind.IdentifierToken, "S"); @@ -1496,7 +1795,6 @@ public void Local_04(LanguageVersion langVersion) { N(SyntaxKind.RefKeyword); N(SyntaxKind.ReadOnlyKeyword); - N(SyntaxKind.ScopedKeyword); N(SyntaxKind.IdentifierName); { N(SyntaxKind.IdentifierToken, "S"); @@ -1517,14 +1815,18 @@ public void Local_04(LanguageVersion langVersion) [Theory] [InlineData(LanguageVersion.CSharp10)] - [InlineData(LanguageVersionFacts.CSharpNext)] + [InlineData(LanguageVersion.CSharp11)] public void Local_05(LanguageVersion langVersion) { string source = @"scoped a; ref scoped b; "; - UsingCompilationRoot(source, TestOptions.Regular.WithLanguageVersion(langVersion)); + UsingTree(source, TestOptions.Regular.WithLanguageVersion(langVersion), + // (2,5): error CS9061: Unexpected contextual keyword 'scoped'. Did you mean 'scoped ref' or '@scoped'? + // ref scoped b; + Diagnostic(ErrorCode.ERR_MisplacedScoped, "scoped").WithLocation(2, 5) + ); N(SyntaxKind.CompilationUnit); { @@ -1536,33 +1838,200 @@ public void Local_05(LanguageVersion langVersion) { N(SyntaxKind.IdentifierName); { - N(SyntaxKind.IdentifierToken, "scoped"); + N(SyntaxKind.IdentifierToken, "scoped"); + } + N(SyntaxKind.VariableDeclarator); + { + N(SyntaxKind.IdentifierToken, "a"); + } + } + N(SyntaxKind.SemicolonToken); + } + } + N(SyntaxKind.IncompleteMember); + { + N(SyntaxKind.RefType); + { + N(SyntaxKind.RefKeyword); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "b"); + } + } + } + N(SyntaxKind.GlobalStatement); + { + N(SyntaxKind.EmptyStatement); + { + N(SyntaxKind.SemicolonToken); + } + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Theory] + [InlineData(LanguageVersion.CSharp10)] + [InlineData(LanguageVersion.CSharp11)] + public void TypeNamedScoped(LanguageVersion langVersion) + { + string source = @" +class scoped { } +"; + UsingTree(source, TestOptions.Regular.WithLanguageVersion(langVersion)); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "scoped"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Theory] + [InlineData(LanguageVersion.CSharp10)] + [InlineData(LanguageVersion.CSharp11)] + public void TypeNamedScoped_Escaped(LanguageVersion langVersion) + { + string source = @" +class @scoped { } +"; + UsingTree(source, TestOptions.Regular.WithLanguageVersion(langVersion)); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "@scoped"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Theory, WorkItem(62950, "https://github.com/dotnet/roslyn/issues/62950")] + [InlineData(LanguageVersion.CSharp10)] + [InlineData(LanguageVersion.CSharp11)] + public void Local_06(LanguageVersion langVersion) + { + string source = +@"scoped.nested a; +ref scoped.nested b; +ref readonly scoped.nested c; +"; + UsingTree(source, TestOptions.Regular.WithLanguageVersion(langVersion), + // (2,5): error CS9061: Unexpected contextual keyword 'scoped'. Did you mean 'scoped ref' or '@scoped'? + // ref scoped.nested b; + Diagnostic(ErrorCode.ERR_MisplacedScoped, "scoped").WithLocation(2, 5), + // (2,11): error CS1031: Type expected + // ref scoped.nested b; + Diagnostic(ErrorCode.ERR_TypeExpected, ".").WithLocation(2, 11), + // (2,11): error CS1022: Type or namespace definition, or end-of-file expected + // ref scoped.nested b; + Diagnostic(ErrorCode.ERR_EOFExpected, ".").WithLocation(2, 11), + // (3,14): error CS9061: Unexpected contextual keyword 'scoped'. Did you mean 'scoped ref' or '@scoped'? + // ref readonly scoped.nested c; + Diagnostic(ErrorCode.ERR_MisplacedScoped, "scoped").WithLocation(3, 14), + // (3,20): error CS1031: Type expected + // ref readonly scoped.nested c; + Diagnostic(ErrorCode.ERR_TypeExpected, ".").WithLocation(3, 20), + // (3,20): error CS1022: Type or namespace definition, or end-of-file expected + // ref readonly scoped.nested c; + Diagnostic(ErrorCode.ERR_EOFExpected, ".").WithLocation(3, 20) + ); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.GlobalStatement); + { + N(SyntaxKind.LocalDeclarationStatement); + { + N(SyntaxKind.VariableDeclaration); + { + N(SyntaxKind.QualifiedName); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "scoped"); + } + N(SyntaxKind.DotToken); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "nested"); + } + } + N(SyntaxKind.VariableDeclarator); + { + N(SyntaxKind.IdentifierToken, "a"); + } + } + N(SyntaxKind.SemicolonToken); + } + } + N(SyntaxKind.IncompleteMember); + { + N(SyntaxKind.RefType); + { + N(SyntaxKind.RefKeyword); + M(SyntaxKind.IdentifierName); + { + M(SyntaxKind.IdentifierToken); + } + } + } + N(SyntaxKind.GlobalStatement); + { + N(SyntaxKind.LocalDeclarationStatement); + { + N(SyntaxKind.VariableDeclaration); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "nested"); } N(SyntaxKind.VariableDeclarator); { - N(SyntaxKind.IdentifierToken, "a"); + N(SyntaxKind.IdentifierToken, "b"); } } N(SyntaxKind.SemicolonToken); } } + N(SyntaxKind.IncompleteMember); + { + N(SyntaxKind.RefType); + { + N(SyntaxKind.RefKeyword); + N(SyntaxKind.ReadOnlyKeyword); + M(SyntaxKind.IdentifierName); + { + M(SyntaxKind.IdentifierToken); + } + } + } N(SyntaxKind.GlobalStatement); { N(SyntaxKind.LocalDeclarationStatement); { N(SyntaxKind.VariableDeclaration); { - N(SyntaxKind.RefType); + N(SyntaxKind.IdentifierName); { - N(SyntaxKind.RefKeyword); - N(SyntaxKind.IdentifierName); - { - N(SyntaxKind.IdentifierToken, "scoped"); - } + N(SyntaxKind.IdentifierToken, "nested"); } N(SyntaxKind.VariableDeclarator); { - N(SyntaxKind.IdentifierToken, "b"); + N(SyntaxKind.IdentifierToken, "c"); } } N(SyntaxKind.SemicolonToken); @@ -1575,15 +2044,15 @@ public void Local_05(LanguageVersion langVersion) [Theory] [InlineData(LanguageVersion.CSharp10)] - [InlineData(LanguageVersionFacts.CSharpNext)] - public void Local_06(LanguageVersion langVersion) + [InlineData(LanguageVersion.CSharp11)] + public void Local_06_Escaped(LanguageVersion langVersion) { string source = -@"scoped.nested a; -ref scoped.nested b; -ref readonly scoped.nested c; +@"@scoped.nested a; +ref @scoped.nested b; +ref readonly @scoped.nested c; "; - UsingCompilationRoot(source, TestOptions.Regular.WithLanguageVersion(langVersion)); + UsingTree(source, TestOptions.Regular.WithLanguageVersion(langVersion)); N(SyntaxKind.CompilationUnit); { @@ -1597,7 +2066,7 @@ public void Local_06(LanguageVersion langVersion) { N(SyntaxKind.IdentifierName); { - N(SyntaxKind.IdentifierToken, "scoped"); + N(SyntaxKind.IdentifierToken, "@scoped"); } N(SyntaxKind.DotToken); N(SyntaxKind.IdentifierName); @@ -1626,7 +2095,7 @@ public void Local_06(LanguageVersion langVersion) { N(SyntaxKind.IdentifierName); { - N(SyntaxKind.IdentifierToken, "scoped"); + N(SyntaxKind.IdentifierToken, "@scoped"); } N(SyntaxKind.DotToken); N(SyntaxKind.IdentifierName); @@ -1657,7 +2126,7 @@ public void Local_06(LanguageVersion langVersion) { N(SyntaxKind.IdentifierName); { - N(SyntaxKind.IdentifierToken, "scoped"); + N(SyntaxKind.IdentifierToken, "@scoped"); } N(SyntaxKind.DotToken); N(SyntaxKind.IdentifierName); @@ -1681,17 +2150,22 @@ public void Local_06(LanguageVersion langVersion) [Theory] [InlineData(LanguageVersion.CSharp10)] - [InlineData(LanguageVersionFacts.CSharpNext)] + [InlineData(LanguageVersion.CSharp11)] public void Local_07(LanguageVersion langVersion) { string source = @"scoped scoped a; scoped ref scoped b; scoped ref readonly scoped c; -ref scoped scoped d; -ref readonly scoped scoped e; "; - UsingCompilationRoot(source, TestOptions.Regular.WithLanguageVersion(langVersion)); + UsingTree(source, TestOptions.Regular.WithLanguageVersion(langVersion), + // (2,12): error CS9061: Unexpected contextual keyword 'scoped'. Did you mean 'scoped ref' or '@scoped'? + // scoped ref scoped b; + Diagnostic(ErrorCode.ERR_MisplacedScoped, "scoped").WithLocation(2, 12), + // (3,21): error CS9061: Unexpected contextual keyword 'scoped'. Did you mean 'scoped ref' or '@scoped'? + // scoped ref readonly scoped c; + Diagnostic(ErrorCode.ERR_MisplacedScoped, "scoped").WithLocation(3, 21) + ); N(SyntaxKind.CompilationUnit); { @@ -1714,29 +2188,62 @@ public void Local_07(LanguageVersion langVersion) N(SyntaxKind.SemicolonToken); } } + N(SyntaxKind.IncompleteMember); + { + N(SyntaxKind.ScopedKeyword); + N(SyntaxKind.RefType); + { + N(SyntaxKind.RefKeyword); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "b"); + } + } + } N(SyntaxKind.GlobalStatement); { - N(SyntaxKind.LocalDeclarationStatement); + N(SyntaxKind.EmptyStatement); { - N(SyntaxKind.ScopedKeyword); - N(SyntaxKind.VariableDeclaration); + N(SyntaxKind.SemicolonToken); + } + } + N(SyntaxKind.IncompleteMember); + { + N(SyntaxKind.ScopedKeyword); + N(SyntaxKind.RefType); + { + N(SyntaxKind.RefKeyword); + N(SyntaxKind.ReadOnlyKeyword); + N(SyntaxKind.IdentifierName); { - N(SyntaxKind.RefType); - { - N(SyntaxKind.RefKeyword); - N(SyntaxKind.IdentifierName); - { - N(SyntaxKind.IdentifierToken, "scoped"); - } - } - N(SyntaxKind.VariableDeclarator); - { - N(SyntaxKind.IdentifierToken, "b"); - } + N(SyntaxKind.IdentifierToken, "c"); } + } + } + N(SyntaxKind.GlobalStatement); + { + N(SyntaxKind.EmptyStatement); + { N(SyntaxKind.SemicolonToken); } } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Theory, WorkItem(62950, "https://github.com/dotnet/roslyn/issues/62950")] + [InlineData(LanguageVersion.CSharp10)] + [InlineData(LanguageVersion.CSharp11)] + public void Local_07_WithInitializer(LanguageVersion langVersion) + { + string source = +@"scoped scoped a = default; +"; + UsingTree(source, TestOptions.Regular.WithLanguageVersion(langVersion)); + + N(SyntaxKind.CompilationUnit); + { N(SyntaxKind.GlobalStatement); { N(SyntaxKind.LocalDeclarationStatement); @@ -1744,23 +2251,51 @@ public void Local_07(LanguageVersion langVersion) N(SyntaxKind.ScopedKeyword); N(SyntaxKind.VariableDeclaration); { - N(SyntaxKind.RefType); + N(SyntaxKind.IdentifierName); { - N(SyntaxKind.RefKeyword); - N(SyntaxKind.ReadOnlyKeyword); - N(SyntaxKind.IdentifierName); - { - N(SyntaxKind.IdentifierToken, "scoped"); - } + N(SyntaxKind.IdentifierToken, "scoped"); } N(SyntaxKind.VariableDeclarator); { - N(SyntaxKind.IdentifierToken, "c"); + N(SyntaxKind.IdentifierToken, "a"); + N(SyntaxKind.EqualsValueClause); + { + N(SyntaxKind.EqualsToken); + N(SyntaxKind.DefaultLiteralExpression); + { + N(SyntaxKind.DefaultKeyword); + } + } } } N(SyntaxKind.SemicolonToken); } } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Theory] + [InlineData(LanguageVersion.CSharp10)] + [InlineData(LanguageVersion.CSharp11)] + public void Local_07_RefScoped(LanguageVersion langVersion) + { + string source = @" +ref scoped scoped d; +ref readonly scoped scoped e; +"; + UsingTree(source, TestOptions.Regular.WithLanguageVersion(langVersion), + // (2,5): error CS9061: Unexpected contextual keyword 'scoped'. Did you mean 'scoped ref' or '@scoped'? + // ref scoped scoped d; + Diagnostic(ErrorCode.ERR_MisplacedScoped, "scoped").WithLocation(2, 5), + // (3,14): error CS9061: Unexpected contextual keyword 'scoped'. Did you mean 'scoped ref' or '@scoped'? + // ref readonly scoped scoped e; + Diagnostic(ErrorCode.ERR_MisplacedScoped, "scoped").WithLocation(3, 14) + ); + + N(SyntaxKind.CompilationUnit); + { N(SyntaxKind.GlobalStatement); { N(SyntaxKind.LocalDeclarationStatement); @@ -1770,7 +2305,6 @@ public void Local_07(LanguageVersion langVersion) N(SyntaxKind.RefType); { N(SyntaxKind.RefKeyword); - N(SyntaxKind.ScopedKeyword); N(SyntaxKind.IdentifierName); { N(SyntaxKind.IdentifierToken, "scoped"); @@ -1794,7 +2328,6 @@ public void Local_07(LanguageVersion langVersion) { N(SyntaxKind.RefKeyword); N(SyntaxKind.ReadOnlyKeyword); - N(SyntaxKind.ScopedKeyword); N(SyntaxKind.IdentifierName); { N(SyntaxKind.IdentifierToken, "scoped"); @@ -1815,15 +2348,14 @@ public void Local_07(LanguageVersion langVersion) [Theory] [InlineData(LanguageVersion.CSharp10)] - [InlineData(LanguageVersionFacts.CSharpNext)] + [InlineData(LanguageVersion.CSharp11)] public void Local_08(LanguageVersion langVersion) { string source = @"scoped var a; scoped ref var b; -ref scoped var c; "; - UsingCompilationRoot(source, TestOptions.Regular.WithLanguageVersion(langVersion)); + UsingTree(source, TestOptions.Regular.WithLanguageVersion(langVersion)); N(SyntaxKind.CompilationUnit); { @@ -1869,6 +2401,27 @@ public void Local_08(LanguageVersion langVersion) N(SyntaxKind.SemicolonToken); } } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Theory] + [InlineData(LanguageVersion.CSharp10)] + [InlineData(LanguageVersion.CSharp11)] + public void Local_08_RefScoped(LanguageVersion langVersion) + { + string source = @" +ref scoped var c; +"; + UsingTree(source, TestOptions.Regular.WithLanguageVersion(langVersion), + // (2,5): error CS9061: Unexpected contextual keyword 'scoped'. Did you mean 'scoped ref' or '@scoped'? + // ref scoped var c; + Diagnostic(ErrorCode.ERR_MisplacedScoped, "scoped").WithLocation(2, 5) + ); + + N(SyntaxKind.CompilationUnit); + { N(SyntaxKind.GlobalStatement); { N(SyntaxKind.LocalDeclarationStatement); @@ -1878,7 +2431,6 @@ public void Local_08(LanguageVersion langVersion) N(SyntaxKind.RefType); { N(SyntaxKind.RefKeyword); - N(SyntaxKind.ScopedKeyword); N(SyntaxKind.IdentifierName); { N(SyntaxKind.IdentifierToken, "var"); @@ -1899,15 +2451,13 @@ public void Local_08(LanguageVersion langVersion) [Theory] [InlineData(LanguageVersion.CSharp10)] - [InlineData(LanguageVersionFacts.CSharpNext)] + [InlineData(LanguageVersion.CSharp11)] public void Local_09(LanguageVersion langVersion) { string source = @"scoped ref readonly var a; -ref readonly scoped var b; -scoped ref readonly scoped var c; "; - UsingCompilationRoot(source, TestOptions.Regular.WithLanguageVersion(langVersion)); + UsingTree(source, TestOptions.Regular.WithLanguageVersion(langVersion)); N(SyntaxKind.CompilationUnit); { @@ -1935,6 +2485,31 @@ public void Local_09(LanguageVersion langVersion) N(SyntaxKind.SemicolonToken); } } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Theory] + [InlineData(LanguageVersion.CSharp10)] + [InlineData(LanguageVersion.CSharp11)] + public void Local_09_RefReadonlyScoped(LanguageVersion langVersion) + { + string source = @" +ref readonly scoped var b; +scoped ref readonly scoped var c; +"; + UsingTree(source, TestOptions.Regular.WithLanguageVersion(langVersion), + // (2,14): error CS9061: Unexpected contextual keyword 'scoped'. Did you mean 'scoped ref' or '@scoped'? + // ref readonly scoped var b; + Diagnostic(ErrorCode.ERR_MisplacedScoped, "scoped").WithLocation(2, 14), + // (3,21): error CS9061: Unexpected contextual keyword 'scoped'. Did you mean 'scoped ref' or '@scoped'? + // scoped ref readonly scoped var c; + Diagnostic(ErrorCode.ERR_MisplacedScoped, "scoped").WithLocation(3, 21) + ); + + N(SyntaxKind.CompilationUnit); + { N(SyntaxKind.GlobalStatement); { N(SyntaxKind.LocalDeclarationStatement); @@ -1945,7 +2520,6 @@ public void Local_09(LanguageVersion langVersion) { N(SyntaxKind.RefKeyword); N(SyntaxKind.ReadOnlyKeyword); - N(SyntaxKind.ScopedKeyword); N(SyntaxKind.IdentifierName); { N(SyntaxKind.IdentifierToken, "var"); @@ -1970,7 +2544,6 @@ public void Local_09(LanguageVersion langVersion) { N(SyntaxKind.RefKeyword); N(SyntaxKind.ReadOnlyKeyword); - N(SyntaxKind.ScopedKeyword); N(SyntaxKind.IdentifierName); { N(SyntaxKind.IdentifierToken, "var"); @@ -1991,14 +2564,18 @@ public void Local_09(LanguageVersion langVersion) [Theory] [InlineData(LanguageVersion.CSharp10)] - [InlineData(LanguageVersionFacts.CSharpNext)] + [InlineData(LanguageVersion.CSharp11)] public void Local_10(LanguageVersion langVersion) { string source = @"scoped var; ref scoped var; "; - UsingCompilationRoot(source, TestOptions.Regular.WithLanguageVersion(langVersion)); + UsingTree(source, TestOptions.Regular.WithLanguageVersion(langVersion), + // (2,5): error CS9061: Unexpected contextual keyword 'scoped'. Did you mean 'scoped ref' or '@scoped'? + // ref scoped var; + Diagnostic(ErrorCode.ERR_MisplacedScoped, "scoped").WithLocation(2, 5) + ); N(SyntaxKind.CompilationUnit); { @@ -2020,25 +2597,21 @@ public void Local_10(LanguageVersion langVersion) N(SyntaxKind.SemicolonToken); } } - N(SyntaxKind.GlobalStatement); + N(SyntaxKind.IncompleteMember); { - N(SyntaxKind.LocalDeclarationStatement); + N(SyntaxKind.RefType); { - N(SyntaxKind.VariableDeclaration); + N(SyntaxKind.RefKeyword); + N(SyntaxKind.IdentifierName); { - N(SyntaxKind.RefType); - { - N(SyntaxKind.RefKeyword); - N(SyntaxKind.IdentifierName); - { - N(SyntaxKind.IdentifierToken, "scoped"); - } - } - N(SyntaxKind.VariableDeclarator); - { - N(SyntaxKind.IdentifierToken, "var"); - } + N(SyntaxKind.IdentifierToken, "var"); } + } + } + N(SyntaxKind.GlobalStatement); + { + N(SyntaxKind.EmptyStatement); + { N(SyntaxKind.SemicolonToken); } } @@ -2053,10 +2626,13 @@ public void Local_11() string source = @"ref scoped readonly S a; "; - UsingCompilationRoot(source, TestOptions.RegularNext, - // (1,12): error CS1585: Member modifier 'readonly' must precede the member type and name + UsingTree(source, TestOptions.Regular11, + // (1,5): error CS9061: Unexpected contextual keyword 'scoped'. Did you mean 'scoped ref' or '@scoped'? + // ref scoped readonly S a; + Diagnostic(ErrorCode.ERR_MisplacedScoped, "scoped").WithLocation(1, 5), + // (1,12): error CS1031: Type expected // ref scoped readonly S a; - Diagnostic(ErrorCode.ERR_BadModifierLocation, "readonly").WithArguments("readonly").WithLocation(1, 12), + Diagnostic(ErrorCode.ERR_TypeExpected, "readonly").WithLocation(1, 12), // (1,12): error CS0106: The modifier 'readonly' is not valid for this item // ref scoped readonly S a; Diagnostic(ErrorCode.ERR_BadMemberFlag, "readonly").WithArguments("readonly").WithLocation(1, 12)); @@ -2068,9 +2644,9 @@ public void Local_11() N(SyntaxKind.RefType); { N(SyntaxKind.RefKeyword); - N(SyntaxKind.IdentifierName); + M(SyntaxKind.IdentifierName); { - N(SyntaxKind.IdentifierToken, "scoped"); + M(SyntaxKind.IdentifierToken); } } } @@ -2105,7 +2681,7 @@ public void Local_12() @"scoped scoped int a; scoped scoped var b; "; - UsingCompilationRoot(source, TestOptions.RegularNext, + UsingTree(source, TestOptions.Regular11, // (1,15): error CS1003: Syntax error, ',' expected // scoped scoped int a; Diagnostic(ErrorCode.ERR_SyntaxError, "int").WithArguments(",").WithLocation(1, 15), @@ -2160,7 +2736,7 @@ public void Local_12() [Theory] [InlineData(LanguageVersion.CSharp10)] - [InlineData(LanguageVersionFacts.CSharpNext)] + [InlineData(LanguageVersion.CSharp11)] public void FunctionPointer_01(LanguageVersion langVersion) { string source = @"delegate* f;"; @@ -2208,7 +2784,7 @@ public void FunctionPointer_01(LanguageVersion langVersion) [Theory] [InlineData(LanguageVersion.CSharp10)] - [InlineData(LanguageVersionFacts.CSharpNext)] + [InlineData(LanguageVersion.CSharp11)] public void FunctionPointer_02(LanguageVersion langVersion) { string source = @"delegate* f;"; @@ -2276,14 +2852,14 @@ public void FunctionPointer_02(LanguageVersion langVersion) [Theory] [InlineData(LanguageVersion.CSharp10)] - [InlineData(LanguageVersionFacts.CSharpNext)] + [InlineData(LanguageVersion.CSharp11)] public void Type_01(LanguageVersion langVersion) { string source = @"scoped struct A { } scoped ref struct B { } "; - UsingCompilationRoot(source, TestOptions.Regular.WithLanguageVersion(langVersion)); + UsingTree(source, TestOptions.Regular.WithLanguageVersion(langVersion)); N(SyntaxKind.CompilationUnit); { @@ -2317,7 +2893,7 @@ public void Type_02() scoped readonly record struct B; readonly scoped record struct C(); "; - UsingCompilationRoot(source, TestOptions.RegularNext); + UsingTree(source, TestOptions.Regular11); N(SyntaxKind.CompilationUnit); { @@ -2363,7 +2939,7 @@ public void Type_03() string source = @"delegate scoped int A(); "; - UsingCompilationRoot(source, TestOptions.RegularNext, + UsingTree(source, TestOptions.Regular11, // (1,17): error CS1001: Identifier expected // delegate scoped int A(); Diagnostic(ErrorCode.ERR_IdentifierExpected, "int").WithLocation(1, 17), @@ -2440,13 +3016,13 @@ public void Type_03() [Theory] [InlineData(LanguageVersion.CSharp10)] - [InlineData(LanguageVersionFacts.CSharpNext)] + [InlineData(LanguageVersion.CSharp11)] public void Type_04(LanguageVersion langVersion) { string source = @"delegate scoped A(); "; - UsingCompilationRoot(source, TestOptions.Regular.WithLanguageVersion(langVersion)); + UsingTree(source, TestOptions.Regular.WithLanguageVersion(langVersion)); N(SyntaxKind.CompilationUnit); { @@ -2472,13 +3048,17 @@ public void Type_04(LanguageVersion langVersion) [Theory] [InlineData(LanguageVersion.CSharp10)] - [InlineData(LanguageVersionFacts.CSharpNext)] + [InlineData(LanguageVersion.CSharp11)] public void Type_05(LanguageVersion langVersion) { string source = @"delegate ref scoped int B(); "; - UsingCompilationRoot(source, TestOptions.Regular.WithLanguageVersion(langVersion)); + UsingTree(source, TestOptions.Regular.WithLanguageVersion(langVersion), + // (1,14): error CS9061: Unexpected contextual keyword 'scoped'. Did you mean 'scoped ref' or '@scoped'? + // delegate ref scoped int B(); + Diagnostic(ErrorCode.ERR_MisplacedScoped, "scoped").WithLocation(1, 14) + ); N(SyntaxKind.CompilationUnit); { @@ -2488,7 +3068,6 @@ public void Type_05(LanguageVersion langVersion) N(SyntaxKind.RefType); { N(SyntaxKind.RefKeyword); - N(SyntaxKind.ScopedKeyword); N(SyntaxKind.PredefinedType); { N(SyntaxKind.IntKeyword); @@ -2509,13 +3088,19 @@ public void Type_05(LanguageVersion langVersion) [Theory] [InlineData(LanguageVersion.CSharp10)] - [InlineData(LanguageVersionFacts.CSharpNext)] + [InlineData(LanguageVersion.CSharp11)] public void Type_06(LanguageVersion langVersion) { string source = @"delegate ref scoped B(); "; - UsingCompilationRoot(source, TestOptions.Regular.WithLanguageVersion(langVersion)); + UsingTree(source, TestOptions.Regular.WithLanguageVersion(langVersion), + // (1,14): error CS9061: Unexpected contextual keyword 'scoped'. Did you mean 'scoped ref' or '@scoped'? + // delegate ref scoped B(); + Diagnostic(ErrorCode.ERR_MisplacedScoped, "scoped").WithLocation(1, 14), + // (1,22): error CS1001: Identifier expected + // delegate ref scoped B(); + Diagnostic(ErrorCode.ERR_IdentifierExpected, "(").WithLocation(1, 22)); N(SyntaxKind.CompilationUnit); { @@ -2527,10 +3112,10 @@ public void Type_06(LanguageVersion langVersion) N(SyntaxKind.RefKeyword); N(SyntaxKind.IdentifierName); { - N(SyntaxKind.IdentifierToken, "scoped"); + N(SyntaxKind.IdentifierToken, "B"); } } - N(SyntaxKind.IdentifierToken, "B"); + M(SyntaxKind.IdentifierToken); N(SyntaxKind.ParameterList); { N(SyntaxKind.OpenParenToken); @@ -2545,14 +3130,14 @@ public void Type_06(LanguageVersion langVersion) [Theory] [InlineData(LanguageVersion.CSharp10)] - [InlineData(LanguageVersionFacts.CSharpNext)] + [InlineData(LanguageVersion.CSharp11)] public void Type_07(LanguageVersion langVersion) { string source = @"[A] scoped struct A { } [A, B] scoped ref struct B { } "; - UsingCompilationRoot(source, TestOptions.Regular.WithLanguageVersion(langVersion)); + UsingTree(source, TestOptions.Regular.WithLanguageVersion(langVersion)); N(SyntaxKind.CompilationUnit); { @@ -2612,7 +3197,7 @@ public void Type_07(LanguageVersion langVersion) [Theory] [InlineData(LanguageVersion.CSharp10)] - [InlineData(LanguageVersionFacts.CSharpNext)] + [InlineData(LanguageVersion.CSharp11)] public void LocalAssignment_01(LanguageVersion langVersion) { string source = @@ -2624,7 +3209,7 @@ static void Main() scoped = true; } }"; - UsingCompilationRoot(source, TestOptions.Regular.WithLanguageVersion(langVersion)); + UsingTree(source, TestOptions.Regular.WithLanguageVersion(langVersion)); N(SyntaxKind.CompilationUnit); { @@ -2692,14 +3277,14 @@ static void Main() [Theory] [InlineData(LanguageVersion.CSharp10)] - [InlineData(LanguageVersionFacts.CSharpNext)] + [InlineData(LanguageVersion.CSharp11)] public void LocalAssignment_02(LanguageVersion langVersion) { string source = @"bool scoped; scoped = true; "; - UsingCompilationRoot(source, TestOptions.Regular.WithLanguageVersion(langVersion)); + UsingTree(source, TestOptions.Regular.WithLanguageVersion(langVersion)); N(SyntaxKind.CompilationUnit); { @@ -2747,14 +3332,21 @@ public void LocalAssignment_02(LanguageVersion langVersion) [Theory] [InlineData(LanguageVersion.CSharp10)] - [InlineData(LanguageVersionFacts.CSharpNext)] + [InlineData(LanguageVersion.CSharp11)] public void Using_01(LanguageVersion langVersion) { string source = @"using scoped s; using ref scoped r; "; - UsingTree(source, TestOptions.Regular.WithLanguageVersion(langVersion)); + UsingTree(source, TestOptions.Regular.WithLanguageVersion(langVersion), + // (2,11): error CS9061: Unexpected contextual keyword 'scoped'. Did you mean 'scoped ref' or '@scoped'? + // using ref scoped r; + Diagnostic(ErrorCode.ERR_MisplacedScoped, "scoped").WithLocation(2, 11), + // (2,19): error CS1001: Identifier expected + // using ref scoped r; + Diagnostic(ErrorCode.ERR_IdentifierExpected, ";").WithLocation(2, 19) + ); N(SyntaxKind.CompilationUnit); { @@ -2789,12 +3381,12 @@ public void Using_01(LanguageVersion langVersion) N(SyntaxKind.RefKeyword); N(SyntaxKind.IdentifierName); { - N(SyntaxKind.IdentifierToken, "scoped"); + N(SyntaxKind.IdentifierToken, "r"); } } - N(SyntaxKind.VariableDeclarator); + M(SyntaxKind.VariableDeclarator); { - N(SyntaxKind.IdentifierToken, "r"); + M(SyntaxKind.IdentifierToken); } } N(SyntaxKind.SemicolonToken); @@ -2807,12 +3399,11 @@ public void Using_01(LanguageVersion langVersion) [Theory] [InlineData(LanguageVersion.CSharp10)] - [InlineData(LanguageVersionFacts.CSharpNext)] + [InlineData(LanguageVersion.CSharp11)] public void Using_02(LanguageVersion langVersion) { string source = @"using scoped R r1; -using ref scoped R r2; "; UsingTree(source, TestOptions.Regular.WithLanguageVersion(langVersion)); @@ -2838,6 +3429,27 @@ public void Using_02(LanguageVersion langVersion) N(SyntaxKind.SemicolonToken); } } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Theory] + [InlineData(LanguageVersion.CSharp10)] + [InlineData(LanguageVersion.CSharp11)] + public void Using_02_RefScoped(LanguageVersion langVersion) + { + string source = @" +using ref scoped R r2; +"; + UsingTree(source, TestOptions.Regular.WithLanguageVersion(langVersion), + // (2,11): error CS9061: Unexpected contextual keyword 'scoped'. Did you mean 'scoped ref' or '@scoped'? + // using ref scoped R r2; + Diagnostic(ErrorCode.ERR_MisplacedScoped, "scoped").WithLocation(2, 11) + ); + + N(SyntaxKind.CompilationUnit); + { N(SyntaxKind.GlobalStatement); { N(SyntaxKind.LocalDeclarationStatement); @@ -2848,7 +3460,6 @@ public void Using_02(LanguageVersion langVersion) N(SyntaxKind.RefType); { N(SyntaxKind.RefKeyword); - N(SyntaxKind.ScopedKeyword); N(SyntaxKind.IdentifierName); { N(SyntaxKind.IdentifierToken, "R"); @@ -2869,14 +3480,30 @@ public void Using_02(LanguageVersion langVersion) [Theory] [InlineData(LanguageVersion.CSharp10)] - [InlineData(LanguageVersionFacts.CSharpNext)] + [InlineData(LanguageVersion.CSharp11)] public void Using_03(LanguageVersion langVersion) { string source = @"await using scoped s; +await using ref scoped; await using ref scoped r; "; - UsingTree(source, TestOptions.Regular.WithLanguageVersion(langVersion)); + UsingTree(source, TestOptions.Regular.WithLanguageVersion(langVersion), + // (2,17): error CS9061: Unexpected contextual keyword 'scoped'. Did you mean 'scoped ref' or '@scoped'? + // await using ref scoped; + Diagnostic(ErrorCode.ERR_MisplacedScoped, "scoped").WithLocation(2, 17), + // (2,23): error CS1031: Type expected + // await using ref scoped; + Diagnostic(ErrorCode.ERR_TypeExpected, ";").WithLocation(2, 23), + // (2,23): error CS1001: Identifier expected + // await using ref scoped; + Diagnostic(ErrorCode.ERR_IdentifierExpected, ";").WithLocation(2, 23), + // (3,17): error CS9061: Unexpected contextual keyword 'scoped'. Did you mean 'scoped ref' or '@scoped'? + // await using ref scoped r; + Diagnostic(ErrorCode.ERR_MisplacedScoped, "scoped").WithLocation(3, 17), + // (3,25): error CS1001: Identifier expected + // await using ref scoped r; + Diagnostic(ErrorCode.ERR_IdentifierExpected, ";").WithLocation(3, 25)); N(SyntaxKind.CompilationUnit); { @@ -2901,6 +3528,30 @@ public void Using_03(LanguageVersion langVersion) } } N(SyntaxKind.GlobalStatement); + { + N(SyntaxKind.LocalDeclarationStatement); + { + N(SyntaxKind.AwaitKeyword); + N(SyntaxKind.UsingKeyword); + N(SyntaxKind.VariableDeclaration); + { + N(SyntaxKind.RefType); + { + N(SyntaxKind.RefKeyword); + M(SyntaxKind.IdentifierName); + { + M(SyntaxKind.IdentifierToken); + } + } + M(SyntaxKind.VariableDeclarator); + { + M(SyntaxKind.IdentifierToken); + } + } + N(SyntaxKind.SemicolonToken); + } + } + N(SyntaxKind.GlobalStatement); { N(SyntaxKind.LocalDeclarationStatement); { @@ -2913,12 +3564,12 @@ public void Using_03(LanguageVersion langVersion) N(SyntaxKind.RefKeyword); N(SyntaxKind.IdentifierName); { - N(SyntaxKind.IdentifierToken, "scoped"); + N(SyntaxKind.IdentifierToken, "r"); } } - N(SyntaxKind.VariableDeclarator); + M(SyntaxKind.VariableDeclarator); { - N(SyntaxKind.IdentifierToken, "r"); + M(SyntaxKind.IdentifierToken); } } N(SyntaxKind.SemicolonToken); @@ -2931,12 +3582,11 @@ public void Using_03(LanguageVersion langVersion) [Theory] [InlineData(LanguageVersion.CSharp10)] - [InlineData(LanguageVersionFacts.CSharpNext)] + [InlineData(LanguageVersion.CSharp11)] public void Using_04(LanguageVersion langVersion) { string source = @"await using scoped R r1; -await using ref scoped R r2; "; UsingTree(source, TestOptions.Regular.WithLanguageVersion(langVersion)); @@ -2963,6 +3613,27 @@ public void Using_04(LanguageVersion langVersion) N(SyntaxKind.SemicolonToken); } } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Theory] + [InlineData(LanguageVersion.CSharp10)] + [InlineData(LanguageVersion.CSharp11)] + public void Using_04_RefScoped(LanguageVersion langVersion) + { + string source = @" +await using ref scoped R r2; +"; + UsingTree(source, TestOptions.Regular.WithLanguageVersion(langVersion), + // (2,17): error CS9061: Unexpected contextual keyword 'scoped'. Did you mean 'scoped ref' or '@scoped'? + // await using ref scoped R r2; + Diagnostic(ErrorCode.ERR_MisplacedScoped, "scoped").WithLocation(2, 17) + ); + + N(SyntaxKind.CompilationUnit); + { N(SyntaxKind.GlobalStatement); { N(SyntaxKind.LocalDeclarationStatement); @@ -2974,7 +3645,6 @@ public void Using_04(LanguageVersion langVersion) N(SyntaxKind.RefType); { N(SyntaxKind.RefKeyword); - N(SyntaxKind.ScopedKeyword); N(SyntaxKind.IdentifierName); { N(SyntaxKind.IdentifierToken, "R"); diff --git a/src/Compilers/CSharp/Test/Syntax/Parsing/DeconstructionTests.cs b/src/Compilers/CSharp/Test/Syntax/Parsing/DeconstructionTests.cs index fee620a78b8cb..903cb67544db5 100644 --- a/src/Compilers/CSharp/Test/Syntax/Parsing/DeconstructionTests.cs +++ b/src/Compilers/CSharp/Test/Syntax/Parsing/DeconstructionTests.cs @@ -3378,7 +3378,7 @@ void M() } } "; - UsingTree(source).GetDiagnostics().Verify( + UsingTree(source, // (7,10): error CS1525: Invalid expression term 'int' // (int* x1, int y1) = e; Diagnostic(ErrorCode.ERR_InvalidExprTerm, "int").WithArguments("int").WithLocation(7, 10) diff --git a/src/Compilers/CSharp/Test/Syntax/Parsing/ExpressionParsingTests.cs b/src/Compilers/CSharp/Test/Syntax/Parsing/ExpressionParsingTests.cs index 61aff46fd40a4..cce5b664d489c 100644 --- a/src/Compilers/CSharp/Test/Syntax/Parsing/ExpressionParsingTests.cs +++ b/src/Compilers/CSharp/Test/Syntax/Parsing/ExpressionParsingTests.cs @@ -2671,7 +2671,7 @@ async void M() } } "; - ParseAndValidate(text, + UsingTree(text, // (6,14): error CS1001: Identifier expected // Task. Diagnostic(ErrorCode.ERR_IdentifierExpected, "").WithLocation(6, 14), @@ -2679,7 +2679,6 @@ async void M() // Task. Diagnostic(ErrorCode.ERR_SemicolonExpected, "").WithLocation(6, 14)); - UsingTree(text); N(SyntaxKind.CompilationUnit); { N(SyntaxKind.ClassDeclaration); @@ -2769,7 +2768,7 @@ async void M() } } "; - ParseAndValidate(text, + UsingTree(text, // (6,14): error CS4003: 'await' cannot be used as an identifier within an async method or lambda expression // Task.await Task.Delay(); Diagnostic(ErrorCode.ERR_BadAwaitAsIdentifier, "await").WithLocation(6, 14), @@ -2780,7 +2779,6 @@ async void M() // Task.await Task.Delay(); Diagnostic(ErrorCode.ERR_SemicolonExpected, "Delay").WithLocation(6, 25)); - UsingTree(text); N(SyntaxKind.CompilationUnit); { N(SyntaxKind.ClassDeclaration); @@ -2866,12 +2864,11 @@ async void M() } } "; - ParseAndValidate(text, + UsingTree(text, // (7,9): error CS4003: 'await' cannot be used as an identifier within an async method or lambda expression // await Task; Diagnostic(ErrorCode.ERR_BadAwaitAsIdentifier, "await").WithLocation(7, 9)); - UsingTree(text); N(SyntaxKind.CompilationUnit); { N(SyntaxKind.ClassDeclaration); @@ -2941,12 +2938,11 @@ async void M() } } "; - ParseAndValidate(text, + UsingTree(text, // (7,9): error CS4003: 'await' cannot be used as an identifier within an async method or lambda expression // await Task = 1; Diagnostic(ErrorCode.ERR_BadAwaitAsIdentifier, "await").WithLocation(7, 9)); - UsingTree(text); N(SyntaxKind.CompilationUnit); { N(SyntaxKind.ClassDeclaration); @@ -3024,12 +3020,11 @@ async void M() } } "; - ParseAndValidate(text, + UsingTree(text, // (7,9): error CS4003: 'await' cannot be used as an identifier within an async method or lambda expression // await Task, Task2; Diagnostic(ErrorCode.ERR_BadAwaitAsIdentifier, "await").WithLocation(7, 9)); - UsingTree(text); N(SyntaxKind.CompilationUnit); { N(SyntaxKind.ClassDeclaration); @@ -3104,12 +3099,11 @@ async void M() } } "; - ParseAndValidate(text, + UsingTree(text, // (7,9): error CS4003: 'await' cannot be used as an identifier within an async method or lambda expression // await Task(); Diagnostic(ErrorCode.ERR_BadAwaitAsIdentifier, "await").WithLocation(7, 9)); - UsingTree(text); N(SyntaxKind.CompilationUnit); { N(SyntaxKind.ClassDeclaration); @@ -3178,12 +3172,11 @@ async void M() } } "; - ParseAndValidate(text, + UsingTree(text, // (7,9): error CS4003: 'await' cannot be used as an identifier within an async method or lambda expression // await Task(); Diagnostic(ErrorCode.ERR_BadAwaitAsIdentifier, "await").WithLocation(7, 9)); - UsingTree(text); N(SyntaxKind.CompilationUnit); { N(SyntaxKind.ClassDeclaration); @@ -3261,7 +3254,7 @@ async void M() } } "; - ParseAndValidate(text, + UsingTree(text, // (6,14): error CS1001: Identifier expected // Task. Diagnostic(ErrorCode.ERR_IdentifierExpected, "").WithLocation(6, 14), @@ -3269,7 +3262,6 @@ async void M() // Task. Diagnostic(ErrorCode.ERR_SemicolonExpected, "").WithLocation(6, 14)); - UsingTree(text); N(SyntaxKind.CompilationUnit); { N(SyntaxKind.ClassDeclaration); @@ -3816,8 +3808,7 @@ void M() } } "; - var tree = UsingTree(text); - tree.GetDiagnostics().Verify( + var tree = UsingTree(text, // (7,30): error CS1525: Invalid expression term '<<' // var j = e is a < i > << 2; Diagnostic(ErrorCode.ERR_InvalidExprTerm, "<<").WithArguments("<<").WithLocation(7, 30) @@ -3922,8 +3913,7 @@ void M() } } "; - var tree = UsingTree(text); - tree.GetDiagnostics().Verify( + var tree = UsingTree(text, // (7,31): error CS1525: Invalid expression term '>' // var j = e is a < i >>>> 2; Diagnostic(ErrorCode.ERR_InvalidExprTerm, ">").WithArguments(">").WithLocation(7, 31) @@ -5683,9 +5673,6 @@ public void AnonymousObjectCreation_BadRef() public void ObjectInitializer_BadRef() { UsingExpression("new C { P = ref }", - // (1,13): error CS1525: Invalid expression term 'ref' - // new C { P = ref } - Diagnostic(ErrorCode.ERR_InvalidExprTerm, "ref ").WithArguments("ref").WithLocation(1, 13), // (1,17): error CS1525: Invalid expression term '}' // new C { P = ref } Diagnostic(ErrorCode.ERR_InvalidExprTerm, "}").WithArguments("}").WithLocation(1, 17)); @@ -5727,9 +5714,6 @@ public void ObjectInitializer_BadRef() public void CollectionInitializer_BadRef_01() { UsingExpression("new C { ref }", - // (1,9): error CS1525: Invalid expression term 'ref' - // new C { ref } - Diagnostic(ErrorCode.ERR_InvalidExprTerm, "ref ").WithArguments("ref").WithLocation(1, 9), // (1,13): error CS1525: Invalid expression term '}' // new C { ref } Diagnostic(ErrorCode.ERR_InvalidExprTerm, "}").WithArguments("}").WithLocation(1, 13)); @@ -5808,7 +5792,7 @@ public void CollectionInitializer_BadRef_02() [WorkItem(39072, "https://github.com/dotnet/roslyn/issues/39072")] public void AttributeArgument_BadRef() { - UsingTree("class C { [Attr(ref)] void M() { } }").GetDiagnostics().Verify( + UsingTree("class C { [Attr(ref)] void M() { } }", // (1,17): error CS1525: Invalid expression term 'ref' // class C { [Attr(ref)] void M() { } } Diagnostic(ErrorCode.ERR_InvalidExprTerm, "ref").WithArguments("ref").WithLocation(1, 17), @@ -6143,7 +6127,7 @@ void M() [Fact] public void UnsignedRightShift_01() { - foreach (var options in new[] { TestOptions.RegularPreview, TestOptions.Regular10, TestOptions.RegularNext }) + foreach (var options in new[] { TestOptions.RegularPreview, TestOptions.Regular10, TestOptions.Regular11 }) { UsingExpression("x >>> y", options); @@ -6166,7 +6150,7 @@ public void UnsignedRightShift_01() [Fact] public void UnsignedRightShift_02() { - foreach (var options in new[] { TestOptions.RegularPreview, TestOptions.Regular10, TestOptions.RegularNext }) + foreach (var options in new[] { TestOptions.RegularPreview, TestOptions.Regular10, TestOptions.Regular11 }) { UsingExpression("x > >> y", options, // (1,5): error CS1525: Invalid expression term '>' @@ -6201,7 +6185,7 @@ public void UnsignedRightShift_02() [Fact] public void UnsignedRightShift_03() { - foreach (var options in new[] { TestOptions.RegularPreview, TestOptions.Regular10, TestOptions.RegularNext }) + foreach (var options in new[] { TestOptions.RegularPreview, TestOptions.Regular10, TestOptions.Regular11 }) { UsingExpression("x >> > y", options, // (1,6): error CS1525: Invalid expression term '>' @@ -6236,7 +6220,7 @@ public void UnsignedRightShift_03() [Fact] public void UnsignedRightShiftAssignment_01() { - foreach (var options in new[] { TestOptions.RegularPreview, TestOptions.Regular10, TestOptions.RegularNext }) + foreach (var options in new[] { TestOptions.RegularPreview, TestOptions.Regular10, TestOptions.Regular11 }) { UsingExpression("x >>>= y", options); @@ -6259,7 +6243,7 @@ public void UnsignedRightShiftAssignment_01() [Fact] public void UnsignedRightShiftAssignment_02() { - foreach (var options in new[] { TestOptions.RegularPreview, TestOptions.Regular10, TestOptions.RegularNext }) + foreach (var options in new[] { TestOptions.RegularPreview, TestOptions.Regular10, TestOptions.Regular11 }) { UsingExpression("x > >>= y", options, // (1,5): error CS1525: Invalid expression term '>' @@ -6294,7 +6278,7 @@ public void UnsignedRightShiftAssignment_02() [Fact] public void UnsignedRightShiftAssignment_03() { - foreach (var options in new[] { TestOptions.RegularPreview, TestOptions.Regular10, TestOptions.RegularNext }) + foreach (var options in new[] { TestOptions.RegularPreview, TestOptions.Regular10, TestOptions.Regular11 }) { UsingExpression("x >> >= y", options, // (1,6): error CS1525: Invalid expression term '>=' @@ -6329,7 +6313,7 @@ public void UnsignedRightShiftAssignment_03() [Fact] public void UnsignedRightShiftAssignment_04() { - foreach (var options in new[] { TestOptions.RegularPreview, TestOptions.Regular10, TestOptions.RegularNext }) + foreach (var options in new[] { TestOptions.RegularPreview, TestOptions.Regular10, TestOptions.Regular11 }) { UsingExpression("x >>> = y", options, // (1,7): error CS1525: Invalid expression term '=' diff --git a/src/Compilers/CSharp/Test/Syntax/Parsing/FileModifierParsingTests.cs b/src/Compilers/CSharp/Test/Syntax/Parsing/FileModifierParsingTests.cs new file mode 100644 index 0000000000000..fcbd84a47a552 --- /dev/null +++ b/src/Compilers/CSharp/Test/Syntax/Parsing/FileModifierParsingTests.cs @@ -0,0 +1,2976 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation 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 Microsoft.CodeAnalysis.CSharp.Test.Utilities; +using Microsoft.CodeAnalysis.Test.Utilities; +using Xunit; +using Xunit.Abstractions; + +namespace Microsoft.CodeAnalysis.CSharp.UnitTests; + +public class FileModifierParsingTests : ParsingTests +{ + public FileModifierParsingTests(ITestOutputHelper output) : base(output) { } + + protected override SyntaxTree ParseTree(string text, CSharpParseOptions? options) + { + return SyntaxFactory.ParseSyntaxTree(text, options ?? TestOptions.Regular); + } + + private void UsingNode(string text, params DiagnosticDescription[] expectedDiagnostics) + { + UsingNode(text, options: null, expectedParsingDiagnostics: expectedDiagnostics); + } + + private new void UsingNode(string text, CSharpParseOptions? options, params DiagnosticDescription[] expectedDiagnostics) + { + UsingNode(text, options, expectedParsingDiagnostics: expectedDiagnostics); + } + + private void UsingNode(string text, CSharpParseOptions? options = null, DiagnosticDescription[]? expectedParsingDiagnostics = null, DiagnosticDescription[]? expectedBindingDiagnostics = null) + { + options ??= TestOptions.RegularPreview; + expectedParsingDiagnostics ??= Array.Empty(); + expectedBindingDiagnostics ??= expectedParsingDiagnostics; + + var tree = UsingTree(text, options, expectedParsingDiagnostics); + Validate(text, (CSharpSyntaxNode)tree.GetRoot(), expectedParsingDiagnostics); + + var comp = CreateCompilation(tree); + comp.VerifyDiagnostics(expectedBindingDiagnostics); + } + + [Theory] + [InlineData(SyntaxKind.ClassKeyword)] + [InlineData(SyntaxKind.StructKeyword)] + [InlineData(SyntaxKind.InterfaceKeyword)] + [InlineData(SyntaxKind.RecordKeyword)] + [InlineData(SyntaxKind.EnumKeyword)] + public void FileModifier_01(SyntaxKind typeKeyword) + { + UsingNode($$""" + file {{SyntaxFacts.GetText(typeKeyword)}} C { } + """); + N(SyntaxKind.CompilationUnit); + { + N(SyntaxFacts.GetBaseTypeDeclarationKind(typeKeyword)); + { + N(SyntaxKind.FileKeyword); + N(typeKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Theory] + [InlineData(SyntaxKind.ClassKeyword)] + [InlineData(SyntaxKind.StructKeyword)] + [InlineData(SyntaxKind.InterfaceKeyword)] + [InlineData(SyntaxKind.RecordKeyword)] + public void FileModifier_02(SyntaxKind typeKeyword) + { + UsingNode($$""" + file partial {{SyntaxFacts.GetText(typeKeyword)}} C { } + """); + N(SyntaxKind.CompilationUnit); + { + N(SyntaxFacts.GetBaseTypeDeclarationKind(typeKeyword)); + { + N(SyntaxKind.FileKeyword); + N(SyntaxKind.PartialKeyword); + N(typeKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void FileModifier_02_Enum() + { + UsingNode($$""" + file partial enum C { } + """, + expectedBindingDiagnostics: new[] + { + // (1,19): error CS0267: The 'partial' modifier can only appear immediately before 'class', 'record', 'struct', 'interface', or a method return type. + // file partial enum C { } + Diagnostic(ErrorCode.ERR_PartialMisplaced, "C").WithLocation(1, 19) + }); + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.EnumDeclaration); + { + N(SyntaxKind.FileKeyword); + N(SyntaxKind.PartialKeyword); + N(SyntaxKind.EnumKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Theory] + [InlineData(SyntaxKind.ClassKeyword)] + [InlineData(SyntaxKind.StructKeyword)] + [InlineData(SyntaxKind.InterfaceKeyword)] + public void FileModifier_03(SyntaxKind typeKeyword) + { + UsingNode($$""" + partial file {{SyntaxFacts.GetText(typeKeyword)}} C { } + """, + expectedParsingDiagnostics: new[] + { + // (1,14): error CS1002: ; expected + // partial file {{SyntaxFacts.GetText(typeKeyword)}} C { } + Diagnostic(ErrorCode.ERR_SemicolonExpected, SyntaxFacts.GetText(typeKeyword)).WithLocation(1, 14) + }, + expectedBindingDiagnostics: new[] + { + // (1,1): error CS0246: The type or namespace name 'partial' could not be found (are you missing a using directive or an assembly reference?) + // partial file interface C { } + Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "partial").WithArguments("partial").WithLocation(1, 1), + // (1,9): warning CS0168: The variable 'file' is declared but never used + // partial file interface C { } + Diagnostic(ErrorCode.WRN_UnreferencedVar, "file").WithArguments("file").WithLocation(1, 9), + // (1,14): error CS1002: ; expected + // partial file {{SyntaxFacts.GetText(typeKeyword)}} C { } + Diagnostic(ErrorCode.ERR_SemicolonExpected, SyntaxFacts.GetText(typeKeyword)).WithLocation(1, 14) + }); + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.GlobalStatement); + { + N(SyntaxKind.LocalDeclarationStatement); + { + N(SyntaxKind.VariableDeclaration); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "partial"); + } + N(SyntaxKind.VariableDeclarator); + { + N(SyntaxKind.IdentifierToken, "file"); + } + } + M(SyntaxKind.SemicolonToken); + } + } + N(SyntaxFacts.GetBaseTypeDeclarationKind(typeKeyword)); + { + N(typeKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void FileModifier_04() + { + UsingNode(""" + partial file record C { } + """, + expectedBindingDiagnostics: new DiagnosticDescription[] + { + // (1,1): error CS0267: The 'partial' modifier can only appear immediately before 'class', 'record', 'struct', 'interface', or a method return type. + // partial file record C { } + Diagnostic(ErrorCode.ERR_PartialMisplaced, "partial").WithLocation(1, 1) + }); + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.RecordDeclaration); + { + N(SyntaxKind.PartialKeyword); + N(SyntaxKind.FileKeyword); + N(SyntaxKind.RecordKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void FileModifier_05() + { + UsingNode($$""" + file partial record struct C { } + """); + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.RecordStructDeclaration); + { + N(SyntaxKind.FileKeyword); + N(SyntaxKind.PartialKeyword); + N(SyntaxKind.RecordKeyword); + N(SyntaxKind.StructKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void FileModifier_06() + { + UsingNode($$""" + partial file record struct C { } + """, + expectedBindingDiagnostics: new DiagnosticDescription[] + { + // (1,1): error CS0267: The 'partial' modifier can only appear immediately before 'class', 'record', 'struct', 'interface', or a method return type. + // partial file record struct C { } + Diagnostic(ErrorCode.ERR_PartialMisplaced, "partial").WithLocation(1, 1) + }); + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.RecordStructDeclaration); + { + N(SyntaxKind.PartialKeyword); + N(SyntaxKind.FileKeyword); + N(SyntaxKind.RecordKeyword); + N(SyntaxKind.StructKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void FileModifier_07_CSharp10() + { + UsingNode($$""" + file partial ref struct C { } + """, + options: TestOptions.Regular10, + expectedParsingDiagnostics: new[] + { + // (1,14): error CS1003: Syntax error, ',' expected + // file partial ref struct C { } + Diagnostic(ErrorCode.ERR_SyntaxError, "ref").WithArguments(",").WithLocation(1, 14), + // (1,18): error CS1002: ; expected + // file partial ref struct C { } + Diagnostic(ErrorCode.ERR_SemicolonExpected, "struct").WithLocation(1, 18) + }, + expectedBindingDiagnostics: new[] + { + // (1,1): error CS0246: The type or namespace name 'file' could not be found (are you missing a using directive or an assembly reference?) + // file partial ref struct C { } + Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "file").WithArguments("file").WithLocation(1, 1), + // (1,6): warning CS0168: The variable 'partial' is declared but never used + // file partial ref struct C { } + Diagnostic(ErrorCode.WRN_UnreferencedVar, "partial").WithArguments("partial").WithLocation(1, 6), + // (1,14): error CS1003: Syntax error, ',' expected + // file partial ref struct C { } + Diagnostic(ErrorCode.ERR_SyntaxError, "ref").WithArguments(",").WithLocation(1, 14), + // (1,18): error CS1002: ; expected + // file partial ref struct C { } + Diagnostic(ErrorCode.ERR_SemicolonExpected, "struct").WithLocation(1, 18) + }); + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.GlobalStatement); + { + N(SyntaxKind.LocalDeclarationStatement); + { + N(SyntaxKind.VariableDeclaration); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "file"); + } + N(SyntaxKind.VariableDeclarator); + { + N(SyntaxKind.IdentifierToken, "partial"); + } + } + M(SyntaxKind.SemicolonToken); + } + } + N(SyntaxKind.StructDeclaration); + { + N(SyntaxKind.StructKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void FileModifier_07() + { + UsingNode($$""" + file partial ref struct C { } + """, + expectedParsingDiagnostics: new[] + { + // (1,14): error CS1003: Syntax error, ',' expected + // file partial ref struct C { } + Diagnostic(ErrorCode.ERR_SyntaxError, "ref").WithArguments(",").WithLocation(1, 14), + // (1,18): error CS1002: ; expected + // file partial ref struct C { } + Diagnostic(ErrorCode.ERR_SemicolonExpected, "struct").WithLocation(1, 18) + }, + expectedBindingDiagnostics: new[] + { + // (1,1): error CS0246: The type or namespace name 'file' could not be found (are you missing a using directive or an assembly reference?) + // file partial ref struct C { } + Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "file").WithArguments("file").WithLocation(1, 1), + // (1,6): warning CS0168: The variable 'partial' is declared but never used + // file partial ref struct C { } + Diagnostic(ErrorCode.WRN_UnreferencedVar, "partial").WithArguments("partial").WithLocation(1, 6), + // (1,14): error CS1003: Syntax error, ',' expected + // file partial ref struct C { } + Diagnostic(ErrorCode.ERR_SyntaxError, "ref").WithArguments(",").WithLocation(1, 14), + // (1,18): error CS1002: ; expected + // file partial ref struct C { } + Diagnostic(ErrorCode.ERR_SemicolonExpected, "struct").WithLocation(1, 18) + }); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.GlobalStatement); + { + N(SyntaxKind.LocalDeclarationStatement); + { + N(SyntaxKind.VariableDeclaration); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "file"); + } + N(SyntaxKind.VariableDeclarator); + { + N(SyntaxKind.IdentifierToken, "partial"); + } + } + M(SyntaxKind.SemicolonToken); + } + } + N(SyntaxKind.StructDeclaration); + { + N(SyntaxKind.StructKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void FileModifier_08() + { + UsingNode($$""" + partial file ref struct C { } + """, + expectedParsingDiagnostics: new[] + { + // (1,14): error CS1003: Syntax error, ',' expected + // partial file ref struct C { } + Diagnostic(ErrorCode.ERR_SyntaxError, "ref").WithArguments(",").WithLocation(1, 14), + // (1,18): error CS1002: ; expected + // partial file ref struct C { } + Diagnostic(ErrorCode.ERR_SemicolonExpected, "struct").WithLocation(1, 18) + }, + expectedBindingDiagnostics: new[] + { + // (1,1): error CS0246: The type or namespace name 'partial' could not be found (are you missing a using directive or an assembly reference?) + // partial file ref struct C { } + Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "partial").WithArguments("partial").WithLocation(1, 1), + // (1,9): warning CS0168: The variable 'file' is declared but never used + // partial file ref struct C { } + Diagnostic(ErrorCode.WRN_UnreferencedVar, "file").WithArguments("file").WithLocation(1, 9), + // (1,14): error CS1003: Syntax error, ',' expected + // partial file ref struct C { } + Diagnostic(ErrorCode.ERR_SyntaxError, "ref").WithArguments(",").WithLocation(1, 14), + // (1,18): error CS1002: ; expected + // partial file ref struct C { } + Diagnostic(ErrorCode.ERR_SemicolonExpected, "struct").WithLocation(1, 18) + }); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.GlobalStatement); + { + N(SyntaxKind.LocalDeclarationStatement); + { + N(SyntaxKind.VariableDeclaration); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "partial"); + } + N(SyntaxKind.VariableDeclarator); + { + N(SyntaxKind.IdentifierToken, "file"); + } + } + M(SyntaxKind.SemicolonToken); + } + } + N(SyntaxKind.StructDeclaration); + { + N(SyntaxKind.StructKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void FileModifier_09() + { + UsingNode($$""" + file abstract class C { } + """); + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.FileKeyword); + N(SyntaxKind.AbstractKeyword); + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void FileModifier_10() + { + UsingNode($$""" + abstract file class C { } + """); + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.AbstractKeyword); + N(SyntaxKind.FileKeyword); + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Theory] + [InlineData(SyntaxKind.ClassKeyword)] + [InlineData(SyntaxKind.StructKeyword)] + [InlineData(SyntaxKind.InterfaceKeyword)] + [InlineData(SyntaxKind.RecordKeyword)] + [InlineData(SyntaxKind.EnumKeyword)] + public void FileModifier_11(SyntaxKind typeKeyword) + { + UsingNode($$""" + public file {{SyntaxFacts.GetText(typeKeyword)}} C { } + """, + expectedBindingDiagnostics: new[] + { + // (1,20): error CS9052: File-local type 'C' cannot use accessibility modifiers. + // public file {{SyntaxFacts.GetText(typeKeyword)}} C { } + Diagnostic(ErrorCode.ERR_FileTypeNoExplicitAccessibility, "C").WithArguments("C") + }); + N(SyntaxKind.CompilationUnit); + { + N(SyntaxFacts.GetBaseTypeDeclarationKind(typeKeyword)); + { + N(SyntaxKind.PublicKeyword); + N(SyntaxKind.FileKeyword); + N(typeKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Theory] + [InlineData(SyntaxKind.ClassKeyword)] + [InlineData(SyntaxKind.StructKeyword)] + [InlineData(SyntaxKind.InterfaceKeyword)] + [InlineData(SyntaxKind.RecordKeyword)] + [InlineData(SyntaxKind.EnumKeyword)] + public void FileModifier_12(SyntaxKind typeKeyword) + { + UsingNode($$""" + file public {{SyntaxFacts.GetText(typeKeyword)}} C { } + """, + expectedBindingDiagnostics: new[] + { + // (1,19): error CS9052: File-local type 'C' cannot use accessibility modifiers. + // file public {{SyntaxFacts.GetText(typeKeyword)}} C { } + Diagnostic(ErrorCode.ERR_FileTypeNoExplicitAccessibility, "C").WithArguments("C") + }); + N(SyntaxKind.CompilationUnit); + { + N(SyntaxFacts.GetBaseTypeDeclarationKind(typeKeyword)); + { + N(SyntaxKind.FileKeyword); + N(SyntaxKind.PublicKeyword); + N(typeKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void FileModifier_13() + { + UsingNode(""" + file class C { } + """, + options: TestOptions.Regular10, + expectedBindingDiagnostics: new[] + { + // (1,12): error CS8936: Feature 'file types' is not available in C# 10.0. Please use language version 11.0 or greater. + // file class C { } + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "C").WithArguments("file types", "11.0").WithLocation(1, 12) + }); + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.FileKeyword); + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void FileModifier_14() + { + UsingNode(""" + file delegate void D(); + """); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.DelegateDeclaration); + { + N(SyntaxKind.FileKeyword); + N(SyntaxKind.DelegateKeyword); + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.VoidKeyword); + } + N(SyntaxKind.IdentifierToken, "D"); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.SemicolonToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void FileModifier_15() + { + UsingNode(""" + namespace NS + { + file class C { } + } + """); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.NamespaceDeclaration); + { + N(SyntaxKind.NamespaceKeyword); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "NS"); + } + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.FileKeyword); + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void FileModifier_16() + { + UsingNode(""" + namespace NS; + file class C { } + """); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.FileScopedNamespaceDeclaration); + { + N(SyntaxKind.NamespaceKeyword); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "NS"); + } + N(SyntaxKind.SemicolonToken); + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.FileKeyword); + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void FileModifier_17() + { + UsingNode(""" + class Outer + { + file class C { } + } + """, + expectedBindingDiagnostics: new[] + { + // (3,16): error CS9054: File-local type 'Outer.C' must be defined in a top level type; 'Outer.C' is a nested type. + // file class C { } + Diagnostic(ErrorCode.ERR_FileTypeNested, "C").WithArguments("Outer.C").WithLocation(3, 16) + }); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "Outer"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.FileKeyword); + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void FileModifier_18() + { + UsingNode(""" + class C + { + file delegate* M(); + } + """, + expectedBindingDiagnostics: new[] + { + // (3,10): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context + // file delegate* M(); + Diagnostic(ErrorCode.ERR_UnsafeNeeded, "delegate*").WithLocation(3, 10), + // (3,31): error CS0106: The modifier 'file' is not valid for this item + // file delegate* M(); + Diagnostic(ErrorCode.ERR_BadMemberFlag, "M").WithArguments("file").WithLocation(3, 31), + // (3,31): error CS0501: 'C.M()' must declare a body because it is not marked abstract, extern, or partial + // file delegate* M(); + Diagnostic(ErrorCode.ERR_ConcreteMissingBody, "M").WithArguments("C.M()").WithLocation(3, 31) + }); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.MethodDeclaration); + { + N(SyntaxKind.FileKeyword); + N(SyntaxKind.FunctionPointerType); + { + N(SyntaxKind.DelegateKeyword); + N(SyntaxKind.AsteriskToken); + N(SyntaxKind.FunctionPointerParameterList); + { + N(SyntaxKind.LessThanToken); + N(SyntaxKind.FunctionPointerParameter); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.IntKeyword); + } + } + N(SyntaxKind.CommaToken); + N(SyntaxKind.FunctionPointerParameter); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.VoidKeyword); + } + } + N(SyntaxKind.GreaterThanToken); + } + } + N(SyntaxKind.IdentifierToken, "M"); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.SemicolonToken); + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void FileMember_01() + { + UsingNode(""" + class C + { + file void M() { } + } + """, + expectedBindingDiagnostics: new[] + { + // (3,15): error CS0106: The modifier 'file' is not valid for this item + // file void M() { } + Diagnostic(ErrorCode.ERR_BadMemberFlag, "M").WithArguments("file").WithLocation(3, 15) + }); + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.MethodDeclaration); + { + N(SyntaxKind.FileKeyword); + 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); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void FileMember_02() + { + UsingNode(""" + class C + { + file int x; + } + """, + expectedBindingDiagnostics: new[] + { + // (3,14): error CS0106: The modifier 'file' is not valid for this item + // file int x; + Diagnostic(ErrorCode.ERR_BadMemberFlag, "x").WithArguments("file").WithLocation(3, 14), + // (3,14): warning CS0169: The field 'C.x' is never used + // file int x; + Diagnostic(ErrorCode.WRN_UnreferencedField, "x").WithArguments("C.x").WithLocation(3, 14) + }); + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.FieldDeclaration); + { + N(SyntaxKind.FileKeyword); + N(SyntaxKind.VariableDeclaration); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.IntKeyword); + } + N(SyntaxKind.VariableDeclarator); + { + N(SyntaxKind.IdentifierToken, "x"); + } + } + N(SyntaxKind.SemicolonToken); + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void FileMember_03() + { + UsingNode($$""" + class C + { + file event Action x; + } + """, + expectedBindingDiagnostics: new[] + { + // (3,16): error CS0246: The type or namespace name 'Action' could not be found (are you missing a using directive or an assembly reference?) + // file event Action x; + Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "Action").WithArguments("Action").WithLocation(3, 16), + // (3,23): error CS0106: The modifier 'file' is not valid for this item + // file event Action x; + Diagnostic(ErrorCode.ERR_BadMemberFlag, "x").WithArguments("file").WithLocation(3, 23), + // (3,23): warning CS0067: The event 'C.x' is never used + // file event Action x; + Diagnostic(ErrorCode.WRN_UnreferencedEvent, "x").WithArguments("C.x").WithLocation(3, 23) + }); + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.EventFieldDeclaration); + { + N(SyntaxKind.FileKeyword); + N(SyntaxKind.EventKeyword); + N(SyntaxKind.VariableDeclaration); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "Action"); + } + N(SyntaxKind.VariableDeclarator); + { + N(SyntaxKind.IdentifierToken, "x"); + } + } + N(SyntaxKind.SemicolonToken); + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void FileMember_04() + { + var source = $$""" + class C + { + file int x { get; set; } + } + """; + + UsingNode(source, expectedBindingDiagnostics: new[] + { + // (3,14): error CS0106: The modifier 'file' is not valid for this item + // file int x { get; set; } + Diagnostic(ErrorCode.ERR_BadMemberFlag, "x").WithArguments("file").WithLocation(3, 14) + }); + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.PropertyDeclaration); + { + N(SyntaxKind.FileKeyword); + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.IntKeyword); + } + N(SyntaxKind.IdentifierToken, "x"); + 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.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void FileMember_05() + { + var source = $$""" + class C + { + async file void M() { } + } + """; + + UsingNode(source, expectedBindingDiagnostics: new[] + { + // (3,21): error CS0106: The modifier 'file' is not valid for this item + // async file void M() { } + Diagnostic(ErrorCode.ERR_BadMemberFlag, "M").WithArguments("file").WithLocation(3, 21), + // (3,21): warning CS1998: This async method lacks 'await' operators and will run synchronously. Consider using the 'await' operator to await non-blocking API calls, or 'await Task.Run(...)' to do CPU-bound work on a background thread. + // async file void M() { } + Diagnostic(ErrorCode.WRN_AsyncLacksAwaits, "M").WithLocation(3, 21) + }); + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.MethodDeclaration); + { + N(SyntaxKind.AsyncKeyword); + N(SyntaxKind.FileKeyword); + 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); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void MemberNamedFile_01() + { + UsingNode($$""" + class C + { + int file; + } + """, expectedBindingDiagnostics: new[] + { + // (3,9): warning CS0169: The field 'C.file' is never used + // int file; + Diagnostic(ErrorCode.WRN_UnreferencedField, "file").WithArguments("C.file").WithLocation(3, 9) + }); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.FieldDeclaration); + { + N(SyntaxKind.VariableDeclaration); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.IntKeyword); + } + N(SyntaxKind.VariableDeclarator); + { + N(SyntaxKind.IdentifierToken, "file"); + } + } + N(SyntaxKind.SemicolonToken); + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void MemberNamedFile_02() + { + UsingNode($$""" + class C + { + int file { get; set; } + } + """); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.PropertyDeclaration); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.IntKeyword); + } + N(SyntaxKind.IdentifierToken, "file"); + 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.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void MemberNamedFile_03() + { + UsingNode($$""" + class C + { + event Action file; + } + """, + expectedBindingDiagnostics: new[] + { + // (3,11): error CS0246: The type or namespace name 'Action' could not be found (are you missing a using directive or an assembly reference?) + // event Action file; + Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "Action").WithArguments("Action").WithLocation(3, 11), + // (3,18): warning CS0067: The event 'C.file' is never used + // event Action file; + Diagnostic(ErrorCode.WRN_UnreferencedEvent, "file").WithArguments("C.file").WithLocation(3, 18) + }); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.EventFieldDeclaration); + { + N(SyntaxKind.EventKeyword); + N(SyntaxKind.VariableDeclaration); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "Action"); + } + N(SyntaxKind.VariableDeclarator); + { + N(SyntaxKind.IdentifierToken, "file"); + } + } + N(SyntaxKind.SemicolonToken); + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void MemberNamedFile_04() + { + UsingNode($$""" + class C + { + void file() { } + } + """); + + 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, "file"); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.Block); + { + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void MemberNamedFile_05() + { + UsingNode($$""" + file class file { } + """, + expectedBindingDiagnostics: new[] + { + // (1,12): error CS9056: Types and aliases cannot be named 'file'. + // file class file { } + Diagnostic(ErrorCode.ERR_FileTypeNameDisallowed, "file").WithLocation(1, 12) + }); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.FileKeyword); + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "file"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void MemberNamedFile_06_CSharp10() + { + UsingNode($$""" + class C + { + file async; + } + """, + options: TestOptions.Regular10, + expectedBindingDiagnostics: new[] + { + // (3,5): error CS0246: The type or namespace name 'file' could not be found (are you missing a using directive or an assembly reference?) + // file async; + Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "file").WithArguments("file").WithLocation(3, 5), + // (3,10): warning CS0169: The field 'C.async' is never used + // file async; + Diagnostic(ErrorCode.WRN_UnreferencedField, "async").WithArguments("C.async").WithLocation(3, 10) + }); + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.FieldDeclaration); + { + N(SyntaxKind.VariableDeclaration); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "file"); + } + N(SyntaxKind.VariableDeclarator); + { + N(SyntaxKind.IdentifierToken, "async"); + } + } + N(SyntaxKind.SemicolonToken); + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void MemberNamedFile_06() + { + UsingNode($$""" + class C + { + file async; + } + """, + // (3,15): error CS1519: Invalid token ';' in class, record, struct, or interface member declaration + // file async; + Diagnostic(ErrorCode.ERR_InvalidMemberDecl, ";").WithArguments(";").WithLocation(3, 15), + // (3,15): error CS1519: Invalid token ';' in class, record, struct, or interface member declaration + // file async; + Diagnostic(ErrorCode.ERR_InvalidMemberDecl, ";").WithArguments(";").WithLocation(3, 15)); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.IncompleteMember); + { + N(SyntaxKind.FileKeyword); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "async"); + } + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void MemberNamedFile_07_CSharp10() + { + UsingNode($$""" + class C + { + file item; + } + """, + options: TestOptions.Regular10, + expectedBindingDiagnostics: new[] + { + // (3,5): error CS0246: The type or namespace name 'file' could not be found (are you missing a using directive or an assembly reference?) + // file item; + Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "file").WithArguments("file").WithLocation(3, 5), + // (3,10): warning CS0169: The field 'C.item' is never used + // file item; + Diagnostic(ErrorCode.WRN_UnreferencedField, "item").WithArguments("C.item").WithLocation(3, 10) + }); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.FieldDeclaration); + { + N(SyntaxKind.VariableDeclaration); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "file"); + } + N(SyntaxKind.VariableDeclarator); + { + N(SyntaxKind.IdentifierToken, "item"); + } + } + N(SyntaxKind.SemicolonToken); + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void MemberNamedFile_07() + { + UsingNode($$""" + class C + { + file item; + } + """, + expectedParsingDiagnostics: new[] + { + // (3,14): error CS1519: Invalid token ';' in class, record, struct, or interface member declaration + // file item; + Diagnostic(ErrorCode.ERR_InvalidMemberDecl, ";").WithArguments(";").WithLocation(3, 14), + // (3,14): error CS1519: Invalid token ';' in class, record, struct, or interface member declaration + // file item; + Diagnostic(ErrorCode.ERR_InvalidMemberDecl, ";").WithArguments(";").WithLocation(3, 14) + }); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.IncompleteMember); + { + N(SyntaxKind.FileKeyword); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "item"); + } + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void MemberNamedFile_08() + { + UsingNode($$""" + record file { } + """, + expectedBindingDiagnostics: new[] + { + // (1,8): error CS9056: Types and aliases cannot be named 'file'. + // record file { } + Diagnostic(ErrorCode.ERR_FileTypeNameDisallowed, "file").WithLocation(1, 8) + }); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.RecordDeclaration); + { + N(SyntaxKind.RecordKeyword); + N(SyntaxKind.IdentifierToken, "file"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void TypeNamedFile_01() + { + UsingNode($$""" + class file { } + """, + expectedBindingDiagnostics: new[] + { + // (1,7): error CS9056: Types and aliases cannot be named 'file'. + // class file { } + Diagnostic(ErrorCode.ERR_FileTypeNameDisallowed, "file").WithLocation(1, 7) + }); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "file"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void TypeNamedFile_01_CSharp10() + { + UsingNode($$""" + class file { } + """, + options: TestOptions.Regular10, + expectedBindingDiagnostics: new[] + { + // (1,7): warning CS8981: The type name 'file' only contains lower-cased ascii characters. Such names may become reserved for the language. + // class file { } + Diagnostic(ErrorCode.WRN_LowerCaseTypeName, "file").WithArguments("file").WithLocation(1, 7) + }); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "file"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Theory] + [InlineData(LanguageVersion.CSharp10)] + [InlineData(LanguageVersion.CSharp11)] + public void TypeNamedFile_02(LanguageVersion languageVersion) + { + UsingNode($$""" + class @file { } + """, + options: TestOptions.Regular.WithLanguageVersion(languageVersion)); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "@file"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void Errors_01_CSharp10() + { + UsingNode($$""" + file + """, + options: TestOptions.Regular10, + // (1,1): error CS0116: A namespace cannot directly contain members such as fields, methods or statements + // file + Diagnostic(ErrorCode.ERR_NamespaceUnexpected, "file").WithLocation(1, 1)); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.IncompleteMember); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "file"); + } + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void Errors_01() + { + UsingNode($$""" + file + """, + // (1,1): error CS0116: A namespace cannot directly contain members such as fields, methods or statements + // file + Diagnostic(ErrorCode.ERR_NamespaceUnexpected, "file").WithLocation(1, 1)); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.IncompleteMember); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "file"); + } + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void Errors_02_CSharp10() + { + UsingNode($$""" + file; + """, + options: TestOptions.Regular10, + expectedBindingDiagnostics: new[] + { + // (1,1): error CS0103: The name 'file' does not exist in the current context + // file; + Diagnostic(ErrorCode.ERR_NameNotInContext, "file").WithArguments("file").WithLocation(1, 1), + // (1,1): error CS0201: Only assignment, call, increment, decrement, await, and new object expressions can be used as a statement + // file; + Diagnostic(ErrorCode.ERR_IllegalStatement, "file").WithLocation(1, 1) + }); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.GlobalStatement); + { + N(SyntaxKind.ExpressionStatement); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "file"); + } + N(SyntaxKind.SemicolonToken); + } + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void Errors_02() + { + UsingNode($$""" + file; + """, + expectedBindingDiagnostics: new[] + { + // (1,1): error CS0103: The name 'file' does not exist in the current context + // file; + Diagnostic(ErrorCode.ERR_NameNotInContext, "file").WithArguments("file").WithLocation(1, 1), + // (1,1): error CS0201: Only assignment, call, increment, decrement, await, and new object expressions can be used as a statement + // file; + Diagnostic(ErrorCode.ERR_IllegalStatement, "file").WithLocation(1, 1) + }); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.GlobalStatement); + { + N(SyntaxKind.ExpressionStatement); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "file"); + } + N(SyntaxKind.SemicolonToken); + } + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void Errors_03_CSharp10() + { + UsingNode($$""" + file namespace NS; + """, + options: TestOptions.Regular10, + expectedParsingDiagnostics: new[] + { + // (1,1): error CS0116: A namespace cannot directly contain members such as fields, methods or statements + // file namespace NS; + Diagnostic(ErrorCode.ERR_NamespaceUnexpected, "file").WithLocation(1, 1) + }, + expectedBindingDiagnostics: new[] + { + // (1,1): error CS0116: A namespace cannot directly contain members such as fields, methods or statements + // file namespace NS; + Diagnostic(ErrorCode.ERR_NamespaceUnexpected, "file").WithLocation(1, 1), + // (1,16): error CS8956: File-scoped namespace must precede all other members in a file. + // file namespace NS; + Diagnostic(ErrorCode.ERR_FileScopedNamespaceNotBeforeAllMembers, "NS").WithLocation(1, 16) + }); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.IncompleteMember); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "file"); + } + } + N(SyntaxKind.FileScopedNamespaceDeclaration); + { + N(SyntaxKind.NamespaceKeyword); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "NS"); + } + N(SyntaxKind.SemicolonToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void Errors_03() + { + UsingNode($$""" + file namespace NS; + """, + expectedParsingDiagnostics: new[] + { + // (1,1): error CS0116: A namespace cannot directly contain members such as fields, methods or statements + // file namespace NS; + Diagnostic(ErrorCode.ERR_NamespaceUnexpected, "file").WithLocation(1, 1) + }, + expectedBindingDiagnostics: new[] + { + // (1,1): error CS0116: A namespace cannot directly contain members such as fields, methods or statements + // file namespace NS; + Diagnostic(ErrorCode.ERR_NamespaceUnexpected, "file").WithLocation(1, 1), + // (1,16): error CS8956: File-scoped namespace must precede all other members in a file. + // file namespace NS; + Diagnostic(ErrorCode.ERR_FileScopedNamespaceNotBeforeAllMembers, "NS").WithLocation(1, 16) + }); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.IncompleteMember); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "file"); + } + } + N(SyntaxKind.FileScopedNamespaceDeclaration); + { + N(SyntaxKind.NamespaceKeyword); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "NS"); + } + N(SyntaxKind.SemicolonToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void Errors_04_CSharp10() + { + UsingNode($$""" + file namespace NS { } + """, + options: TestOptions.Regular10, + expectedParsingDiagnostics: new[] + { + // (1,1): error CS0116: A namespace cannot directly contain members such as fields, methods or statements + // file namespace NS { } + Diagnostic(ErrorCode.ERR_NamespaceUnexpected, "file").WithLocation(1, 1) + }); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.IncompleteMember); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "file"); + } + } + N(SyntaxKind.NamespaceDeclaration); + { + N(SyntaxKind.NamespaceKeyword); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "NS"); + } + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void Errors_04() + { + UsingNode($$""" + file namespace NS { } + """, + expectedParsingDiagnostics: new[] + { + // (1,1): error CS0116: A namespace cannot directly contain members such as fields, methods or statements + // file namespace NS { } + Diagnostic(ErrorCode.ERR_NamespaceUnexpected, "file").WithLocation(1, 1) + }); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.IncompleteMember); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "file"); + } + } + N(SyntaxKind.NamespaceDeclaration); + { + N(SyntaxKind.NamespaceKeyword); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "NS"); + } + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void File_Repeated() + { + const int FileModifiersCount = 100000; + var manyFileModifiers = string.Join(" ", Enumerable.Repeat("file", FileModifiersCount)); + UsingNode(manyFileModifiers, + expectedParsingDiagnostics: new[] + { + Diagnostic(ErrorCode.ERR_NamespaceUnexpected, "file").WithLocation(1, 499996) + }); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.IncompleteMember); + { + for (var i = 0; i < FileModifiersCount - 1; i++) + { + N(SyntaxKind.FileKeyword); + } + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "file"); + } + N(SyntaxKind.EndOfFileToken); + } + } + EOF(); + + UsingNode(manyFileModifiers + " class { }", + expectedParsingDiagnostics: new[] + { + Diagnostic(ErrorCode.ERR_IdentifierExpected, "{").WithLocation(1, 500007) + }, + expectedBindingDiagnostics: new[] + { + Diagnostic(ErrorCode.ERR_DuplicateModifier, "file").WithArguments("file").WithLocation(1, 6), + Diagnostic(ErrorCode.ERR_IdentifierExpected, "{").WithLocation(1, 500007) + }); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + for (int i = 0; i < FileModifiersCount; i++) + { + N(SyntaxKind.FileKeyword); + } + N(SyntaxKind.ClassKeyword); + M(SyntaxKind.IdentifierToken); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void MethodNamedRecord_01_CSharp8() + { + UsingNode(""" + class C + { + file record(); + } + """, + options: TestOptions.Regular8, + expectedBindingDiagnostics: new[] + { + // (3,5): error CS0246: The type or namespace name 'file' could not be found (are you missing a using directive or an assembly reference?) + // file record(); + Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "file").WithArguments("file").WithLocation(3, 5), + // (3,10): error CS0501: 'C.record()' must declare a body because it is not marked abstract, extern, or partial + // file record(); + Diagnostic(ErrorCode.ERR_ConcreteMissingBody, "record").WithArguments("C.record()").WithLocation(3, 10) + }); + + 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, "file"); + } + N(SyntaxKind.IdentifierToken, "record"); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.SemicolonToken); + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void MethodNamedRecord_01_CSharp11() + { + UsingNode(""" + class C + { + file record(); + } + """, + expectedBindingDiagnostics: new[] + { + // (3,10): error CS0106: The modifier 'file' is not valid for this item + // file record(); + Diagnostic(ErrorCode.ERR_BadMemberFlag, "record").WithArguments("file").WithLocation(3, 10), + // (3,10): error CS1520: Method must have a return type + // file record(); + Diagnostic(ErrorCode.ERR_MemberNeedsType, "record").WithLocation(3, 10) + }); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.ConstructorDeclaration); + { + N(SyntaxKind.FileKeyword); + N(SyntaxKind.IdentifierToken, "record"); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.SemicolonToken); + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void MethodNamedRecord_02_CSharp8() + { + UsingNode(""" + class C + { + file record() { } + } + """, + options: TestOptions.Regular8, + expectedBindingDiagnostics: new[] + { + // (3,5): error CS0246: The type or namespace name 'file' could not be found (are you missing a using directive or an assembly reference?) + // file record() { } + Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "file").WithArguments("file").WithLocation(3, 5), + // (3,10): error CS0161: 'C.record()': not all code paths return a value + // file record() { } + Diagnostic(ErrorCode.ERR_ReturnExpected, "record").WithArguments("C.record()").WithLocation(3, 10) + }); + + 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, "file"); + } + N(SyntaxKind.IdentifierToken, "record"); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.Block); + { + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void MethodNamedRecord_02_CSharp11() + { + UsingNode(""" + class C + { + file record() { } + } + """, expectedBindingDiagnostics: new[] + { + // (3,10): error CS0106: The modifier 'file' is not valid for this item + // file record() { } + Diagnostic(ErrorCode.ERR_BadMemberFlag, "record").WithArguments("file").WithLocation(3, 10), + // (3,10): error CS1520: Method must have a return type + // file record() { } + Diagnostic(ErrorCode.ERR_MemberNeedsType, "record").WithLocation(3, 10) + }); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.ConstructorDeclaration); + { + N(SyntaxKind.FileKeyword); + N(SyntaxKind.IdentifierToken, "record"); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.Block); + { + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void FileRecord_01_CSharp8() + { + UsingNode(""" + class C + { + file record X(); + } + """, + options: TestOptions.Regular8, + expectedBindingDiagnostics: new[] + { + // (3,10): error CS0246: The type or namespace name 'record' could not be found (are you missing a using directive or an assembly reference?) + // file record X(); + Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "record").WithArguments("record").WithLocation(3, 10), + // (3,17): error CS0106: The modifier 'file' is not valid for this item + // file record X(); + Diagnostic(ErrorCode.ERR_BadMemberFlag, "X").WithArguments("file").WithLocation(3, 17), + // (3,17): error CS0501: 'C.X()' must declare a body because it is not marked abstract, extern, or partial + // file record X(); + Diagnostic(ErrorCode.ERR_ConcreteMissingBody, "X").WithArguments("C.X()").WithLocation(3, 17) + }); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.MethodDeclaration); + { + N(SyntaxKind.FileKeyword); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "record"); + } + N(SyntaxKind.IdentifierToken, "X"); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.SemicolonToken); + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void FileRecord_01_CSharp11() + { + UsingNode(""" + class C + { + file record X(); + } + """, + expectedBindingDiagnostics: new[] + { + // (3,17): error CS9054: File-local type 'C.X' must be defined in a top level type; 'C.X' is a nested type. + // file record X(); + Diagnostic(ErrorCode.ERR_FileTypeNested, "X").WithArguments("C.X").WithLocation(3, 17) + }); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.RecordDeclaration); + { + N(SyntaxKind.FileKeyword); + N(SyntaxKind.RecordKeyword); + N(SyntaxKind.IdentifierToken, "X"); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.SemicolonToken); + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void FileRecord_02_CSharp8() + { + UsingNode(""" + class C + { + file record X() { } + } + """, + options: TestOptions.Regular8, + expectedBindingDiagnostics: new[] + { + // (3,10): error CS0246: The type or namespace name 'record' could not be found (are you missing a using directive or an assembly reference?) + // file record X() { } + Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "record").WithArguments("record").WithLocation(3, 10), + // (3,17): error CS0106: The modifier 'file' is not valid for this item + // file record X() { } + Diagnostic(ErrorCode.ERR_BadMemberFlag, "X").WithArguments("file").WithLocation(3, 17), + // (3,17): error CS0161: 'C.X()': not all code paths return a value + // file record X() { } + Diagnostic(ErrorCode.ERR_ReturnExpected, "X").WithArguments("C.X()").WithLocation(3, 17) + }); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.MethodDeclaration); + { + N(SyntaxKind.FileKeyword); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "record"); + } + N(SyntaxKind.IdentifierToken, "X"); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.Block); + { + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void FileRecord_02_CSharp11() + { + UsingNode(""" + class C + { + file record X() { } + } + """, + expectedBindingDiagnostics: new[] + { + // (3,17): error CS9054: File-local type 'C.X' must be defined in a top level type; 'C.X' is a nested type. + // file record X() { } + Diagnostic(ErrorCode.ERR_FileTypeNested, "X").WithArguments("C.X").WithLocation(3, 17) + }); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.RecordDeclaration); + { + N(SyntaxKind.FileKeyword); + N(SyntaxKind.RecordKeyword); + N(SyntaxKind.IdentifierToken, "X"); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void FileRecord_03_CSharp8() + { + UsingNode(""" + class C + { + file record X; + } + """, + options: TestOptions.Regular8, expectedBindingDiagnostics: new[] + { + // (3,10): error CS0246: The type or namespace name 'record' could not be found (are you missing a using directive or an assembly reference?) + // file record X; + Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "record").WithArguments("record").WithLocation(3, 10), + // (3,17): error CS0106: The modifier 'file' is not valid for this item + // file record X; + Diagnostic(ErrorCode.ERR_BadMemberFlag, "X").WithArguments("file").WithLocation(3, 17), + // (3,17): warning CS0169: The field 'C.X' is never used + // file record X; + Diagnostic(ErrorCode.WRN_UnreferencedField, "X").WithArguments("C.X").WithLocation(3, 17) + }); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.FieldDeclaration); + { + N(SyntaxKind.FileKeyword); + N(SyntaxKind.VariableDeclaration); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "record"); + } + N(SyntaxKind.VariableDeclarator); + { + N(SyntaxKind.IdentifierToken, "X"); + } + } + N(SyntaxKind.SemicolonToken); + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void FileRecord_03_CSharp11() + { + UsingNode(""" + class C + { + file record X; + } + """, + expectedBindingDiagnostics: new[] + { + // (3,17): error CS9054: File-local type 'C.X' must be defined in a top level type; 'C.X' is a nested type. + // file record X; + Diagnostic(ErrorCode.ERR_FileTypeNested, "X").WithArguments("C.X").WithLocation(3, 17) + }); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.RecordDeclaration); + { + N(SyntaxKind.FileKeyword); + N(SyntaxKind.RecordKeyword); + N(SyntaxKind.IdentifierToken, "X"); + N(SyntaxKind.SemicolonToken); + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void FileRecord_04_CSharp11() + { + UsingNode(""" + file record X(); + """); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.RecordDeclaration); + { + N(SyntaxKind.FileKeyword); + N(SyntaxKind.RecordKeyword); + N(SyntaxKind.IdentifierToken, "X"); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.SemicolonToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void LocalVariable_01() + { + UsingNode(""" + void M() + { + file file; + } + """, + expectedBindingDiagnostics: new[] + { + // (1,6): warning CS8321: The local function 'M' is declared but never used + // void M() + Diagnostic(ErrorCode.WRN_UnreferencedLocalFunction, "M").WithArguments("M").WithLocation(1, 6), + // (3,5): error CS0118: 'file' is a variable but is used like a type + // file file; + Diagnostic(ErrorCode.ERR_BadSKknown, "file").WithArguments("file", "variable", "type").WithLocation(3, 5), + // (3,10): warning CS0168: The variable 'file' is declared but never used + // file file; + Diagnostic(ErrorCode.WRN_UnreferencedVar, "file").WithArguments("file").WithLocation(3, 10) + }); + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.GlobalStatement); + { + N(SyntaxKind.LocalFunctionStatement); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.VoidKeyword); + } + N(SyntaxKind.IdentifierToken, "M"); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.Block); + { + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.LocalDeclarationStatement); + { + N(SyntaxKind.VariableDeclaration); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "file"); + } + N(SyntaxKind.VariableDeclarator); + { + N(SyntaxKind.IdentifierToken, "file"); + } + } + N(SyntaxKind.SemicolonToken); + } + N(SyntaxKind.CloseBraceToken); + } + } + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void LocalVariable_02() + { + UsingNode(""" + void M() + { + int file; + } + """, + expectedBindingDiagnostics: new[] + { + // (1,6): warning CS8321: The local function 'M' is declared but never used + // void M() + Diagnostic(ErrorCode.WRN_UnreferencedLocalFunction, "M").WithArguments("M").WithLocation(1, 6), + // (3,9): warning CS0168: The variable 'file' is declared but never used + // int file; + Diagnostic(ErrorCode.WRN_UnreferencedVar, "file").WithArguments("file").WithLocation(3, 9) + }); + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.GlobalStatement); + { + N(SyntaxKind.LocalFunctionStatement); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.VoidKeyword); + } + N(SyntaxKind.IdentifierToken, "M"); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.Block); + { + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.LocalDeclarationStatement); + { + N(SyntaxKind.VariableDeclaration); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.IntKeyword); + } + N(SyntaxKind.VariableDeclarator); + { + N(SyntaxKind.IdentifierToken, "file"); + } + } + N(SyntaxKind.SemicolonToken); + } + N(SyntaxKind.CloseBraceToken); + } + } + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Theory] + [InlineData(LanguageVersion.CSharp10)] + [InlineData(LanguageVersion.CSharp11)] + public void TopLevelVariable_01(LanguageVersion languageVersion) + { + UsingNode(""" + file file; + """, + options: TestOptions.Regular.WithLanguageVersion(languageVersion), + expectedBindingDiagnostics: new[] + { + // (1,1): error CS0118: 'file' is a variable but is used like a type + // file file; + Diagnostic(ErrorCode.ERR_BadSKknown, "file").WithArguments("file", "variable", "type").WithLocation(1, 1), + // (1,6): warning CS0168: The variable 'file' is declared but never used + // file file; + Diagnostic(ErrorCode.WRN_UnreferencedVar, "file").WithArguments("file").WithLocation(1, 6) + }); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.GlobalStatement); + { + N(SyntaxKind.LocalDeclarationStatement); + { + N(SyntaxKind.VariableDeclaration); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "file"); + } + N(SyntaxKind.VariableDeclarator); + { + N(SyntaxKind.IdentifierToken, "file"); + } + } + N(SyntaxKind.SemicolonToken); + } + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Theory] + [InlineData(LanguageVersion.CSharp10)] + [InlineData(LanguageVersion.CSharp11)] + public void TopLevelVariable_02(LanguageVersion languageVersion) + { + UsingNode(""" + int file; + """, + options: TestOptions.Regular.WithLanguageVersion(languageVersion), + expectedBindingDiagnostics: new[] + { + // (1,5): warning CS0168: The variable 'file' is declared but never used + // int file; + Diagnostic(ErrorCode.WRN_UnreferencedVar, "file").WithArguments("file").WithLocation(1, 5) + }); + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.GlobalStatement); + { + N(SyntaxKind.LocalDeclarationStatement); + { + N(SyntaxKind.VariableDeclaration); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.IntKeyword); + } + N(SyntaxKind.VariableDeclarator); + { + N(SyntaxKind.IdentifierToken, "file"); + } + } + N(SyntaxKind.SemicolonToken); + } + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Theory] + [InlineData(LanguageVersion.CSharp10)] + [InlineData(LanguageVersion.CSharp11)] + public void TopLevelVariable_03(LanguageVersion languageVersion) + { + UsingNode(""" + bool file; + file = true; + """, + options: TestOptions.Regular.WithLanguageVersion(languageVersion), + expectedBindingDiagnostics: new[] + { + // (1,6): warning CS0219: The variable 'file' is assigned but its value is never used + // bool file; + Diagnostic(ErrorCode.WRN_UnreferencedVarAssg, "file").WithArguments("file").WithLocation(1, 6) + }); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.GlobalStatement); + { + N(SyntaxKind.LocalDeclarationStatement); + { + N(SyntaxKind.VariableDeclaration); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.BoolKeyword); + } + N(SyntaxKind.VariableDeclarator); + { + N(SyntaxKind.IdentifierToken, "file"); + } + } + N(SyntaxKind.SemicolonToken); + } + } + N(SyntaxKind.GlobalStatement); + { + N(SyntaxKind.ExpressionStatement); + { + N(SyntaxKind.SimpleAssignmentExpression); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "file"); + } + N(SyntaxKind.EqualsToken); + N(SyntaxKind.TrueLiteralExpression); + { + N(SyntaxKind.TrueKeyword); + } + } + N(SyntaxKind.SemicolonToken); + } + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void Variable_01() + { + UsingNode(""" + void M() + { + bool file; + file = true; + } + """, + expectedBindingDiagnostics: new[] + { + // (1,6): warning CS8321: The local function 'M' is declared but never used + // void M() + Diagnostic(ErrorCode.WRN_UnreferencedLocalFunction, "M").WithArguments("M").WithLocation(1, 6), + // (3,10): warning CS0219: The variable 'file' is assigned but its value is never used + // bool file; + Diagnostic(ErrorCode.WRN_UnreferencedVarAssg, "file").WithArguments("file").WithLocation(3, 10) + }); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.GlobalStatement); + { + N(SyntaxKind.LocalFunctionStatement); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.VoidKeyword); + } + N(SyntaxKind.IdentifierToken, "M"); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.Block); + { + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.LocalDeclarationStatement); + { + N(SyntaxKind.VariableDeclaration); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.BoolKeyword); + } + N(SyntaxKind.VariableDeclarator); + { + N(SyntaxKind.IdentifierToken, "file"); + } + } + N(SyntaxKind.SemicolonToken); + } + N(SyntaxKind.ExpressionStatement); + { + N(SyntaxKind.SimpleAssignmentExpression); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "file"); + } + N(SyntaxKind.EqualsToken); + N(SyntaxKind.TrueLiteralExpression); + { + N(SyntaxKind.TrueKeyword); + } + } + N(SyntaxKind.SemicolonToken); + } + N(SyntaxKind.CloseBraceToken); + } + } + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void LambdaReturn() + { + UsingNode(""" + _ = file () => { }; + """, + expectedBindingDiagnostics: new[] + { + // (1,1): error CS8183: Cannot infer the type of implicitly-typed discard. + // _ = file () => { }; + Diagnostic(ErrorCode.ERR_DiscardTypeInferenceFailed, "_").WithLocation(1, 1), + // (1,5): error CS0246: The type or namespace name 'file' could not be found (are you missing a using directive or an assembly reference?) + // _ = file () => { }; + Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "file").WithArguments("file").WithLocation(1, 5) + }); + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.GlobalStatement); + { + N(SyntaxKind.ExpressionStatement); + { + N(SyntaxKind.SimpleAssignmentExpression); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "_"); + } + N(SyntaxKind.EqualsToken); + N(SyntaxKind.ParenthesizedLambdaExpression); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "file"); + } + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.EqualsGreaterThanToken); + N(SyntaxKind.Block); + { + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + } + } + N(SyntaxKind.SemicolonToken); + } + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void LocalFunctionReturn() + { + UsingNode(""" + file local() { }; + """, + expectedBindingDiagnostics: new[] + { + // (1,1): error CS0246: The type or namespace name 'file' could not be found (are you missing a using directive or an assembly reference?) + // file local() { }; + Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "file").WithArguments("file").WithLocation(1, 1), + // (1,6): error CS0161: 'local()': not all code paths return a value + // file local() { }; + Diagnostic(ErrorCode.ERR_ReturnExpected, "local").WithArguments("local()").WithLocation(1, 6), + // (1,6): warning CS8321: The local function 'local' is declared but never used + // file local() { }; + Diagnostic(ErrorCode.WRN_UnreferencedLocalFunction, "local").WithArguments("local").WithLocation(1, 6) + }); + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.GlobalStatement); + { + N(SyntaxKind.LocalFunctionStatement); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "file"); + } + N(SyntaxKind.IdentifierToken, "local"); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.Block); + { + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + } + } + N(SyntaxKind.GlobalStatement); + { + N(SyntaxKind.EmptyStatement); + { + N(SyntaxKind.SemicolonToken); + } + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void ParameterModifier() + { + UsingNode(""" + class C + { + void M(file int x) { } + } + """, + expectedParsingDiagnostics: new[] + { + // (3,17): error CS1001: Identifier expected + // void M(file int x) { } + Diagnostic(ErrorCode.ERR_IdentifierExpected, "int").WithLocation(3, 17), + // (3,17): error CS1003: Syntax error, ',' expected + // void M(file int x) { } + Diagnostic(ErrorCode.ERR_SyntaxError, "int").WithArguments(",").WithLocation(3, 17) + }, + expectedBindingDiagnostics: new[] + { + // (3,12): error CS0246: The type or namespace name 'file' could not be found (are you missing a using directive or an assembly reference?) + // void M(file int x) { } + Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "file").WithArguments("file").WithLocation(3, 12), + // (3,17): error CS1001: Identifier expected + // void M(file int x) { } + Diagnostic(ErrorCode.ERR_IdentifierExpected, "int").WithLocation(3, 17), + // (3,17): error CS1003: Syntax error, ',' expected + // void M(file int x) { } + Diagnostic(ErrorCode.ERR_SyntaxError, "int").WithArguments(",").WithLocation(3, 17) + }); + 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.Parameter); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "file"); + } + M(SyntaxKind.IdentifierToken); + } + M(SyntaxKind.CommaToken); + N(SyntaxKind.Parameter); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.IntKeyword); + } + N(SyntaxKind.IdentifierToken, "x"); + } + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.Block); + { + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void ParameterType() + { + UsingNode(""" + class C + { + void M(file x) { } + } + """, + expectedBindingDiagnostics: new[] + { + // (3,12): error CS0246: The type or namespace name 'file' could not be found (are you missing a using directive or an assembly reference?) + // void M(file x) { } + Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "file").WithArguments("file").WithLocation(3, 12) + }); + 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.Parameter); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "file"); + } + N(SyntaxKind.IdentifierToken, "x"); + } + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.Block); + { + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } +} diff --git a/src/Compilers/CSharp/Test/Syntax/Parsing/LambdaParameterParsingTests.cs b/src/Compilers/CSharp/Test/Syntax/Parsing/LambdaParameterParsingTests.cs index 73d389581ae72..4875f16038259 100644 --- a/src/Compilers/CSharp/Test/Syntax/Parsing/LambdaParameterParsingTests.cs +++ b/src/Compilers/CSharp/Test/Syntax/Parsing/LambdaParameterParsingTests.cs @@ -34,7 +34,25 @@ public void EndOfFileAfterOut() class C { void Goo() { System.Func f = (out -"); +", + // (4,38): error CS1525: Invalid expression term 'out' + // System.Func f = (out + Diagnostic(ErrorCode.ERR_InvalidExprTerm, "out").WithArguments("out").WithLocation(4, 38), + // (4,38): error CS1026: ) expected + // System.Func f = (out + Diagnostic(ErrorCode.ERR_CloseParenExpected, "out").WithLocation(4, 38), + // (4,38): error CS1003: Syntax error, ',' expected + // System.Func f = (out + Diagnostic(ErrorCode.ERR_SyntaxError, "out").WithArguments(",").WithLocation(4, 38), + // (4,41): error CS1002: ; expected + // System.Func f = (out + Diagnostic(ErrorCode.ERR_SemicolonExpected, "").WithLocation(4, 41), + // (4,41): error CS1513: } expected + // System.Func f = (out + Diagnostic(ErrorCode.ERR_RbraceExpected, "").WithLocation(4, 41), + // (4,41): error CS1513: } expected + // System.Func f = (out + Diagnostic(ErrorCode.ERR_RbraceExpected, "").WithLocation(4, 41)); N(SyntaxKind.CompilationUnit); { N(SyntaxKind.ClassDeclaration); @@ -124,7 +142,28 @@ public void EndOfFileAfterOutType() class C { void Goo() { System.Func f = (out C -"); +", + // (4,38): error CS1525: Invalid expression term 'out' + // System.Func f = (out C + Diagnostic(ErrorCode.ERR_InvalidExprTerm, "out").WithArguments("out").WithLocation(4, 38), + // (4,38): error CS1026: ) expected + // System.Func f = (out C + Diagnostic(ErrorCode.ERR_CloseParenExpected, "out").WithLocation(4, 38), + // (4,38): error CS1003: Syntax error, ',' expected + // System.Func f = (out C + Diagnostic(ErrorCode.ERR_SyntaxError, "out").WithArguments(",").WithLocation(4, 38), + // (4,42): error CS1002: ; expected + // System.Func f = (out C + Diagnostic(ErrorCode.ERR_SemicolonExpected, "C").WithLocation(4, 42), + // (4,43): error CS1002: ; expected + // System.Func f = (out C + Diagnostic(ErrorCode.ERR_SemicolonExpected, "").WithLocation(4, 43), + // (4,43): error CS1513: } expected + // System.Func f = (out C + Diagnostic(ErrorCode.ERR_RbraceExpected, "").WithLocation(4, 43), + // (4,43): error CS1513: } expected + // System.Func f = (out C + Diagnostic(ErrorCode.ERR_RbraceExpected, "").WithLocation(4, 43)); N(SyntaxKind.CompilationUnit); { N(SyntaxKind.ClassDeclaration); @@ -222,7 +261,28 @@ public void EndOfFileAfterOutTypeIdentifier() class C { void Goo() { System.Func f = (out C c -"); +", + // (4,38): error CS1525: Invalid expression term 'out' + // System.Func f = (out C c + Diagnostic(ErrorCode.ERR_InvalidExprTerm, "out").WithArguments("out").WithLocation(4, 38), + // (4,38): error CS1026: ) expected + // System.Func f = (out C c + Diagnostic(ErrorCode.ERR_CloseParenExpected, "out").WithLocation(4, 38), + // (4,38): error CS1003: Syntax error, ',' expected + // System.Func f = (out C c + Diagnostic(ErrorCode.ERR_SyntaxError, "out").WithArguments(",").WithLocation(4, 38), + // (4,42): error CS1002: ; expected + // System.Func f = (out C c + Diagnostic(ErrorCode.ERR_SemicolonExpected, "C").WithLocation(4, 42), + // (4,45): error CS1002: ; expected + // System.Func f = (out C c + Diagnostic(ErrorCode.ERR_SemicolonExpected, "").WithLocation(4, 45), + // (4,45): error CS1513: } expected + // System.Func f = (out C c + Diagnostic(ErrorCode.ERR_RbraceExpected, "").WithLocation(4, 45), + // (4,45): error CS1513: } expected + // System.Func f = (out C c + Diagnostic(ErrorCode.ERR_RbraceExpected, "").WithLocation(4, 45)); N(SyntaxKind.CompilationUnit); { N(SyntaxKind.ClassDeclaration); @@ -327,7 +387,28 @@ public void EndOfFileAfterOutTypeIdentifierParen() class C { void Goo() { System.Func f = (out C c -"); +", + // (4,38): error CS1525: Invalid expression term 'out' + // System.Func f = (out C c + Diagnostic(ErrorCode.ERR_InvalidExprTerm, "out").WithArguments("out").WithLocation(4, 38), + // (4,38): error CS1026: ) expected + // System.Func f = (out C c + Diagnostic(ErrorCode.ERR_CloseParenExpected, "out").WithLocation(4, 38), + // (4,38): error CS1003: Syntax error, ',' expected + // System.Func f = (out C c + Diagnostic(ErrorCode.ERR_SyntaxError, "out").WithArguments(",").WithLocation(4, 38), + // (4,42): error CS1002: ; expected + // System.Func f = (out C c + Diagnostic(ErrorCode.ERR_SemicolonExpected, "C").WithLocation(4, 42), + // (4,45): error CS1002: ; expected + // System.Func f = (out C c + Diagnostic(ErrorCode.ERR_SemicolonExpected, "").WithLocation(4, 45), + // (4,45): error CS1513: } expected + // System.Func f = (out C c + Diagnostic(ErrorCode.ERR_RbraceExpected, "").WithLocation(4, 45), + // (4,45): error CS1513: } expected + // System.Func f = (out C c + Diagnostic(ErrorCode.ERR_RbraceExpected, "").WithLocation(4, 45)); N(SyntaxKind.CompilationUnit); { N(SyntaxKind.ClassDeclaration); @@ -432,7 +513,31 @@ public void EndOfFileAfterOutTypeIdentifierComma() class C { void Goo() { System.Func f = (out C c, -"); +", + // (4,38): error CS1525: Invalid expression term 'out' + // System.Func f = (out C c, + Diagnostic(ErrorCode.ERR_InvalidExprTerm, "out").WithArguments("out").WithLocation(4, 38), + // (4,38): error CS1026: ) expected + // System.Func f = (out C c, + Diagnostic(ErrorCode.ERR_CloseParenExpected, "out").WithLocation(4, 38), + // (4,38): error CS1003: Syntax error, ',' expected + // System.Func f = (out C c, + Diagnostic(ErrorCode.ERR_SyntaxError, "out").WithArguments(",").WithLocation(4, 38), + // (4,42): error CS1002: ; expected + // System.Func f = (out C c, + Diagnostic(ErrorCode.ERR_SemicolonExpected, "C").WithLocation(4, 42), + // (4,46): error CS1001: Identifier expected + // System.Func f = (out C c, + Diagnostic(ErrorCode.ERR_IdentifierExpected, "").WithLocation(4, 46), + // (4,46): error CS1002: ; expected + // System.Func f = (out C c, + Diagnostic(ErrorCode.ERR_SemicolonExpected, "").WithLocation(4, 46), + // (4,46): error CS1513: } expected + // System.Func f = (out C c, + Diagnostic(ErrorCode.ERR_RbraceExpected, "").WithLocation(4, 46), + // (4,46): error CS1513: } expected + // System.Func f = (out C c, + Diagnostic(ErrorCode.ERR_RbraceExpected, "").WithLocation(4, 46)); N(SyntaxKind.CompilationUnit); { N(SyntaxKind.ClassDeclaration); @@ -3053,7 +3158,7 @@ public void AsyncAwaitInLambda() [WorkItem(60661, "https://github.com/dotnet/roslyn/issues/60661")] [InlineData(LanguageVersion.CSharp9)] - [InlineData(LanguageVersionFacts.CSharpNext)] + [InlineData(LanguageVersion.CSharp11)] [Theory] public void KeywordParameterName_01(LanguageVersion languageVersion) { @@ -3083,7 +3188,7 @@ public void KeywordParameterName_01(LanguageVersion languageVersion) [WorkItem(60661, "https://github.com/dotnet/roslyn/issues/60661")] [InlineData(LanguageVersion.CSharp9)] - [InlineData(LanguageVersionFacts.CSharpNext)] + [InlineData(LanguageVersion.CSharp11)] [Theory] public void KeywordParameterName_02(LanguageVersion languageVersion) { @@ -3111,7 +3216,7 @@ public void KeywordParameterName_02(LanguageVersion languageVersion) [WorkItem(60661, "https://github.com/dotnet/roslyn/issues/60661")] [InlineData(LanguageVersion.CSharp9)] - [InlineData(LanguageVersionFacts.CSharpNext)] + [InlineData(LanguageVersion.CSharp11)] [Theory] public void KeywordParameterName_03(LanguageVersion languageVersion) { @@ -3385,8 +3490,7 @@ public void KeywordParameterName_11() public void KeywordParameterName_12() { string source = "Action a = public => { };"; - var tree = UsingTree(source); - tree.GetDiagnostics().Verify( + var tree = UsingTree(source, // (1,20): error CS1525: Invalid expression term 'public' // Action a = public => { }; Diagnostic(ErrorCode.ERR_InvalidExprTerm, "public").WithArguments("public").WithLocation(1, 20), diff --git a/src/Compilers/CSharp/Test/Syntax/Parsing/LocalFunctionParsingTests.cs b/src/Compilers/CSharp/Test/Syntax/Parsing/LocalFunctionParsingTests.cs index 7931cc1c4080d..ec62ad86029b4 100644 --- a/src/Compilers/CSharp/Test/Syntax/Parsing/LocalFunctionParsingTests.cs +++ b/src/Compilers/CSharp/Test/Syntax/Parsing/LocalFunctionParsingTests.cs @@ -50,7 +50,61 @@ void M6() { int? L( } -}"); +}", + // (6,17): error CS1525: Invalid expression term '}' + // await L< + Diagnostic(ErrorCode.ERR_InvalidExprTerm, "").WithArguments("}").WithLocation(6, 17), + // (6,17): error CS1002: ; expected + // await L< + Diagnostic(ErrorCode.ERR_SemicolonExpected, "").WithLocation(6, 17), + // (10,15): error CS1001: Identifier expected + // int L< + Diagnostic(ErrorCode.ERR_IdentifierExpected, "").WithLocation(10, 15), + // (10,15): error CS1003: Syntax error, '>' expected + // int L< + Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments(">").WithLocation(10, 15), + // (10,15): error CS1003: Syntax error, '(' expected + // int L< + Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments("(").WithLocation(10, 15), + // (10,15): error CS1026: ) expected + // int L< + Diagnostic(ErrorCode.ERR_CloseParenExpected, "").WithLocation(10, 15), + // (10,15): error CS1002: ; expected + // int L< + Diagnostic(ErrorCode.ERR_SemicolonExpected, "").WithLocation(10, 15), + // (14,16): error CS1001: Identifier expected + // int? L< + Diagnostic(ErrorCode.ERR_IdentifierExpected, "").WithLocation(14, 16), + // (14,16): error CS1003: Syntax error, '>' expected + // int? L< + Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments(">").WithLocation(14, 16), + // (14,16): error CS1003: Syntax error, '(' expected + // int? L< + Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments("(").WithLocation(14, 16), + // (14,16): error CS1026: ) expected + // int? L< + Diagnostic(ErrorCode.ERR_CloseParenExpected, "").WithLocation(14, 16), + // (14,16): error CS1002: ; expected + // int? L< + Diagnostic(ErrorCode.ERR_SemicolonExpected, "").WithLocation(14, 16), + // (18,17): error CS1026: ) expected + // await L( + Diagnostic(ErrorCode.ERR_CloseParenExpected, "").WithLocation(18, 17), + // (18,17): error CS1002: ; expected + // await L( + Diagnostic(ErrorCode.ERR_SemicolonExpected, "").WithLocation(18, 17), + // (22,15): error CS1026: ) expected + // int L( + Diagnostic(ErrorCode.ERR_CloseParenExpected, "").WithLocation(22, 15), + // (22,15): error CS1002: ; expected + // int L( + Diagnostic(ErrorCode.ERR_SemicolonExpected, "").WithLocation(22, 15), + // (26,16): error CS1026: ) expected + // int? L( + Diagnostic(ErrorCode.ERR_CloseParenExpected, "").WithLocation(26, 16), + // (26,16): error CS1002: ; expected + // int? L( + Diagnostic(ErrorCode.ERR_SemicolonExpected, "").WithLocation(26, 16)); N(SyntaxKind.CompilationUnit); { N(SyntaxKind.ClassDeclaration); @@ -503,7 +557,13 @@ void M() { public object local; } -}", TestOptions.Regular9); +}", TestOptions.Regular9, + // (5,6): error CS1513: } expected + // { + Diagnostic(ErrorCode.ERR_RbraceExpected, "").WithLocation(5, 6), + // (8,1): error CS1022: Type or namespace definition, or end-of-file expected + // } + Diagnostic(ErrorCode.ERR_EOFExpected, "}").WithLocation(8, 1)); N(SyntaxKind.CompilationUnit); { @@ -636,7 +696,7 @@ void M() UsingTree(code, TestOptions.Regular9).GetDiagnostics().Verify(); verifyTree(); - UsingTree(code, TestOptions.Regular8).GetDiagnostics().Verify( + UsingTree(code, TestOptions.Regular8, // (6,9): error CS8400: Feature 'extern local functions' is not available in C# 8.0. Please use language version 9.0 or greater. // extern void local(); Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion8, "extern").WithArguments("extern local functions", "9.0").WithLocation(6, 9)); @@ -708,7 +768,7 @@ extern void local() { } UsingTree(code, TestOptions.Regular9).GetDiagnostics().Verify(); verifyTree(); - UsingTree(code, TestOptions.Regular8).GetDiagnostics().Verify( + UsingTree(code, TestOptions.Regular8, // (6,9): error CS8400: Feature 'extern local functions' is not available in C# 8.0. Please use language version 9.0 or greater. // extern void local() { } Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion8, "extern").WithArguments("extern local functions", "9.0").WithLocation(6, 9)); @@ -986,7 +1046,13 @@ void M() { [A] } -}"); +}", + // (6,12): error CS1525: Invalid expression term '}' + // [A] + Diagnostic(ErrorCode.ERR_InvalidExprTerm, "").WithArguments("}").WithLocation(6, 12), + // (6,12): error CS1002: ; expected + // [A] + Diagnostic(ErrorCode.ERR_SemicolonExpected, "").WithLocation(6, 12)); N(SyntaxKind.CompilationUnit); { @@ -1268,7 +1334,28 @@ class c async void m3() { await () => new await(); } void m4() { async await() => new await(); } async void m5() { await async () => new await(); } -}"); +}", + // (6,30): error CS1525: Invalid expression term ')' + // async void m3() { await () => new await(); } + Diagnostic(ErrorCode.ERR_InvalidExprTerm, ")").WithArguments(")").WithLocation(6, 30), + // (6,32): error CS1002: ; expected + // async void m3() { await () => new await(); } + Diagnostic(ErrorCode.ERR_SemicolonExpected, "=>").WithLocation(6, 32), + // (6,32): error CS1513: } expected + // async void m3() { await () => new await(); } + Diagnostic(ErrorCode.ERR_RbraceExpected, "=>").WithLocation(6, 32), + // (6,39): error CS4003: 'await' cannot be used as an identifier within an async method or lambda expression + // async void m3() { await () => new await(); } + Diagnostic(ErrorCode.ERR_BadAwaitAsIdentifier, "await").WithLocation(6, 39), + // (8,38): error CS1002: ; expected + // async void m5() { await async () => new await(); } + Diagnostic(ErrorCode.ERR_SemicolonExpected, "=>").WithLocation(8, 38), + // (8,38): error CS1513: } expected + // async void m5() { await async () => new await(); } + Diagnostic(ErrorCode.ERR_RbraceExpected, "=>").WithLocation(8, 38), + // (8,45): error CS4003: 'await' cannot be used as an identifier within an async method or lambda expression + // async void m5() { await async () => new await(); } + Diagnostic(ErrorCode.ERR_BadAwaitAsIdentifier, "await").WithLocation(8, 45)); N(SyntaxKind.CompilationUnit); { diff --git a/src/Compilers/CSharp/Test/Syntax/Parsing/MemberDeclarationParsingTests.cs b/src/Compilers/CSharp/Test/Syntax/Parsing/MemberDeclarationParsingTests.cs index 91c17017ab136..76dbf0214a9b0 100644 --- a/src/Compilers/CSharp/Test/Syntax/Parsing/MemberDeclarationParsingTests.cs +++ b/src/Compilers/CSharp/Test/Syntax/Parsing/MemberDeclarationParsingTests.cs @@ -25,17 +25,7 @@ private MemberDeclarationSyntax ParseDeclaration(string text, int offset = 0, Pa return SyntaxFactory.ParseMemberDeclaration(text, offset, options); } - private SyntaxTree UsingTree(string text, CSharpParseOptions options, params DiagnosticDescription[] expectedErrors) - { - var tree = base.UsingTree(text, options); - - var actualErrors = tree.GetDiagnostics(); - actualErrors.Verify(expectedErrors); - - return tree; - } - - private static readonly CSharpParseOptions RequiredMembersOptions = TestOptions.RegularNext; + private static readonly CSharpParseOptions RequiredMembersOptions = TestOptions.Regular11; public static readonly IEnumerable Regular10AndScriptAndRequiredMembersMinimum = new[] { new[] { TestOptions.Regular10 }, new[] { RequiredMembersOptions }, new[] { TestOptions.Script.WithLanguageVersion(LanguageVersion.CSharp10) } }; public static readonly IEnumerable Regular10AndScript = new[] { new[] { TestOptions.Regular10 }, new[] { TestOptions.Script.WithLanguageVersion(LanguageVersion.CSharp10) } }; @@ -435,7 +425,7 @@ public void OperatorDeclaration() [Fact] public void UnsignedRightShiftOperator_01() { - foreach (var options in new[] { TestOptions.RegularPreview, TestOptions.Regular10, TestOptions.RegularNext }) + foreach (var options in new[] { TestOptions.RegularPreview, TestOptions.Regular10, TestOptions.Regular11 }) { UsingDeclaration("C operator >>>(C x, C y) => x;", options: options); @@ -486,7 +476,7 @@ public void UnsignedRightShiftOperator_01() [Fact] public void UnsignedRightShiftOperator_02() { - foreach (var options in new[] { TestOptions.RegularPreview, TestOptions.Regular10, TestOptions.RegularNext }) + foreach (var options in new[] { TestOptions.RegularPreview, TestOptions.Regular10, TestOptions.Regular11 }) { UsingDeclaration("C operator > >>(C x, C y) => x;", options: options, // (1,14): error CS1003: Syntax error, '(' expected @@ -569,7 +559,7 @@ public void UnsignedRightShiftOperator_02() [Fact] public void UnsignedRightShiftOperator_03() { - foreach (var options in new[] { TestOptions.RegularPreview, TestOptions.Regular10, TestOptions.RegularNext }) + foreach (var options in new[] { TestOptions.RegularPreview, TestOptions.Regular10, TestOptions.Regular11 }) { UsingDeclaration("C operator >> >(C x, C y) => x;", options: options, // (1,15): error CS1003: Syntax error, '(' expected @@ -652,7 +642,7 @@ public void UnsignedRightShiftOperator_03() [Fact] public void UnsignedRightShiftOperator_04() { - foreach (var options in new[] { TestOptions.RegularPreview, TestOptions.Regular10, TestOptions.RegularNext }) + foreach (var options in new[] { TestOptions.RegularPreview, TestOptions.Regular10, TestOptions.Regular11 }) { UsingDeclaration("C operator >>>=(C x, C y) => x;", options: options, // (1,14): error CS1003: Syntax error, '(' expected @@ -1657,9 +1647,9 @@ public void RequiredModifierConversion_01(CSharpParseOptions parseOptions) public void RequiredModifierConversion_02(CSharpParseOptions parseOptions) { UsingDeclaration("static implicit required operator C(S s) {}", options: parseOptions, - // (1,17): error CS8652: The feature 'static abstract members in interfaces' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // (1,17): error CS8936: Feature 'static abstract members in interfaces' is not available in C# 10.0. Please use language version 11.0 or greater. // static implicit required operator C(S s) {} - Diagnostic(ErrorCode.ERR_FeatureInPreview, "required ").WithArguments("static abstract members in interfaces").WithLocation(1, 17), + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "required ").WithArguments("static abstract members in interfaces", "11.0").WithLocation(1, 17), // (1,26): error CS1003: Syntax error, '.' expected // static implicit required operator C(S s) {} Diagnostic(ErrorCode.ERR_SyntaxError, "operator").WithArguments(".").WithLocation(1, 26) @@ -1926,9 +1916,9 @@ public void RequiredModifier_LocalNamedRequired_TopLevelStatements(CSharpParseOp public void OperatorDeclaration_ExplicitImplementation_01() { var error = - // (1,12): error CS8652: The feature 'static abstract members in interfaces' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // (1,12): error CS8773: Feature 'static abstract members in interfaces' is not available in C# 9.0. Please use language version 11.0 or greater. // public int N.I.operator +(int x, int y) => x + y; - Diagnostic(ErrorCode.ERR_FeatureInPreview, "N.I.").WithArguments("static abstract members in interfaces").WithLocation(1, 12); + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion9, "N.I.").WithArguments("static abstract members in interfaces", "11.0").WithLocation(1, 12); foreach (var options in new[] { TestOptions.Script, TestOptions.Regular }) { @@ -2029,9 +2019,9 @@ public void OperatorDeclaration_ExplicitImplementation_02() UsingDeclaration("public int N.I.implicit (int x) => x;", options: options.WithLanguageVersion(version), version == LanguageVersion.CSharp9 ? errors.Append( - // (1,12): error CS8652: The feature 'static abstract members in interfaces' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // (1,12): error CS8773: Feature 'static abstract members in interfaces' is not available in C# 9.0. Please use language version 11.0 or greater. // public int N.I.implicit (int x) => x; - Diagnostic(ErrorCode.ERR_FeatureInPreview, "N.I.").WithArguments("static abstract members in interfaces").WithLocation(1, 12) + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion9, "N.I.").WithArguments("static abstract members in interfaces", "11.0").WithLocation(1, 12) ).ToArray() : errors); @@ -2110,9 +2100,9 @@ public void OperatorDeclaration_ExplicitImplementation_03() UsingDeclaration("public int N.I.explicit (int x) => x;", options: options.WithLanguageVersion(version), version == LanguageVersion.CSharp9 ? errors.Append( - // (1,12): error CS8652: The feature 'static abstract members in interfaces' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // (1,12): error CS8773: Feature 'static abstract members in interfaces' is not available in C# 9.0. Please use language version 11.0 or greater. // public int N.I.explicit (int x) => x; - Diagnostic(ErrorCode.ERR_FeatureInPreview, "N.I.").WithArguments("static abstract members in interfaces").WithLocation(1, 12) + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion9, "N.I.").WithArguments("static abstract members in interfaces", "11.0").WithLocation(1, 12) ).ToArray() : errors); @@ -2185,9 +2175,9 @@ public void OperatorDeclaration_ExplicitImplementation_04() UsingDeclaration("public int N.I operator +(int x) => x;", options: options.WithLanguageVersion(version), version == LanguageVersion.CSharp9 ? errors.Append( - // (1,12): error CS8652: The feature 'static abstract members in interfaces' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // (1,12): error CS8773: Feature 'static abstract members in interfaces' is not available in C# 9.0. Please use language version 11.0 or greater. // public int N.I operator +(int x) => x; - Diagnostic(ErrorCode.ERR_FeatureInPreview, "N.I ").WithArguments("static abstract members in interfaces").WithLocation(1, 12) + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion9, "N.I ").WithArguments("static abstract members in interfaces", "11.0").WithLocation(1, 12) ).ToArray() : errors); @@ -2260,9 +2250,9 @@ public void OperatorDeclaration_ExplicitImplementation_05() UsingDeclaration("public int I operator +(int x) => x;", options: options.WithLanguageVersion(version), version == LanguageVersion.CSharp9 ? errors.Append( - // (1,12): error CS8652: The feature 'static abstract members in interfaces' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // (1,12): error CS8773: Feature 'static abstract members in interfaces' is not available in C# 9.0. Please use language version 11.0 or greater. // public int I operator +(int x) => x; - Diagnostic(ErrorCode.ERR_FeatureInPreview, "I ").WithArguments("static abstract members in interfaces").WithLocation(1, 12) + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion9, "I ").WithArguments("static abstract members in interfaces", "11.0").WithLocation(1, 12) ).ToArray() : errors); @@ -2632,9 +2622,9 @@ public void OperatorDeclaration_ExplicitImplementation_10() public void OperatorDeclaration_ExplicitImplementation_11() { var error = - // (1,12): error CS8652: The feature 'static abstract members in interfaces' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // (1,12): error CS8773: Feature 'static abstract members in interfaces' is not available in C# 9.0. Please use language version 11.0 or greater. // public int N.I.operator +(int x, int y) => x + y; - Diagnostic(ErrorCode.ERR_FeatureInPreview, "N.I.").WithArguments("static abstract members in interfaces").WithLocation(1, 12); + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion9, "N.I.").WithArguments("static abstract members in interfaces", "11.0").WithLocation(1, 12); foreach (var options in new[] { TestOptions.Script, TestOptions.Regular }) { @@ -2739,9 +2729,9 @@ public void OperatorDeclaration_ExplicitImplementation_12() UsingTree("public int N.I.implicit (int x) => x;", options: options.WithLanguageVersion(version), version == LanguageVersion.CSharp9 ? errors.Append( - // (1,12): error CS8652: The feature 'static abstract members in interfaces' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // (1,12): error CS8773: Feature 'static abstract members in interfaces' is not available in C# 9.0. Please use language version 11.0 or greater. // public int N.I.implicit (int x) => x; - Diagnostic(ErrorCode.ERR_FeatureInPreview, "N.I.").WithArguments("static abstract members in interfaces").WithLocation(1, 12) + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion9, "N.I.").WithArguments("static abstract members in interfaces", "11.0").WithLocation(1, 12) ).ToArray() : errors); @@ -2824,9 +2814,9 @@ public void OperatorDeclaration_ExplicitImplementation_13() UsingTree("public int N.I.explicit (int x) => x;", options: options.WithLanguageVersion(version), version == LanguageVersion.CSharp9 ? errors.Append( - // (1,12): error CS8652: The feature 'static abstract members in interfaces' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // (1,12): error CS8773: Feature 'static abstract members in interfaces' is not available in C# 9.0. Please use language version 11.0 or greater. // public int N.I.explicit (int x) => x; - Diagnostic(ErrorCode.ERR_FeatureInPreview, "N.I.").WithArguments("static abstract members in interfaces").WithLocation(1, 12) + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion9, "N.I.").WithArguments("static abstract members in interfaces", "11.0").WithLocation(1, 12) ).ToArray() : errors); @@ -2903,9 +2893,9 @@ public void OperatorDeclaration_ExplicitImplementation_14() UsingTree("public int N.I operator +(int x) => x;", options: options.WithLanguageVersion(version), version == LanguageVersion.CSharp9 ? errors.Append( - // (1,12): error CS8652: The feature 'static abstract members in interfaces' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // (1,12): error CS8773: Feature 'static abstract members in interfaces' is not available in C# 9.0. Please use language version 11.0 or greater. // public int N.I operator +(int x) => x; - Diagnostic(ErrorCode.ERR_FeatureInPreview, "N.I ").WithArguments("static abstract members in interfaces").WithLocation(1, 12) + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion9, "N.I ").WithArguments("static abstract members in interfaces", "11.0").WithLocation(1, 12) ).ToArray() : errors); @@ -2982,9 +2972,9 @@ public void OperatorDeclaration_ExplicitImplementation_15() UsingTree("public int I operator +(int x) => x;", options: options.WithLanguageVersion(version), version == LanguageVersion.CSharp9 ? errors.Append( - // (1,12): error CS8652: The feature 'static abstract members in interfaces' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // (1,12): error CS8773: Feature 'static abstract members in interfaces' is not available in C# 9.0. Please use language version 11.0 or greater. // public int I operator +(int x) => x; - Diagnostic(ErrorCode.ERR_FeatureInPreview, "I ").WithArguments("static abstract members in interfaces").WithLocation(1, 12) + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion9, "I ").WithArguments("static abstract members in interfaces", "11.0").WithLocation(1, 12) ).ToArray() : errors); @@ -3504,9 +3494,9 @@ public void OperatorDeclaration_ExplicitImplementation_22() public void OperatorDeclaration_ExplicitImplementation_23() { var error = - // (1,5): error CS8652: The feature 'static abstract members in interfaces' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // (1,5): error CS8773: Feature 'static abstract members in interfaces' is not available in C# 9.0. Please use language version 11.0 or greater. // int N.I.operator +(int x, int y) => x + y; - Diagnostic(ErrorCode.ERR_FeatureInPreview, "N.I.").WithArguments("static abstract members in interfaces").WithLocation(1, 5); + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion9, "N.I.").WithArguments("static abstract members in interfaces", "11.0").WithLocation(1, 5); foreach (var options in new[] { TestOptions.Script, TestOptions.Regular }) { @@ -3606,9 +3596,9 @@ public void OperatorDeclaration_ExplicitImplementation_24() UsingDeclaration("int N.I.implicit (int x) => x;", options: options.WithLanguageVersion(version), version == LanguageVersion.CSharp9 ? errors.Append( - // (1,5): error CS8652: The feature 'static abstract members in interfaces' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // (1,5): error CS8773: Feature 'static abstract members in interfaces' is not available in C# 9.0. Please use language version 11.0 or greater. // int N.I.implicit (int x) => x; - Diagnostic(ErrorCode.ERR_FeatureInPreview, "N.I.").WithArguments("static abstract members in interfaces").WithLocation(1, 5) + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion9, "N.I.").WithArguments("static abstract members in interfaces", "11.0").WithLocation(1, 5) ).ToArray() : errors); @@ -3686,9 +3676,9 @@ public void OperatorDeclaration_ExplicitImplementation_25() UsingDeclaration("int N.I.explicit (int x) => x;", options: options.WithLanguageVersion(version), version == LanguageVersion.CSharp9 ? errors.Append( - // (1,5): error CS8652: The feature 'static abstract members in interfaces' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // (1,5): error CS8773: Feature 'static abstract members in interfaces' is not available in C# 9.0. Please use language version 11.0 or greater. // int N.I.explicit (int x) => x; - Diagnostic(ErrorCode.ERR_FeatureInPreview, "N.I.").WithArguments("static abstract members in interfaces").WithLocation(1, 5) + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion9, "N.I.").WithArguments("static abstract members in interfaces", "11.0").WithLocation(1, 5) ).ToArray() : errors); @@ -3760,9 +3750,9 @@ public void OperatorDeclaration_ExplicitImplementation_26() UsingDeclaration("int N.I operator +(int x) => x;", options: options.WithLanguageVersion(version), version == LanguageVersion.CSharp9 ? errors.Append( - // (1,5): error CS8652: The feature 'static abstract members in interfaces' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // (1,5): error CS8773: Feature 'static abstract members in interfaces' is not available in C# 9.0. Please use language version 11.0 or greater. // int N.I operator +(int x) => x; - Diagnostic(ErrorCode.ERR_FeatureInPreview, "N.I ").WithArguments("static abstract members in interfaces").WithLocation(1, 5) + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion9, "N.I ").WithArguments("static abstract members in interfaces", "11.0").WithLocation(1, 5) ).ToArray() : errors); @@ -3834,9 +3824,9 @@ public void OperatorDeclaration_ExplicitImplementation_27() UsingDeclaration("int I operator +(int x) => x;", options: options.WithLanguageVersion(version), version == LanguageVersion.CSharp9 ? errors.Append( - // (1,5): error CS8652: The feature 'static abstract members in interfaces' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // (1,5): error CS8773: Feature 'static abstract members in interfaces' is not available in C# 9.0. Please use language version 11.0 or greater. // int I operator +(int x) => x; - Diagnostic(ErrorCode.ERR_FeatureInPreview, "I ").WithArguments("static abstract members in interfaces").WithLocation(1, 5) + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion9, "I ").WithArguments("static abstract members in interfaces", "11.0").WithLocation(1, 5) ).ToArray() : errors); @@ -4200,9 +4190,9 @@ public void OperatorDeclaration_ExplicitImplementation_32() public void OperatorDeclaration_ExplicitImplementation_33() { var error = - // (1,5): error CS8652: The feature 'static abstract members in interfaces' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // (1,5): error CS8773: Feature 'static abstract members in interfaces' is not available in C# 9.0. Please use language version 11.0 or greater. // int N.I.operator +(int x, int y) => x + y; - Diagnostic(ErrorCode.ERR_FeatureInPreview, "N.I.").WithArguments("static abstract members in interfaces").WithLocation(1, 5); + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion9, "N.I.").WithArguments("static abstract members in interfaces", "11.0").WithLocation(1, 5); foreach (var options in new[] { TestOptions.Script, TestOptions.Regular }) { @@ -4306,9 +4296,9 @@ public void OperatorDeclaration_ExplicitImplementation_34() UsingTree("int N.I.implicit (int x) => x;", options: options.WithLanguageVersion(version), version == LanguageVersion.CSharp9 ? errors.Append( - // (1,5): error CS8652: The feature 'static abstract members in interfaces' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // (1,5): error CS8773: Feature 'static abstract members in interfaces' is not available in C# 9.0. Please use language version 11.0 or greater. // int N.I.implicit (int x) => x; - Diagnostic(ErrorCode.ERR_FeatureInPreview, "N.I.").WithArguments("static abstract members in interfaces").WithLocation(1, 5) + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion9, "N.I.").WithArguments("static abstract members in interfaces", "11.0").WithLocation(1, 5) ).ToArray() : errors); @@ -4390,9 +4380,9 @@ public void OperatorDeclaration_ExplicitImplementation_35() UsingTree("int N.I.explicit (int x) => x;", options: options.WithLanguageVersion(version), version == LanguageVersion.CSharp9 ? errors.Append( - // (1,5): error CS8652: The feature 'static abstract members in interfaces' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // (1,5): error CS8773: Feature 'static abstract members in interfaces' is not available in C# 9.0. Please use language version 11.0 or greater. // int N.I.explicit (int x) => x; - Diagnostic(ErrorCode.ERR_FeatureInPreview, "N.I.").WithArguments("static abstract members in interfaces").WithLocation(1, 5) + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion9, "N.I.").WithArguments("static abstract members in interfaces", "11.0").WithLocation(1, 5) ).ToArray() : errors); @@ -4468,9 +4458,9 @@ public void OperatorDeclaration_ExplicitImplementation_36() UsingTree("int N.I operator +(int x) => x;", options: options.WithLanguageVersion(version), version == LanguageVersion.CSharp9 ? errors.Append( - // (1,5): error CS8652: The feature 'static abstract members in interfaces' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // (1,5): error CS8773: Feature 'static abstract members in interfaces' is not available in C# 9.0. Please use language version 11.0 or greater. // int N.I operator +(int x) => x; - Diagnostic(ErrorCode.ERR_FeatureInPreview, "N.I ").WithArguments("static abstract members in interfaces").WithLocation(1, 5) + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion9, "N.I ").WithArguments("static abstract members in interfaces", "11.0").WithLocation(1, 5) ).ToArray() : errors); @@ -4546,9 +4536,9 @@ public void OperatorDeclaration_ExplicitImplementation_37() UsingTree("int I operator +(int x) => x;", options: options.WithLanguageVersion(version), version == LanguageVersion.CSharp9 ? errors.Append( - // (1,5): error CS8652: The feature 'static abstract members in interfaces' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // (1,5): error CS8773: Feature 'static abstract members in interfaces' is not available in C# 9.0. Please use language version 11.0 or greater. // int I operator +(int x) => x; - Diagnostic(ErrorCode.ERR_FeatureInPreview, "I ").WithArguments("static abstract members in interfaces").WithLocation(1, 5) + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion9, "I ").WithArguments("static abstract members in interfaces", "11.0").WithLocation(1, 5) ).ToArray() : errors); @@ -5243,9 +5233,9 @@ public void OperatorDeclaration_ExplicitImplementation_47() public void ConversionDeclaration_ExplicitImplementation_01() { var error = - // (1,10): error CS8652: The feature 'static abstract members in interfaces' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // (1,10): error CS8773: Feature 'static abstract members in interfaces' is not available in C# 9.0. Please use language version 11.0 or greater. // implicit N.I.operator int(int x) => x; - Diagnostic(ErrorCode.ERR_FeatureInPreview, "N.I.").WithArguments("static abstract members in interfaces").WithLocation(1, 10); + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion9, "N.I.").WithArguments("static abstract members in interfaces", "11.0").WithLocation(1, 10); foreach (var options in new[] { TestOptions.Script, TestOptions.Regular }) { @@ -5322,9 +5312,9 @@ public void ConversionDeclaration_ExplicitImplementation_02() UsingDeclaration("N.I.operator int(int x) => x;", options: options.WithLanguageVersion(version), version == LanguageVersion.CSharp9 ? errors.Append( - // (1,1): error CS8652: The feature 'static abstract members in interfaces' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // (1,1): error CS8773: Feature 'static abstract members in interfaces' is not available in C# 9.0. Please use language version 11.0 or greater. // N.I.operator int(int x) => x; - Diagnostic(ErrorCode.ERR_FeatureInPreview, "N.I.").WithArguments("static abstract members in interfaces").WithLocation(1, 1) + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion9, "N.I.").WithArguments("static abstract members in interfaces", "11.0").WithLocation(1, 1) ).ToArray() : errors); @@ -5447,9 +5437,9 @@ public void ConversionDeclaration_ExplicitImplementation_04() UsingDeclaration("implicit N.I operator int(int x) => x;", options: options.WithLanguageVersion(version), version == LanguageVersion.CSharp9 ? errors.Append( - // (1,10): error CS8652: The feature 'static abstract members in interfaces' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // (1,10): error CS8773: Feature 'static abstract members in interfaces' is not available in C# 9.0. Please use language version 11.0 or greater. // implicit N.I operator int(int x) => x; - Diagnostic(ErrorCode.ERR_FeatureInPreview, "N.I ").WithArguments("static abstract members in interfaces").WithLocation(1, 10) + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion9, "N.I ").WithArguments("static abstract members in interfaces", "11.0").WithLocation(1, 10) ).ToArray() : errors); @@ -5521,9 +5511,9 @@ public void ConversionDeclaration_ExplicitImplementation_05() UsingDeclaration("explicit I operator int(int x) => x;", options: options.WithLanguageVersion(version), version == LanguageVersion.CSharp9 ? errors.Append( - // (1,10): error CS8652: The feature 'static abstract members in interfaces' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // (1,10): error CS8773: Feature 'static abstract members in interfaces' is not available in C# 9.0. Please use language version 11.0 or greater. // explicit I operator int(int x) => x; - Diagnostic(ErrorCode.ERR_FeatureInPreview, "I ").WithArguments("static abstract members in interfaces").WithLocation(1, 10) + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion9, "I ").WithArguments("static abstract members in interfaces", "11.0").WithLocation(1, 10) ).ToArray() : errors); @@ -5870,9 +5860,9 @@ public void ConversionDeclaration_ExplicitImplementation_10() public void ConversionDeclaration_ExplicitImplementation_11() { var error = - // (1,10): error CS8652: The feature 'static abstract members in interfaces' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // (1,10): error CS8773: Feature 'static abstract members in interfaces' is not available in C# 9.0. Please use language version 11.0 or greater. // explicit N.I.operator int(int x) => x; - Diagnostic(ErrorCode.ERR_FeatureInPreview, "N.I.").WithArguments("static abstract members in interfaces").WithLocation(1, 10); + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion9, "N.I.").WithArguments("static abstract members in interfaces", "11.0").WithLocation(1, 10); foreach (var options in new[] { TestOptions.Script, TestOptions.Regular }) { @@ -5956,9 +5946,9 @@ public void ConversionDeclaration_ExplicitImplementation_12() UsingTree("implicit N.I int(int x) => x;", options: options.WithLanguageVersion(version), version == LanguageVersion.CSharp9 ? errors.Append( - // (1,10): error CS8652: The feature 'static abstract members in interfaces' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // (1,10): error CS8773: Feature 'static abstract members in interfaces' is not available in C# 9.0. Please use language version 11.0 or greater. // implicit N.I int(int x) => x; - Diagnostic(ErrorCode.ERR_FeatureInPreview, "N.I ").WithArguments("static abstract members in interfaces").WithLocation(1, 10) + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion9, "N.I ").WithArguments("static abstract members in interfaces", "11.0").WithLocation(1, 10) ).ToArray() : errors); @@ -6034,9 +6024,9 @@ public void ConversionDeclaration_ExplicitImplementation_13() UsingTree("explicit N.I. int(int x) => x;", options: options.WithLanguageVersion(version), version == LanguageVersion.CSharp9 ? errors.Append( - // (1,10): error CS8652: The feature 'static abstract members in interfaces' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // (1,10): error CS8773: Feature 'static abstract members in interfaces' is not available in C# 9.0. Please use language version 11.0 or greater. // explicit N.I. int(int x) => x; - Diagnostic(ErrorCode.ERR_FeatureInPreview, "N.I.").WithArguments("static abstract members in interfaces").WithLocation(1, 10) + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion9, "N.I.").WithArguments("static abstract members in interfaces", "11.0").WithLocation(1, 10) ).ToArray() : errors); @@ -6112,9 +6102,9 @@ public void ConversionDeclaration_ExplicitImplementation_14() UsingTree("implicit N.I operator int(int x) => x;", options: options.WithLanguageVersion(version), version == LanguageVersion.CSharp9 ? errors.Append( - // (1,10): error CS8652: The feature 'static abstract members in interfaces' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // (1,10): error CS8773: Feature 'static abstract members in interfaces' is not available in C# 9.0. Please use language version 11.0 or greater. // implicit N.I operator int(int x) => x; - Diagnostic(ErrorCode.ERR_FeatureInPreview, "N.I ").WithArguments("static abstract members in interfaces").WithLocation(1, 10) + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion9, "N.I ").WithArguments("static abstract members in interfaces", "11.0").WithLocation(1, 10) ).ToArray() : errors); @@ -6190,9 +6180,9 @@ public void ConversionDeclaration_ExplicitImplementation_15() UsingTree("explicit I operator int(int x) => x;", options: options.WithLanguageVersion(version), version == LanguageVersion.CSharp9 ? errors.Append( - // (1,10): error CS8652: The feature 'static abstract members in interfaces' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // (1,10): error CS8773: Feature 'static abstract members in interfaces' is not available in C# 9.0. Please use language version 11.0 or greater. // explicit I operator int(int x) => x; - Diagnostic(ErrorCode.ERR_FeatureInPreview, "I ").WithArguments("static abstract members in interfaces").WithLocation(1, 10) + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion9, "I ").WithArguments("static abstract members in interfaces", "11.0").WithLocation(1, 10) ).ToArray() : errors); diff --git a/src/Compilers/CSharp/Test/Syntax/Parsing/NullableParsingTests.cs b/src/Compilers/CSharp/Test/Syntax/Parsing/NullableParsingTests.cs index 9df274fda8355..a54807c70397e 100644 --- a/src/Compilers/CSharp/Test/Syntax/Parsing/NullableParsingTests.cs +++ b/src/Compilers/CSharp/Test/Syntax/Parsing/NullableParsingTests.cs @@ -27,7 +27,22 @@ public void PartialAccessibilityAndNullableArray() @"class C { privat C[]? F; -}"); +}", + // (3,13): error CS0650: Bad array declarator: To declare a managed array the rank specifier precedes the variable's identifier. To declare a fixed size buffer field, use the fixed keyword before the field type. + // privat C[]? F; + Diagnostic(ErrorCode.ERR_CStyleArray, "[]").WithLocation(3, 13), + // (3,15): error CS1003: Syntax error, ',' expected + // privat C[]? F; + Diagnostic(ErrorCode.ERR_SyntaxError, "?").WithArguments(",").WithLocation(3, 15), + // (3,17): error CS1002: ; expected + // privat C[]? F; + Diagnostic(ErrorCode.ERR_SemicolonExpected, "F").WithLocation(3, 17), + // (3,18): error CS1519: Invalid token ';' in class, record, struct, or interface member declaration + // privat C[]? F; + Diagnostic(ErrorCode.ERR_InvalidMemberDecl, ";").WithArguments(";").WithLocation(3, 18), + // (3,18): error CS1519: Invalid token ';' in class, record, struct, or interface member declaration + // privat C[]? F; + Diagnostic(ErrorCode.ERR_InvalidMemberDecl, ";").WithArguments(";").WithLocation(3, 18)); N(SyntaxKind.CompilationUnit); { N(SyntaxKind.ClassDeclaration); diff --git a/src/Compilers/CSharp/Test/Syntax/Parsing/ParserErrorMessageTests.cs b/src/Compilers/CSharp/Test/Syntax/Parsing/ParserErrorMessageTests.cs index d4850639edc30..6ab46ca6c10b8 100644 --- a/src/Compilers/CSharp/Test/Syntax/Parsing/ParserErrorMessageTests.cs +++ b/src/Compilers/CSharp/Test/Syntax/Parsing/ParserErrorMessageTests.cs @@ -622,9 +622,6 @@ partial enum E { } "; CreateCompilation(test).VerifyDiagnostics( - // (2,1): error CS0267: The 'partial' modifier can only appear immediately before 'class', 'record', 'struct', 'interface', or a method return type. - // partial enum E { } - Diagnostic(ErrorCode.ERR_PartialMisplaced, "partial").WithLocation(2, 1), // (2,14): error CS0267: The 'partial' modifier can only appear immediately before 'class', 'record', 'struct', 'interface', or a method return type. // partial enum E { } Diagnostic(ErrorCode.ERR_PartialMisplaced, "E").WithLocation(2, 14)); @@ -639,9 +636,6 @@ partial delegate E { } // Extra errors CreateCompilation(test, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular9).VerifyDiagnostics( - // (2,1): error CS0267: The 'partial' modifier can only appear immediately before 'class', 'record', 'struct', 'interface', or a method return type. - // partial delegate E { } - Diagnostic(ErrorCode.ERR_PartialMisplaced, "partial").WithLocation(2, 1), // (2,20): error CS1001: Identifier expected // partial delegate E { } Diagnostic(ErrorCode.ERR_IdentifierExpected, "{").WithLocation(2, 20), @@ -672,11 +666,7 @@ public void CS0267ERR_PartialMisplaced_Delegate2() partial delegate void E(); "; - // Extra errors CreateCompilation(test).VerifyDiagnostics( - // (2,1): error CS0267: The 'partial' modifier can only appear immediately before 'class', 'record', 'struct', 'interface', or a method return type. - // partial delegate void E(); - Diagnostic(ErrorCode.ERR_PartialMisplaced, "partial").WithLocation(2, 1), // (2,23): error CS0267: The 'partial' modifier can only appear immediately before 'class', 'record', 'struct', 'interface', or a method return type. // partial delegate void E(); Diagnostic(ErrorCode.ERR_PartialMisplaced, "E").WithLocation(2, 23)); @@ -5710,8 +5700,7 @@ public void MissingCommaInAttribute() var text = @"[One Two] // error: missing comma class TestClass { }"; - var tree = UsingTree(text); - tree.GetDiagnostics().Verify( + var tree = UsingTree(text, // (1,6): error CS1003: Syntax error, ',' expected // [One Two] // error: missing comma Diagnostic(ErrorCode.ERR_SyntaxError, "Two").WithArguments(",").WithLocation(1, 6) diff --git a/src/Compilers/CSharp/Test/Syntax/Parsing/ParserRegressionTests.cs b/src/Compilers/CSharp/Test/Syntax/Parsing/ParserRegressionTests.cs index 2a397b1c693ac..54ad8b295ed43 100644 --- a/src/Compilers/CSharp/Test/Syntax/Parsing/ParserRegressionTests.cs +++ b/src/Compilers/CSharp/Test/Syntax/Parsing/ParserRegressionTests.cs @@ -332,15 +332,14 @@ static void Main() A::B.C y; } }"; - ParseAndValidate(source, + + UsingTree(source, // (6,10): error CS1002: ; expected // A::B.C y; Diagnostic(ErrorCode.ERR_SemicolonExpected, "::").WithLocation(6, 10), // (6,10): error CS1001: Identifier expected // A::B.C y; Diagnostic(ErrorCode.ERR_IdentifierExpected, "::").WithLocation(6, 10)); - - UsingTree(source); N(SyntaxKind.CompilationUnit); { N(SyntaxKind.ClassDeclaration); @@ -470,12 +469,11 @@ static void Main() ::A.B x; } }"; - ParseAndValidate(source, + + UsingTree(source, // (4,6): error CS1001: Identifier expected // { Diagnostic(ErrorCode.ERR_IdentifierExpected, "").WithLocation(4, 6)); - - UsingTree(source); N(SyntaxKind.CompilationUnit); { N(SyntaxKind.ClassDeclaration); @@ -561,12 +559,11 @@ static void Main() ::A.B(); } }"; - ParseAndValidate(source, + + UsingTree(source, // (4,6): error CS1001: Identifier expected // { Diagnostic(ErrorCode.ERR_IdentifierExpected, "").WithLocation(4, 6)); - - UsingTree(source); N(SyntaxKind.CompilationUnit); { N(SyntaxKind.ClassDeclaration); @@ -652,12 +649,11 @@ static void Main() A::C(); } }"; - ParseAndValidate(source, + + UsingTree(source, // (5,13): error CS1001: Identifier expected // A::C(); Diagnostic(ErrorCode.ERR_IdentifierExpected, "::").WithLocation(5, 13)); - - UsingTree(source); N(SyntaxKind.CompilationUnit); { N(SyntaxKind.ClassDeclaration); @@ -742,12 +738,10 @@ static void Main() A::C d; } }"; - ParseAndValidate(source, + UsingTree(source, // (5,13): error CS7000: Unexpected use of an aliased name // A::C d; Diagnostic(ErrorCode.ERR_UnexpectedAliasedName, "::").WithLocation(5, 13)); - - UsingTree(source); N(SyntaxKind.CompilationUnit); { N(SyntaxKind.ClassDeclaration); diff --git a/src/Compilers/CSharp/Test/Syntax/Parsing/ParsingTests.cs b/src/Compilers/CSharp/Test/Syntax/Parsing/ParsingTests.cs index 8b7cd615c2b13..3ed4678713b75 100644 --- a/src/Compilers/CSharp/Test/Syntax/Parsing/ParsingTests.cs +++ b/src/Compilers/CSharp/Test/Syntax/Parsing/ParsingTests.cs @@ -117,11 +117,6 @@ internal void UsingDeclaration(string text, int offset = 0, ParseOptions? option UsingNode(node); } - internal void UsingCompilationRoot(string text, CSharpParseOptions? options, params DiagnosticDescription[] expectedErrors) - { - UsingTree(text, options, verifyErrors: true, expectedErrors); - } - internal void UsingExpression(string text, ParseOptions? options, params DiagnosticDescription[] expectedErrors) { UsingNode(text, SyntaxFactory.ParseExpression(text, options: options), expectedErrors); @@ -146,24 +141,18 @@ internal void UsingExpression(string text, params DiagnosticDescription[] expect UsingExpression(text, options: null, expectedErrors); } - /// - /// Parses given string and initializes a depth-first preorder enumerator. - /// - protected SyntaxTree UsingTree(string text, CSharpParseOptions? options = null) + protected SyntaxTree UsingTree(string text, params DiagnosticDescription[] expectedErrors) { - return UsingTree(text, options, verifyErrors: false, expectedErrors: null); + return UsingTree(text, options: null, expectedErrors); } - protected SyntaxTree UsingTree(string text, CSharpParseOptions? options, bool verifyErrors, DiagnosticDescription[]? expectedErrors) + protected SyntaxTree UsingTree(string text, CSharpParseOptions? options, params DiagnosticDescription[] expectedErrors) { VerifyEnumeratorConsumed(); var tree = ParseTree(text, options); _node = tree.GetCompilationUnitRoot(); - if (verifyErrors) - { - var actualErrors = _node.GetDiagnostics(); - actualErrors.Verify(expectedErrors); - } + var actualErrors = _node.GetDiagnostics(); + actualErrors.Verify(expectedErrors); var nodes = EnumerateNodes(_node, dump: false); _treeEnumerator = nodes.GetEnumerator(); diff --git a/src/Compilers/CSharp/Test/Syntax/Parsing/RawInterpolatedStringLiteralCompilingTests.cs b/src/Compilers/CSharp/Test/Syntax/Parsing/RawInterpolatedStringLiteralCompilingTests.cs index 239d113222d0c..3b2fcb1d8fbc9 100644 --- a/src/Compilers/CSharp/Test/Syntax/Parsing/RawInterpolatedStringLiteralCompilingTests.cs +++ b/src/Compilers/CSharp/Test/Syntax/Parsing/RawInterpolatedStringLiteralCompilingTests.cs @@ -71,9 +71,9 @@ public void TestDownlevel() { const string s = $"""""" """"""; }", parseOptions: TestOptions.Regular10).VerifyDiagnostics( - // (3,22): error CS8652: The feature 'raw string literals' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. - // const string s = """ """; - Diagnostic(ErrorCode.ERR_FeatureInPreview, @"$"""""" """"""").WithArguments("raw string literals").WithLocation(3, 22)); + // (3,22): error CS8936: Feature 'raw string literals' is not available in C# 10.0. Please use language version 11.0 or greater. + // const string s = $""" """; + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, @"$"""""" """"""").WithArguments("raw string literals", "11.0").WithLocation(3, 22)); } [Fact] @@ -83,7 +83,7 @@ public void TestAtLevel() @"class C { const string s = $"""""" """"""; -}", parseOptions: TestOptions.RegularNext).VerifyDiagnostics(); +}", parseOptions: TestOptions.Regular11).VerifyDiagnostics(); } [Fact] @@ -284,14 +284,14 @@ void M() """"""}""; } }", parseOptions: TestOptions.Regular9).VerifyDiagnostics( - // (5,20): error CS8652: The feature 'raw string literals' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // (5,20): error CS8773: Feature 'raw string literals' is not available in C# 9.0. Please use language version 11.0 or greater. // var v = $"{$""" - Diagnostic(ErrorCode.ERR_FeatureInPreview, @"$"""""" + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion9, @"$"""""" -""""""").WithArguments("raw string literals").WithLocation(5, 20), - // (7,4): error CS8967: Newlines inside a non-verbatim interpolated string are not supported in C# 9.0. Please use language version preview or greater. +""""""").WithArguments("raw string literals", "11.0").WithLocation(5, 20), + // (7,4): error CS8967: Newlines inside a non-verbatim interpolated string are not supported in C# 9.0. Please use language version 11.0 or greater. // """}"; - Diagnostic(ErrorCode.ERR_NewlinesAreNotAllowedInsideANonVerbatimInterpolatedString, "}").WithArguments("9.0", "preview").WithLocation(7, 4)); + Diagnostic(ErrorCode.ERR_NewlinesAreNotAllowedInsideANonVerbatimInterpolatedString, "}").WithArguments("9.0", "11.0").WithLocation(7, 4)); } [Fact] diff --git a/src/Compilers/CSharp/Test/Syntax/Parsing/RawStringLiteralCompilingTests.cs b/src/Compilers/CSharp/Test/Syntax/Parsing/RawStringLiteralCompilingTests.cs index ebefc81bf7f87..8f91183f10de1 100644 --- a/src/Compilers/CSharp/Test/Syntax/Parsing/RawStringLiteralCompilingTests.cs +++ b/src/Compilers/CSharp/Test/Syntax/Parsing/RawStringLiteralCompilingTests.cs @@ -17,9 +17,9 @@ public void TestDownlevel() { const string s = """""" """"""; }", parseOptions: TestOptions.Regular10).VerifyDiagnostics( - // (3,22): error CS8652: The feature 'raw string literals' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // (3,22): error CS8936: Feature 'raw string literals' is not available in C# 10.0. Please use language version 11.0 or greater. // const string s = """ """; - Diagnostic(ErrorCode.ERR_FeatureInPreview, @""""""" """"""").WithArguments("raw string literals").WithLocation(3, 22)); + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, @""""""" """"""").WithArguments("raw string literals", "11.0").WithLocation(3, 22)); } [Fact] @@ -212,14 +212,14 @@ void M() """"""}""; } }", parseOptions: TestOptions.Regular9).VerifyDiagnostics( - // (5,20): error CS8652: The feature 'raw string literals' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. - // var v = $"{""" - Diagnostic(ErrorCode.ERR_FeatureInPreview, @""""""" - -""""""").WithArguments("raw string literals").WithLocation(5, 20), - // (7,4): error CS8967: Newlines inside a non-verbatim interpolated string are not supported in C# 9.0. Please use language version preview or greater. - // """}"; - Diagnostic(ErrorCode.ERR_NewlinesAreNotAllowedInsideANonVerbatimInterpolatedString, "}").WithArguments("9.0", "preview").WithLocation(7, 4)); + // (5,20): error CS8773: Feature 'raw string literals' is not available in C# 9.0. Please use language version 11.0 or greater. + // var v = $"{""" + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion9, @""""""" + +""""""").WithArguments("raw string literals", "11.0").WithLocation(5, 20), + // (7,4): error CS8967: Newlines inside a non-verbatim interpolated string are not supported in C# 9.0. Please use language version 11.0 or greater. + // """}"; + Diagnostic(ErrorCode.ERR_NewlinesAreNotAllowedInsideANonVerbatimInterpolatedString, "}").WithArguments("9.0", "11.0").WithLocation(7, 4)); } [Fact] diff --git a/src/Compilers/CSharp/Test/Syntax/Parsing/RecordParsing.cs b/src/Compilers/CSharp/Test/Syntax/Parsing/RecordParsing.cs index d636224ecf25a..6c628d0978f35 100644 --- a/src/Compilers/CSharp/Test/Syntax/Parsing/RecordParsing.cs +++ b/src/Compilers/CSharp/Test/Syntax/Parsing/RecordParsing.cs @@ -12,14 +12,7 @@ namespace Microsoft.CodeAnalysis.CSharp.UnitTests { public sealed class RecordParsingTests : ParsingTests { - private SyntaxTree UsingTree(string text, CSharpParseOptions? options, params DiagnosticDescription[] expectedErrors) - { - var tree = SyntaxFactory.ParseSyntaxTree(text, options); - UsingNode(text, tree.GetCompilationUnitRoot(), expectedErrors); - return tree; - } - - private SyntaxTree UsingTree(string text, params DiagnosticDescription[] expectedErrors) + private new SyntaxTree UsingTree(string text, params DiagnosticDescription[] expectedErrors) => UsingTree(text, TestOptions.Regular9, expectedErrors); private new void UsingExpression(string text, params DiagnosticDescription[] expectedErrors) diff --git a/src/Compilers/CSharp/Test/Syntax/Parsing/RefFieldParsingTests.cs b/src/Compilers/CSharp/Test/Syntax/Parsing/RefFieldParsingTests.cs index 1c6274e164fb9..395ee4bbf2c31 100644 --- a/src/Compilers/CSharp/Test/Syntax/Parsing/RefFieldParsingTests.cs +++ b/src/Compilers/CSharp/Test/Syntax/Parsing/RefFieldParsingTests.cs @@ -3,6 +3,7 @@ // See the LICENSE file in the project root for more information. using Microsoft.CodeAnalysis.CSharp.Test.Utilities; +using Roslyn.Test.Utilities; using Xunit; using Xunit.Abstractions; @@ -16,7 +17,7 @@ public RefFieldParsingTests(ITestOutputHelper output) : base(output) [Theory] [InlineData(LanguageVersion.CSharp10)] - [InlineData(LanguageVersionFacts.CSharpNext)] + [InlineData(LanguageVersion.CSharp11)] public void FieldDeclaration_01(LanguageVersion languageVersion) { string source = "struct S { ref T F; }"; @@ -53,7 +54,7 @@ public void FieldDeclaration_01(LanguageVersion languageVersion) [Theory] [InlineData(LanguageVersion.CSharp10)] - [InlineData(LanguageVersionFacts.CSharpNext)] + [InlineData(LanguageVersion.CSharp11)] public void FieldDeclaration_02(LanguageVersion languageVersion) { string source = "struct S { ref readonly T F; }"; @@ -91,7 +92,7 @@ public void FieldDeclaration_02(LanguageVersion languageVersion) [Theory] [InlineData(LanguageVersion.CSharp10)] - [InlineData(LanguageVersionFacts.CSharpNext)] + [InlineData(LanguageVersion.CSharp11)] public void FieldDeclaration_03(LanguageVersion languageVersion) { string source = "struct S { out T F; }"; @@ -127,7 +128,7 @@ public void FieldDeclaration_03(LanguageVersion languageVersion) [Theory] [InlineData(LanguageVersion.CSharp10)] - [InlineData(LanguageVersionFacts.CSharpNext)] + [InlineData(LanguageVersion.CSharp11)] public void FieldDeclaration_04(LanguageVersion languageVersion) { string source = "struct S { in T F; }"; @@ -163,7 +164,7 @@ public void FieldDeclaration_04(LanguageVersion languageVersion) [Theory] [InlineData(LanguageVersion.CSharp10)] - [InlineData(LanguageVersionFacts.CSharpNext)] + [InlineData(LanguageVersion.CSharp11)] public void Fixed_01(LanguageVersion languageVersion) { string source = "struct S { fixed ref int F1[1]; fixed ref readonly int F2[2]; }"; @@ -246,7 +247,7 @@ public void Fixed_01(LanguageVersion languageVersion) [Theory] [InlineData(LanguageVersion.CSharp10)] - [InlineData(LanguageVersionFacts.CSharpNext)] + [InlineData(LanguageVersion.CSharp11)] public void Fixed_02(LanguageVersion languageVersion) { string source = "struct S { ref fixed int F1[1]; ref readonly fixed int F2[2]; }"; @@ -349,7 +350,7 @@ public void Fixed_02(LanguageVersion languageVersion) [Theory] [InlineData(LanguageVersion.CSharp10)] - [InlineData(LanguageVersionFacts.CSharpNext)] + [InlineData(LanguageVersion.CSharp11)] public void ReadOnlyRefParameter(LanguageVersion languageVersion) { string source = "class C { void M(readonly ref int i) { } }"; @@ -414,17 +415,104 @@ public void ReadOnlyRefParameter(LanguageVersion languageVersion) EOF(); } - // https://github.com/dotnet/roslyn/issues/62120: Support ref field assignment in object initializers. - [Theory] + [Theory, WorkItem(62120, "https://github.com/dotnet/roslyn/issues/62120")] [InlineData(LanguageVersion.CSharp10)] - [InlineData(LanguageVersionFacts.CSharpNext)] + [InlineData(LanguageVersion.CSharp11)] public void ObjectInitializer(LanguageVersion languageVersion) { string source = "new S { F = ref t }"; + UsingExpression(source, TestOptions.Regular.WithLanguageVersion(languageVersion)); + + N(SyntaxKind.ObjectCreationExpression); + { + N(SyntaxKind.NewKeyword); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "S"); + } + N(SyntaxKind.ObjectInitializerExpression); + { + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.SimpleAssignmentExpression); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "F"); + } + N(SyntaxKind.EqualsToken); + N(SyntaxKind.RefExpression); + { + N(SyntaxKind.RefKeyword); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "t"); + } + } + } + N(SyntaxKind.CloseBraceToken); + } + } + EOF(); + } + + [Theory, WorkItem(62120, "https://github.com/dotnet/roslyn/issues/62120")] + [InlineData(LanguageVersion.CSharp10)] + [InlineData(LanguageVersion.CSharp11)] + public void ObjectInitializer_CompoundAssignment(LanguageVersion languageVersion) + { + string source = "new S { F += ref t }"; UsingExpression(source, TestOptions.Regular.WithLanguageVersion(languageVersion), - // (1,13): error CS1525: Invalid expression term 'ref' - // new S { F = ref t } - Diagnostic(ErrorCode.ERR_InvalidExprTerm, "ref t").WithArguments("ref").WithLocation(1, 13)); + // (1,14): error CS1525: Invalid expression term 'ref' + // new S { F += ref t } + Diagnostic(ErrorCode.ERR_InvalidExprTerm, "ref t").WithArguments("ref").WithLocation(1, 14) + ); + + N(SyntaxKind.ObjectCreationExpression); + { + N(SyntaxKind.NewKeyword); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "S"); + } + N(SyntaxKind.CollectionInitializerExpression); + { + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.AddAssignmentExpression); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "F"); + } + N(SyntaxKind.PlusEqualsToken); + N(SyntaxKind.RefExpression); + { + N(SyntaxKind.RefKeyword); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "t"); + } + } + } + N(SyntaxKind.CloseBraceToken); + } + } + EOF(); + } + + [Theory] + [InlineData(LanguageVersion.CSharp10)] + [InlineData(LanguageVersion.CSharp11)] + public void RefObjectInitializer_NestedInitializer(LanguageVersion languageVersion) + { + string source = "new S { F = ref { F2 = t } }"; + UsingExpression(source, TestOptions.Regular.WithLanguageVersion(languageVersion), + // (1,17): error CS1525: Invalid expression term '{' + // new S { F = ref { F2 = t } } + Diagnostic(ErrorCode.ERR_InvalidExprTerm, "{").WithArguments("{").WithLocation(1, 17), + // (1,17): error CS1003: Syntax error, ',' expected + // new S { F = ref { F2 = t } } + Diagnostic(ErrorCode.ERR_SyntaxError, "{").WithArguments(",").WithLocation(1, 17) + ); N(SyntaxKind.ObjectCreationExpression); { @@ -444,6 +532,107 @@ public void ObjectInitializer(LanguageVersion languageVersion) } N(SyntaxKind.EqualsToken); N(SyntaxKind.RefExpression); + { + N(SyntaxKind.RefKeyword); + M(SyntaxKind.IdentifierName); + { + M(SyntaxKind.IdentifierToken); + } + } + } + M(SyntaxKind.CommaToken); + N(SyntaxKind.ComplexElementInitializerExpression); + { + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.SimpleAssignmentExpression); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "F2"); + } + N(SyntaxKind.EqualsToken); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "t"); + } + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.CloseBraceToken); + } + } + EOF(); + } + + [Theory] + [InlineData(LanguageVersion.CSharp10)] + [InlineData(LanguageVersion.CSharp11)] + public void RefCollectionInitializer(LanguageVersion languageVersion) + { + string source = "new S { ref t }"; + UsingExpression(source, TestOptions.Regular.WithLanguageVersion(languageVersion)); + + N(SyntaxKind.ObjectCreationExpression); + { + N(SyntaxKind.NewKeyword); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "S"); + } + N(SyntaxKind.CollectionInitializerExpression); + { + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.RefExpression); + { + N(SyntaxKind.RefKeyword); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "t"); + } + } + N(SyntaxKind.CloseBraceToken); + } + } + EOF(); + } + + [Theory] + [InlineData(LanguageVersion.CSharp10)] + [InlineData(LanguageVersion.CSharp11)] + public void RefDictionaryInitializer(LanguageVersion languageVersion) + { + string source = "new S { [0] = ref t }"; + UsingExpression(source, TestOptions.Regular.WithLanguageVersion(languageVersion)); + + N(SyntaxKind.ObjectCreationExpression); + { + N(SyntaxKind.NewKeyword); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "S"); + } + N(SyntaxKind.ObjectInitializerExpression); + { + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.SimpleAssignmentExpression); + { + N(SyntaxKind.ImplicitElementAccess); + { + N(SyntaxKind.BracketedArgumentList); + { + N(SyntaxKind.OpenBracketToken); + N(SyntaxKind.Argument); + { + N(SyntaxKind.NumericLiteralExpression); + { + N(SyntaxKind.NumericLiteralToken, "0"); + } + } + N(SyntaxKind.CloseBracketToken); + } + } + N(SyntaxKind.EqualsToken); + N(SyntaxKind.RefExpression); { N(SyntaxKind.RefKeyword); N(SyntaxKind.IdentifierName); @@ -457,5 +646,59 @@ public void ObjectInitializer(LanguageVersion languageVersion) } EOF(); } + + [Theory] + [InlineData(LanguageVersion.CSharp10)] + [InlineData(LanguageVersion.CSharp11)] + public void RefComplexElementInitializer(LanguageVersion languageVersion) + { + string source = "new S { ref { 1, 2 } }"; + UsingExpression(source, TestOptions.Regular.WithLanguageVersion(languageVersion), + // (1,13): error CS1525: Invalid expression term '{' + // new S { ref { 1, 2 } } + Diagnostic(ErrorCode.ERR_InvalidExprTerm, "{").WithArguments("{").WithLocation(1, 13), + // (1,13): error CS1003: Syntax error, ',' expected + // new S { ref { 1, 2 } } + Diagnostic(ErrorCode.ERR_SyntaxError, "{").WithArguments(",").WithLocation(1, 13) + ); + + N(SyntaxKind.ObjectCreationExpression); + { + N(SyntaxKind.NewKeyword); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "S"); + } + N(SyntaxKind.CollectionInitializerExpression); + { + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.RefExpression); + { + N(SyntaxKind.RefKeyword); + M(SyntaxKind.IdentifierName); + { + M(SyntaxKind.IdentifierToken); + } + } + M(SyntaxKind.CommaToken); + N(SyntaxKind.ComplexElementInitializerExpression); + { + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.NumericLiteralExpression); + { + N(SyntaxKind.NumericLiteralToken, "1"); + } + N(SyntaxKind.CommaToken); + N(SyntaxKind.NumericLiteralExpression); + { + N(SyntaxKind.NumericLiteralToken, "2"); + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.CloseBraceToken); + } + } + EOF(); + } } } diff --git a/src/Compilers/CSharp/Test/Syntax/Parsing/RoundTrippingTests.cs b/src/Compilers/CSharp/Test/Syntax/Parsing/RoundTrippingTests.cs index 52fa43128dc55..acd3ae2240809 100644 --- a/src/Compilers/CSharp/Test/Syntax/Parsing/RoundTrippingTests.cs +++ b/src/Compilers/CSharp/Test/Syntax/Parsing/RoundTrippingTests.cs @@ -402,7 +402,8 @@ public partial() public void TestNegBug876575() { var text = @"partial enum E{}"; - ParseAndRoundTripping(text, errorCount: 1); + // ERR_PartialMisplaced is not produced during parsing. + ParseAndRoundTripping(text, errorCount: 0); } [Fact] diff --git a/src/Compilers/CSharp/Test/Syntax/Parsing/ScriptParsingTests.cs b/src/Compilers/CSharp/Test/Syntax/Parsing/ScriptParsingTests.cs index 6f29acb3999dd..17d12a4d447e1 100644 --- a/src/Compilers/CSharp/Test/Syntax/Parsing/ScriptParsingTests.cs +++ b/src/Compilers/CSharp/Test/Syntax/Parsing/ScriptParsingTests.cs @@ -87,7 +87,7 @@ public void Error_NewKeywordUsedAsOperator() new in "; - UsingTree(test).GetDiagnostics().Verify( + UsingTree(test, // (2,5): error CS1526: A new expression requires an argument list or (), [], or {} after type // new in Diagnostic(ErrorCode.ERR_BadNewExpr, "in").WithLocation(2, 5), @@ -184,7 +184,10 @@ void bar() { } [Fact] public void FieldDeclarationError1() { - var tree = UsingTree("int x y;"); + var tree = UsingTree("int x y;", + // (1,7): error CS1002: ; expected + // int x y; + Diagnostic(ErrorCode.ERR_SemicolonExpected, "y").WithLocation(1, 7)); Assert.True(tree.GetCompilationUnitRoot().ContainsDiagnostics); N(SyntaxKind.CompilationUnit); @@ -223,7 +226,10 @@ public void FieldDeclarationError1() [Fact] public void FieldDeclarationError2() { - var tree = UsingTree("int x y z;"); + var tree = UsingTree("int x y z;", + // (1,7): error CS1002: ; expected + // int x y z; + Diagnostic(ErrorCode.ERR_SemicolonExpected, "y").WithLocation(1, 7)); Assert.True(tree.GetCompilationUnitRoot().ContainsDiagnostics); N(SyntaxKind.CompilationUnit); @@ -1034,9 +1040,16 @@ public void NewModifier_PartialClass() [Fact] public void NewModifier_ClassWithMisplacedModifiers1() { - var tree = UsingTree(@" -new partial public class C { } -"); + var source = "new partial public class C { }"; + CreateCompilation(source).VerifyDiagnostics( + // (1,5): error CS0267: The 'partial' modifier can only appear immediately before 'class', 'record', 'struct', 'interface', or a method return type. + // new partial public class C { } + Diagnostic(ErrorCode.ERR_PartialMisplaced, "partial").WithLocation(1, 5), + // (1,26): error CS0106: The modifier 'new' is not valid for this item + // new partial public class C { } + Diagnostic(ErrorCode.ERR_BadMemberFlag, "C").WithArguments("new").WithLocation(1, 26) + ); + var tree = UsingTree(source); N(SyntaxKind.CompilationUnit); { N(SyntaxKind.ClassDeclaration); @@ -1056,9 +1069,15 @@ public void NewModifier_ClassWithMisplacedModifiers1() [Fact] public void NewModifier_ClassWithMisplacedModifiers2() { - var tree = UsingTree(@" -new static partial public class C { } -"); + var source = "new static partial public class C { }"; + CreateCompilation(source).VerifyDiagnostics( + // (1,12): error CS0267: The 'partial' modifier can only appear immediately before 'class', 'record', 'struct', 'interface', or a method return type. + // new static partial public class C { } + Diagnostic(ErrorCode.ERR_PartialMisplaced, "partial").WithLocation(1, 12), + // (1,33): error CS0106: The modifier 'new' is not valid for this item + // new static partial public class C { } + Diagnostic(ErrorCode.ERR_BadMemberFlag, "C").WithArguments("new").WithLocation(1, 33)); + var tree = UsingTree(source); N(SyntaxKind.CompilationUnit); { @@ -1723,7 +1742,10 @@ public void ExternAlias() extern alias Goo(); extern alias Goo { get; } extern alias Goo { get; } -"); +", + // (5,14): error CS7002: Unexpected use of a generic name + // extern alias Goo { get; } + Diagnostic(ErrorCode.ERR_UnexpectedGenericName, "Goo").WithLocation(5, 14)); N(SyntaxKind.CompilationUnit); { @@ -1956,9 +1978,6 @@ public void EnumDeclaration() partial enum @en {}; "; CreateCompilation(test).VerifyDiagnostics( - // (2,1): error CS0267: The 'partial' modifier can only appear immediately before 'class', 'record', 'struct', 'interface', or a method return type. - // partial enum @en {}; - Diagnostic(ErrorCode.ERR_PartialMisplaced, "partial").WithLocation(2, 1), // (2,14): error CS0267: The 'partial' modifier can only appear immediately before 'class', 'record', 'struct', 'interface', or a method return type. // partial enum @en {}; Diagnostic(ErrorCode.ERR_PartialMisplaced, "@en").WithLocation(2, 14)); @@ -2261,7 +2280,10 @@ struct C { } enum C { } [Baz] delegate D(); -"); +", + // (15,11): error CS1001: Identifier expected + // delegate D(); + Diagnostic(ErrorCode.ERR_IdentifierExpected, "(").WithLocation(15, 11)); N(SyntaxKind.CompilationUnit); { @@ -2956,7 +2978,13 @@ public void Ternary_FieldDecl_Semicolon4() [Fact] public void Ternary_FieldDecl_Comma1() { - var tree = UsingTree(@"T ? a,", TestOptions.Script); + var tree = UsingTree(@"T ? a,", TestOptions.Script, + // (1,7): error CS1001: Identifier expected + // T ? a, + Diagnostic(ErrorCode.ERR_IdentifierExpected, "").WithLocation(1, 7), + // (1,7): error CS1002: ; expected + // T ? a, + Diagnostic(ErrorCode.ERR_SemicolonExpected, "").WithLocation(1, 7)); N(SyntaxKind.CompilationUnit); { @@ -2992,7 +3020,13 @@ public void Ternary_FieldDecl_Comma1() [Fact] public void Ternary_FieldDecl_Comma2() { - var tree = UsingTree(@"T ? a = 1,", TestOptions.Script); + var tree = UsingTree(@"T ? a = 1,", TestOptions.Script, + // (1,11): error CS1001: Identifier expected + // T ? a = 1, + Diagnostic(ErrorCode.ERR_IdentifierExpected, "").WithLocation(1, 11), + // (1,11): error CS1002: ; expected + // T ? a = 1, + Diagnostic(ErrorCode.ERR_SemicolonExpected, "").WithLocation(1, 11)); N(SyntaxKind.CompilationUnit); { N(SyntaxKind.FieldDeclaration); @@ -3037,7 +3071,10 @@ public void Ternary_FieldDecl_Comma2() [Fact] public void Ternary_PropertyDecl1() { - var tree = UsingTree(@"T ? a {", TestOptions.Script); + var tree = UsingTree(@"T ? a {", TestOptions.Script, + // (1,8): error CS1513: } expected + // T ? a { + Diagnostic(ErrorCode.ERR_RbraceExpected, "").WithLocation(1, 8)); N(SyntaxKind.CompilationUnit); { N(SyntaxKind.PropertyDeclaration); @@ -3065,7 +3102,10 @@ public void Ternary_PropertyDecl1() [Fact] public void Ternary_PropertyDecl2() { - var tree = UsingTree(@"T ? a.b {", TestOptions.Script); + var tree = UsingTree(@"T ? a.b {", TestOptions.Script, + // (1,10): error CS1513: } expected + // T ? a.b { + Diagnostic(ErrorCode.ERR_RbraceExpected, "").WithLocation(1, 10)); N(SyntaxKind.CompilationUnit); { N(SyntaxKind.PropertyDeclaration); @@ -3101,7 +3141,10 @@ public void Ternary_PropertyDecl2() [Fact] public void Ternary_PropertyDecl3() { - var tree = UsingTree(@"T ? a.b {", TestOptions.Script); + var tree = UsingTree(@"T ? a.b {", TestOptions.Script, + // (1,13): error CS1513: } expected + // T ? a.b { + Diagnostic(ErrorCode.ERR_RbraceExpected, "").WithLocation(1, 13)); N(SyntaxKind.CompilationUnit); { N(SyntaxKind.PropertyDeclaration); @@ -3146,7 +3189,10 @@ public void Ternary_PropertyDecl3() [Fact] public void Ternary_PropertyDecl4() { - var tree = UsingTree(@"T ? a.b.c {", TestOptions.Script); + var tree = UsingTree(@"T ? a.b.c {", TestOptions.Script, + // (1,19): error CS1513: } expected + // T ? a.b.c { + Diagnostic(ErrorCode.ERR_RbraceExpected, "").WithLocation(1, 19)); N(SyntaxKind.CompilationUnit); { N(SyntaxKind.PropertyDeclaration); @@ -3214,7 +3260,10 @@ public void Ternary_PropertyDecl4() [Fact] public void Ternary_MethodDecl1() { - var tree = UsingTree(@"T ? a() {", TestOptions.Script); + var tree = UsingTree(@"T ? a() {", TestOptions.Script, + // (1,10): error CS1513: } expected + // T ? a() { + Diagnostic(ErrorCode.ERR_RbraceExpected, "").WithLocation(1, 10)); N(SyntaxKind.CompilationUnit); { N(SyntaxKind.MethodDeclaration); @@ -3247,7 +3296,19 @@ public void Ternary_MethodDecl1() [Fact] public void Ternary_MethodDecl1_Where() { - var tree = UsingTree(@"T ? a() where", TestOptions.Script); + var tree = UsingTree(@"T ? a() where", TestOptions.Script, + // (1,14): error CS1001: Identifier expected + // T ? a() where + Diagnostic(ErrorCode.ERR_IdentifierExpected, "").WithLocation(1, 14), + // (1,14): error CS1003: Syntax error, ':' expected + // T ? a() where + Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments(":").WithLocation(1, 14), + // (1,14): error CS1031: Type expected + // T ? a() where + Diagnostic(ErrorCode.ERR_TypeExpected, "").WithLocation(1, 14), + // (1,14): error CS1002: ; expected + // T ? a() where + Diagnostic(ErrorCode.ERR_SemicolonExpected, "").WithLocation(1, 14)); N(SyntaxKind.CompilationUnit); { N(SyntaxKind.MethodDeclaration); @@ -3292,7 +3353,13 @@ public void Ternary_MethodDecl1_Where() [Fact] public void Ternary_MethodDecl2() { - var tree = UsingTree(@"T ? a(T b", TestOptions.Script); + var tree = UsingTree(@"T ? a(T b", TestOptions.Script, + // (1,10): error CS1026: ) expected + // T ? a(T b + Diagnostic(ErrorCode.ERR_CloseParenExpected, "").WithLocation(1, 10), + // (1,10): error CS1002: ; expected + // T ? a(T b + Diagnostic(ErrorCode.ERR_SemicolonExpected, "").WithLocation(1, 10)); N(SyntaxKind.CompilationUnit); { N(SyntaxKind.MethodDeclaration); @@ -3329,7 +3396,13 @@ public void Ternary_MethodDecl2() [Fact] public void Ternary_MethodDecl3() { - var tree = UsingTree(@"T ? a.b(T c", TestOptions.Script); + var tree = UsingTree(@"T ? a.b(T c", TestOptions.Script, + // (1,12): error CS1026: ) expected + // T ? a.b(T c + Diagnostic(ErrorCode.ERR_CloseParenExpected, "").WithLocation(1, 12), + // (1,12): error CS1002: ; expected + // T ? a.b(T c + Diagnostic(ErrorCode.ERR_SemicolonExpected, "").WithLocation(1, 12)); N(SyntaxKind.CompilationUnit); { N(SyntaxKind.MethodDeclaration); @@ -3374,7 +3447,13 @@ public void Ternary_MethodDecl3() [Fact] public void Ternary_MethodDecl4() { - var tree = UsingTree(@"T ? a.b(C c", TestOptions.Script); + var tree = UsingTree(@"T ? a.b(C c", TestOptions.Script, + // (1,18): error CS1026: ) expected + // T ? a.b(C c + Diagnostic(ErrorCode.ERR_CloseParenExpected, "").WithLocation(1, 18), + // (1,18): error CS1002: ; expected + // T ? a.b(C c + Diagnostic(ErrorCode.ERR_SemicolonExpected, "").WithLocation(1, 18)); N(SyntaxKind.CompilationUnit); { N(SyntaxKind.MethodDeclaration); @@ -3437,7 +3516,13 @@ public void Ternary_MethodDecl4() [Fact] public void Ternary_MethodDecl5() { - var tree = UsingTree(@"T ? a([Attr]C c", TestOptions.Script); + var tree = UsingTree(@"T ? a([Attr]C c", TestOptions.Script, + // (1,16): error CS1026: ) expected + // T ? a([Attr]C c + Diagnostic(ErrorCode.ERR_CloseParenExpected, "").WithLocation(1, 16), + // (1,16): error CS1002: ; expected + // T ? a([Attr]C c + Diagnostic(ErrorCode.ERR_SemicolonExpected, "").WithLocation(1, 16)); N(SyntaxKind.CompilationUnit); { N(SyntaxKind.MethodDeclaration); @@ -3486,7 +3571,16 @@ public void Ternary_MethodDecl5() [Fact] public void Ternary_MethodDecl6() { - var tree = UsingTree(@"T ? a([Attr(a = b)]c", TestOptions.Script); + var tree = UsingTree(@"T ? a([Attr(a = b)]c", TestOptions.Script, + // (1,21): error CS1001: Identifier expected + // T ? a([Attr(a = b)]c + Diagnostic(ErrorCode.ERR_IdentifierExpected, "").WithLocation(1, 21), + // (1,21): error CS1026: ) expected + // T ? a([Attr(a = b)]c + Diagnostic(ErrorCode.ERR_CloseParenExpected, "").WithLocation(1, 21), + // (1,21): error CS1002: ; expected + // T ? a([Attr(a = b)]c + Diagnostic(ErrorCode.ERR_SemicolonExpected, "").WithLocation(1, 21)); N(SyntaxKind.CompilationUnit); { N(SyntaxKind.MethodDeclaration); @@ -3555,7 +3649,13 @@ public void Ternary_MethodDecl6() [Fact] public void Ternary_MethodDecl7() { - var tree = UsingTree(@"T ? a(out C c", TestOptions.Script); + var tree = UsingTree(@"T ? a(out C c", TestOptions.Script, + // (1,14): error CS1026: ) expected + // T ? a(out C c + Diagnostic(ErrorCode.ERR_CloseParenExpected, "").WithLocation(1, 14), + // (1,14): error CS1002: ; expected + // T ? a(out C c + Diagnostic(ErrorCode.ERR_SemicolonExpected, "").WithLocation(1, 14)); N(SyntaxKind.CompilationUnit); { N(SyntaxKind.MethodDeclaration); @@ -3593,7 +3693,13 @@ public void Ternary_MethodDecl7() [Fact] public void Ternary_MethodDecl8() { - var tree = UsingTree(@"T ? a(C[] a", TestOptions.Script); + var tree = UsingTree(@"T ? a(C[] a", TestOptions.Script, + // (1,12): error CS1026: ) expected + // T ? a(C[] a + Diagnostic(ErrorCode.ERR_CloseParenExpected, "").WithLocation(1, 12), + // (1,12): error CS1002: ; expected + // T ? a(C[] a + Diagnostic(ErrorCode.ERR_SemicolonExpected, "").WithLocation(1, 12)); N(SyntaxKind.CompilationUnit); { N(SyntaxKind.MethodDeclaration); @@ -3642,7 +3748,19 @@ public void Ternary_MethodDecl8() [Fact] public void Ternary_MethodDecl9() { - var tree = UsingTree(@"T ? a(params", TestOptions.Script); + var tree = UsingTree(@"T ? a(params", TestOptions.Script, + // (1,13): error CS1031: Type expected + // T ? a(params + Diagnostic(ErrorCode.ERR_TypeExpected, "").WithLocation(1, 13), + // (1,13): error CS1001: Identifier expected + // T ? a(params + Diagnostic(ErrorCode.ERR_IdentifierExpected, "").WithLocation(1, 13), + // (1,13): error CS1026: ) expected + // T ? a(params + Diagnostic(ErrorCode.ERR_CloseParenExpected, "").WithLocation(1, 13), + // (1,13): error CS1002: ; expected + // T ? a(params + Diagnostic(ErrorCode.ERR_SemicolonExpected, "").WithLocation(1, 13)); N(SyntaxKind.CompilationUnit); { N(SyntaxKind.MethodDeclaration); @@ -3680,7 +3798,13 @@ public void Ternary_MethodDecl9() [Fact] public void Ternary_MethodDecl10() { - var tree = UsingTree(@"T ? a(out T ? b", TestOptions.Script); + var tree = UsingTree(@"T ? a(out T ? b", TestOptions.Script, + // (1,16): error CS1026: ) expected + // T ? a(out T ? b + Diagnostic(ErrorCode.ERR_CloseParenExpected, "").WithLocation(1, 16), + // (1,16): error CS1002: ; expected + // T ? a(out T ? b + Diagnostic(ErrorCode.ERR_SemicolonExpected, "").WithLocation(1, 16)); N(SyntaxKind.CompilationUnit); { N(SyntaxKind.MethodDeclaration); @@ -3722,7 +3846,13 @@ public void Ternary_MethodDecl10() [Fact] public void Ternary_MethodDecl11() { - var tree = UsingTree(@"T ? a(ref T ? b", TestOptions.Script); + var tree = UsingTree(@"T ? a(ref T ? b", TestOptions.Script, + // (1,16): error CS1026: ) expected + // T ? a(ref T ? b + Diagnostic(ErrorCode.ERR_CloseParenExpected, "").WithLocation(1, 16), + // (1,16): error CS1002: ; expected + // T ? a(ref T ? b + Diagnostic(ErrorCode.ERR_SemicolonExpected, "").WithLocation(1, 16)); N(SyntaxKind.CompilationUnit); { N(SyntaxKind.MethodDeclaration); @@ -3764,7 +3894,13 @@ public void Ternary_MethodDecl11() [Fact] public void Ternary_MethodDecl12() { - var tree = UsingTree(@"T ? a(params T ? b", TestOptions.Script); + var tree = UsingTree(@"T ? a(params T ? b", TestOptions.Script, + // (1,19): error CS1026: ) expected + // T ? a(params T ? b + Diagnostic(ErrorCode.ERR_CloseParenExpected, "").WithLocation(1, 19), + // (1,19): error CS1002: ; expected + // T ? a(params T ? b + Diagnostic(ErrorCode.ERR_SemicolonExpected, "").WithLocation(1, 19)); N(SyntaxKind.CompilationUnit); { N(SyntaxKind.MethodDeclaration); @@ -3806,7 +3942,13 @@ public void Ternary_MethodDecl12() [Fact] public void Ternary_MethodDecl13() { - var tree = UsingTree(@"T ? a([Attr]T ? b", TestOptions.Script); + var tree = UsingTree(@"T ? a([Attr]T ? b", TestOptions.Script, + // (1,18): error CS1026: ) expected + // T ? a([Attr]T ? b + Diagnostic(ErrorCode.ERR_CloseParenExpected, "").WithLocation(1, 18), + // (1,18): error CS1002: ; expected + // T ? a([Attr]T ? b + Diagnostic(ErrorCode.ERR_SemicolonExpected, "").WithLocation(1, 18)); N(SyntaxKind.CompilationUnit); { N(SyntaxKind.MethodDeclaration); @@ -3859,7 +4001,19 @@ public void Ternary_MethodDecl13() [Fact] public void Ternary_MethodDecl14A() { - var tree = UsingTree(@"T ? a(T ? b,", TestOptions.Script); + var tree = UsingTree(@"T ? a(T ? b,", TestOptions.Script, + // (1,13): error CS1031: Type expected + // T ? a(T ? b, + Diagnostic(ErrorCode.ERR_TypeExpected, "").WithLocation(1, 13), + // (1,13): error CS1001: Identifier expected + // T ? a(T ? b, + Diagnostic(ErrorCode.ERR_IdentifierExpected, "").WithLocation(1, 13), + // (1,13): error CS1026: ) expected + // T ? a(T ? b, + Diagnostic(ErrorCode.ERR_CloseParenExpected, "").WithLocation(1, 13), + // (1,13): error CS1002: ; expected + // T ? a(T ? b, + Diagnostic(ErrorCode.ERR_SemicolonExpected, "").WithLocation(1, 13)); N(SyntaxKind.CompilationUnit); { N(SyntaxKind.MethodDeclaration); @@ -3909,7 +4063,10 @@ public void Ternary_MethodDecl14A() [Fact] public void Ternary_MethodDecl14B() { - var tree = UsingTree(@"T ? a(T ? b)", TestOptions.Script); + var tree = UsingTree(@"T ? a(T ? b)", TestOptions.Script, + // (1,13): error CS1002: ; expected + // T ? a(T ? b) + Diagnostic(ErrorCode.ERR_SemicolonExpected, "").WithLocation(1, 13)); N(SyntaxKind.CompilationUnit); { N(SyntaxKind.MethodDeclaration); @@ -3950,7 +4107,10 @@ public void Ternary_MethodDecl14B() [Fact] public void Ternary_MethodDecl15() { - var tree = UsingTree(@"T ? a(T c)", TestOptions.Script); + var tree = UsingTree(@"T ? a(T c)", TestOptions.Script, + // (1,11): error CS1002: ; expected + // T ? a(T c) + Diagnostic(ErrorCode.ERR_SemicolonExpected, "").WithLocation(1, 11)); N(SyntaxKind.CompilationUnit); { N(SyntaxKind.MethodDeclaration); @@ -3987,7 +4147,13 @@ public void Ternary_MethodDecl15() [Fact] public void Ternary_MethodDecl16() { - var tree = UsingTree(@"T ? a(this c d", TestOptions.Script); + var tree = UsingTree(@"T ? a(this c d", TestOptions.Script, + // (1,15): error CS1026: ) expected + // T ? a(this c d + Diagnostic(ErrorCode.ERR_CloseParenExpected, "").WithLocation(1, 15), + // (1,15): error CS1002: ; expected + // T ? a(this c d + Diagnostic(ErrorCode.ERR_SemicolonExpected, "").WithLocation(1, 15)); N(SyntaxKind.CompilationUnit); { N(SyntaxKind.MethodDeclaration); @@ -4025,7 +4191,13 @@ public void Ternary_MethodDecl16() [Fact] public void Ternary_MethodDecl17() { - var tree = UsingTree(@"T ? a(ref out T a", TestOptions.Script); + var tree = UsingTree(@"T ? a(ref out T a", TestOptions.Script, + // (1,18): error CS1026: ) expected + // T ? a(ref out T a + Diagnostic(ErrorCode.ERR_CloseParenExpected, "").WithLocation(1, 18), + // (1,18): error CS1002: ; expected + // T ? a(ref out T a + Diagnostic(ErrorCode.ERR_SemicolonExpected, "").WithLocation(1, 18)); N(SyntaxKind.CompilationUnit); { N(SyntaxKind.MethodDeclaration); @@ -4064,7 +4236,13 @@ public void Ternary_MethodDecl17() [Fact] public void Ternary_MethodDecl18() { - var tree = UsingTree(@"T ? a(int a", TestOptions.Script); + var tree = UsingTree(@"T ? a(int a", TestOptions.Script, + // (1,12): error CS1026: ) expected + // T ? a(int a + Diagnostic(ErrorCode.ERR_CloseParenExpected, "").WithLocation(1, 12), + // (1,12): error CS1002: ; expected + // T ? a(int a + Diagnostic(ErrorCode.ERR_SemicolonExpected, "").WithLocation(1, 12)); N(SyntaxKind.CompilationUnit); { N(SyntaxKind.MethodDeclaration); @@ -4101,7 +4279,13 @@ public void Ternary_MethodDecl18() [Fact] public void Ternary_MethodDecl19() { - var tree = UsingTree(@"T ? a(ref int a", TestOptions.Script); + var tree = UsingTree(@"T ? a(ref int a", TestOptions.Script, + // (1,16): error CS1026: ) expected + // T ? a(ref int a + Diagnostic(ErrorCode.ERR_CloseParenExpected, "").WithLocation(1, 16), + // (1,16): error CS1002: ; expected + // T ? a(ref int a + Diagnostic(ErrorCode.ERR_SemicolonExpected, "").WithLocation(1, 16)); N(SyntaxKind.CompilationUnit); { N(SyntaxKind.MethodDeclaration); @@ -4139,7 +4323,16 @@ public void Ternary_MethodDecl19() [Fact] public void Ternary_MethodDecl20() { - var tree = UsingTree(@"T ? a(T a =", TestOptions.Script); + var tree = UsingTree(@"T ? a(T a =", TestOptions.Script, + // (1,12): error CS1733: Expected expression + // T ? a(T a = + Diagnostic(ErrorCode.ERR_ExpressionExpected, "").WithLocation(1, 12), + // (1,12): error CS1026: ) expected + // T ? a(T a = + Diagnostic(ErrorCode.ERR_CloseParenExpected, "").WithLocation(1, 12), + // (1,12): error CS1002: ; expected + // T ? a(T a = + Diagnostic(ErrorCode.ERR_SemicolonExpected, "").WithLocation(1, 12)); N(SyntaxKind.CompilationUnit); { N(SyntaxKind.MethodDeclaration); @@ -4184,7 +4377,13 @@ public void Ternary_MethodDecl20() [Fact] public void Ternary_MethodDecl21() { - var tree = UsingTree(@"T ? a(T[,] a", TestOptions.Script); + var tree = UsingTree(@"T ? a(T[,] a", TestOptions.Script, + // (1,13): error CS1026: ) expected + // T ? a(T[,] a + Diagnostic(ErrorCode.ERR_CloseParenExpected, "").WithLocation(1, 13), + // (1,13): error CS1002: ; expected + // T ? a(T[,] a + Diagnostic(ErrorCode.ERR_SemicolonExpected, "").WithLocation(1, 13)); N(SyntaxKind.CompilationUnit); { N(SyntaxKind.MethodDeclaration); @@ -4238,7 +4437,10 @@ public void Ternary_MethodDecl21() [Fact] public void Ternary_MethodDecl22() { - var tree = UsingTree(@"T ? a(T?[10] a)"); + var tree = UsingTree(@"T ? a(T?[10] a)", + // (1,16): error CS1002: ; expected + // T ? a(T?[10] a) + Diagnostic(ErrorCode.ERR_SemicolonExpected, "").WithLocation(1, 16)); N(SyntaxKind.CompilationUnit); { N(SyntaxKind.MethodDeclaration); @@ -4294,7 +4496,10 @@ public void Ternary_MethodDecl22() [Fact] public void Ternary_MethodDecl_GenericAmbiguity1() { - var tree = UsingTree(@"T ? m(a < b, c > d)", TestOptions.Script); + var tree = UsingTree(@"T ? m(a < b, c > d)", TestOptions.Script, + // (1,20): error CS1002: ; expected + // T ? m(a < b, c > d) + Diagnostic(ErrorCode.ERR_SemicolonExpected, "").WithLocation(1, 20)); N(SyntaxKind.CompilationUnit); { N(SyntaxKind.MethodDeclaration); @@ -4347,7 +4552,13 @@ public void Ternary_MethodDecl_GenericAmbiguity1() [Fact] public void Ternary_Expression1() { - var tree = UsingTree(@"T ? 1", TestOptions.Script); + var tree = UsingTree(@"T ? 1", TestOptions.Script, + // (1,6): error CS1003: Syntax error, ':' expected + // T ? 1 + Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments(":").WithLocation(1, 6), + // (1,6): error CS1733: Expected expression + // T ? 1 + Diagnostic(ErrorCode.ERR_ExpressionExpected, "").WithLocation(1, 6)); N(SyntaxKind.CompilationUnit); { N(SyntaxKind.GlobalStatement); @@ -4382,7 +4593,13 @@ public void Ternary_Expression1() [Fact] public void Ternary_Expression2() { - var tree = UsingTree(@"T ? a", TestOptions.Script); + var tree = UsingTree(@"T ? a", TestOptions.Script, + // (1,6): error CS1003: Syntax error, ':' expected + // T ? a + Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments(":").WithLocation(1, 6), + // (1,6): error CS1733: Expected expression + // T ? a + Diagnostic(ErrorCode.ERR_ExpressionExpected, "").WithLocation(1, 6)); N(SyntaxKind.CompilationUnit); { N(SyntaxKind.GlobalStatement); @@ -4417,7 +4634,16 @@ public void Ternary_Expression2() [Fact] public void Ternary_Expression3() { - var tree = UsingTree(@"T ? a.", TestOptions.Script); + var tree = UsingTree(@"T ? a.", TestOptions.Script, + // (1,7): error CS1001: Identifier expected + // T ? a. + Diagnostic(ErrorCode.ERR_IdentifierExpected, "").WithLocation(1, 7), + // (1,7): error CS1003: Syntax error, ':' expected + // T ? a. + Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments(":").WithLocation(1, 7), + // (1,7): error CS1733: Expected expression + // T ? a. + Diagnostic(ErrorCode.ERR_ExpressionExpected, "").WithLocation(1, 7)); N(SyntaxKind.CompilationUnit); { N(SyntaxKind.GlobalStatement); @@ -4460,7 +4686,16 @@ public void Ternary_Expression3() [Fact] public void Ternary_Expression4() { - var tree = UsingTree(@"T ? a[", TestOptions.Script); + var tree = UsingTree(@"T ? a[", TestOptions.Script, + // (1,7): error CS1003: Syntax error, ']' expected + // T ? a[ + Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments("]").WithLocation(1, 7), + // (1,7): error CS1003: Syntax error, ':' expected + // T ? a[ + Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments(":").WithLocation(1, 7), + // (1,7): error CS1733: Expected expression + // T ? a[ + Diagnostic(ErrorCode.ERR_ExpressionExpected, "").WithLocation(1, 7)); N(SyntaxKind.CompilationUnit); { N(SyntaxKind.GlobalStatement); @@ -4503,7 +4738,16 @@ public void Ternary_Expression4() [Fact] public void Ternary_Expression5() { - var tree = UsingTree(@"T ? a<", TestOptions.Script); + var tree = UsingTree(@"T ? a<", TestOptions.Script, + // (1,7): error CS1733: Expected expression + // T ? a< + Diagnostic(ErrorCode.ERR_ExpressionExpected, "").WithLocation(1, 7), + // (1,7): error CS1003: Syntax error, ':' expected + // T ? a< + Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments(":").WithLocation(1, 7), + // (1,7): error CS1733: Expected expression + // T ? a< + Diagnostic(ErrorCode.ERR_ExpressionExpected, "").WithLocation(1, 7)); N(SyntaxKind.CompilationUnit); { N(SyntaxKind.GlobalStatement); @@ -4546,7 +4790,13 @@ public void Ternary_Expression5() [Fact] public void Ternary_Expression6() { - var tree = UsingTree(@"T ? a", TestOptions.Script); + var tree = UsingTree(@"T ? a", TestOptions.Script, + // (1,9): error CS1003: Syntax error, ':' expected + // T ? a + Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments(":").WithLocation(1, 9), + // (1,9): error CS1733: Expected expression + // T ? a + Diagnostic(ErrorCode.ERR_ExpressionExpected, "").WithLocation(1, 9)); N(SyntaxKind.CompilationUnit); { N(SyntaxKind.GlobalStatement); @@ -4633,7 +4889,13 @@ public void Ternary_Expression7() [Fact] public void Ternary_Expression8() { - var tree = UsingTree(@"T ? a", TestOptions.Script); + var tree = UsingTree(@"T ? a", TestOptions.Script, + // (1,11): error CS1003: Syntax error, ':' expected + // T ? a + Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments(":").WithLocation(1, 11), + // (1,11): error CS1733: Expected expression + // T ? a + Diagnostic(ErrorCode.ERR_ExpressionExpected, "").WithLocation(1, 11)); N(SyntaxKind.CompilationUnit); { N(SyntaxKind.GlobalStatement); @@ -4682,7 +4944,16 @@ public void Ternary_Expression8() [Fact] public void Ternary_Expression9() { - var tree = UsingTree(@"T ? a.", TestOptions.Script); + var tree = UsingTree(@"T ? a.", TestOptions.Script, + // (1,10): error CS1001: Identifier expected + // T ? a. + Diagnostic(ErrorCode.ERR_IdentifierExpected, "").WithLocation(1, 10), + // (1,10): error CS1003: Syntax error, ':' expected + // T ? a. + Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments(":").WithLocation(1, 10), + // (1,10): error CS1733: Expected expression + // T ? a. + Diagnostic(ErrorCode.ERR_ExpressionExpected, "").WithLocation(1, 10)); N(SyntaxKind.CompilationUnit); { N(SyntaxKind.GlobalStatement); @@ -4734,7 +5005,13 @@ public void Ternary_Expression9() [Fact] public void Ternary_Expression10() { - var tree = UsingTree(@"T ? a.c", TestOptions.Script); + var tree = UsingTree(@"T ? a.c", TestOptions.Script, + // (1,11): error CS1003: Syntax error, ':' expected + // T ? a.c + Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments(":").WithLocation(1, 11), + // (1,11): error CS1733: Expected expression + // T ? a.c + Diagnostic(ErrorCode.ERR_ExpressionExpected, "").WithLocation(1, 11)); N(SyntaxKind.CompilationUnit); { N(SyntaxKind.GlobalStatement); @@ -4786,7 +5063,16 @@ public void Ternary_Expression10() [Fact] public void Ternary_Expression11() { - var tree = UsingTree(@"T ? a.c(", TestOptions.Script); + var tree = UsingTree(@"T ? a.c(", TestOptions.Script, + // (1,12): error CS1026: ) expected + // T ? a.c( + Diagnostic(ErrorCode.ERR_CloseParenExpected, "").WithLocation(1, 12), + // (1,12): error CS1003: Syntax error, ':' expected + // T ? a.c( + Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments(":").WithLocation(1, 12), + // (1,12): error CS1733: Expected expression + // T ? a.c( + Diagnostic(ErrorCode.ERR_ExpressionExpected, "").WithLocation(1, 12)); N(SyntaxKind.CompilationUnit); { N(SyntaxKind.GlobalStatement); @@ -4846,7 +5132,16 @@ public void Ternary_Expression11() [Fact] public void Ternary_Expression12() { - var tree = UsingTree(@"T ? a(", TestOptions.Script); + var tree = UsingTree(@"T ? a(", TestOptions.Script, + // (1,7): error CS1026: ) expected + // T ? a( + Diagnostic(ErrorCode.ERR_CloseParenExpected, "").WithLocation(1, 7), + // (1,7): error CS1003: Syntax error, ':' expected + // T ? a( + Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments(":").WithLocation(1, 7), + // (1,7): error CS1733: Expected expression + // T ? a( + Diagnostic(ErrorCode.ERR_ExpressionExpected, "").WithLocation(1, 7)); N(SyntaxKind.CompilationUnit); { N(SyntaxKind.GlobalStatement); @@ -4889,7 +5184,16 @@ public void Ternary_Expression12() [Fact] public void Ternary_Expression13() { - var tree = UsingTree(@"T ? a.b(", TestOptions.Script); + var tree = UsingTree(@"T ? a.b(", TestOptions.Script, + // (1,9): error CS1026: ) expected + // T ? a.b( + Diagnostic(ErrorCode.ERR_CloseParenExpected, "").WithLocation(1, 9), + // (1,9): error CS1003: Syntax error, ':' expected + // T ? a.b( + Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments(":").WithLocation(1, 9), + // (1,9): error CS1733: Expected expression + // T ? a.b( + Diagnostic(ErrorCode.ERR_ExpressionExpected, "").WithLocation(1, 9)); N(SyntaxKind.CompilationUnit); { N(SyntaxKind.GlobalStatement); @@ -4940,7 +5244,16 @@ public void Ternary_Expression13() [Fact] public void Ternary_Expression14() { - var tree = UsingTree(@"T ? m(c", TestOptions.Script); + var tree = UsingTree(@"T ? m(c", TestOptions.Script, + // (1,8): error CS1026: ) expected + // T ? m(c + Diagnostic(ErrorCode.ERR_CloseParenExpected, "").WithLocation(1, 8), + // (1,8): error CS1003: Syntax error, ':' expected + // T ? m(c + Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments(":").WithLocation(1, 8), + // (1,8): error CS1733: Expected expression + // T ? m(c + Diagnostic(ErrorCode.ERR_ExpressionExpected, "").WithLocation(1, 8)); N(SyntaxKind.CompilationUnit); { N(SyntaxKind.GlobalStatement); @@ -4990,7 +5303,19 @@ public void Ternary_Expression14() [Fact] public void Ternary_Expression15() { - var tree = UsingTree(@"T ? m(c,", TestOptions.Script); + var tree = UsingTree(@"T ? m(c,", TestOptions.Script, + // (1,9): error CS1733: Expected expression + // T ? m(c, + Diagnostic(ErrorCode.ERR_ExpressionExpected, "").WithLocation(1, 9), + // (1,9): error CS1026: ) expected + // T ? m(c, + Diagnostic(ErrorCode.ERR_CloseParenExpected, "").WithLocation(1, 9), + // (1,9): error CS1003: Syntax error, ':' expected + // T ? m(c, + Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments(":").WithLocation(1, 9), + // (1,9): error CS1733: Expected expression + // T ? m(c, + Diagnostic(ErrorCode.ERR_ExpressionExpected, "").WithLocation(1, 9)); N(SyntaxKind.CompilationUnit); { N(SyntaxKind.GlobalStatement); @@ -5048,7 +5373,19 @@ public void Ternary_Expression15() [Fact] public void Ternary_Expression16() { - var tree = UsingTree(@"T ? m(c:", TestOptions.Script); + var tree = UsingTree(@"T ? m(c:", TestOptions.Script, + // (1,9): error CS1733: Expected expression + // T ? m(c: + Diagnostic(ErrorCode.ERR_ExpressionExpected, "").WithLocation(1, 9), + // (1,9): error CS1026: ) expected + // T ? m(c: + Diagnostic(ErrorCode.ERR_CloseParenExpected, "").WithLocation(1, 9), + // (1,9): error CS1003: Syntax error, ':' expected + // T ? m(c: + Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments(":").WithLocation(1, 9), + // (1,9): error CS1733: Expected expression + // T ? m(c: + Diagnostic(ErrorCode.ERR_ExpressionExpected, "").WithLocation(1, 9)); N(SyntaxKind.CompilationUnit); { N(SyntaxKind.GlobalStatement); @@ -5106,7 +5443,25 @@ public void Ternary_Expression16() [Fact] public void Ternary_Expression17() { - var tree = UsingTree(@"T ? m(c?", TestOptions.Script); + var tree = UsingTree(@"T ? m(c?", TestOptions.Script, + // (1,9): error CS1733: Expected expression + // T ? m(c? + Diagnostic(ErrorCode.ERR_ExpressionExpected, "").WithLocation(1, 9), + // (1,9): error CS1003: Syntax error, ':' expected + // T ? m(c? + Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments(":").WithLocation(1, 9), + // (1,9): error CS1733: Expected expression + // T ? m(c? + Diagnostic(ErrorCode.ERR_ExpressionExpected, "").WithLocation(1, 9), + // (1,9): error CS1026: ) expected + // T ? m(c? + Diagnostic(ErrorCode.ERR_CloseParenExpected, "").WithLocation(1, 9), + // (1,9): error CS1003: Syntax error, ':' expected + // T ? m(c? + Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments(":").WithLocation(1, 9), + // (1,9): error CS1733: Expected expression + // T ? m(c? + Diagnostic(ErrorCode.ERR_ExpressionExpected, "").WithLocation(1, 9)); N(SyntaxKind.CompilationUnit); { N(SyntaxKind.GlobalStatement); @@ -5169,7 +5524,22 @@ public void Ternary_Expression17() [Fact] public void Ternary_Expression18() { - var tree = UsingTree(@"T ? m(c? a", TestOptions.Script); + var tree = UsingTree(@"T ? m(c? a", TestOptions.Script, + // (1,11): error CS1003: Syntax error, ':' expected + // T ? m(c? a + Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments(":").WithLocation(1, 11), + // (1,11): error CS1733: Expected expression + // T ? m(c? a + Diagnostic(ErrorCode.ERR_ExpressionExpected, "").WithLocation(1, 11), + // (1,11): error CS1026: ) expected + // T ? m(c? a + Diagnostic(ErrorCode.ERR_CloseParenExpected, "").WithLocation(1, 11), + // (1,11): error CS1003: Syntax error, ':' expected + // T ? m(c? a + Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments(":").WithLocation(1, 11), + // (1,11): error CS1733: Expected expression + // T ? m(c? a + Diagnostic(ErrorCode.ERR_ExpressionExpected, "").WithLocation(1, 11)); N(SyntaxKind.CompilationUnit); { N(SyntaxKind.GlobalStatement); @@ -5232,7 +5602,25 @@ public void Ternary_Expression18() [Fact] public void Ternary_Expression19() { - var tree = UsingTree(@"T ? m(c? a =", TestOptions.Script); + var tree = UsingTree(@"T ? m(c? a =", TestOptions.Script, + // (1,13): error CS1733: Expected expression + // T ? m(c? a = + Diagnostic(ErrorCode.ERR_ExpressionExpected, "").WithLocation(1, 13), + // (1,13): error CS1003: Syntax error, ':' expected + // T ? m(c? a = + Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments(":").WithLocation(1, 13), + // (1,13): error CS1733: Expected expression + // T ? m(c? a = + Diagnostic(ErrorCode.ERR_ExpressionExpected, "").WithLocation(1, 13), + // (1,13): error CS1026: ) expected + // T ? m(c? a = + Diagnostic(ErrorCode.ERR_CloseParenExpected, "").WithLocation(1, 13), + // (1,13): error CS1003: Syntax error, ':' expected + // T ? m(c? a = + Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments(":").WithLocation(1, 13), + // (1,13): error CS1733: Expected expression + // T ? m(c? a = + Diagnostic(ErrorCode.ERR_ExpressionExpected, "").WithLocation(1, 13)); N(SyntaxKind.CompilationUnit); { N(SyntaxKind.GlobalStatement); @@ -5303,7 +5691,31 @@ public void Ternary_Expression19() [Fact] public void Ternary_Expression20() { - var tree = UsingTree(@"T ? m(c? a = b ?", TestOptions.Script); + var tree = UsingTree(@"T ? m(c? a = b ?", TestOptions.Script, + // (1,17): error CS1733: Expected expression + // T ? m(c? a = b ? + Diagnostic(ErrorCode.ERR_ExpressionExpected, "").WithLocation(1, 17), + // (1,17): error CS1003: Syntax error, ':' expected + // T ? m(c? a = b ? + Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments(":").WithLocation(1, 17), + // (1,17): error CS1733: Expected expression + // T ? m(c? a = b ? + Diagnostic(ErrorCode.ERR_ExpressionExpected, "").WithLocation(1, 17), + // (1,17): error CS1003: Syntax error, ':' expected + // T ? m(c? a = b ? + Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments(":").WithLocation(1, 17), + // (1,17): error CS1733: Expected expression + // T ? m(c? a = b ? + Diagnostic(ErrorCode.ERR_ExpressionExpected, "").WithLocation(1, 17), + // (1,17): error CS1026: ) expected + // T ? m(c? a = b ? + Diagnostic(ErrorCode.ERR_CloseParenExpected, "").WithLocation(1, 17), + // (1,17): error CS1003: Syntax error, ':' expected + // T ? m(c? a = b ? + Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments(":").WithLocation(1, 17), + // (1,17): error CS1733: Expected expression + // T ? m(c? a = b ? + Diagnostic(ErrorCode.ERR_ExpressionExpected, "").WithLocation(1, 17)); N(SyntaxKind.CompilationUnit); { N(SyntaxKind.GlobalStatement); @@ -5387,7 +5799,13 @@ public void Ternary_Expression20() [Fact] public void Ternary_Expression21() { - var tree = UsingTree(@"T ? m()", TestOptions.Script); + var tree = UsingTree(@"T ? m()", TestOptions.Script, + // (1,8): error CS1003: Syntax error, ':' expected + // T ? m() + Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments(":").WithLocation(1, 8), + // (1,8): error CS1733: Expected expression + // T ? m() + Diagnostic(ErrorCode.ERR_ExpressionExpected, "").WithLocation(1, 8)); N(SyntaxKind.CompilationUnit); { N(SyntaxKind.GlobalStatement); @@ -5430,7 +5848,13 @@ public void Ternary_Expression21() [Fact] public void Ternary_Expression22() { - var tree = UsingTree(@"T ? m(a)", TestOptions.Script); + var tree = UsingTree(@"T ? m(a)", TestOptions.Script, + // (1,9): error CS1003: Syntax error, ':' expected + // T ? m(a) + Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments(":").WithLocation(1, 9), + // (1,9): error CS1733: Expected expression + // T ? m(a) + Diagnostic(ErrorCode.ERR_ExpressionExpected, "").WithLocation(1, 9)); N(SyntaxKind.CompilationUnit); { N(SyntaxKind.GlobalStatement); @@ -5480,7 +5904,13 @@ public void Ternary_Expression22() [Fact] public void Ternary_Expression23() { - var tree = UsingTree(@"T ? m();", TestOptions.Script); + var tree = UsingTree(@"T ? m();", TestOptions.Script, + // (1,8): error CS1003: Syntax error, ':' expected + // T ? m(); + Diagnostic(ErrorCode.ERR_SyntaxError, ";").WithArguments(":").WithLocation(1, 8), + // (1,8): error CS1525: Invalid expression term ';' + // T ? m(); + Diagnostic(ErrorCode.ERR_InvalidExprTerm, ";").WithArguments(";").WithLocation(1, 8)); N(SyntaxKind.CompilationUnit); { N(SyntaxKind.GlobalStatement); @@ -5523,7 +5953,13 @@ public void Ternary_Expression23() [Fact] public void Ternary_Expression24() { - var tree = UsingTree(@"T ? m(a);", TestOptions.Script); + var tree = UsingTree(@"T ? m(a);", TestOptions.Script, + // (1,9): error CS1003: Syntax error, ':' expected + // T ? m(a); + Diagnostic(ErrorCode.ERR_SyntaxError, ";").WithArguments(":").WithLocation(1, 9), + // (1,9): error CS1525: Invalid expression term ';' + // T ? m(a); + Diagnostic(ErrorCode.ERR_InvalidExprTerm, ";").WithArguments(";").WithLocation(1, 9)); N(SyntaxKind.CompilationUnit); { N(SyntaxKind.GlobalStatement); @@ -5573,7 +6009,16 @@ public void Ternary_Expression24() [Fact] public void Ternary_Expression25() { - var tree = UsingTree(@"T ? m(x: 1", TestOptions.Script); + var tree = UsingTree(@"T ? m(x: 1", TestOptions.Script, + // (1,11): error CS1026: ) expected + // T ? m(x: 1 + Diagnostic(ErrorCode.ERR_CloseParenExpected, "").WithLocation(1, 11), + // (1,11): error CS1003: Syntax error, ':' expected + // T ? m(x: 1 + Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments(":").WithLocation(1, 11), + // (1,11): error CS1733: Expected expression + // T ? m(x: 1 + Diagnostic(ErrorCode.ERR_ExpressionExpected, "").WithLocation(1, 11)); N(SyntaxKind.CompilationUnit); { N(SyntaxKind.GlobalStatement); @@ -5631,7 +6076,13 @@ public void Ternary_Expression25() [Fact] public void Ternary_Expression26() { - var tree = UsingTree(@"T ? m(x: 1, y: a ? b : c)", TestOptions.Script); + var tree = UsingTree(@"T ? m(x: 1, y: a ? b : c)", TestOptions.Script, + // (1,26): error CS1003: Syntax error, ':' expected + // T ? m(x: 1, y: a ? b : c) + Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments(":").WithLocation(1, 26), + // (1,26): error CS1733: Expected expression + // T ? m(x: 1, y: a ? b : c) + Diagnostic(ErrorCode.ERR_ExpressionExpected, "").WithLocation(1, 26)); N(SyntaxKind.CompilationUnit); { N(SyntaxKind.GlobalStatement); @@ -5871,7 +6322,22 @@ public void Ternary_Expression28() [Fact] public void Ternary_Expression30() { - var tree = UsingTree(@"T ? a ?", TestOptions.Script); + var tree = UsingTree(@"T ? a ?", TestOptions.Script, + // (1,8): error CS1733: Expected expression + // T ? a ? + Diagnostic(ErrorCode.ERR_ExpressionExpected, "").WithLocation(1, 8), + // (1,8): error CS1003: Syntax error, ':' expected + // T ? a ? + Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments(":").WithLocation(1, 8), + // (1,8): error CS1733: Expected expression + // T ? a ? + Diagnostic(ErrorCode.ERR_ExpressionExpected, "").WithLocation(1, 8), + // (1,8): error CS1003: Syntax error, ':' expected + // T ? a ? + Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments(":").WithLocation(1, 8), + // (1,8): error CS1733: Expected expression + // T ? a ? + Diagnostic(ErrorCode.ERR_ExpressionExpected, "").WithLocation(1, 8)); N(SyntaxKind.CompilationUnit); { N(SyntaxKind.GlobalStatement); @@ -5919,7 +6385,16 @@ public void Ternary_Expression30() [Fact] public void Ternary_Expression31() { - var tree = UsingTree(@"T ? a =", TestOptions.Script); + var tree = UsingTree(@"T ? a =", TestOptions.Script, + // (1,8): error CS1733: Expected expression + // T ? a = + Diagnostic(ErrorCode.ERR_ExpressionExpected, "").WithLocation(1, 8), + // (1,8): error CS1003: Syntax error, ':' expected + // T ? a = + Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments(":").WithLocation(1, 8), + // (1,8): error CS1733: Expected expression + // T ? a = + Diagnostic(ErrorCode.ERR_ExpressionExpected, "").WithLocation(1, 8)); N(SyntaxKind.CompilationUnit); { N(SyntaxKind.GlobalStatement); @@ -5962,7 +6437,13 @@ public void Ternary_Expression31() [Fact] public void Ternary_Expression32() { - var tree = UsingTree(@"T ? a = b", TestOptions.Script); + var tree = UsingTree(@"T ? a = b", TestOptions.Script, + // (1,10): error CS1003: Syntax error, ':' expected + // T ? a = b + Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments(":").WithLocation(1, 10), + // (1,10): error CS1733: Expected expression + // T ? a = b + Diagnostic(ErrorCode.ERR_ExpressionExpected, "").WithLocation(1, 10)); N(SyntaxKind.CompilationUnit); { N(SyntaxKind.GlobalStatement); @@ -6005,7 +6486,10 @@ public void Ternary_Expression32() [Fact] public void Ternary_Expression33() { - var tree = UsingTree(@"T ? a = b : ", TestOptions.Script); + var tree = UsingTree(@"T ? a = b : ", TestOptions.Script, + // (1,13): error CS1733: Expected expression + // T ? a = b : + Diagnostic(ErrorCode.ERR_ExpressionExpected, "").WithLocation(1, 13)); N(SyntaxKind.CompilationUnit); { N(SyntaxKind.GlobalStatement); @@ -6048,7 +6532,16 @@ public void Ternary_Expression33() [Fact] public void Ternary_Expression34() { - var tree = UsingTree(@"T ? m(out c", TestOptions.Script); + var tree = UsingTree(@"T ? m(out c", TestOptions.Script, + // (1,12): error CS1026: ) expected + // T ? m(out c + Diagnostic(ErrorCode.ERR_CloseParenExpected, "").WithLocation(1, 12), + // (1,12): error CS1003: Syntax error, ':' expected + // T ? m(out c + Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments(":").WithLocation(1, 12), + // (1,12): error CS1733: Expected expression + // T ? m(out c + Diagnostic(ErrorCode.ERR_ExpressionExpected, "").WithLocation(1, 12)); N(SyntaxKind.CompilationUnit); { N(SyntaxKind.GlobalStatement); @@ -6099,7 +6592,16 @@ public void Ternary_Expression34() [Fact] public void Ternary_Expression35() { - var tree = UsingTree(@"T ? m(ref c", TestOptions.Script); + var tree = UsingTree(@"T ? m(ref c", TestOptions.Script, + // (1,12): error CS1026: ) expected + // T ? m(ref c + Diagnostic(ErrorCode.ERR_CloseParenExpected, "").WithLocation(1, 12), + // (1,12): error CS1003: Syntax error, ':' expected + // T ? m(ref c + Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments(":").WithLocation(1, 12), + // (1,12): error CS1733: Expected expression + // T ? m(ref c + Diagnostic(ErrorCode.ERR_ExpressionExpected, "").WithLocation(1, 12)); N(SyntaxKind.CompilationUnit); { N(SyntaxKind.GlobalStatement); @@ -6150,7 +6652,25 @@ public void Ternary_Expression35() [Fact] public void Ternary_Expression36() { - var tree = UsingTree(@"T ? m(ref out", TestOptions.Script); + var tree = UsingTree(@"T ? m(ref out", TestOptions.Script, + // (1,11): error CS1525: Invalid expression term 'out' + // T ? m(ref out + Diagnostic(ErrorCode.ERR_InvalidExprTerm, "out").WithArguments("out").WithLocation(1, 11), + // (1,11): error CS1003: Syntax error, ',' expected + // T ? m(ref out + Diagnostic(ErrorCode.ERR_SyntaxError, "out").WithArguments(",").WithLocation(1, 11), + // (1,14): error CS1733: Expected expression + // T ? m(ref out + Diagnostic(ErrorCode.ERR_ExpressionExpected, "").WithLocation(1, 14), + // (1,14): error CS1026: ) expected + // T ? m(ref out + Diagnostic(ErrorCode.ERR_CloseParenExpected, "").WithLocation(1, 14), + // (1,14): error CS1003: Syntax error, ':' expected + // T ? m(ref out + Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments(":").WithLocation(1, 14), + // (1,14): error CS1733: Expected expression + // T ? m(ref out + Diagnostic(ErrorCode.ERR_ExpressionExpected, "").WithLocation(1, 14)); N(SyntaxKind.CompilationUnit); { N(SyntaxKind.GlobalStatement); @@ -6210,7 +6730,22 @@ public void Ternary_Expression36() [Fact] public void Ternary_Expression37() { - var tree = UsingTree(@"T ? m(ref out c", TestOptions.Script); + var tree = UsingTree(@"T ? m(ref out c", TestOptions.Script, + // (1,11): error CS1525: Invalid expression term 'out' + // T ? m(ref out c + Diagnostic(ErrorCode.ERR_InvalidExprTerm, "out").WithArguments("out").WithLocation(1, 11), + // (1,11): error CS1003: Syntax error, ',' expected + // T ? m(ref out c + Diagnostic(ErrorCode.ERR_SyntaxError, "out").WithArguments(",").WithLocation(1, 11), + // (1,16): error CS1026: ) expected + // T ? m(ref out c + Diagnostic(ErrorCode.ERR_CloseParenExpected, "").WithLocation(1, 16), + // (1,16): error CS1003: Syntax error, ':' expected + // T ? m(ref out c + Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments(":").WithLocation(1, 16), + // (1,16): error CS1733: Expected expression + // T ? m(ref out c + Diagnostic(ErrorCode.ERR_ExpressionExpected, "").WithLocation(1, 16)); N(SyntaxKind.CompilationUnit); { N(SyntaxKind.GlobalStatement); @@ -6270,7 +6805,16 @@ public void Ternary_Expression37() [Fact] public void Ternary_Expression38() { - var tree = UsingTree(@"T ? m(this", TestOptions.Script); + var tree = UsingTree(@"T ? m(this", TestOptions.Script, + // (1,11): error CS1026: ) expected + // T ? m(this + Diagnostic(ErrorCode.ERR_CloseParenExpected, "").WithLocation(1, 11), + // (1,11): error CS1003: Syntax error, ':' expected + // T ? m(this + Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments(":").WithLocation(1, 11), + // (1,11): error CS1733: Expected expression + // T ? m(this + Diagnostic(ErrorCode.ERR_ExpressionExpected, "").WithLocation(1, 11)); N(SyntaxKind.CompilationUnit); { N(SyntaxKind.GlobalStatement); @@ -6320,7 +6864,19 @@ public void Ternary_Expression38() [Fact] public void Ternary_Expression39() { - var tree = UsingTree(@"T ? m(this.", TestOptions.Script); + var tree = UsingTree(@"T ? m(this.", TestOptions.Script, + // (1,12): error CS1001: Identifier expected + // T ? m(this. + Diagnostic(ErrorCode.ERR_IdentifierExpected, "").WithLocation(1, 12), + // (1,12): error CS1026: ) expected + // T ? m(this. + Diagnostic(ErrorCode.ERR_CloseParenExpected, "").WithLocation(1, 12), + // (1,12): error CS1003: Syntax error, ':' expected + // T ? m(this. + Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments(":").WithLocation(1, 12), + // (1,12): error CS1733: Expected expression + // T ? m(this. + Diagnostic(ErrorCode.ERR_ExpressionExpected, "").WithLocation(1, 12)); N(SyntaxKind.CompilationUnit); { N(SyntaxKind.GlobalStatement); @@ -6378,7 +6934,19 @@ public void Ternary_Expression39() [Fact] public void Ternary_Expression40() { - var tree = UsingTree(@"T ? m(this<", TestOptions.Script); + var tree = UsingTree(@"T ? m(this<", TestOptions.Script, + // (1,12): error CS1733: Expected expression + // T ? m(this< + Diagnostic(ErrorCode.ERR_ExpressionExpected, "").WithLocation(1, 12), + // (1,12): error CS1026: ) expected + // T ? m(this< + Diagnostic(ErrorCode.ERR_CloseParenExpected, "").WithLocation(1, 12), + // (1,12): error CS1003: Syntax error, ':' expected + // T ? m(this< + Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments(":").WithLocation(1, 12), + // (1,12): error CS1733: Expected expression + // T ? m(this< + Diagnostic(ErrorCode.ERR_ExpressionExpected, "").WithLocation(1, 12)); N(SyntaxKind.CompilationUnit); { N(SyntaxKind.GlobalStatement); @@ -6436,7 +7004,19 @@ public void Ternary_Expression40() [Fact] public void Ternary_Expression41() { - var tree = UsingTree(@"T ? m(this[", TestOptions.Script); + var tree = UsingTree(@"T ? m(this[", TestOptions.Script, + // (1,12): error CS1003: Syntax error, ']' expected + // T ? m(this[ + Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments("]").WithLocation(1, 12), + // (1,12): error CS1026: ) expected + // T ? m(this[ + Diagnostic(ErrorCode.ERR_CloseParenExpected, "").WithLocation(1, 12), + // (1,12): error CS1003: Syntax error, ':' expected + // T ? m(this[ + Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments(":").WithLocation(1, 12), + // (1,12): error CS1733: Expected expression + // T ? m(this[ + Diagnostic(ErrorCode.ERR_ExpressionExpected, "").WithLocation(1, 12)); N(SyntaxKind.CompilationUnit); { N(SyntaxKind.GlobalStatement); @@ -6494,7 +7074,19 @@ public void Ternary_Expression41() [Fact] public void Ternary_Expression41A() { - var tree = UsingTree(@"T ? m(this a", TestOptions.Script); + var tree = UsingTree(@"T ? m(this a", TestOptions.Script, + // (1,12): error CS1003: Syntax error, ',' expected + // T ? m(this a + Diagnostic(ErrorCode.ERR_SyntaxError, "a").WithArguments(",").WithLocation(1, 12), + // (1,13): error CS1026: ) expected + // T ? m(this a + Diagnostic(ErrorCode.ERR_CloseParenExpected, "").WithLocation(1, 13), + // (1,13): error CS1003: Syntax error, ':' expected + // T ? m(this a + Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments(":").WithLocation(1, 13), + // (1,13): error CS1733: Expected expression + // T ? m(this a + Diagnostic(ErrorCode.ERR_ExpressionExpected, "").WithLocation(1, 13)); N(SyntaxKind.CompilationUnit); { N(SyntaxKind.GlobalStatement); @@ -6552,7 +7144,19 @@ public void Ternary_Expression41A() [Fact] public void Ternary_Expression42() { - var tree = UsingTree(@"T ? m(this(", TestOptions.Script); + var tree = UsingTree(@"T ? m(this(", TestOptions.Script, + // (1,12): error CS1026: ) expected + // T ? m(this( + Diagnostic(ErrorCode.ERR_CloseParenExpected, "").WithLocation(1, 12), + // (1,12): error CS1026: ) expected + // T ? m(this( + Diagnostic(ErrorCode.ERR_CloseParenExpected, "").WithLocation(1, 12), + // (1,12): error CS1003: Syntax error, ':' expected + // T ? m(this( + Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments(":").WithLocation(1, 12), + // (1,12): error CS1733: Expected expression + // T ? m(this( + Diagnostic(ErrorCode.ERR_ExpressionExpected, "").WithLocation(1, 12)); N(SyntaxKind.CompilationUnit); { N(SyntaxKind.GlobalStatement); @@ -6610,7 +7214,19 @@ public void Ternary_Expression42() [Fact] public void Ternary_Expression43() { - var tree = UsingTree(@"T ? m(T[", TestOptions.Script); + var tree = UsingTree(@"T ? m(T[", TestOptions.Script, + // (1,9): error CS1003: Syntax error, ']' expected + // T ? m(T[ + Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments("]").WithLocation(1, 9), + // (1,9): error CS1026: ) expected + // T ? m(T[ + Diagnostic(ErrorCode.ERR_CloseParenExpected, "").WithLocation(1, 9), + // (1,9): error CS1003: Syntax error, ':' expected + // T ? m(T[ + Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments(":").WithLocation(1, 9), + // (1,9): error CS1733: Expected expression + // T ? m(T[ + Diagnostic(ErrorCode.ERR_ExpressionExpected, "").WithLocation(1, 9)); N(SyntaxKind.CompilationUnit); { N(SyntaxKind.GlobalStatement); @@ -6668,7 +7284,19 @@ public void Ternary_Expression43() [Fact] public void Ternary_Expression44() { - var tree = UsingTree(@"T ? m(T[1", TestOptions.Script); + var tree = UsingTree(@"T ? m(T[1", TestOptions.Script, + // (1,10): error CS1003: Syntax error, ']' expected + // T ? m(T[1 + Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments("]").WithLocation(1, 10), + // (1,10): error CS1026: ) expected + // T ? m(T[1 + Diagnostic(ErrorCode.ERR_CloseParenExpected, "").WithLocation(1, 10), + // (1,10): error CS1003: Syntax error, ':' expected + // T ? m(T[1 + Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments(":").WithLocation(1, 10), + // (1,10): error CS1733: Expected expression + // T ? m(T[1 + Diagnostic(ErrorCode.ERR_ExpressionExpected, "").WithLocation(1, 10)); N(SyntaxKind.CompilationUnit); { N(SyntaxKind.GlobalStatement); @@ -6733,7 +7361,16 @@ public void Ternary_Expression44() [Fact] public void Ternary_Expression45() { - var tree = UsingTree(@"T ? m(T[1]", TestOptions.Script); + var tree = UsingTree(@"T ? m(T[1]", TestOptions.Script, + // (1,11): error CS1026: ) expected + // T ? m(T[1] + Diagnostic(ErrorCode.ERR_CloseParenExpected, "").WithLocation(1, 11), + // (1,11): error CS1003: Syntax error, ':' expected + // T ? m(T[1] + Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments(":").WithLocation(1, 11), + // (1,11): error CS1733: Expected expression + // T ? m(T[1] + Diagnostic(ErrorCode.ERR_ExpressionExpected, "").WithLocation(1, 11)); N(SyntaxKind.CompilationUnit); { N(SyntaxKind.GlobalStatement); @@ -6798,7 +7435,25 @@ public void Ternary_Expression45() [Fact] public void Ternary_MethodDecl46() { - var tree = UsingTree(@"T ? a(T ? a =", TestOptions.Script); + var tree = UsingTree(@"T ? a(T ? a =", TestOptions.Script, + // (1,14): error CS1733: Expected expression + // T ? a(T ? a = + Diagnostic(ErrorCode.ERR_ExpressionExpected, "").WithLocation(1, 14), + // (1,14): error CS1003: Syntax error, ':' expected + // T ? a(T ? a = + Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments(":").WithLocation(1, 14), + // (1,14): error CS1733: Expected expression + // T ? a(T ? a = + Diagnostic(ErrorCode.ERR_ExpressionExpected, "").WithLocation(1, 14), + // (1,14): error CS1026: ) expected + // T ? a(T ? a = + Diagnostic(ErrorCode.ERR_CloseParenExpected, "").WithLocation(1, 14), + // (1,14): error CS1003: Syntax error, ':' expected + // T ? a(T ? a = + Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments(":").WithLocation(1, 14), + // (1,14): error CS1733: Expected expression + // T ? a(T ? a = + Diagnostic(ErrorCode.ERR_ExpressionExpected, "").WithLocation(1, 14)); N(SyntaxKind.CompilationUnit); { N(SyntaxKind.GlobalStatement); @@ -6869,7 +7524,13 @@ public void Ternary_MethodDecl46() [Fact] public void Ternary_Expression47() { - var tree = UsingTree(@"T ? a(T)", TestOptions.Script); + var tree = UsingTree(@"T ? a(T)", TestOptions.Script, + // (1,9): error CS1003: Syntax error, ':' expected + // T ? a(T) + Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments(":").WithLocation(1, 9), + // (1,9): error CS1733: Expected expression + // T ? a(T) + Diagnostic(ErrorCode.ERR_ExpressionExpected, "").WithLocation(1, 9)); N(SyntaxKind.CompilationUnit); { N(SyntaxKind.GlobalStatement); @@ -6919,7 +7580,13 @@ public void Ternary_Expression47() [Fact] public void Ternary_Expression48() { - var tree = UsingTree(@"T ? a(ref int.MaxValue)", TestOptions.Script); + var tree = UsingTree(@"T ? a(ref int.MaxValue)", TestOptions.Script, + // (1,24): error CS1003: Syntax error, ':' expected + // T ? a(ref int.MaxValue) + Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments(":").WithLocation(1, 24), + // (1,24): error CS1733: Expected expression + // T ? a(ref int.MaxValue) + Diagnostic(ErrorCode.ERR_ExpressionExpected, "").WithLocation(1, 24)); N(SyntaxKind.CompilationUnit); { N(SyntaxKind.GlobalStatement); @@ -6978,7 +7645,19 @@ public void Ternary_Expression48() [Fact] public void Ternary_Expression49() { - var tree = UsingTree(@"T ? a(ref a,", TestOptions.Script); + var tree = UsingTree(@"T ? a(ref a,", TestOptions.Script, + // (1,13): error CS1733: Expected expression + // T ? a(ref a, + Diagnostic(ErrorCode.ERR_ExpressionExpected, "").WithLocation(1, 13), + // (1,13): error CS1026: ) expected + // T ? a(ref a, + Diagnostic(ErrorCode.ERR_CloseParenExpected, "").WithLocation(1, 13), + // (1,13): error CS1003: Syntax error, ':' expected + // T ? a(ref a, + Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments(":").WithLocation(1, 13), + // (1,13): error CS1733: Expected expression + // T ? a(ref a, + Diagnostic(ErrorCode.ERR_ExpressionExpected, "").WithLocation(1, 13)); N(SyntaxKind.CompilationUnit); { N(SyntaxKind.GlobalStatement); @@ -7037,7 +7716,22 @@ public void Ternary_Expression49() [Fact] public void Ternary_Expression50() { - var tree = UsingTree(@"T ? a(,", TestOptions.Script); + var tree = UsingTree(@"T ? a(,", TestOptions.Script, + // (1,7): error CS0839: Argument missing + // T ? a(, + Diagnostic(ErrorCode.ERR_MissingArgument, ",").WithLocation(1, 7), + // (1,8): error CS1733: Expected expression + // T ? a(, + Diagnostic(ErrorCode.ERR_ExpressionExpected, "").WithLocation(1, 8), + // (1,8): error CS1026: ) expected + // T ? a(, + Diagnostic(ErrorCode.ERR_CloseParenExpected, "").WithLocation(1, 8), + // (1,8): error CS1003: Syntax error, ':' expected + // T ? a(, + Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments(":").WithLocation(1, 8), + // (1,8): error CS1733: Expected expression + // T ? a(, + Diagnostic(ErrorCode.ERR_ExpressionExpected, "").WithLocation(1, 8)); N(SyntaxKind.CompilationUnit); { N(SyntaxKind.GlobalStatement); @@ -7095,7 +7789,13 @@ public void Ternary_Expression50() [Fact] public void Ternary_Expression51() { - var tree = UsingTree(@"T ? a(T ? b[1] : b[2])", TestOptions.Script); + var tree = UsingTree(@"T ? a(T ? b[1] : b[2])", TestOptions.Script, + // (1,23): error CS1003: Syntax error, ':' expected + // T ? a(T ? b[1] : b[2]) + Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments(":").WithLocation(1, 23), + // (1,23): error CS1733: Expected expression + // T ? a(T ? b[1] : b[2]) + Diagnostic(ErrorCode.ERR_ExpressionExpected, "").WithLocation(1, 23)); N(SyntaxKind.CompilationUnit); { N(SyntaxKind.GlobalStatement); @@ -7190,7 +7890,13 @@ public void Ternary_Expression52() { var tree = UsingTree(@" T ? f(a ? b : c) -"); +", + // (2,17): error CS1003: Syntax error, ':' expected + // T ? f(a ? b : c) + Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments(":").WithLocation(2, 17), + // (2,17): error CS1733: Expected expression + // T ? f(a ? b : c) + Diagnostic(ErrorCode.ERR_ExpressionExpected, "").WithLocation(2, 17)); N(SyntaxKind.CompilationUnit); { N(SyntaxKind.GlobalStatement); @@ -7256,7 +7962,10 @@ public void Ternary_Expression52() [Fact] public void Ternary_Expression_GenericAmbiguity1() { - var tree = UsingTree(@"T ? m(a < b, c > d) :", TestOptions.Script); + var tree = UsingTree(@"T ? m(a < b, c > d) :", TestOptions.Script, + // (1,22): error CS1733: Expected expression + // T ? m(a < b, c > d) : + Diagnostic(ErrorCode.ERR_ExpressionExpected, "").WithLocation(1, 22)); N(SyntaxKind.CompilationUnit); { N(SyntaxKind.GlobalStatement); @@ -7363,7 +8072,13 @@ public void Ternary_WithQuery_Expression1() { var tree = UsingTree(@" T ? from -"); +", + // (2,9): error CS1003: Syntax error, ':' expected + // T ? from + Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments(":").WithLocation(2, 9), + // (2,9): error CS1733: Expected expression + // T ? from + Diagnostic(ErrorCode.ERR_ExpressionExpected, "").WithLocation(2, 9)); N(SyntaxKind.CompilationUnit); { N(SyntaxKind.GlobalStatement); @@ -7400,7 +8115,25 @@ public void Ternary_WithQuery_Expression2() { var tree = UsingTree(@" T ? from x -"); +", + // (2,11): error CS1001: Identifier expected + // T ? from x + Diagnostic(ErrorCode.ERR_IdentifierExpected, "").WithLocation(2, 11), + // (2,11): error CS1003: Syntax error, 'in' expected + // T ? from x + Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments("in").WithLocation(2, 11), + // (2,11): error CS1733: Expected expression + // T ? from x + Diagnostic(ErrorCode.ERR_ExpressionExpected, "").WithLocation(2, 11), + // (2,11): error CS0742: A query body must end with a select clause or a group clause + // T ? from x + Diagnostic(ErrorCode.ERR_ExpectedSelectOrGroup, "").WithLocation(2, 11), + // (2,11): error CS1003: Syntax error, ':' expected + // T ? from x + Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments(":").WithLocation(2, 11), + // (2,11): error CS1733: Expected expression + // T ? from x + Diagnostic(ErrorCode.ERR_ExpressionExpected, "").WithLocation(2, 11)); N(SyntaxKind.CompilationUnit); { N(SyntaxKind.GlobalStatement); @@ -7461,7 +8194,16 @@ public void Ternary_WithQuery_Expression3() { var tree = UsingTree(@" T ? f(from -"); +", + // (2,11): error CS1026: ) expected + // T ? f(from + Diagnostic(ErrorCode.ERR_CloseParenExpected, "").WithLocation(2, 11), + // (2,11): error CS1003: Syntax error, ':' expected + // T ? f(from + Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments(":").WithLocation(2, 11), + // (2,11): error CS1733: Expected expression + // T ? f(from + Diagnostic(ErrorCode.ERR_ExpressionExpected, "").WithLocation(2, 11)); N(SyntaxKind.CompilationUnit); { N(SyntaxKind.GlobalStatement); @@ -7516,7 +8258,28 @@ public void Ternary_WithQuery_Expression4() { var tree = UsingTree(@" T ? f(from x -"); +", + // (2,13): error CS1001: Identifier expected + // T ? f(from x + Diagnostic(ErrorCode.ERR_IdentifierExpected, "").WithLocation(2, 13), + // (2,13): error CS1003: Syntax error, 'in' expected + // T ? f(from x + Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments("in").WithLocation(2, 13), + // (2,13): error CS1733: Expected expression + // T ? f(from x + Diagnostic(ErrorCode.ERR_ExpressionExpected, "").WithLocation(2, 13), + // (2,13): error CS0742: A query body must end with a select clause or a group clause + // T ? f(from x + Diagnostic(ErrorCode.ERR_ExpectedSelectOrGroup, "").WithLocation(2, 13), + // (2,13): error CS1026: ) expected + // T ? f(from x + Diagnostic(ErrorCode.ERR_CloseParenExpected, "").WithLocation(2, 13), + // (2,13): error CS1003: Syntax error, ':' expected + // T ? f(from x + Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments(":").WithLocation(2, 13), + // (2,13): error CS1733: Expected expression + // T ? f(from x + Diagnostic(ErrorCode.ERR_ExpressionExpected, "").WithLocation(2, 13)); N(SyntaxKind.CompilationUnit); { N(SyntaxKind.GlobalStatement); @@ -7616,7 +8379,10 @@ public void From_Identifier() [Fact] public void From_FieldDecl() { - var tree = UsingTree(@"from c", TestOptions.Script); + var tree = UsingTree(@"from c", TestOptions.Script, + // (1,7): error CS1002: ; expected + // from c + Diagnostic(ErrorCode.ERR_SemicolonExpected, "").WithLocation(1, 7)); N(SyntaxKind.CompilationUnit); { @@ -7642,7 +8408,13 @@ public void From_FieldDecl() [Fact] public void From_FieldDecl2() { - var tree = UsingTree(@"from x,"); + var tree = UsingTree(@"from x,", + // (1,8): error CS1001: Identifier expected + // from x, + Diagnostic(ErrorCode.ERR_IdentifierExpected, "").WithLocation(1, 8), + // (1,8): error CS1002: ; expected + // from x, + Diagnostic(ErrorCode.ERR_SemicolonExpected, "").WithLocation(1, 8)); N(SyntaxKind.CompilationUnit); { @@ -7700,7 +8472,13 @@ public void From_FieldDecl3() [Fact] public void From_FieldDecl4() { - var tree = UsingTree(@"from x ="); + var tree = UsingTree(@"from x =", + // (1,9): error CS1733: Expected expression + // from x = + Diagnostic(ErrorCode.ERR_ExpressionExpected, "").WithLocation(1, 9), + // (1,9): error CS1002: ; expected + // from x = + Diagnostic(ErrorCode.ERR_SemicolonExpected, "").WithLocation(1, 9)); N(SyntaxKind.CompilationUnit); { @@ -7735,7 +8513,16 @@ public void From_FieldDecl4() [Fact] public void From_FieldDecl5() { - var tree = UsingTree(@"from x["); + var tree = UsingTree(@"from x[", + // (1,7): error CS0650: Bad array declarator: To declare a managed array the rank specifier precedes the variable's identifier. To declare a fixed size buffer field, use the fixed keyword before the field type. + // from x[ + Diagnostic(ErrorCode.ERR_CStyleArray, "[").WithLocation(1, 7), + // (1,8): error CS1003: Syntax error, ']' expected + // from x[ + Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments("]").WithLocation(1, 8), + // (1,8): error CS1002: ; expected + // from x[ + Diagnostic(ErrorCode.ERR_SemicolonExpected, "").WithLocation(1, 8)); N(SyntaxKind.CompilationUnit); { @@ -7774,7 +8561,13 @@ public void From_FieldDecl5() [Fact] public void From_MethodDecl1() { - var tree = UsingTree(@"from c("); + var tree = UsingTree(@"from c(", + // (1,8): error CS1026: ) expected + // from c( + Diagnostic(ErrorCode.ERR_CloseParenExpected, "").WithLocation(1, 8), + // (1,8): error CS1002: ; expected + // from c( + Diagnostic(ErrorCode.ERR_SemicolonExpected, "").WithLocation(1, 8)); N(SyntaxKind.CompilationUnit); { N(SyntaxKind.MethodDeclaration); @@ -7799,7 +8592,22 @@ public void From_MethodDecl1() [Fact] public void From_MethodDecl2() { - var tree = UsingTree(@"from a<"); + var tree = UsingTree(@"from a<", + // (1,8): error CS1001: Identifier expected + // from a< + Diagnostic(ErrorCode.ERR_IdentifierExpected, "").WithLocation(1, 8), + // (1,8): error CS1003: Syntax error, '>' expected + // from a< + Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments(">").WithLocation(1, 8), + // (1,8): error CS1003: Syntax error, '(' expected + // from a< + Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments("(").WithLocation(1, 8), + // (1,8): error CS1026: ) expected + // from a< + Diagnostic(ErrorCode.ERR_CloseParenExpected, "").WithLocation(1, 8), + // (1,8): error CS1002: ; expected + // from a< + Diagnostic(ErrorCode.ERR_SemicolonExpected, "").WithLocation(1, 8)); N(SyntaxKind.CompilationUnit); { @@ -7834,7 +8642,19 @@ public void From_MethodDecl2() [Fact] public void From_MethodDecl3() { - var tree = UsingTree(@"from a."); + var tree = UsingTree(@"from a.", + // (1,8): error CS1001: Identifier expected + // from a. + Diagnostic(ErrorCode.ERR_IdentifierExpected, "").WithLocation(1, 8), + // (1,8): error CS1003: Syntax error, '(' expected + // from a. + Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments("(").WithLocation(1, 8), + // (1,8): error CS1026: ) expected + // from a. + Diagnostic(ErrorCode.ERR_CloseParenExpected, "").WithLocation(1, 8), + // (1,8): error CS1002: ; expected + // from a. + Diagnostic(ErrorCode.ERR_SemicolonExpected, "").WithLocation(1, 8)); N(SyntaxKind.CompilationUnit); { @@ -7868,7 +8688,22 @@ public void From_MethodDecl3() [Fact] public void From_MethodDecl4() { - var tree = UsingTree(@"from a::"); + var tree = UsingTree(@"from a::", + // (1,7): error CS0687: The namespace alias qualifier '::' always resolves to a type or namespace so is illegal here. Consider using '.' instead. + // from a:: + Diagnostic(ErrorCode.ERR_AliasQualAsExpression, "::").WithLocation(1, 7), + // (1,9): error CS1001: Identifier expected + // from a:: + Diagnostic(ErrorCode.ERR_IdentifierExpected, "").WithLocation(1, 9), + // (1,9): error CS1003: Syntax error, '(' expected + // from a:: + Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments("(").WithLocation(1, 9), + // (1,9): error CS1026: ) expected + // from a:: + Diagnostic(ErrorCode.ERR_CloseParenExpected, "").WithLocation(1, 9), + // (1,9): error CS1002: ; expected + // from a:: + Diagnostic(ErrorCode.ERR_SemicolonExpected, "").WithLocation(1, 9)); N(SyntaxKind.CompilationUnit); { @@ -7902,7 +8737,22 @@ public void From_MethodDecl4() [Fact] public void From_MethodDecl5() { - var tree = UsingTree(@"from global::"); + var tree = UsingTree(@"from global::", + // (1,12): error CS0687: The namespace alias qualifier '::' always resolves to a type or namespace so is illegal here. Consider using '.' instead. + // from global:: + Diagnostic(ErrorCode.ERR_AliasQualAsExpression, "::").WithLocation(1, 12), + // (1,14): error CS1001: Identifier expected + // from global:: + Diagnostic(ErrorCode.ERR_IdentifierExpected, "").WithLocation(1, 14), + // (1,14): error CS1003: Syntax error, '(' expected + // from global:: + Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments("(").WithLocation(1, 14), + // (1,14): error CS1026: ) expected + // from global:: + Diagnostic(ErrorCode.ERR_CloseParenExpected, "").WithLocation(1, 14), + // (1,14): error CS1002: ; expected + // from global:: + Diagnostic(ErrorCode.ERR_SemicolonExpected, "").WithLocation(1, 14)); N(SyntaxKind.CompilationUnit); { @@ -7936,7 +8786,10 @@ public void From_MethodDecl5() [Fact] public void From_PropertyDecl1() { - var tree = UsingTree(@"from c {"); + var tree = UsingTree(@"from c {", + // (1,9): error CS1513: } expected + // from c { + Diagnostic(ErrorCode.ERR_RbraceExpected, "").WithLocation(1, 9)); N(SyntaxKind.CompilationUnit); { N(SyntaxKind.PropertyDeclaration); @@ -7960,7 +8813,16 @@ public void From_PropertyDecl1() [Fact] public void From_Query1() { - var tree = UsingTree(@"from c d"); + var tree = UsingTree(@"from c d", + // (1,9): error CS1003: Syntax error, 'in' expected + // from c d + Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments("in").WithLocation(1, 9), + // (1,9): error CS1733: Expected expression + // from c d + Diagnostic(ErrorCode.ERR_ExpressionExpected, "").WithLocation(1, 9), + // (1,9): error CS0742: A query body must end with a select clause or a group clause + // from c d + Diagnostic(ErrorCode.ERR_ExpectedSelectOrGroup, "").WithLocation(1, 9)); N(SyntaxKind.CompilationUnit); { N(SyntaxKind.GlobalStatement); @@ -8006,7 +8868,16 @@ public void From_Query1() [Fact] public void From_Query2() { - var tree = UsingTree(@"from x* a"); + var tree = UsingTree(@"from x* a", + // (1,10): error CS1003: Syntax error, 'in' expected + // from x* a + Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments("in").WithLocation(1, 10), + // (1,10): error CS1733: Expected expression + // from x* a + Diagnostic(ErrorCode.ERR_ExpressionExpected, "").WithLocation(1, 10), + // (1,10): error CS0742: A query body must end with a select clause or a group clause + // from x* a + Diagnostic(ErrorCode.ERR_ExpectedSelectOrGroup, "").WithLocation(1, 10)); N(SyntaxKind.CompilationUnit); { @@ -8057,7 +8928,16 @@ public void From_Query2() [Fact] public void From_Query3() { - var tree = UsingTree(@"from x? a"); + var tree = UsingTree(@"from x? a", + // (1,10): error CS1003: Syntax error, 'in' expected + // from x? a + Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments("in").WithLocation(1, 10), + // (1,10): error CS1733: Expected expression + // from x? a + Diagnostic(ErrorCode.ERR_ExpressionExpected, "").WithLocation(1, 10), + // (1,10): error CS0742: A query body must end with a select clause or a group clause + // from x? a + Diagnostic(ErrorCode.ERR_ExpectedSelectOrGroup, "").WithLocation(1, 10)); N(SyntaxKind.CompilationUnit); { @@ -8108,7 +8988,16 @@ public void From_Query3() [Fact] public void From_Query4() { - var tree = UsingTree(@"from x[] a"); + var tree = UsingTree(@"from x[] a", + // (1,11): error CS1003: Syntax error, 'in' expected + // from x[] a + Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments("in").WithLocation(1, 11), + // (1,11): error CS1733: Expected expression + // from x[] a + Diagnostic(ErrorCode.ERR_ExpressionExpected, "").WithLocation(1, 11), + // (1,11): error CS0742: A query body must end with a select clause or a group clause + // from x[] a + Diagnostic(ErrorCode.ERR_ExpectedSelectOrGroup, "").WithLocation(1, 11)); N(SyntaxKind.CompilationUnit); { @@ -8167,7 +9056,13 @@ public void From_Query4() [Fact] public void From_Query5() { - var tree = UsingTree(@"from goo in"); + var tree = UsingTree(@"from goo in", + // (1,12): error CS1733: Expected expression + // from goo in + Diagnostic(ErrorCode.ERR_ExpressionExpected, "").WithLocation(1, 12), + // (1,12): error CS0742: A query body must end with a select clause or a group clause + // from goo in + Diagnostic(ErrorCode.ERR_ExpectedSelectOrGroup, "").WithLocation(1, 12)); N(SyntaxKind.CompilationUnit); { N(SyntaxKind.GlobalStatement); @@ -8209,7 +9104,16 @@ public void From_Query5() [Fact] public void From_Query6() { - var tree = UsingTree(@"from goo.bar in"); + var tree = UsingTree(@"from goo.bar in", + // (1,14): error CS1001: Identifier expected + // from goo.bar in + Diagnostic(ErrorCode.ERR_IdentifierExpected, "in").WithLocation(1, 14), + // (1,16): error CS1733: Expected expression + // from goo.bar in + Diagnostic(ErrorCode.ERR_ExpressionExpected, "").WithLocation(1, 16), + // (1,16): error CS0742: A query body must end with a select clause or a group clause + // from goo.bar in + Diagnostic(ErrorCode.ERR_ExpectedSelectOrGroup, "").WithLocation(1, 16)); N(SyntaxKind.CompilationUnit); { N(SyntaxKind.GlobalStatement); @@ -8270,7 +9174,16 @@ public void From_Query6() [Fact] public void GlobalStatementSeparators_Comma1() { - var tree = UsingTree("a < b,c.", TestOptions.Script); + var tree = UsingTree("a < b,c.", TestOptions.Script, + // (1,6): error CS1002: ; expected + // a < b,c. + Diagnostic(ErrorCode.ERR_SemicolonExpected, ",").WithLocation(1, 6), + // (1,6): error CS7017: Member definition, statement, or end-of-file expected + // a < b,c. + Diagnostic(ErrorCode.ERR_GlobalDefinitionOrStatementExpected, ",").WithLocation(1, 6), + // (1,9): error CS1001: Identifier expected + // a < b,c. + Diagnostic(ErrorCode.ERR_IdentifierExpected, "").WithLocation(1, 9)); N(SyntaxKind.CompilationUnit); { N(SyntaxKind.GlobalStatement); @@ -8322,7 +9235,13 @@ public void GlobalStatementSeparators_Comma2() var tree = UsingTree(@" a < b, void goo() { } -"); +", + // (2,6): error CS1002: ; expected + // a < b, + Diagnostic(ErrorCode.ERR_SemicolonExpected, ",").WithLocation(2, 6), + // (2,6): error CS7017: Member definition, statement, or end-of-file expected + // a < b, + Diagnostic(ErrorCode.ERR_GlobalDefinitionOrStatementExpected, ",").WithLocation(2, 6)); N(SyntaxKind.CompilationUnit); { N(SyntaxKind.GlobalStatement); @@ -8373,7 +9292,13 @@ public void GlobalStatementSeparators_ClosingParen() var tree = UsingTree(@" a < b) void goo() { } -"); +", + // (2,6): error CS1002: ; expected + // a < b) + Diagnostic(ErrorCode.ERR_SemicolonExpected, ")").WithLocation(2, 6), + // (2,6): error CS7017: Member definition, statement, or end-of-file expected + // a < b) + Diagnostic(ErrorCode.ERR_GlobalDefinitionOrStatementExpected, ")").WithLocation(2, 6)); N(SyntaxKind.CompilationUnit); { N(SyntaxKind.GlobalStatement); @@ -8424,7 +9349,13 @@ public void GlobalStatementSeparators_ClosingBracket() var tree = UsingTree(@" a < b] void goo() { } -"); +", + // (2,6): error CS1002: ; expected + // a < b] + Diagnostic(ErrorCode.ERR_SemicolonExpected, "]").WithLocation(2, 6), + // (2,6): error CS7017: Member definition, statement, or end-of-file expected + // a < b] + Diagnostic(ErrorCode.ERR_GlobalDefinitionOrStatementExpected, "]").WithLocation(2, 6)); N(SyntaxKind.CompilationUnit); { N(SyntaxKind.GlobalStatement); @@ -8475,7 +9406,13 @@ public void GlobalStatementSeparators_ClosingBrace() var tree = UsingTree(@" a < b} void goo() { } -"); +", + // (2,6): error CS1002: ; expected + // a < b} + Diagnostic(ErrorCode.ERR_SemicolonExpected, "}").WithLocation(2, 6), + // (2,6): error CS7017: Member definition, statement, or end-of-file expected + // a < b} + Diagnostic(ErrorCode.ERR_GlobalDefinitionOrStatementExpected, "}").WithLocation(2, 6)); N(SyntaxKind.CompilationUnit); { diff --git a/src/Compilers/CSharp/Test/Syntax/Parsing/SeparatedSyntaxListParsingTests.cs b/src/Compilers/CSharp/Test/Syntax/Parsing/SeparatedSyntaxListParsingTests.cs index e20b53de0dd8d..7a83225ecb842 100644 --- a/src/Compilers/CSharp/Test/Syntax/Parsing/SeparatedSyntaxListParsingTests.cs +++ b/src/Compilers/CSharp/Test/Syntax/Parsing/SeparatedSyntaxListParsingTests.cs @@ -39,7 +39,25 @@ class C A<,T> a7; A a8; } -"); +", + // (7,9): error CS1003: Syntax error, ',' expected + // A a4; + Diagnostic(ErrorCode.ERR_SyntaxError, "U").WithArguments(",").WithLocation(7, 9), + // (9,9): error CS1031: Type expected + // A a6; + Diagnostic(ErrorCode.ERR_TypeExpected, ">").WithLocation(9, 9), + // (10,7): error CS1031: Type expected + // A<,T> a7; + Diagnostic(ErrorCode.ERR_TypeExpected, ",").WithLocation(10, 7), + // (11,9): error CS1003: Syntax error, ',' expected + // A a8; + Diagnostic(ErrorCode.ERR_SyntaxError, "U").WithArguments(",").WithLocation(11, 9), + // (11,11): error CS1031: Type expected + // A a8; + Diagnostic(ErrorCode.ERR_TypeExpected, ",").WithLocation(11, 11), + // (11,12): error CS1031: Type expected + // A a8; + Diagnostic(ErrorCode.ERR_TypeExpected, ">").WithLocation(11, 12)); N(SyntaxKind.CompilationUnit); { N(SyntaxKind.ClassDeclaration); @@ -306,7 +324,31 @@ class C } class M<,> { } -", options: TestOptions.Regular); +", options: TestOptions.Regular, + // (4,12): error CS1519: Invalid token '(' in class, record, struct, or interface member declaration + // new C<>(); + Diagnostic(ErrorCode.ERR_InvalidMemberDecl, "(").WithArguments("(").WithLocation(4, 12), + // (4,13): error CS8124: Tuple must contain at least two elements. + // new C<>(); + Diagnostic(ErrorCode.ERR_TupleTooFewElements, ")").WithLocation(4, 13), + // (4,14): error CS1519: Invalid token ';' in class, record, struct, or interface member declaration + // new C<>(); + Diagnostic(ErrorCode.ERR_InvalidMemberDecl, ";").WithArguments(";").WithLocation(4, 14), + // (5,14): error CS1519: Invalid token '(' in class, record, struct, or interface member declaration + // new C<, >(); + Diagnostic(ErrorCode.ERR_InvalidMemberDecl, "(").WithArguments("(").WithLocation(5, 14), + // (5,15): error CS8124: Tuple must contain at least two elements. + // new C<, >(); + Diagnostic(ErrorCode.ERR_TupleTooFewElements, ")").WithLocation(5, 15), + // (5,16): error CS1519: Invalid token ';' in class, record, struct, or interface member declaration + // new C<, >(); + Diagnostic(ErrorCode.ERR_InvalidMemberDecl, ";").WithArguments(";").WithLocation(5, 16), + // (12,9): error CS1001: Identifier expected + // class M<,> { } + Diagnostic(ErrorCode.ERR_IdentifierExpected, ",").WithLocation(12, 9), + // (12,10): error CS1001: Identifier expected + // class M<,> { } + Diagnostic(ErrorCode.ERR_IdentifierExpected, ">").WithLocation(12, 10)); CheckTypeArguments2(); } @@ -626,7 +668,37 @@ class C } class M<,> { } -", TestOptions.Regular.WithLanguageVersion(LanguageVersion.CSharp6)); +", TestOptions.Regular.WithLanguageVersion(LanguageVersion.CSharp6), + // (4,12): error CS1519: Invalid token '(' in class, record, struct, or interface member declaration + // new C<>(); + Diagnostic(ErrorCode.ERR_InvalidMemberDecl, "(").WithArguments("(").WithLocation(4, 12), + // (4,12): error CS8059: Feature 'tuples' is not available in C# 6. Please use language version 7.0 or greater. + // new C<>(); + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion6, "()").WithArguments("tuples", "7.0").WithLocation(4, 12), + // (4,13): error CS8124: Tuple must contain at least two elements. + // new C<>(); + Diagnostic(ErrorCode.ERR_TupleTooFewElements, ")").WithLocation(4, 13), + // (4,14): error CS1519: Invalid token ';' in class, record, struct, or interface member declaration + // new C<>(); + Diagnostic(ErrorCode.ERR_InvalidMemberDecl, ";").WithArguments(";").WithLocation(4, 14), + // (5,14): error CS1519: Invalid token '(' in class, record, struct, or interface member declaration + // new C<, >(); + Diagnostic(ErrorCode.ERR_InvalidMemberDecl, "(").WithArguments("(").WithLocation(5, 14), + // (5,14): error CS8059: Feature 'tuples' is not available in C# 6. Please use language version 7.0 or greater. + // new C<, >(); + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion6, "()").WithArguments("tuples", "7.0").WithLocation(5, 14), + // (5,15): error CS8124: Tuple must contain at least two elements. + // new C<, >(); + Diagnostic(ErrorCode.ERR_TupleTooFewElements, ")").WithLocation(5, 15), + // (5,16): error CS1519: Invalid token ';' in class, record, struct, or interface member declaration + // new C<, >(); + Diagnostic(ErrorCode.ERR_InvalidMemberDecl, ";").WithArguments(";").WithLocation(5, 16), + // (12,9): error CS1001: Identifier expected + // class M<,> { } + Diagnostic(ErrorCode.ERR_IdentifierExpected, ",").WithLocation(12, 9), + // (12,10): error CS1001: Identifier expected + // class M<,> { } + Diagnostic(ErrorCode.ERR_IdentifierExpected, ">").WithLocation(12, 10)); CheckTypeArguments2(); } @@ -646,7 +718,25 @@ class C object a1 = new int[,1]; object a1 = new int[1 1 ,,]; } -"); +", + // (7,27): error CS1003: Syntax error, ',' expected + // object a1 = new int[1 2]; + Diagnostic(ErrorCode.ERR_SyntaxError, "2").WithArguments(",").WithLocation(7, 27), + // (9,27): error CS0443: Syntax error; value expected + // object a1 = new int[1,]; + Diagnostic(ErrorCode.ERR_ValueExpected, "").WithLocation(9, 27), + // (10,25): error CS0443: Syntax error; value expected + // object a1 = new int[,1]; + Diagnostic(ErrorCode.ERR_ValueExpected, "").WithLocation(10, 25), + // (11,27): error CS1003: Syntax error, ',' expected + // object a1 = new int[1 1 ,,]; + Diagnostic(ErrorCode.ERR_SyntaxError, "1").WithArguments(",").WithLocation(11, 27), + // (11,30): error CS0443: Syntax error; value expected + // object a1 = new int[1 1 ,,]; + Diagnostic(ErrorCode.ERR_ValueExpected, "").WithLocation(11, 30), + // (11,31): error CS0443: Syntax error; value expected + // object a1 = new int[1 1 ,,]; + Diagnostic(ErrorCode.ERR_ValueExpected, "").WithLocation(11, 31)); N(SyntaxKind.CompilationUnit); { diff --git a/src/Compilers/CSharp/Test/Syntax/Parsing/StatementAttributeParsingTests.cs b/src/Compilers/CSharp/Test/Syntax/Parsing/StatementAttributeParsingTests.cs index 69a16ccc72b80..34018328b2c4a 100644 --- a/src/Compilers/CSharp/Test/Syntax/Parsing/StatementAttributeParsingTests.cs +++ b/src/Compilers/CSharp/Test/Syntax/Parsing/StatementAttributeParsingTests.cs @@ -791,7 +791,10 @@ void Goo() { [A]yield } -}"); +}", + // (6,17): error CS1002: ; expected + // [A]yield + Diagnostic(ErrorCode.ERR_SemicolonExpected, "").WithLocation(6, 17)); N(SyntaxKind.CompilationUnit); { @@ -1977,7 +1980,19 @@ void Goo() { unsafe [A]{ } } -}"); +}", + // (6,9): error CS0106: The modifier 'unsafe' is not valid for this item + // unsafe [A]{ } + Diagnostic(ErrorCode.ERR_BadMemberFlag, "unsafe").WithArguments("unsafe").WithLocation(6, 9), + // (6,16): error CS1031: Type expected + // unsafe [A]{ } + Diagnostic(ErrorCode.ERR_TypeExpected, "[").WithLocation(6, 16), + // (6,19): error CS1001: Identifier expected + // unsafe [A]{ } + Diagnostic(ErrorCode.ERR_IdentifierExpected, "{").WithLocation(6, 19), + // (6,19): error CS1002: ; expected + // unsafe [A]{ } + Diagnostic(ErrorCode.ERR_SemicolonExpected, "{").WithLocation(6, 19)); N(SyntaxKind.CompilationUnit); { @@ -2397,7 +2412,28 @@ void Goo() return; } } -}"); +}", + // (7,10): error CS1513: } expected + // { + Diagnostic(ErrorCode.ERR_RbraceExpected, "").WithLocation(7, 10), + // (8,16): error CS1525: Invalid expression term 'case' + // [A] + Diagnostic(ErrorCode.ERR_InvalidExprTerm, "").WithArguments("case").WithLocation(8, 16), + // (8,16): error CS1002: ; expected + // [A] + Diagnostic(ErrorCode.ERR_SemicolonExpected, "").WithLocation(8, 16), + // (8,16): error CS1513: } expected + // [A] + Diagnostic(ErrorCode.ERR_RbraceExpected, "").WithLocation(8, 16), + // (9,19): error CS1002: ; expected + // case 0: + Diagnostic(ErrorCode.ERR_SemicolonExpected, ":").WithLocation(9, 19), + // (9,19): error CS1513: } expected + // case 0: + Diagnostic(ErrorCode.ERR_RbraceExpected, ":").WithLocation(9, 19), + // (13,1): error CS1022: Type or namespace definition, or end-of-file expected + // } + Diagnostic(ErrorCode.ERR_EOFExpected, "}").WithLocation(13, 1)); N(SyntaxKind.CompilationUnit); { @@ -2520,7 +2556,19 @@ void Goo() return; } } -}"); +}", + // (7,10): error CS1513: } expected + // { + Diagnostic(ErrorCode.ERR_RbraceExpected, "").WithLocation(7, 10), + // (9,20): error CS1002: ; expected + // default: + Diagnostic(ErrorCode.ERR_SemicolonExpected, ":").WithLocation(9, 20), + // (9,20): error CS1513: } expected + // default: + Diagnostic(ErrorCode.ERR_RbraceExpected, ":").WithLocation(9, 20), + // (13,1): error CS1022: Type or namespace definition, or end-of-file expected + // } + Diagnostic(ErrorCode.ERR_EOFExpected, "}").WithLocation(13, 1)); N(SyntaxKind.CompilationUnit); { @@ -2782,7 +2830,19 @@ void Goo() { try { } [A] finally { } } -}"); +}", + // (6,15): error CS1524: Expected catch or finally + // try { } [A] finally { } + Diagnostic(ErrorCode.ERR_ExpectedEndTry, "}").WithLocation(6, 15), + // (6,21): error CS1003: Syntax error, 'try' expected + // try { } [A] finally { } + Diagnostic(ErrorCode.ERR_SyntaxError, "finally").WithArguments("try").WithLocation(6, 21), + // (6,21): error CS1514: { expected + // try { } [A] finally { } + Diagnostic(ErrorCode.ERR_LbraceExpected, "finally").WithLocation(6, 21), + // (6,21): error CS1513: } expected + // try { } [A] finally { } + Diagnostic(ErrorCode.ERR_RbraceExpected, "finally").WithLocation(6, 21)); N(SyntaxKind.CompilationUnit); { @@ -2970,7 +3030,19 @@ void Goo() { try { } [A] catch { } } -}"); +}", + // (6,15): error CS1524: Expected catch or finally + // try { } [A] catch { } + Diagnostic(ErrorCode.ERR_ExpectedEndTry, "}").WithLocation(6, 15), + // (6,21): error CS1003: Syntax error, 'try' expected + // try { } [A] catch { } + Diagnostic(ErrorCode.ERR_SyntaxError, "catch").WithArguments("try").WithLocation(6, 21), + // (6,21): error CS1514: { expected + // try { } [A] catch { } + Diagnostic(ErrorCode.ERR_LbraceExpected, "catch").WithLocation(6, 21), + // (6,21): error CS1513: } expected + // try { } [A] catch { } + Diagnostic(ErrorCode.ERR_RbraceExpected, "catch").WithLocation(6, 21)); N(SyntaxKind.CompilationUnit); { @@ -3234,7 +3306,10 @@ void Goo() { [A]delegate { } } -}"); +}", + // (6,24): error CS1002: ; expected + // [A]delegate { } + Diagnostic(ErrorCode.ERR_SemicolonExpected, "").WithLocation(6, 24)); N(SyntaxKind.CompilationUnit); { @@ -3311,7 +3386,13 @@ void Goo() { [A]delegate } -}"); +}", + // (6,20): error CS1514: { expected + // [A]delegate + Diagnostic(ErrorCode.ERR_LbraceExpected, "").WithLocation(6, 20), + // (6,20): error CS1002: ; expected + // [A]delegate + Diagnostic(ErrorCode.ERR_SemicolonExpected, "").WithLocation(6, 20)); N(SyntaxKind.CompilationUnit); { @@ -6581,7 +6662,25 @@ void Goo() { [A]int this[int i] => 0; } -}"); +}", + // (6,16): error CS1001: Identifier expected + // [A]int this[int i] => 0; + Diagnostic(ErrorCode.ERR_IdentifierExpected, "this").WithLocation(6, 16), + // (6,16): error CS1002: ; expected + // [A]int this[int i] => 0; + Diagnostic(ErrorCode.ERR_SemicolonExpected, "this").WithLocation(6, 16), + // (6,21): error CS1525: Invalid expression term 'int' + // [A]int this[int i] => 0; + Diagnostic(ErrorCode.ERR_InvalidExprTerm, "int").WithArguments("int").WithLocation(6, 21), + // (6,25): error CS1003: Syntax error, ',' expected + // [A]int this[int i] => 0; + Diagnostic(ErrorCode.ERR_SyntaxError, "i").WithArguments(",").WithLocation(6, 25), + // (6,28): error CS1002: ; expected + // [A]int this[int i] => 0; + Diagnostic(ErrorCode.ERR_SemicolonExpected, "=>").WithLocation(6, 28), + // (6,28): error CS1513: } expected + // [A]int this[int i] => 0; + Diagnostic(ErrorCode.ERR_RbraceExpected, "=>").WithLocation(6, 28)); N(SyntaxKind.CompilationUnit); { @@ -6808,7 +6907,13 @@ void Goo() { public extern int i = 1; } -}"); +}", + // (5,6): error CS1513: } expected + // { + Diagnostic(ErrorCode.ERR_RbraceExpected, "").WithLocation(5, 6), + // (8,1): error CS1022: Type or namespace definition, or end-of-file expected + // } + Diagnostic(ErrorCode.ERR_EOFExpected, "}").WithLocation(8, 1)); N(SyntaxKind.CompilationUnit); { @@ -6888,7 +6993,13 @@ void Goo() { extern public int i = 1; } -}"); +}", + // (6,9): error CS0106: The modifier 'extern' is not valid for this item + // extern public int i = 1; + Diagnostic(ErrorCode.ERR_BadMemberFlag, "extern").WithArguments("extern").WithLocation(6, 9), + // (6,16): error CS0106: The modifier 'public' is not valid for this item + // extern public int i = 1; + Diagnostic(ErrorCode.ERR_BadMemberFlag, "public").WithArguments("public").WithLocation(6, 16)); N(SyntaxKind.CompilationUnit); { @@ -6968,7 +7079,10 @@ void Goo() { [A]public int i = 0; } -}"); +}", + // (6,12): error CS0106: The modifier 'public' is not valid for this item + // [A]public int i = 0; + Diagnostic(ErrorCode.ERR_BadMemberFlag, "public").WithArguments("public").WithLocation(6, 12)); N(SyntaxKind.CompilationUnit); { @@ -7372,7 +7486,16 @@ class C { [Attr] x.y(); } -"); +", + // (4,15): error CS1519: Invalid token '(' in class, record, struct, or interface member declaration + // [Attr] x.y(); + Diagnostic(ErrorCode.ERR_InvalidMemberDecl, "(").WithArguments("(").WithLocation(4, 15), + // (4,16): error CS8124: Tuple must contain at least two elements. + // [Attr] x.y(); + Diagnostic(ErrorCode.ERR_TupleTooFewElements, ")").WithLocation(4, 16), + // (4,17): error CS1519: Invalid token ';' in class, record, struct, or interface member declaration + // [Attr] x.y(); + Diagnostic(ErrorCode.ERR_InvalidMemberDecl, ";").WithArguments(";").WithLocation(4, 17)); N(SyntaxKind.CompilationUnit); { diff --git a/src/Compilers/CSharp/Test/Syntax/Parsing/StatementParsingTests.cs b/src/Compilers/CSharp/Test/Syntax/Parsing/StatementParsingTests.cs index edd597c2033db..a7dfc4ceba4f5 100644 --- a/src/Compilers/CSharp/Test/Syntax/Parsing/StatementParsingTests.cs +++ b/src/Compilers/CSharp/Test/Syntax/Parsing/StatementParsingTests.cs @@ -2685,7 +2685,13 @@ async void M() using await var x = null; } } -"); +", + // (6,15): error CS4003: 'await' cannot be used as an identifier within an async method or lambda expression + // using await var x = null; + Diagnostic(ErrorCode.ERR_BadAwaitAsIdentifier, "await").WithLocation(6, 15), + // (6,25): error CS1002: ; expected + // using await var x = null; + Diagnostic(ErrorCode.ERR_SemicolonExpected, "x").WithLocation(6, 25)); N(SyntaxKind.CompilationUnit); { N(SyntaxKind.ClassDeclaration); diff --git a/src/Compilers/CSharp/Test/Syntax/Parsing/TopLevelStatementsParsingTests.cs b/src/Compilers/CSharp/Test/Syntax/Parsing/TopLevelStatementsParsingTests.cs index 6b4ac8aa74fb3..7872c94b99b28 100644 --- a/src/Compilers/CSharp/Test/Syntax/Parsing/TopLevelStatementsParsingTests.cs +++ b/src/Compilers/CSharp/Test/Syntax/Parsing/TopLevelStatementsParsingTests.cs @@ -17,16 +17,6 @@ public sealed class TopLevelStatementsParsingTests : ParsingTests { public TopLevelStatementsParsingTests(ITestOutputHelper output) : base(output) { } - private SyntaxTree UsingTree(string text, params DiagnosticDescription[] expectedErrors) - { - var tree = base.UsingTree(text); - - var actualErrors = tree.GetDiagnostics(); - actualErrors.Verify(expectedErrors); - - return tree; - } - [Fact] public void InsertOpenBraceBeforeCodes() { @@ -932,10 +922,30 @@ public void CS0267ERR_PartialMisplaced_Delegate1() var test = @" partial delegate E { } "; + CreateCompilation(test).VerifyDiagnostics( + // (2,18): error CS0246: The type or namespace name 'E' could not be found (are you missing a using directive or an assembly reference?) + // partial delegate E { } + Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "E").WithArguments("E").WithLocation(2, 18), + // (2,20): error CS1001: Identifier expected + // partial delegate E { } + Diagnostic(ErrorCode.ERR_IdentifierExpected, "{").WithLocation(2, 20), + // (2,20): error CS1003: Syntax error, '(' expected + // partial delegate E { } + Diagnostic(ErrorCode.ERR_SyntaxError, "{").WithArguments("(").WithLocation(2, 20), + // (2,20): error CS1026: ) expected + // partial delegate E { } + Diagnostic(ErrorCode.ERR_CloseParenExpected, "{").WithLocation(2, 20), + // (2,20): error CS1002: ; expected + // partial delegate E { } + Diagnostic(ErrorCode.ERR_SemicolonExpected, "{").WithLocation(2, 20), + // (2,20): error CS8803: Top-level statements must precede namespace and type declarations. + // partial delegate E { } + Diagnostic(ErrorCode.ERR_TopLevelStatementAfterNamespaceOrType, "{ }").WithLocation(2, 20), + // (2,20): error CS0267: The 'partial' modifier can only appear immediately before 'class', 'record', 'struct', 'interface', or a method return type. + // partial delegate E { } + Diagnostic(ErrorCode.ERR_PartialMisplaced, "").WithLocation(2, 20) + ); UsingTree(test, - // (2,1): error CS0267: The 'partial' modifier can only appear immediately before 'class', 'record', 'struct', 'interface', or a method return type. - // partial delegate E { } - Diagnostic(ErrorCode.ERR_PartialMisplaced, "partial").WithLocation(2, 1), // (2,20): error CS1001: Identifier expected // partial delegate E { } Diagnostic(ErrorCode.ERR_IdentifierExpected, "{").WithLocation(2, 20), diff --git a/src/Compilers/CSharp/Test/Syntax/Parsing/TypeArgumentListParsingTests.cs b/src/Compilers/CSharp/Test/Syntax/Parsing/TypeArgumentListParsingTests.cs index 7ddda6f9fd317..9a47468d3af2b 100644 --- a/src/Compilers/CSharp/Test/Syntax/Parsing/TypeArgumentListParsingTests.cs +++ b/src/Compilers/CSharp/Test/Syntax/Parsing/TypeArgumentListParsingTests.cs @@ -32,7 +32,10 @@ void M() ProjectChange = projectChange; } } -"); +", + // (6,76): error CS1002: ; expected + // var added = ImmutableDictionary> + Diagnostic(ErrorCode.ERR_SemicolonExpected, "").WithLocation(6, 76)); N(SyntaxKind.CompilationUnit); { N(SyntaxKind.ClassDeclaration); @@ -145,7 +148,10 @@ void M() ProjectChange = projectChange; } } -"); +", + // (6,73): error CS1002: ; expected + // var added = ImmutableDictionary> + Diagnostic(ErrorCode.ERR_SemicolonExpected, "").WithLocation(6, 73)); N(SyntaxKind.CompilationUnit); { N(SyntaxKind.ClassDeclaration); @@ -270,7 +276,10 @@ void M() ProjectChange = projectChange; } } -"); +", + // (6,74): error CS1002: ; expected + // var added = ImmutableDictionary> + Diagnostic(ErrorCode.ERR_SemicolonExpected, "").WithLocation(6, 74)); N(SyntaxKind.CompilationUnit); { N(SyntaxKind.ClassDeclaration); @@ -387,7 +396,22 @@ void M() ProjectChange = projectChange; } } -"); +", + // (6,43): error CS1525: Invalid expression term ',' + // var added = ImmutableDictionary> + Diagnostic(ErrorCode.ERR_InvalidExprTerm, ",").WithArguments(",").WithLocation(6, 43), + // (6,65): error CS1002: ; expected + // var added = ImmutableDictionary> + Diagnostic(ErrorCode.ERR_SemicolonExpected, "<").WithLocation(6, 65), + // (6,65): error CS1525: Invalid expression term '<' + // var added = ImmutableDictionary> + Diagnostic(ErrorCode.ERR_InvalidExprTerm, "<").WithArguments("<").WithLocation(6, 65), + // (6,67): error CS1002: ; expected + // var added = ImmutableDictionary> + Diagnostic(ErrorCode.ERR_SemicolonExpected, ",").WithLocation(6, 67), + // (6,67): error CS1513: } expected + // var added = ImmutableDictionary> + Diagnostic(ErrorCode.ERR_RbraceExpected, ",").WithLocation(6, 67)); N(SyntaxKind.CompilationUnit); { @@ -518,7 +542,25 @@ void M() ProjectChange = projectChange; } } -"); +", + // (6,42): error CS1525: Invalid expression term 'int' + // var added = ImmutableDictionary<(int, string), IImmutableDictionary> + Diagnostic(ErrorCode.ERR_InvalidExprTerm, "int").WithArguments("int").WithLocation(6, 42), + // (6,47): error CS1525: Invalid expression term 'string' + // var added = ImmutableDictionary<(int, string), IImmutableDictionary> + Diagnostic(ErrorCode.ERR_InvalidExprTerm, "string").WithArguments("string").WithLocation(6, 47), + // (6,76): error CS1002: ; expected + // var added = ImmutableDictionary<(int, string), IImmutableDictionary> + Diagnostic(ErrorCode.ERR_SemicolonExpected, "<").WithLocation(6, 76), + // (6,76): error CS1525: Invalid expression term '<' + // var added = ImmutableDictionary<(int, string), IImmutableDictionary> + Diagnostic(ErrorCode.ERR_InvalidExprTerm, "<").WithArguments("<").WithLocation(6, 76), + // (6,78): error CS1002: ; expected + // var added = ImmutableDictionary<(int, string), IImmutableDictionary> + Diagnostic(ErrorCode.ERR_SemicolonExpected, ",").WithLocation(6, 78), + // (6,78): error CS1513: } expected + // var added = ImmutableDictionary<(int, string), IImmutableDictionary> + Diagnostic(ErrorCode.ERR_RbraceExpected, ",").WithLocation(6, 78)); N(SyntaxKind.CompilationUnit); { N(SyntaxKind.ClassDeclaration); @@ -966,7 +1008,19 @@ void M() ProjectChange = projectChange; } } -"); +", + // (6,66): error CS1002: ; expected + // var added = ImmutableDictionary<(A), IImmutableDictionary> + Diagnostic(ErrorCode.ERR_SemicolonExpected, "<").WithLocation(6, 66), + // (6,66): error CS1525: Invalid expression term '<' + // var added = ImmutableDictionary<(A), IImmutableDictionary> + Diagnostic(ErrorCode.ERR_InvalidExprTerm, "<").WithArguments("<").WithLocation(6, 66), + // (6,68): error CS1002: ; expected + // var added = ImmutableDictionary<(A), IImmutableDictionary> + Diagnostic(ErrorCode.ERR_SemicolonExpected, ",").WithLocation(6, 68), + // (6,68): error CS1513: } expected + // var added = ImmutableDictionary<(A), IImmutableDictionary> + Diagnostic(ErrorCode.ERR_RbraceExpected, ",").WithLocation(6, 68)); N(SyntaxKind.CompilationUnit); { N(SyntaxKind.ClassDeclaration); @@ -1093,7 +1147,19 @@ void M() ProjectChange = projectChange; } } -"); +", + // (6,66): error CS1002: ; expected + // var added = ImmutableDictionary> + Diagnostic(ErrorCode.ERR_SemicolonExpected, "<").WithLocation(6, 66), + // (6,66): error CS1525: Invalid expression term '<' + // var added = ImmutableDictionary> + Diagnostic(ErrorCode.ERR_InvalidExprTerm, "<").WithArguments("<").WithLocation(6, 66), + // (6,68): error CS1002: ; expected + // var added = ImmutableDictionary> + Diagnostic(ErrorCode.ERR_SemicolonExpected, ",").WithLocation(6, 68), + // (6,68): error CS1513: } expected + // var added = ImmutableDictionary> + Diagnostic(ErrorCode.ERR_RbraceExpected, ",").WithLocation(6, 68)); N(SyntaxKind.CompilationUnit); { N(SyntaxKind.ClassDeclaration); @@ -1223,7 +1289,19 @@ void M() ProjectChange = projectChange; } } -"); +", + // (6,67): error CS1002: ; expected + // var added = ImmutableDictionary> + Diagnostic(ErrorCode.ERR_SemicolonExpected, "<").WithLocation(6, 67), + // (6,67): error CS1525: Invalid expression term '<' + // var added = ImmutableDictionary> + Diagnostic(ErrorCode.ERR_InvalidExprTerm, "<").WithArguments("<").WithLocation(6, 67), + // (6,69): error CS1002: ; expected + // var added = ImmutableDictionary> + Diagnostic(ErrorCode.ERR_SemicolonExpected, ",").WithLocation(6, 69), + // (6,69): error CS1513: } expected + // var added = ImmutableDictionary> + Diagnostic(ErrorCode.ERR_RbraceExpected, ",").WithLocation(6, 69)); N(SyntaxKind.CompilationUnit); { N(SyntaxKind.ClassDeclaration); @@ -1353,7 +1431,10 @@ void M() ProjectChange = projectChange; } } -"); +", + // (6,72): error CS1002: ; expected + // var added = ImmutableDictionary> + Diagnostic(ErrorCode.ERR_SemicolonExpected, "").WithLocation(6, 72)); N(SyntaxKind.CompilationUnit); { N(SyntaxKind.ClassDeclaration); @@ -1470,7 +1551,10 @@ void M() ProjectChange = projectChange; } } -"); +", + // (6,44): error CS1002: ; expected + // var added = ImmutableDictionary + Diagnostic(ErrorCode.ERR_SemicolonExpected, "").WithLocation(6, 44)); N(SyntaxKind.CompilationUnit); { N(SyntaxKind.ClassDeclaration); @@ -1568,7 +1652,13 @@ void M() ProjectChange = projectChange; } } -"); +", + // (8,38): error CS1003: Syntax error, ':' expected + // ProjectChange = projectChange; + Diagnostic(ErrorCode.ERR_SyntaxError, ";").WithArguments(":").WithLocation(8, 38), + // (8,38): error CS1525: Invalid expression term ';' + // ProjectChange = projectChange; + Diagnostic(ErrorCode.ERR_InvalidExprTerm, ";").WithArguments(";").WithLocation(8, 38)); N(SyntaxKind.CompilationUnit); { N(SyntaxKind.ClassDeclaration); @@ -1666,7 +1756,10 @@ void M() ProjectChange = projectChange; } } -"); +", + // (6,74): error CS1002: ; expected + // var added = ImmutableDictionary, IImmutableDictionary> + Diagnostic(ErrorCode.ERR_SemicolonExpected, "").WithLocation(6, 74)); N(SyntaxKind.CompilationUnit); { N(SyntaxKind.ClassDeclaration); @@ -1918,7 +2011,10 @@ void M() ProjectChange = projectChange; } } -"); +", + // (6,77): error CS1002: ; expected + // var added = ImmutableDictionary, U>> + Diagnostic(ErrorCode.ERR_SemicolonExpected, "").WithLocation(6, 77)); N(SyntaxKind.CompilationUnit); { N(SyntaxKind.ClassDeclaration); @@ -2049,7 +2145,10 @@ void M() ProjectChange = projectChange; } } -"); +", + // (6,77): error CS1002: ; expected + // var added = ImmutableDictionary, IImmutableDictionary>> + Diagnostic(ErrorCode.ERR_SemicolonExpected, "").WithLocation(6, 77)); N(SyntaxKind.CompilationUnit); { N(SyntaxKind.ClassDeclaration); diff --git a/src/Compilers/CSharp/Test/Syntax/Parsing/Utf8StringLiteralsParsingTests.cs b/src/Compilers/CSharp/Test/Syntax/Parsing/Utf8StringLiteralsParsingTests.cs index 1fa9bcd6886fa..38ffedbe0ae63 100644 --- a/src/Compilers/CSharp/Test/Syntax/Parsing/Utf8StringLiteralsParsingTests.cs +++ b/src/Compilers/CSharp/Test/Syntax/Parsing/Utf8StringLiteralsParsingTests.cs @@ -112,7 +112,7 @@ public void Utf8StringLiteral_01() [Fact] public void Utf8StringLiteral_02() { - UsingExpression(@"""hello""u8", options: TestOptions.RegularNext); + UsingExpression(@"""hello""u8", options: TestOptions.Regular11); N(SyntaxKind.Utf8StringLiteralExpression); { @@ -148,7 +148,7 @@ public void Utf8StringLiteral_04() [Fact] public void Utf8StringLiteral_05() { - UsingExpression(@"@""hello""u8", options: TestOptions.RegularNext); + UsingExpression(@"@""hello""u8", options: TestOptions.Regular11); N(SyntaxKind.Utf8StringLiteralExpression); { @@ -184,7 +184,7 @@ public void Utf8StringLiteral_07() [Fact] public void Utf8StringLiteral_08() { - UsingExpression(@"""hello""U8", options: TestOptions.RegularNext); + UsingExpression(@"""hello""U8", options: TestOptions.Regular11); N(SyntaxKind.Utf8StringLiteralExpression); { @@ -220,7 +220,7 @@ public void Utf8StringLiteral_10() [Fact] public void Utf8StringLiteral_11() { - UsingExpression(@"@""hello""U8", options: TestOptions.RegularNext); + UsingExpression(@"@""hello""U8", options: TestOptions.Regular11); N(SyntaxKind.Utf8StringLiteralExpression); { @@ -592,7 +592,7 @@ public void Interpolation_04() [Fact] public void Utf8StringLiteral_13() { - foreach (var options in new[] { TestOptions.RegularDefault, TestOptions.RegularNext, TestOptions.Regular10 }) + foreach (var options in new[] { TestOptions.RegularDefault, TestOptions.Regular11, TestOptions.Regular10 }) { foreach (var suffix in new[] { "u8", "U8" }) { @@ -610,7 +610,7 @@ public void Utf8StringLiteral_13() [Fact] public void Utf8StringLiteral_14() { - foreach (var options in new[] { TestOptions.RegularDefault, TestOptions.RegularNext, TestOptions.Regular10 }) + foreach (var options in new[] { TestOptions.RegularDefault, TestOptions.Regular11, TestOptions.Regular10 }) { foreach (var suffix in new[] { "u8", "U8" }) { @@ -746,7 +746,7 @@ public void Interpolation_06(string suffix) [Fact] public void Utf8StringLiteral_15() { - foreach (var options in new[] { TestOptions.RegularDefault, TestOptions.RegularNext, TestOptions.Regular10 }) + foreach (var options in new[] { TestOptions.RegularDefault, TestOptions.Regular11, TestOptions.Regular10 }) { foreach (var suffix in new[] { "u8", "U8" }) { @@ -768,7 +768,7 @@ public void Utf8StringLiteral_15() [Fact] public void Utf8StringLiteral_16() { - foreach (var options in new[] { TestOptions.RegularDefault, TestOptions.RegularNext, TestOptions.Regular10 }) + foreach (var options in new[] { TestOptions.RegularDefault, TestOptions.Regular11, TestOptions.Regular10 }) { foreach (var suffix in new[] { "u8", "U8" }) { diff --git a/src/Compilers/CSharp/Test/Syntax/Parsing/ValueTupleTests.cs b/src/Compilers/CSharp/Test/Syntax/Parsing/ValueTupleTests.cs index 8ee753002d30d..bcf16d54f153d 100644 --- a/src/Compilers/CSharp/Test/Syntax/Parsing/ValueTupleTests.cs +++ b/src/Compilers/CSharp/Test/Syntax/Parsing/ValueTupleTests.cs @@ -499,13 +499,11 @@ void Goo((int, string) a) [Fact] public void TupleTypeWithTooFewElements() { - var tree = UsingTree(@" + UsingTree(@" class C { void M(int x, () y, (int a) z) { } -}", options: TestOptions.Regular); - - tree.GetDiagnostics().Verify( +}", options: TestOptions.Regular, // (4,20): error CS8124: Tuple must contain at least two elements. // void M(int x, () y, (int a) z) { } Diagnostic(ErrorCode.ERR_TupleTooFewElements, ")").WithLocation(4, 20), @@ -608,13 +606,11 @@ void M(int x, () y, (int a) z) { } [Fact] public void TupleExpressionWithTooFewElements() { - var tree = UsingTree(@" + UsingTree(@" class C { object x = ((Alice: 1), ()); -}", options: TestOptions.Regular); - - tree.GetDiagnostics().Verify( +}", options: TestOptions.Regular, // (4,26): error CS8124: Tuple must contain at least two elements. // object x = ((Alice: 1), ()); Diagnostic(ErrorCode.ERR_TupleTooFewElements, ")").WithLocation(4, 26), diff --git a/src/Compilers/CSharp/Test/Syntax/Syntax/SyntaxNormalizerTests.cs b/src/Compilers/CSharp/Test/Syntax/Syntax/SyntaxNormalizerTests.cs index 206747bc1b5f5..181512efa1d79 100644 --- a/src/Compilers/CSharp/Test/Syntax/Syntax/SyntaxNormalizerTests.cs +++ b/src/Compilers/CSharp/Test/Syntax/Syntax/SyntaxNormalizerTests.cs @@ -1364,7 +1364,6 @@ public void TestNormalizeScopedLocals() { TestNormalizeStatement("scoped R x ;", "scoped R x;"); TestNormalizeStatement("scoped ref R y ;", "scoped ref R y;"); - TestNormalizeStatement("ref scoped R z ;", "ref scoped R z;"); } } } diff --git a/src/Compilers/CSharp/Test/Syntax/Syntax/SyntaxTests.cs b/src/Compilers/CSharp/Test/Syntax/Syntax/SyntaxTests.cs index e1c947a75c290..b7a7bafc05a6f 100644 --- a/src/Compilers/CSharp/Test/Syntax/Syntax/SyntaxTests.cs +++ b/src/Compilers/CSharp/Test/Syntax/Syntax/SyntaxTests.cs @@ -18,7 +18,7 @@ private static void AssertIncompleteSubmission(string code) Assert.False(SyntaxFactory.IsCompleteSubmission(SyntaxFactory.ParseSyntaxTree(code, options: TestOptions.Script))); } - private static void AssertCompleteSubmission(string code, bool isComplete = true) + private static void AssertCompleteSubmission(string code) { Assert.True(SyntaxFactory.IsCompleteSubmission(SyntaxFactory.ParseSyntaxTree(code, options: TestOptions.Script))); } diff --git a/src/Compilers/CSharp/Test/Syntax/Syntax/SyntaxTreeTests.cs b/src/Compilers/CSharp/Test/Syntax/Syntax/SyntaxTreeTests.cs index 0b84004d50a4e..ab4c0f5cb8346 100644 --- a/src/Compilers/CSharp/Test/Syntax/Syntax/SyntaxTreeTests.cs +++ b/src/Compilers/CSharp/Test/Syntax/Syntax/SyntaxTreeTests.cs @@ -21,16 +21,6 @@ public class SyntaxTreeTests : ParsingTests { public SyntaxTreeTests(ITestOutputHelper output) : base(output) { } - protected SyntaxTree UsingTree(string text, CSharpParseOptions options, params DiagnosticDescription[] expectedErrors) - { - var tree = base.UsingTree(text, options); - - var actualErrors = tree.GetDiagnostics(); - actualErrors.Verify(expectedErrors); - - return tree; - } - // Diagnostic options on syntax trees are now obsolete #pragma warning disable CS0618 [Fact] @@ -271,7 +261,6 @@ public void GlobalUsingDirective_01() public void GlobalUsingDirective_02() { var test = "global using ns1;"; - UsingTree(test, TestOptions.Regular9, // (1,1): error CS8773: Feature 'global using directive' is not available in C# 9.0. Please use language version 10.0 or greater. // global using ns1; diff --git a/src/Compilers/CSharp/Test/WinRT/Microsoft.CodeAnalysis.CSharp.WinRT.UnitTests.csproj b/src/Compilers/CSharp/Test/WinRT/Microsoft.CodeAnalysis.CSharp.WinRT.UnitTests.csproj index 72a86bd676d9a..2ba1d8d330569 100644 --- a/src/Compilers/CSharp/Test/WinRT/Microsoft.CodeAnalysis.CSharp.WinRT.UnitTests.csproj +++ b/src/Compilers/CSharp/Test/WinRT/Microsoft.CodeAnalysis.CSharp.WinRT.UnitTests.csproj @@ -7,6 +7,7 @@ net472 + diff --git a/src/Compilers/CSharp/csc/CscCommandLine.shproj b/src/Compilers/CSharp/csc/CscCommandLine.shproj index 2bc914979c147..6b03b1d859f7a 100644 --- a/src/Compilers/CSharp/csc/CscCommandLine.shproj +++ b/src/Compilers/CSharp/csc/CscCommandLine.shproj @@ -11,6 +11,7 @@ Condition="Exists('$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\CodeSharing\Microsoft.CodeSharing.Common.Default.props')" /> + \ No newline at end of file diff --git a/src/Compilers/Core/CodeAnalysisTest/CorLibTypesTests.cs b/src/Compilers/Core/CodeAnalysisTest/CorLibTypesTests.cs index 37ff9a1074120..f827959ab0bc0 100644 --- a/src/Compilers/Core/CodeAnalysisTest/CorLibTypesTests.cs +++ b/src/Compilers/Core/CodeAnalysisTest/CorLibTypesTests.cs @@ -6,6 +6,7 @@ using System; using System.Collections.Generic; +using Microsoft.CodeAnalysis.Test.Utilities; using Roslyn.Test.Utilities; using Xunit; @@ -191,10 +192,9 @@ public void ConstantValueGetHashCodeTest02() [Fact] public void ConstantValueToStringTest01() { - var value = "Null"; -#if NETCOREAPP - value = "Nothing"; -#endif + string value = (RuntimeUtilities.IsCoreClrRuntime && !RuntimeUtilities.IsCoreClr6Runtime) + ? "Nothing" + : "Null"; var cv = ConstantValue.Create(null, ConstantValueTypeDiscriminator.Null); Assert.Equal($"ConstantValueNull(null: {value})", cv.ToString()); diff --git a/src/Compilers/Core/CodeAnalysisTest/MetadataReferences/ModuleMetadataTests.cs b/src/Compilers/Core/CodeAnalysisTest/MetadataReferences/ModuleMetadataTests.cs index 2fc08fc64e558..4ec0be5bd174c 100644 --- a/src/Compilers/Core/CodeAnalysisTest/MetadataReferences/ModuleMetadataTests.cs +++ b/src/Compilers/Core/CodeAnalysisTest/MetadataReferences/ModuleMetadataTests.cs @@ -64,7 +64,7 @@ public unsafe void CreateFromMetadata_Assembly_Stream() fixed (byte* ptr = &assembly[h.MetadataStartOffset]) { var stream = new UnmanagedMemoryStream(ptr, h.MetadataSize); - var metadata = ModuleMetadata.CreateFromMetadata((IntPtr)stream.PositionPointer, (int)stream.Length, stream, disposeOwner: true); + var metadata = ModuleMetadata.CreateFromMetadata((IntPtr)stream.PositionPointer, (int)stream.Length, stream.Dispose); Assert.Equal(new AssemblyIdentity("Members"), metadata.Module.ReadAssemblyIdentityOrThrow()); } } @@ -78,7 +78,7 @@ public unsafe void CreateFromMetadata_Module_Stream() fixed (byte* ptr = &netModule[h.MetadataStartOffset]) { var stream = new UnmanagedMemoryStream(ptr, h.MetadataSize); - ModuleMetadata.CreateFromMetadata((IntPtr)stream.PositionPointer, (int)stream.Length, stream, disposeOwner: true); + ModuleMetadata.CreateFromMetadata((IntPtr)stream.PositionPointer, (int)stream.Length, stream.Dispose); } } @@ -214,7 +214,7 @@ public unsafe void CreateFromMetadata_Assembly_Stream_DisposeOwnerTrue() OnSeek = (_, _) => seeked = true, }; - var metadata = ModuleMetadata.CreateFromMetadata((IntPtr)stream.PositionPointer, (int)stream.Length, stream, disposeOwner: true); + var metadata = ModuleMetadata.CreateFromMetadata((IntPtr)stream.PositionPointer, (int)stream.Length, stream.Dispose); Assert.Equal(new AssemblyIdentity("Members"), metadata.Module.ReadAssemblyIdentityOrThrow()); // Disposing the metadata should dispose the stream. @@ -272,7 +272,7 @@ public unsafe void CreateFromMetadata_Assembly_Stream_DisposeOwnerFalse() OnSeek = (_, _) => seeked = true, }; - var metadata = ModuleMetadata.CreateFromMetadata((IntPtr)stream.PositionPointer, (int)stream.Length, stream, disposeOwner: false); + var metadata = ModuleMetadata.CreateFromMetadata((IntPtr)stream.PositionPointer, (int)stream.Length); Assert.Equal(new AssemblyIdentity("Members"), metadata.Module.ReadAssemblyIdentityOrThrow()); // Disposing the metadata should not dispose the stream. diff --git a/src/Compilers/Core/MSBuildTask/ManagedCompiler.cs b/src/Compilers/Core/MSBuildTask/ManagedCompiler.cs index 048f07dae9ca1..42f996abfcf3a 100644 --- a/src/Compilers/Core/MSBuildTask/ManagedCompiler.cs +++ b/src/Compilers/Core/MSBuildTask/ManagedCompiler.cs @@ -642,15 +642,17 @@ private string CurrentDirectoryToUse() /// private int HandleResponse(Guid requestId, BuildResponse? response, string pathToTool, string responseFileCommands, string commandLineCommands, ICompilerServerLogger logger) { - if (response is null) +#if BOOTSTRAP + if (!ValidateBootstrapResponse(response)) { - LogCompilationMessage(logger, requestId, CompilationKind.ToolFallback, "could not launch server"); - return base.ExecuteTool(pathToTool, responseFileCommands, commandLineCommands); + return 1; } +#endif - if (response.Type != BuildResponse.ResponseType.Completed) + if (response is null) { - ValidateBootstrapUtil.AddFailedServerConnection(response.Type, OutputAssembly?.ItemSpec); + LogCompilationMessage(logger, requestId, CompilationKind.ToolFallback, "could not launch server"); + return base.ExecuteTool(pathToTool, responseFileCommands, commandLineCommands); } switch (response.Type) @@ -690,6 +692,66 @@ private int HandleResponse(Guid requestId, BuildResponse? response, string pathT } } +#if BOOTSTRAP +#pragma warning disable IDE0044 + /// + /// Keeps track of the number of times the task failed to connect to the compiler + /// server. Even in valid builds this can be greater than zero (connect is + /// inherently a race condition). If this gets too high though in a bootstrap build + /// it's evidence of a bigger issue the team should be looking at. + /// + private static int s_connectFailedCount; + +#pragma warning restore IDE0044 + + + /// + /// In bootstrap builds this validates the response. When this returns false it + /// indicates the bootstrap build is incorrect and the compilation should fail. + /// + private bool ValidateBootstrapResponse(BuildResponse? response) + { + // This represents the maximum number of failed connection attempts on the server before we will declare + // that the overall build itself failed. Keeping this at zero is not realistic because even in a fully + // functioning server connection failures are expected. The server could be too busy to accept connections + // fast enough. Anything above this count though is considered worth investigating by the compiler team. + // + const int maxCannotConnectCount = 2; + + var responseType = response?.Type ?? BuildResponse.ResponseType.CannotConnect; + switch (responseType) + { + case BuildResponse.ResponseType.AnalyzerInconsistency: + Log.LogError($"Analyzer inconsistency building"); + return false; + case BuildResponse.ResponseType.MismatchedVersion: + case BuildResponse.ResponseType.IncorrectHash: + Log.LogError($"Critical error {responseType} when building"); + return false; + case BuildResponse.ResponseType.Rejected: + Log.LogError($"Compiler request rejected"); + return false; + case BuildResponse.ResponseType.CannotConnect: + if (Interlocked.Increment(ref s_connectFailedCount) > maxCannotConnectCount) + { + Log.LogError("Too many errors connecting to the server"); + return false; + } + return true; + + case BuildResponse.ResponseType.Completed: + case BuildResponse.ResponseType.Shutdown: + // Expected messages + break; + default: + Log.LogError($"Unexpected response type {responseType}"); + return false; + } + + return true; + } +#endif + /// /// Log the compiler output to MSBuild. Each language will override this to parse their output and log it /// in the language specific manner. This often involves parsing the raw output and formatting it as diff --git a/src/Compilers/Core/MSBuildTask/Microsoft.CSharp.Core.targets b/src/Compilers/Core/MSBuildTask/Microsoft.CSharp.Core.targets index 13c33cffbbc55..1cb4a18886d00 100644 --- a/src/Compilers/Core/MSBuildTask/Microsoft.CSharp.Core.targets +++ b/src/Compilers/Core/MSBuildTask/Microsoft.CSharp.Core.targets @@ -21,6 +21,10 @@ <_MaxSupportedLangVersion Condition="'$(TargetFrameworkIdentifier)' == '.NETCoreApp' AND '$(_TargetFrameworkVersionWithoutV)' == '6.0' AND '$(_MaxSupportedLangVersion)' == ''">10.0 + + <_MaxSupportedLangVersion Condition="'$(TargetFrameworkIdentifier)' == '.NETCoreApp' AND '$(_TargetFrameworkVersionWithoutV)' == '7.0' AND + '$(_MaxSupportedLangVersion)' == ''">11.0 + $(_MaxSupportedLangVersion) $(_MaxSupportedLangVersion) @@ -161,4 +165,26 @@ + + + + + -langversion:$(LangVersion) + $(CommandLineArgsForDesignTimeEvaluation) -define:$(DefineConstants) + \ No newline at end of file diff --git a/src/Compilers/Core/MSBuildTask/Microsoft.VisualBasic.Core.targets b/src/Compilers/Core/MSBuildTask/Microsoft.VisualBasic.Core.targets index 87d18a5bab770..e88164ac42f35 100644 --- a/src/Compilers/Core/MSBuildTask/Microsoft.VisualBasic.Core.targets +++ b/src/Compilers/Core/MSBuildTask/Microsoft.VisualBasic.Core.targets @@ -134,4 +134,26 @@ + + + + + -langversion:$(LangVersion) + $(CommandLineArgsForDesignTimeEvaluation) -define:$(FinalDefineConstants) + diff --git a/src/Compilers/Core/MSBuildTask/ValidateBootstrap.cs b/src/Compilers/Core/MSBuildTask/ValidateBootstrap.cs index 239439c80603a..9158aa9abf9dd 100644 --- a/src/Compilers/Core/MSBuildTask/ValidateBootstrap.cs +++ b/src/Compilers/Core/MSBuildTask/ValidateBootstrap.cs @@ -2,9 +2,8 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using System.Reflection; +#if BOOTSTRAP -#if DEBUG || BOOTSTRAP using System; using System.Collections.Concurrent; using System.Diagnostics.CodeAnalysis; @@ -13,23 +12,15 @@ using System.Threading; using Microsoft.Build.Utilities; using Roslyn.Utilities; -#endif namespace Microsoft.CodeAnalysis.BuildTasks { - using static Microsoft.CodeAnalysis.CommandLine.BuildResponse; - -#if DEBUG || BOOTSTRAP /// - /// This task exists to help us validate our bootstrap building phase is executing correctly. The bootstrap - /// phase of CI is the best way to validate the integration of our components is functioning correctly. Items - /// which are difficult to validate in a unit test scenario. + /// This task exists to help us validate our bootstrap build is loading the correct binary from disk. Ensuring + /// it loads the bootstrap binaries and not the standard build binaries. /// public sealed partial class ValidateBootstrap : Task { - private static readonly ConcurrentDictionary s_failedLoadSet = new ConcurrentDictionary(); - private static readonly ConcurrentQueue<(ResponseType ResponseType, string? OutputAssembly)> s_failedQueue = new ConcurrentQueue<(ResponseType ResponseType, string? OutputAssembly)>(); - private string? _tasksAssemblyFullPath; [DisallowNull] @@ -52,68 +43,14 @@ public override bool Execute() return false; } - var allGood = true; var fullPath = typeof(ValidateBootstrap).Assembly.Location; if (!StringComparer.OrdinalIgnoreCase.Equals(TasksAssemblyFullPath, fullPath)) { Log.LogError($"Bootstrap assembly {Path.GetFileName(fullPath)} incorrectly loaded from {fullPath} instead of {TasksAssemblyFullPath}"); - allGood = false; - } - - var failedLoads = s_failedLoadSet.Keys.ToList(); - if (failedLoads.Count > 0) - { - foreach (var name in failedLoads.OrderBy(x => x.Name)) - { - Log.LogError($"Assembly resolution failed for {name}"); - allGood = false; - } - } - - // This represents the maximum number of failed connection attempts on the server before we will declare - // that the overall build itself failed. Keeping this at zero is not realistic because even in a fully - // functioning server connection failures are expected. The server could be too busy to accept connections - // fast enough. Anything above this count though is considered worth investigating by the compiler team. - // - const int maxCannotConnectCount = 2; - var cannotConnectCount = 0; - foreach (var tuple in s_failedQueue.ToList()) - { - switch (tuple.ResponseType) - { - case ResponseType.AnalyzerInconsistency: - Log.LogError($"Analyzer inconsistency building {tuple.OutputAssembly}"); - allGood = false; - break; - case ResponseType.MismatchedVersion: - case ResponseType.IncorrectHash: - Log.LogError($"Critical error {tuple.ResponseType} building {tuple.OutputAssembly}"); - allGood = false; - break; - case ResponseType.Rejected: - Log.LogError($"Compiler request rejected"); - allGood = false; - break; - case ResponseType.CannotConnect: - cannotConnectCount++; - if (cannotConnectCount > maxCannotConnectCount) - { - Log.LogError("Too many errors connecting to the server"); - allGood = false; - } - break; - case ResponseType.Completed: - case ResponseType.Shutdown: - // Expected messages - break; - default: - Log.LogError($"Unexpected response type {tuple.ResponseType}"); - allGood = false; - break; - } + return false; } - return allGood; + return true; } [return: NotNullIfNotNull("path")] @@ -132,45 +69,6 @@ public override bool Execute() return path; } - - private string? GetDirectory(Assembly assembly) => Path.GetDirectoryName(Utilities.TryGetAssemblyPath(assembly)); - - internal static void AddFailedLoad(AssemblyName name) - { - switch (name.Name) - { - case "System": - case "System.Core": - case "Microsoft.Build.Tasks.CodeAnalysis.resources": - // These are failures are expected by design. - break; - default: - s_failedLoadSet.TryAdd(name, 0); - break; - } - } - - internal static void AddFailedServerConnection(ResponseType type, string? outputAssembly) - { - s_failedQueue.Enqueue((type, outputAssembly)); - } - } -#endif - - internal static class ValidateBootstrapUtil - { - internal static void AddFailedLoad(AssemblyName name) - { -#if DEBUG || BOOTSTRAP - ValidateBootstrap.AddFailedLoad(name); -#endif - } - - internal static void AddFailedServerConnection(ResponseType type, string? outputAssembly) - { -#if DEBUG || BOOTSTRAP - ValidateBootstrap.AddFailedServerConnection(type, outputAssembly); -#endif - } } } +#endif diff --git a/src/Compilers/Core/MSBuildTaskTests/TargetTests.cs b/src/Compilers/Core/MSBuildTaskTests/TargetTests.cs index becbb2d6a46bc..b2335b269d65f 100644 --- a/src/Compilers/Core/MSBuildTaskTests/TargetTests.cs +++ b/src/Compilers/Core/MSBuildTaskTests/TargetTests.cs @@ -400,7 +400,8 @@ public void GenerateEditorConfigCoreHandlesMalformedCompilerVisibleItemMetadata( [InlineData(".NETCoreApp", "3.1", "8.0")] [InlineData(".NETCoreApp", "5.0", "9.0")] [InlineData(".NETCoreApp", "6.0", "10.0")] - [InlineData(".NETCoreApp", "7.0", "")] + [InlineData(".NETCoreApp", "7.0", "11.0")] + [InlineData(".NETCoreApp", "8.0", "")] [InlineData(".NETStandard", "1.0", "7.3")] [InlineData(".NETStandard", "1.5", "7.3")] @@ -434,7 +435,7 @@ public void LanguageVersionGivenTargetFramework(string tfi, string tfv, string e // This will fail whenever the current language version is updated. // Ensure you update the target files to select the correct CSharp version for the newest target framework // and add to the theory data above to cover it, before changing this version to make the test pass again. - Assert.Equal(CSharp.LanguageVersion.CSharp10, CSharp.LanguageVersionFacts.CurrentVersion); + Assert.Equal(CSharp.LanguageVersion.CSharp11, CSharp.LanguageVersionFacts.CurrentVersion); } [Fact] diff --git a/src/Compilers/Core/Portable/CodeAnalysisResources.resx b/src/Compilers/Core/Portable/CodeAnalysisResources.resx index c8c5d135b2883..4565948834d19 100644 --- a/src/Compilers/Core/Portable/CodeAnalysisResources.resx +++ b/src/Compilers/Core/Portable/CodeAnalysisResources.resx @@ -728,4 +728,10 @@ Edit and Continue can't resume suspended iterator since the corresponding yield return statement has been deleted - \ No newline at end of file + + Generator + + + Total generator execution time: {0} seconds. + + diff --git a/src/Compilers/Core/Portable/CodeGen/CompilationTestData.cs b/src/Compilers/Core/Portable/CodeGen/CompilationTestData.cs index b0cb635e5360a..084f15f4153f2 100644 --- a/src/Compilers/Core/Portable/CodeGen/CompilationTestData.cs +++ b/src/Compilers/Core/Portable/CodeGen/CompilationTestData.cs @@ -68,7 +68,7 @@ public ImmutableDictionary GetMethodsByName() } private static readonly SymbolDisplayFormat _testDataKeyFormat = new SymbolDisplayFormat( - compilerInternalOptions: SymbolDisplayCompilerInternalOptions.UseMetadataMethodNames | SymbolDisplayCompilerInternalOptions.UseValueTuple, + compilerInternalOptions: SymbolDisplayCompilerInternalOptions.UseMetadataMethodNames | SymbolDisplayCompilerInternalOptions.UseValueTuple | SymbolDisplayCompilerInternalOptions.IncludeContainingFileForFileTypes, globalNamespaceStyle: SymbolDisplayGlobalNamespaceStyle.OmittedAsContaining, typeQualificationStyle: SymbolDisplayTypeQualificationStyle.NameAndContainingTypesAndNamespaces, genericsOptions: SymbolDisplayGenericsOptions.IncludeTypeParameters | SymbolDisplayGenericsOptions.IncludeVariance, diff --git a/src/Compilers/Core/Portable/CodeGen/ILBuilderConversions.cs b/src/Compilers/Core/Portable/CodeGen/ILBuilderConversions.cs index f3f42b1d9a983..53e9a6aae240b 100644 --- a/src/Compilers/Core/Portable/CodeGen/ILBuilderConversions.cs +++ b/src/Compilers/Core/Portable/CodeGen/ILBuilderConversions.cs @@ -128,6 +128,7 @@ public void EmitNumericConversion(Microsoft.Cci.PrimitiveTypeCode fromPredefType switch (fromPredefTypeKind) { case Microsoft.Cci.PrimitiveTypeCode.IntPtr: + case Microsoft.Cci.PrimitiveTypeCode.UIntPtr when !@checked: break; // NOP case Microsoft.Cci.PrimitiveTypeCode.Int8: case Microsoft.Cci.PrimitiveTypeCode.Int16: @@ -166,6 +167,7 @@ public void EmitNumericConversion(Microsoft.Cci.PrimitiveTypeCode fromPredefType switch (fromPredefTypeKind) { case Microsoft.Cci.PrimitiveTypeCode.UIntPtr: + case Microsoft.Cci.PrimitiveTypeCode.IntPtr when !@checked: case Microsoft.Cci.PrimitiveTypeCode.Pointer: case Microsoft.Cci.PrimitiveTypeCode.FunctionPointer: break; // NOP diff --git a/src/Compilers/Core/Portable/CodeGen/PrivateImplementationDetails.cs b/src/Compilers/Core/Portable/CodeGen/PrivateImplementationDetails.cs index e65375f0206bf..6d97be32cc7ab 100644 --- a/src/Compilers/Core/Portable/CodeGen/PrivateImplementationDetails.cs +++ b/src/Compilers/Core/Portable/CodeGen/PrivateImplementationDetails.cs @@ -596,6 +596,8 @@ public TypeDefinitionHandle TypeDef public bool MangleName => false; + public string? AssociatedFileIdentifier => null; + public virtual ushort Alignment => 0; public virtual Cci.ITypeReference GetBaseClass(EmitContext context) diff --git a/src/Compilers/Core/Portable/CodeGen/StateMachineState.cs b/src/Compilers/Core/Portable/CodeGen/StateMachineState.cs new file mode 100644 index 0000000000000..4143c648836ba --- /dev/null +++ b/src/Compilers/Core/Portable/CodeGen/StateMachineState.cs @@ -0,0 +1,46 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +namespace Microsoft.CodeAnalysis; + +internal enum StateMachineState +{ + /// + /// First state of an async iterator state machine that is used to resume the machine after yield return. + /// Initial state is not used to resume state machine that yielded. State numbers decrease as the iterator makes progress. + /// + FirstResumableAsyncIteratorState = InitialAsyncIteratorState - 1, + + /// + /// Initial iterator state of an async iterator. + /// Distinct from so that DisposeAsync can throw in latter case. + /// + InitialAsyncIteratorState = -3, + + /// + /// First state of an iterator state machine. State numbers decrease for subsequent finalize states. + /// + FirstIteratorFinalizeState = -3, + + FinishedState = -2, + NotStartedOrRunningState = -1, + FirstUnusedState = 0, + + /// + /// First state in async state machine that is used to resume the machine after await. + /// State numbers increase as the async computation makes progress. + /// + FirstResumableAsyncState = 0, + + /// + /// Initial iterator state of an iterator. + /// + InitialIteratorState = 0, + + /// + /// First state in iterator state machine that is used to resume the machine after yield return. + /// Initial state is not used to resume state machine that yielded. State numbers increase as the iterator makes progress. + /// + FirstResumableIteratorState = InitialIteratorState + 1, +} diff --git a/src/Compilers/Core/Portable/CodeGen/StateMachineStateDebugInfo.cs b/src/Compilers/Core/Portable/CodeGen/StateMachineStateDebugInfo.cs index e772df5aab45e..e4196126666fb 100644 --- a/src/Compilers/Core/Portable/CodeGen/StateMachineStateDebugInfo.cs +++ b/src/Compilers/Core/Portable/CodeGen/StateMachineStateDebugInfo.cs @@ -5,28 +5,49 @@ using System; using System.Collections.Immutable; using System.Linq; +using Microsoft.CodeAnalysis.Emit; namespace Microsoft.CodeAnalysis.CodeGen; internal readonly struct StateMachineStateDebugInfo { public readonly int SyntaxOffset; - public readonly int StateNumber; + public readonly StateMachineState StateNumber; - public StateMachineStateDebugInfo(int syntaxOffset, int stateNumber) + public StateMachineStateDebugInfo(int syntaxOffset, StateMachineState stateNumber) { SyntaxOffset = syntaxOffset; StateNumber = stateNumber; } } +/// +/// Debug information maintained for each state machine. +/// Facilitates mapping of state machine states from a compilation to the previous one (or to a metadata baseline) during EnC. +/// internal readonly struct StateMachineStatesDebugInfo { public readonly ImmutableArray States; - public readonly int? FirstUnusedIncreasingStateMachineState; - public readonly int? FirstUnusedDecreasingStateMachineState; - public StateMachineStatesDebugInfo(ImmutableArray states, int? firstUnusedIncreasingStateMachineState, int? firstUnusedDecreasingStateMachineState) + /// + /// The number of the first state that has not been used in any of the previous versions of the state machine, + /// or null if we are not generating EnC delta. + /// + /// For 1st generation EnC delta, this is calculated by examining the stored in the baseline metadata. + /// For subsequent generations, the number is updated to account for newly generated states in that generation. + /// + public readonly StateMachineState? FirstUnusedIncreasingStateMachineState; + + /// + /// The number of the first state that has not been used in any of the previous versions of the state machine, + /// or null if we are not generating EnC delta, or the state machine has no decreasing states. + /// + /// For 1st generation EnC delta, this is calculated by examining the stored in the baseline metadata. + /// For subsequent generations, the number is updated to account for newly generated states in that generation. + /// + public readonly StateMachineState? FirstUnusedDecreasingStateMachineState; + + private StateMachineStatesDebugInfo(ImmutableArray states, StateMachineState? firstUnusedIncreasingStateMachineState, StateMachineState? firstUnusedDecreasingStateMachineState) { States = states; FirstUnusedIncreasingStateMachineState = firstUnusedIncreasingStateMachineState; @@ -35,7 +56,7 @@ public StateMachineStatesDebugInfo(ImmutableArray st public static StateMachineStatesDebugInfo Create(VariableSlotAllocator? variableSlotAllocator, ImmutableArray stateInfos) { - int? firstUnusedIncreasingStateMachineState = null, firstUnusedDecreasingStateMachineState = null; + StateMachineState? firstUnusedIncreasingStateMachineState = null, firstUnusedDecreasingStateMachineState = null; if (variableSlotAllocator != null) { @@ -51,11 +72,11 @@ public static StateMachineStatesDebugInfo Create(VariableSlotAllocator? variable var maxState = stateInfos.Max(info => info.StateNumber) + 1; var minState = stateInfos.Min(info => info.StateNumber) - 1; - firstUnusedIncreasingStateMachineState = (firstUnusedIncreasingStateMachineState != null) ? Math.Max(firstUnusedIncreasingStateMachineState.Value, maxState) : maxState; + firstUnusedIncreasingStateMachineState = (firstUnusedIncreasingStateMachineState != null) ? (StateMachineState)Math.Max((int)firstUnusedIncreasingStateMachineState.Value, (int)maxState) : maxState; if (minState < 0) { - firstUnusedDecreasingStateMachineState = (firstUnusedDecreasingStateMachineState != null) ? Math.Min(firstUnusedDecreasingStateMachineState.Value, minState) : minState; + firstUnusedDecreasingStateMachineState = (firstUnusedDecreasingStateMachineState != null) ? (StateMachineState)Math.Min((int)firstUnusedDecreasingStateMachineState.Value, (int)minState) : minState; } } } diff --git a/src/Compilers/Core/Portable/CodeGen/VariableSlotAllocator.cs b/src/Compilers/Core/Portable/CodeGen/VariableSlotAllocator.cs index d0bac38235b1f..557bffc19b857 100644 --- a/src/Compilers/Core/Portable/CodeGen/VariableSlotAllocator.cs +++ b/src/Compilers/Core/Portable/CodeGen/VariableSlotAllocator.cs @@ -83,10 +83,10 @@ public abstract bool TryGetPreviousHoistedLocalSlotIndex( /// /// State number to be used for next state of the state machine, - /// or if none of the previous versions of the method was a state machine with a increasing state + /// or if none of the previous versions of the method was a state machine with an increasing state /// - /// True if the state number increases with progress, false if it decreases. - public abstract int? GetFirstUnusedStateMachineState(bool increasing); + /// True if the state number increases with progress, false if it decreases (e.g. states for iterator try-finally blocks, or iterator states of async iterators). + public abstract StateMachineState? GetFirstUnusedStateMachineState(bool increasing); /// /// For a given node associated with entering a state of a state machine in the new compilation, @@ -98,6 +98,6 @@ public abstract bool TryGetPreviousHoistedLocalSlotIndex( /// /// is an await expression, yield return statement, or try block syntax node. /// - public abstract bool TryGetPreviousStateMachineState(SyntaxNode syntax, out int stateOrdinal); + public abstract bool TryGetPreviousStateMachineState(SyntaxNode syntax, out StateMachineState state); } } diff --git a/src/Compilers/Core/Portable/Collections/ImmutableArrayExtensions.cs b/src/Compilers/Core/Portable/Collections/ImmutableArrayExtensions.cs index 889885970e3f9..9702f9e6408a3 100644 --- a/src/Compilers/Core/Portable/Collections/ImmutableArrayExtensions.cs +++ b/src/Compilers/Core/Portable/Collections/ImmutableArrayExtensions.cs @@ -738,6 +738,15 @@ public static int Count(this ImmutableArray items, Func predicate return count; } + public static int Sum(this ImmutableArray items, Func selector) + { + var sum = 0; + foreach (var item in items) + sum += selector(item); + + return sum; + } + internal static Dictionary> ToDictionary(this ImmutableArray items, Func keySelector, IEqualityComparer? comparer = null) where K : notnull { diff --git a/src/Compilers/Core/Portable/CommandLine/CommonCompiler.cs b/src/Compilers/Core/Portable/CommandLine/CommonCompiler.cs index 8baa2e86d268d..772ef2fef629e 100644 --- a/src/Compilers/Core/Portable/CommandLine/CommonCompiler.cs +++ b/src/Compilers/Core/Portable/CommandLine/CommonCompiler.cs @@ -730,15 +730,23 @@ public virtual int Run(TextWriter consoleOutput, CancellationToken cancellationT /// The compilation before any source generation has occurred. /// The to use when parsing any generated sources. /// The generators to run - /// A provider that returns analyzer config options + /// A provider that returns analyzer config options. /// Any additional texts that should be passed to the generators when run. - /// Any diagnostics that were produced during generation + /// Any diagnostics that were produced during generation. /// A compilation that represents the original compilation with any additional, generated texts added to it. - private protected Compilation RunGenerators(Compilation input, ParseOptions parseOptions, ImmutableArray generators, AnalyzerConfigOptionsProvider analyzerConfigOptionsProvider, ImmutableArray additionalTexts, DiagnosticBag generatorDiagnostics) + private protected (Compilation Compilation, GeneratorDriverTimingInfo DriverTimingInfo) RunGenerators( + Compilation input, + ParseOptions parseOptions, + ImmutableArray generators, + AnalyzerConfigOptionsProvider analyzerConfigOptionsProvider, + ImmutableArray additionalTexts, + DiagnosticBag generatorDiagnostics) { GeneratorDriver? driver = null; string cacheKey = string.Empty; - bool disableCache = !Arguments.ParseOptions.Features.ContainsKey("enable-generator-cache") || string.IsNullOrWhiteSpace(Arguments.OutputFileName); + bool disableCache = + !Arguments.ParseOptions.Features.ContainsKey("enable-generator-cache") || + string.IsNullOrWhiteSpace(Arguments.OutputFileName); if (this.GeneratorDriverCache is object && !disableCache) { cacheKey = deriveCacheKey(); @@ -756,7 +764,8 @@ private protected Compilation RunGenerators(Compilation input, ParseOptions pars { this.GeneratorDriverCache?.CacheGenerator(cacheKey, driver); } - return compilationOut; + + return (compilationOut, driver.GetTimingInfo()); string deriveCacheKey() { @@ -878,8 +887,8 @@ private int RunCore(TextWriter consoleOutput, ErrorLogger? errorLogger, Cancella diagnostics, cancellationToken, out CancellationTokenSource? analyzerCts, - out bool reportAnalyzer, - out var analyzerDriver); + out var analyzerDriver, + out var driverTimingInfo); // At this point analyzers are already complete in which case this is a no-op. Or they are // still running because the compilation failed before all of the compilation events were @@ -905,10 +914,9 @@ private int RunCore(TextWriter consoleOutput, ErrorLogger? errorLogger, Cancella } diagnostics.Free(); - if (reportAnalyzer) + if (Arguments.ReportAnalyzer) { - Debug.Assert(analyzerDriver is object); - ReportAnalyzerExecutionTime(consoleOutput, analyzerDriver, Culture, compilation.Options.ConcurrentBuild); + ReportAnalyzerUtil.Report(consoleOutput, analyzerDriver, driverTimingInfo, Culture, compilation.Options.ConcurrentBuild); } return exitCode; @@ -972,12 +980,12 @@ private void CompileAndEmit( DiagnosticBag diagnostics, CancellationToken cancellationToken, out CancellationTokenSource? analyzerCts, - out bool reportAnalyzer, - out AnalyzerDriver? analyzerDriver) + out AnalyzerDriver? analyzerDriver, + out GeneratorDriverTimingInfo? generatorTimingInfo) { analyzerCts = null; - reportAnalyzer = false; analyzerDriver = null; + generatorTimingInfo = null; // Print the diagnostics produced during the parsing stage and exit if there were any errors. compilation.GetDiagnostics(CompilationStage.Parse, includeEarlierStages: false, diagnostics, cancellationToken); @@ -1017,13 +1025,11 @@ private void CompileAndEmit( { // At this point we have a compilation with nothing yet computed. // We pass it to the generators, which will realize any symbols they require. - compilation = RunGenerators(compilation, Arguments.ParseOptions, generators, analyzerConfigProvider, additionalTextFiles, diagnostics); + (compilation, generatorTimingInfo) = RunGenerators(compilation, Arguments.ParseOptions, generators, analyzerConfigProvider, additionalTextFiles, diagnostics); bool hasAnalyzerConfigs = !Arguments.AnalyzerConfigPaths.IsEmpty; bool hasGeneratedOutputPath = !string.IsNullOrWhiteSpace(Arguments.GeneratedFilesOutputDirectory); - var generatedSyntaxTrees = compilation.SyntaxTrees.Skip(Arguments.SourceFiles.Length).ToList(); - var analyzerOptionsBuilder = hasAnalyzerConfigs ? ArrayBuilder.GetInstance(generatedSyntaxTrees.Count) : null; var embeddedTextBuilder = ArrayBuilder.GetInstance(generatedSyntaxTrees.Count); try @@ -1106,7 +1112,6 @@ private void CompileAndEmit( severityFilter, out compilation, analyzerCts.Token); - reportAnalyzer = Arguments.ReportAnalyzer && !analyzers.IsEmpty; } } @@ -1461,72 +1466,6 @@ protected virtual ImmutableArray ResolveAdditionalFilesFromA return builder.ToImmutableAndFree(); } - private static void ReportAnalyzerExecutionTime(TextWriter consoleOutput, AnalyzerDriver analyzerDriver, CultureInfo culture, bool isConcurrentBuild) - { - Debug.Assert(analyzerDriver.AnalyzerExecutionTimes != null); - if (analyzerDriver.AnalyzerExecutionTimes.IsEmpty) - { - return; - } - - var totalAnalyzerExecutionTime = analyzerDriver.AnalyzerExecutionTimes.Sum(kvp => kvp.Value.TotalSeconds); - Func getFormattedTime = d => d.ToString("##0.000", culture); - consoleOutput.WriteLine(); - consoleOutput.WriteLine(string.Format(CodeAnalysisResources.AnalyzerTotalExecutionTime, getFormattedTime(totalAnalyzerExecutionTime))); - - if (isConcurrentBuild) - { - consoleOutput.WriteLine(CodeAnalysisResources.MultithreadedAnalyzerExecutionNote); - } - - var analyzersByAssembly = analyzerDriver.AnalyzerExecutionTimes - .GroupBy(kvp => kvp.Key.GetType().GetTypeInfo().Assembly) - .OrderByDescending(kvp => kvp.Sum(entry => entry.Value.Ticks)); - - consoleOutput.WriteLine(); - - getFormattedTime = d => d < 0.001 ? - string.Format(culture, "{0,8:<0.000}", 0.001) : - string.Format(culture, "{0,8:##0.000}", d); - Func getFormattedPercentage = i => string.Format("{0,5}", i < 1 ? "<1" : i.ToString()); - Func getFormattedAnalyzerName = s => " " + s; - - // Table header - var analyzerTimeColumn = string.Format("{0,8}", CodeAnalysisResources.AnalyzerExecutionTimeColumnHeader); - var analyzerPercentageColumn = string.Format("{0,5}", "%"); - var analyzerNameColumn = getFormattedAnalyzerName(CodeAnalysisResources.AnalyzerNameColumnHeader); - consoleOutput.WriteLine(analyzerTimeColumn + analyzerPercentageColumn + analyzerNameColumn); - - // Table rows grouped by assembly. - foreach (var analyzerGroup in analyzersByAssembly) - { - var executionTime = analyzerGroup.Sum(kvp => kvp.Value.TotalSeconds); - var percentage = (int)(executionTime * 100 / totalAnalyzerExecutionTime); - - analyzerTimeColumn = getFormattedTime(executionTime); - analyzerPercentageColumn = getFormattedPercentage(percentage); - analyzerNameColumn = getFormattedAnalyzerName(analyzerGroup.Key.FullName); - - consoleOutput.WriteLine(analyzerTimeColumn + analyzerPercentageColumn + analyzerNameColumn); - - // Rows for each diagnostic analyzer in the assembly. - foreach (var kvp in analyzerGroup.OrderByDescending(kvp => kvp.Value)) - { - executionTime = kvp.Value.TotalSeconds; - percentage = (int)(executionTime * 100 / totalAnalyzerExecutionTime); - - analyzerTimeColumn = getFormattedTime(executionTime); - analyzerPercentageColumn = getFormattedPercentage(percentage); - var analyzerIds = string.Join(", ", kvp.Key.SupportedDiagnostics.Select(d => d.Id).Distinct().OrderBy(id => id)); - analyzerNameColumn = getFormattedAnalyzerName($" {kvp.Key} ({analyzerIds})"); - - consoleOutput.WriteLine(analyzerTimeColumn + analyzerPercentageColumn + analyzerNameColumn); - } - - consoleOutput.WriteLine(); - } - } - /// /// Returns the name with which the assembly should be output /// diff --git a/src/Compilers/Core/Portable/CommandLine/ReportAnalyzerUtil.cs b/src/Compilers/Core/Portable/CommandLine/ReportAnalyzerUtil.cs new file mode 100644 index 0000000000000..bccdbf2d24980 --- /dev/null +++ b/src/Compilers/Core/Portable/CommandLine/ReportAnalyzerUtil.cs @@ -0,0 +1,135 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation 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.Text; +using Microsoft.CodeAnalysis.Diagnostics; + +namespace Microsoft.CodeAnalysis +{ + internal static class ReportAnalyzerUtil + { + public static void Report( + TextWriter consoleOutput, + AnalyzerDriver? analyzerDriver, + GeneratorDriverTimingInfo? driverTimingInfo, + CultureInfo culture, + bool isConcurrentBuild) + { + if (isConcurrentBuild && (analyzerDriver is { } || driverTimingInfo is { })) + { + consoleOutput.WriteLine(CodeAnalysisResources.MultithreadedAnalyzerExecutionNote); + consoleOutput.WriteLine(); + } + + if (analyzerDriver is { }) + { + ReportAnalyzerExecutionTime(consoleOutput, analyzerDriver, culture); + } + + if (driverTimingInfo is { } info) + { + ReportGeneratorExecutionTime(consoleOutput, info, culture); + } + } + + private static string GetFormattedTime(double d, CultureInfo culture) => d < 0.001 ? + string.Format(culture, "{0,8:<0.000}", 0.001) : + string.Format(culture, "{0,8:##0.000}", d); + + private static string GetColumnHeader(string kind) + { + var time = string.Format("{0,8}", CodeAnalysisResources.AnalyzerExecutionTimeColumnHeader); + var percent = string.Format("{0,5}", "%"); + return time + percent + " " + kind; + } + + private static string GetColumnEntry(double totalSeconds, int percentage, string? name, CultureInfo culture) + { + var time = GetFormattedTime(totalSeconds, culture); + var percent = string.Format("{0,5}", percentage < 1 ? "<1" : percentage.ToString(culture)); + + return time + percent + " " + name; + } + + private static void ReportAnalyzerExecutionTime(TextWriter consoleOutput, AnalyzerDriver analyzerDriver, CultureInfo culture) + { + Debug.Assert(analyzerDriver.AnalyzerExecutionTimes != null); + if (analyzerDriver.AnalyzerExecutionTimes.IsEmpty) + { + return; + } + + var totalAnalyzerExecutionTime = analyzerDriver.AnalyzerExecutionTimes.Sum(kvp => kvp.Value.TotalSeconds); + consoleOutput.WriteLine(string.Format(CodeAnalysisResources.AnalyzerTotalExecutionTime, totalAnalyzerExecutionTime.ToString("##0.000", culture))); + consoleOutput.WriteLine(); + + // Table header + consoleOutput.WriteLine(GetColumnHeader(CodeAnalysisResources.AnalyzerNameColumnHeader)); + + // Table rows grouped by assembly. + var analyzersByAssembly = analyzerDriver.AnalyzerExecutionTimes + .GroupBy(kvp => kvp.Key.GetType().Assembly) + .OrderByDescending(kvp => kvp.Sum(entry => entry.Value.Ticks)); + foreach (var analyzerGroup in analyzersByAssembly) + { + var executionTime = analyzerGroup.Sum(kvp => kvp.Value.TotalSeconds); + var percentage = (int)(executionTime * 100 / totalAnalyzerExecutionTime); + consoleOutput.WriteLine(GetColumnEntry(executionTime, percentage, analyzerGroup.Key.FullName, culture)); + + // Rows for each diagnostic analyzer in the assembly. + foreach (var kvp in analyzerGroup.OrderByDescending(kvp => kvp.Value)) + { + executionTime = kvp.Value.TotalSeconds; + percentage = (int)(executionTime * 100 / totalAnalyzerExecutionTime); + + var analyzerIds = string.Join(", ", kvp.Key.SupportedDiagnostics.Select(d => d.Id).Distinct().OrderBy(id => id)); + var analyzerNameColumn = $" {kvp.Key} ({analyzerIds})"; + consoleOutput.WriteLine(GetColumnEntry(executionTime, percentage, analyzerNameColumn, culture)); + } + + consoleOutput.WriteLine(); + } + } + + private static void ReportGeneratorExecutionTime(TextWriter consoleOutput, GeneratorDriverTimingInfo driverTimingInfo, CultureInfo culture) + { + if (driverTimingInfo.GeneratorTimes.IsEmpty) + { + return; + } + + var totalTime = driverTimingInfo.ElapsedTime.TotalSeconds; + consoleOutput.WriteLine(string.Format(CodeAnalysisResources.GeneratorTotalExecutionTime, totalTime.ToString("##0.000", culture))); + consoleOutput.WriteLine(); + + // Table header + consoleOutput.WriteLine(GetColumnHeader(CodeAnalysisResources.GeneratorNameColumnHeader)); + + // Table rows grouped by assembly. + var generatorsByAssembly = driverTimingInfo.GeneratorTimes + .GroupBy(t => t.Generator.GetGeneratorType().Assembly) + .OrderByDescending(kvp => kvp.Sum(entry => entry.ElapsedTime.Ticks)); + + foreach (var generatorGroup in generatorsByAssembly) + { + var executionTime = generatorGroup.Sum(x => x.ElapsedTime.TotalSeconds); + var percentage = (int)(executionTime * 100 / totalTime); + consoleOutput.WriteLine(GetColumnEntry(executionTime, percentage, generatorGroup.Key.FullName, culture)); + + foreach (var timingInfo in generatorGroup.OrderByDescending(x => x.ElapsedTime)) + { + executionTime = timingInfo.ElapsedTime.TotalSeconds; + percentage = (int)(executionTime * 100 / totalTime); + consoleOutput.WriteLine(GetColumnEntry(executionTime, percentage, " " + timingInfo.Generator.GetGeneratorType().FullName, culture)); + } + } + } + } +} diff --git a/src/Compilers/Core/Portable/Compilation/Compilation.cs b/src/Compilers/Core/Portable/Compilation/Compilation.cs index 984bc1256d632..37469eb98ccef 100644 --- a/src/Compilers/Core/Portable/Compilation/Compilation.cs +++ b/src/Compilers/Core/Portable/Compilation/Compilation.cs @@ -533,7 +533,7 @@ internal static bool IsValidHostObjectType(Type type) /// Gets the syntax trees (parsed from source code) that this compilation was created with. /// public IEnumerable SyntaxTrees { get { return CommonSyntaxTrees; } } - protected abstract ImmutableArray CommonSyntaxTrees { get; } + protected internal abstract ImmutableArray CommonSyntaxTrees { get; } /// /// Creates a new compilation with additional syntax trees. diff --git a/src/Compilers/Core/Portable/Compilation/CompilationOptions.cs b/src/Compilers/Core/Portable/Compilation/CompilationOptions.cs index 117354e214d75..dcc5aa05c87cf 100644 --- a/src/Compilers/Core/Portable/Compilation/CompilationOptions.cs +++ b/src/Compilers/Core/Portable/Compilation/CompilationOptions.cs @@ -261,6 +261,8 @@ protected set private readonly Lazy> _lazyErrors; + private int _hashCode; + // Expects correct arguments. internal CompilationOptions( OutputKind outputKind, @@ -651,7 +653,18 @@ protected bool EqualsHelper([NotNullWhen(true)] CompilationOptions? other) return equal; } - public abstract override int GetHashCode(); + public sealed override int GetHashCode() + { + if (_hashCode == 0) + { + var hashCode = ComputeHashCode(); + _hashCode = hashCode == 0 ? 1 : hashCode; + } + + return _hashCode; + } + + protected abstract int ComputeHashCode(); protected int GetHashCodeHelper() { diff --git a/src/Compilers/Core/Portable/Compilation/IImportScope.cs b/src/Compilers/Core/Portable/Compilation/IImportScope.cs index 0650f2b8bb070..1b7527e5125db 100644 --- a/src/Compilers/Core/Portable/Compilation/IImportScope.cs +++ b/src/Compilers/Core/Portable/Compilation/IImportScope.cs @@ -81,11 +81,15 @@ public readonly struct ImportedNamespaceOrType { public INamespaceOrTypeSymbol NamespaceOrType { get; } + +#pragma warning disable CA1200 // Avoid using cref tags with a prefix /// - /// Location in source where the using directive or Imports clause was declared. Will never be - /// null for C#, may be null for Visual Basic for a project-level import directive. + /// Location in source where the using directive or Imports clause was declared. May be null for + /// Visual Basic for a project-level import directive, or for a C# global using provided directly through . /// public SyntaxReference? DeclaringSyntaxReference { get; } +#pragma warning restore CA1200 // Avoid using cref tags with a prefix internal ImportedNamespaceOrType(INamespaceOrTypeSymbol namespaceOrType, SyntaxReference? declaringSyntaxReference) { diff --git a/src/Compilers/Core/Portable/Compilation/NullableContext.cs b/src/Compilers/Core/Portable/Compilation/NullableContext.cs index 91d292c796191..a0770aa965476 100644 --- a/src/Compilers/Core/Portable/Compilation/NullableContext.cs +++ b/src/Compilers/Core/Portable/Compilation/NullableContext.cs @@ -37,35 +37,35 @@ public enum NullableContext /// /// The nullable warning state is inherited from the project default. - /// - /// + /// /// The project default can change depending on the file type. Generated /// files have nullable off by default, regardless of the project-level /// default setting. - /// + /// + /// WarningsContextInherited = 1 << 2, /// /// The nullable annotation state is inherited from the project default. - /// - /// + /// /// The project default can change depending on the file type. Generated /// files have nullable off by default, regardless of the project-level /// default setting. - /// + /// + /// AnnotationsContextInherited = 1 << 3, /// /// The current state of both warnings and annotations are inherited from /// the project default. - /// - /// + /// /// This flag is set by default at the start of all files. /// /// The project default can change depending on the file type. Generated /// files have nullable off by default, regardless of the project-level /// default setting. - /// + /// + /// ContextInherited = WarningsContextInherited | AnnotationsContextInherited } diff --git a/src/Compilers/Core/Portable/Compilation/OptimizationLevel.cs b/src/Compilers/Core/Portable/Compilation/OptimizationLevel.cs index ac457e8fa9d22..7d6cf18e29d94 100644 --- a/src/Compilers/Core/Portable/Compilation/OptimizationLevel.cs +++ b/src/Compilers/Core/Portable/Compilation/OptimizationLevel.cs @@ -14,9 +14,9 @@ public enum OptimizationLevel { /// /// Disables all optimizations and instruments the generated code to improve debugging experience. - /// - /// + /// /// The compiler prefers debuggability over performance. Do not use for code running in a production environment. + /// /// /// JIT optimizations are disabled via assembly level attribute (). /// Edit and Continue is enabled. @@ -25,14 +25,14 @@ public enum OptimizationLevel /// /// Corresponds to command line argument /optimize-. /// - /// + /// Debug = 0, /// /// Enables all optimizations, debugging experience might be degraded. - /// - /// + /// /// The compiler prefers performance over debuggability. Use for code running in a production environment. + /// /// /// JIT optimizations are enabled via assembly level attribute (). /// Edit and Continue is disabled. @@ -42,7 +42,7 @@ public enum OptimizationLevel /// /// Corresponds to command line argument /optimize+. /// - /// + /// Release = 1 } diff --git a/src/Compilers/Core/Portable/DiagnosticAnalyzer/AnalysisState.SyntaxReferenceAnalyzerStateData.cs b/src/Compilers/Core/Portable/DiagnosticAnalyzer/AnalysisState.SyntaxReferenceAnalyzerStateData.cs index 6faab21ff6f31..d987ff7a6adad 100644 --- a/src/Compilers/Core/Portable/DiagnosticAnalyzer/AnalysisState.SyntaxReferenceAnalyzerStateData.cs +++ b/src/Compilers/Core/Portable/DiagnosticAnalyzer/AnalysisState.SyntaxReferenceAnalyzerStateData.cs @@ -26,15 +26,29 @@ internal sealed class DeclarationAnalyzerStateData : SyntaxNodeAnalyzerStateData /// /// Partial analysis state for operation block actions executed on the declaration. + /// + /// NOTE: This state tracks operations actions registered inside operation block start context. + /// Operation actions registered outside operation block start context are tracked + /// with . /// public OperationBlockAnalyzerStateData OperationBlockAnalysisState { get; } + /// + /// Partial analysis state for operation actions executed on the declaration. + /// + /// NOTE: This state tracks operations actions registered outside of operation block start context. + /// Operation actions registered inside operation block start context are tracked + /// with . + /// + public OperationAnalyzerStateData OperationAnalysisState { get; } + public static new readonly DeclarationAnalyzerStateData FullyProcessedInstance = CreateFullyProcessedInstance(); public DeclarationAnalyzerStateData() { CodeBlockAnalysisState = new CodeBlockAnalyzerStateData(); OperationBlockAnalysisState = new OperationBlockAnalyzerStateData(); + OperationAnalysisState = new OperationAnalyzerStateData(); } private static DeclarationAnalyzerStateData CreateFullyProcessedInstance() @@ -48,6 +62,7 @@ public override void SetStateKind(StateKind stateKind) { CodeBlockAnalysisState.SetStateKind(stateKind); OperationBlockAnalysisState.SetStateKind(stateKind); + OperationAnalysisState.SetStateKind(stateKind); base.SetStateKind(stateKind); } @@ -56,6 +71,7 @@ public override void Free() base.Free(); CodeBlockAnalysisState.Free(); OperationBlockAnalysisState.Free(); + OperationAnalysisState.Free(); } } @@ -73,10 +89,11 @@ public SyntaxNodeAnalyzerStateData() ProcessedNodes = new HashSet(); } - public void ClearNodeAnalysisState() + public void OnAllActionsExecutedForNode(SyntaxNode node) { CurrentNode = null; ProcessedActions.Clear(); + ProcessedNodes.Add(node); } public override void Free() @@ -101,10 +118,11 @@ public OperationAnalyzerStateData() ProcessedOperations = new HashSet(); } - public void ClearNodeAnalysisState() + public void OnAllActionsExecutedForOperation(IOperation operation) { CurrentOperation = null; ProcessedActions.Clear(); + ProcessedOperations.Add(operation); } public override void Free() diff --git a/src/Compilers/Core/Portable/DiagnosticAnalyzer/AnalyzerDriver.cs b/src/Compilers/Core/Portable/DiagnosticAnalyzer/AnalyzerDriver.cs index c4387cff5d268..cf6ebf4af17b3 100644 --- a/src/Compilers/Core/Portable/DiagnosticAnalyzer/AnalyzerDriver.cs +++ b/src/Compilers/Core/Portable/DiagnosticAnalyzer/AnalyzerDriver.cs @@ -889,8 +889,12 @@ public async Task> GetDiagnosticsAsync(Compilation co private SemanticModel GetOrCreateSemanticModel(SyntaxTree tree) => GetOrCreateSemanticModel(tree, AnalyzerExecutor.Compilation); - private SemanticModel GetOrCreateSemanticModel(SyntaxTree tree, Compilation compilation) - => SemanticModelProvider.GetSemanticModel(tree, compilation); + protected SemanticModel GetOrCreateSemanticModel(SyntaxTree tree, Compilation compilation) + { + Debug.Assert(compilation.ContainsSyntaxTree(tree)); + + return SemanticModelProvider.GetSemanticModel(tree, compilation); + } public void ApplyProgrammaticSuppressions(DiagnosticBag reportedDiagnostics, Compilation compilation) { @@ -1796,7 +1800,7 @@ private bool TryProcessCompilationUnitCompleted(CompilationUnitCompletedEvent co // might want to ask the compiler for all the diagnostics in the source file, for example // to get information about unnecessary usings. - var semanticModel = SemanticModelProvider.GetSemanticModel(completedEvent.CompilationUnit, completedEvent.Compilation); + var semanticModel = GetOrCreateSemanticModel(completedEvent.CompilationUnit, completedEvent.Compilation); if (!analysisScope.ShouldAnalyze(semanticModel.SyntaxTree)) { return true; @@ -2576,7 +2580,7 @@ private bool TryExecuteDeclaringReferenceActions( var symbol = symbolEvent.Symbol; var semanticModel = symbolEvent.SemanticModelWithCachedBoundNodes ?? - SemanticModelProvider.GetSemanticModel(decl.SyntaxTree, symbolEvent.Compilation); + GetOrCreateSemanticModel(decl.SyntaxTree, symbolEvent.Compilation); var cacheAnalysisData = analysisScope.Analyzers.Length < Analyzers.Length && (!analysisScope.FilterSpanOpt.HasValue || analysisScope.FilterSpanOpt.Value.Length >= decl.SyntaxTree.GetRoot(cancellationToken).Span.Length); diff --git a/src/Compilers/Core/Portable/DiagnosticAnalyzer/AnalyzerExecutor.cs b/src/Compilers/Core/Portable/DiagnosticAnalyzer/AnalyzerExecutor.cs index 22d5ca5db7c1f..60c72c75c625e 100644 --- a/src/Compilers/Core/Portable/DiagnosticAnalyzer/AnalyzerExecutor.cs +++ b/src/Compilers/Core/Portable/DiagnosticAnalyzer/AnalyzerExecutor.cs @@ -1397,7 +1397,7 @@ private void ExecuteSyntaxNodeActions( } } - analyzerState?.ClearNodeAnalysisState(); + analyzerState?.OnAllActionsExecutedForNode(node); } internal static ImmutableSegmentedDictionary> GetOperationActionsByKind(IEnumerable operationActions) @@ -1449,7 +1449,7 @@ public bool TryExecuteOperationActions( { if (TryStartAnalyzingDeclaration(declaredSymbol, declarationIndex, analyzer, analysisScope, analysisState, out analyzerState)) { - ExecuteOperationActionsCore(operationsToAnalyze, operationActionsByKind, analyzer, declaredSymbol, model, filterSpan, analyzerState?.OperationBlockAnalysisState.ExecutableNodesAnalysisState, isGeneratedCode); + ExecuteOperationActionsCore(operationsToAnalyze, operationActionsByKind, analyzer, declaredSymbol, model, filterSpan, analyzerState?.OperationAnalysisState, isGeneratedCode); return true; } @@ -1532,7 +1532,7 @@ private void ExecuteOperationActions( } } - analyzerState?.ClearNodeAnalysisState(); + analyzerState?.OnAllActionsExecutedForOperation(operation); } internal static bool CanHaveExecutableCodeBlock(ISymbol symbol) diff --git a/src/Compilers/Core/Portable/DiagnosticAnalyzer/AnalyzerFileReference.cs b/src/Compilers/Core/Portable/DiagnosticAnalyzer/AnalyzerFileReference.cs index 8d7bb54ffbe35..95b4e0484bf48 100644 --- a/src/Compilers/Core/Portable/DiagnosticAnalyzer/AnalyzerFileReference.cs +++ b/src/Compilers/Core/Portable/DiagnosticAnalyzer/AnalyzerFileReference.cs @@ -198,9 +198,6 @@ internal void AddGenerators(ImmutableArray.Builder builder, st private static AnalyzerLoadFailureEventArgs CreateAnalyzerFailedArgs(Exception e, string? typeName = null) { - // unwrap: - e = (e as TargetInvocationException) ?? e; - // remove all line breaks from the exception message string message = e.Message.Replace("\r", "").Replace("\n", ""); diff --git a/src/Compilers/Core/Portable/DiagnosticAnalyzer/CompilationUnitCompletedEvent.cs b/src/Compilers/Core/Portable/DiagnosticAnalyzer/CompilationUnitCompletedEvent.cs index 92a9655990971..ea3c262809bef 100644 --- a/src/Compilers/Core/Portable/DiagnosticAnalyzer/CompilationUnitCompletedEvent.cs +++ b/src/Compilers/Core/Portable/DiagnosticAnalyzer/CompilationUnitCompletedEvent.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; +using System.Diagnostics; using Microsoft.CodeAnalysis.Text; namespace Microsoft.CodeAnalysis.Diagnostics @@ -11,6 +13,8 @@ internal sealed class CompilationUnitCompletedEvent : CompilationEvent public CompilationUnitCompletedEvent(Compilation compilation, SyntaxTree compilationUnit, TextSpan? filterSpan = null) : base(compilation) { + Debug.Assert(compilation.ContainsSyntaxTree(compilationUnit)); + this.CompilationUnit = compilationUnit; this.FilterSpan = filterSpan; } diff --git a/src/Compilers/Core/Portable/DiagnosticAnalyzer/CompilationWithAnalyzers.cs b/src/Compilers/Core/Portable/DiagnosticAnalyzer/CompilationWithAnalyzers.cs index b7eda14dbe1aa..855a5202fc6b8 100644 --- a/src/Compilers/Core/Portable/DiagnosticAnalyzer/CompilationWithAnalyzers.cs +++ b/src/Compilers/Core/Portable/DiagnosticAnalyzer/CompilationWithAnalyzers.cs @@ -1338,13 +1338,13 @@ private static IEnumerable GetEffectiveDiagnosticsImpl(ImmutableArra /// /// Returns true if all the diagnostics that can be produced by this analyzer are suppressed through options. + /// /// Analyzer to be checked for suppression. /// Compilation options. /// /// Optional delegate which is invoked when an analyzer throws an exception. /// Delegate can do custom tasks such as report the given analyzer exception diagnostic, report a non-fatal watson for the exception, etc. - /// - /// + /// public static bool IsDiagnosticAnalyzerSuppressed( DiagnosticAnalyzer analyzer, CompilationOptions options, diff --git a/src/Compilers/Core/Portable/Emit/CommonPEModuleBuilder.cs b/src/Compilers/Core/Portable/Emit/CommonPEModuleBuilder.cs index e26ebb058b82b..bd9687d74c9a2 100644 --- a/src/Compilers/Core/Portable/Emit/CommonPEModuleBuilder.cs +++ b/src/Compilers/Core/Portable/Emit/CommonPEModuleBuilder.cs @@ -691,7 +691,7 @@ protected bool ContainsTopLevelType(string fullEmittedName) static void AddTopLevelType(HashSet names, Cci.INamespaceTypeDefinition type) // _namesOfTopLevelTypes are only used to generated exported types, which are not emitted in EnC deltas (hence generation 0): - => names?.Add(MetadataHelpers.BuildQualifiedName(type.NamespaceName, Cci.MetadataWriter.GetMangledName(type, generation: 0))); + => names?.Add(MetadataHelpers.BuildQualifiedName(type.NamespaceName, Cci.MetadataWriter.GetMetadataName(type, generation: 0))); } public virtual ImmutableArray GetAdditionalTopLevelTypes() diff --git a/src/Compilers/Core/Portable/Emit/EditAndContinue/DefinitionMap.cs b/src/Compilers/Core/Portable/Emit/EditAndContinue/DefinitionMap.cs index 5eb02ef5dfe3c..f6a2c304bc5ca 100644 --- a/src/Compilers/Core/Portable/Emit/EditAndContinue/DefinitionMap.cs +++ b/src/Compilers/Core/Portable/Emit/EditAndContinue/DefinitionMap.cs @@ -167,9 +167,9 @@ protected abstract void GetStateMachineFieldMapFromMetadata( IReadOnlyDictionary? awaiterMap = null; IReadOnlyDictionary>? lambdaMap = null; IReadOnlyDictionary? closureMap = null; - IReadOnlyDictionary? stateMachineStateMap = null; - int? firstUnusedIncreasingStateMachineState = null; - int? firstUnusedDecreasingStateMachineState = null; + IReadOnlyDictionary? stateMachineStateMap = null; + StateMachineState? firstUnusedIncreasingStateMachineState = null; + StateMachineState? firstUnusedDecreasingStateMachineState = null; int hoistedLocalSlotCount = 0; int awaiterSlotCount = 0; @@ -259,7 +259,9 @@ protected abstract void GetStateMachineFieldMapFromMetadata( ITypeSymbolInternal? stateMachineType = TryGetStateMachineType(previousHandle); if (stateMachineType != null) { - // method is async/iterator kickoff method + // Method is async/iterator kickoff method. + + // Use local slots stored in CDI (encLocalSlotMap) to calculate map of local variables hoisted to fields of the state machine. var localSlotDebugInfo = debugInfo.LocalSlots.NullToEmpty(); GetStateMachineFieldMapFromMetadata(stateMachineType, localSlotDebugInfo, out hoistedLocalMap, out awaiterMap, out awaiterSlotCount); hoistedLocalSlotCount = localSlotDebugInfo.Length; @@ -297,6 +299,8 @@ protected abstract void GetStateMachineFieldMapFromMetadata( } } + // Calculate local slot mapping for the current method (might be the MoveNext method of a state machine). + try { previousLocals = localSignature.IsNil ? ImmutableArray.Empty : @@ -376,7 +380,7 @@ private static void MakeLambdaAndClosureMaps( private static void MakeStateMachineStateMap( ImmutableArray debugInfos, - out IReadOnlyDictionary? map) + out IReadOnlyDictionary? map) { map = debugInfos.IsDefault ? null : diff --git a/src/Compilers/Core/Portable/Emit/EditAndContinue/DeltaMetadataWriter.cs b/src/Compilers/Core/Portable/Emit/EditAndContinue/DeltaMetadataWriter.cs index a4b3a56940f98..0352f4fb059ce 100644 --- a/src/Compilers/Core/Portable/Emit/EditAndContinue/DeltaMetadataWriter.cs +++ b/src/Compilers/Core/Portable/Emit/EditAndContinue/DeltaMetadataWriter.cs @@ -190,6 +190,9 @@ internal EmitBaseline GetDelta(Compilation compilation, Guid encId, MetadataSize // otherwise members from the current compilation have already been merged into the baseline. var synthesizedMembers = (_previousGeneration.Ordinal == 0) ? module.GetAllSynthesizedMembers() : _previousGeneration.SynthesizedMembers; + Debug.Assert(module.EncSymbolChanges is not null); + var deletedMembers = (_previousGeneration.Ordinal == 0) ? module.EncSymbolChanges.GetAllDeletedMethods() : _previousGeneration.DeletedMembers; + var currentGenerationOrdinal = _previousGeneration.Ordinal + 1; var addedTypes = _typeDefs.GetAdded(); @@ -231,7 +234,7 @@ internal EmitBaseline GetDelta(Compilation compilation, Guid encId, MetadataSize anonymousDelegates: ((IPEDeltaAssemblyBuilder)module).GetAnonymousDelegates(), anonymousDelegatesWithFixedTypes: ((IPEDeltaAssemblyBuilder)module).GetAnonymousDelegatesWithFixedTypes(), synthesizedMembers: synthesizedMembers, - deletedMembers: _previousGeneration.DeletedMembers, + deletedMembers: deletedMembers, addedOrChangedMethods: AddRange(_previousGeneration.AddedOrChangedMethods, addedOrChangedMethodsByIndex), debugInformationProvider: _previousGeneration.DebugInformationProvider, localSignatureProvider: _previousGeneration.LocalSignatureProvider); diff --git a/src/Compilers/Core/Portable/Emit/EditAndContinue/EncVariableSlotAllocator.cs b/src/Compilers/Core/Portable/Emit/EditAndContinue/EncVariableSlotAllocator.cs index 841bd83956ca3..d2761d6eb5344 100644 --- a/src/Compilers/Core/Portable/Emit/EditAndContinue/EncVariableSlotAllocator.cs +++ b/src/Compilers/Core/Portable/Emit/EditAndContinue/EncVariableSlotAllocator.cs @@ -35,9 +35,9 @@ internal sealed class EncVariableSlotAllocator : VariableSlotAllocator private readonly IReadOnlyDictionary? _hoistedLocalSlots; private readonly int _awaiterCount; private readonly IReadOnlyDictionary? _awaiterMap; - private readonly IReadOnlyDictionary? _stateMachineStateMap; // SyntaxOffset -> State Ordinal - private readonly int? _firstUnusedDecreasingStateMachineState; - private readonly int? _firstUnusedIncreasingStateMachineState; + private readonly IReadOnlyDictionary? _stateMachineStateMap; // SyntaxOffset -> State Ordinal + private readonly StateMachineState? _firstUnusedDecreasingStateMachineState; + private readonly StateMachineState? _firstUnusedIncreasingStateMachineState; // closures: private readonly IReadOnlyDictionary>? _lambdaMap; // SyntaxOffset -> (Lambda Id, Closure Ordinal) @@ -58,9 +58,9 @@ public EncVariableSlotAllocator( IReadOnlyDictionary? hoistedLocalSlots, int awaiterCount, IReadOnlyDictionary? awaiterMap, - IReadOnlyDictionary? stateMachineStateMap, - int? firstUnusedIncreasingStateMachineState, - int? firstUnusedDecreasingStateMachineState, + IReadOnlyDictionary? stateMachineStateMap, + StateMachineState? firstUnusedIncreasingStateMachineState, + StateMachineState? firstUnusedDecreasingStateMachineState, LambdaSyntaxFacts lambdaSyntaxFacts) { Debug.Assert(!previousLocals.IsDefault); @@ -329,19 +329,19 @@ public override bool TryGetPreviousLambda(SyntaxNode lambdaOrLambdaBodySyntax, b return false; } - public override int? GetFirstUnusedStateMachineState(bool increasing) + public override StateMachineState? GetFirstUnusedStateMachineState(bool increasing) => increasing ? _firstUnusedIncreasingStateMachineState : _firstUnusedDecreasingStateMachineState; - public override bool TryGetPreviousStateMachineState(SyntaxNode syntax, out int stateOrdinal) + public override bool TryGetPreviousStateMachineState(SyntaxNode syntax, out StateMachineState state) { if (_stateMachineStateMap != null && TryGetPreviousSyntaxOffset(syntax, out int syntaxOffset) && - _stateMachineStateMap.TryGetValue(syntaxOffset, out stateOrdinal)) + _stateMachineStateMap.TryGetValue(syntaxOffset, out state)) { return true; } - stateOrdinal = -1; + state = default; return false; } } diff --git a/src/Compilers/Core/Portable/Emit/EditAndContinue/SymbolChanges.cs b/src/Compilers/Core/Portable/Emit/EditAndContinue/SymbolChanges.cs index a032b0d408ab3..63591700029fd 100644 --- a/src/Compilers/Core/Portable/Emit/EditAndContinue/SymbolChanges.cs +++ b/src/Compilers/Core/Portable/Emit/EditAndContinue/SymbolChanges.cs @@ -99,12 +99,15 @@ private ImmutableArray ToInternalSymbolArray(ISet symb } public bool IsReplaced(IDefinition definition, bool checkEnclosingTypes = false) + => definition.GetInternalSymbol() is { } internalSymbol && IsReplaced(internalSymbol.GetISymbol(), checkEnclosingTypes); + + public bool IsReplaced(ISymbol symbol, bool checkEnclosingTypes = false) { - var symbol = definition.GetInternalSymbol()?.GetISymbol(); + ISymbol? currentSymbol = symbol; - while (symbol != null) + while (currentSymbol != null) { - if (_replacedSymbols.Contains(symbol)) + if (_replacedSymbols.Contains(currentSymbol)) { return true; } @@ -114,7 +117,7 @@ public bool IsReplaced(IDefinition definition, bool checkEnclosingTypes = false) return false; } - symbol = symbol.ContainingType; + currentSymbol = currentSymbol.ContainingType; } return false; diff --git a/src/Compilers/Core/Portable/Emit/EditAndContinue/SymbolMatcher.cs b/src/Compilers/Core/Portable/Emit/EditAndContinue/SymbolMatcher.cs index b497c0c700e83..3321441dfeff1 100644 --- a/src/Compilers/Core/Portable/Emit/EditAndContinue/SymbolMatcher.cs +++ b/src/Compilers/Core/Portable/Emit/EditAndContinue/SymbolMatcher.cs @@ -146,8 +146,8 @@ private IReadOnlyDictionary MapAnonymousDelegatesWit } /// - /// Merges synthesized members generated during lowering of the current compilation with aggregate synthesized members - /// from all previous source generations (gen >= 1). + /// Merges synthesized or deleted members generated during lowering, or emit, of the current compilation with aggregate + /// synthesized or deleted members from all previous source generations (gen >= 1). /// /// /// Suppose {S -> {A, B, D}, T -> {E, F}} are all synthesized members in previous generations, @@ -159,9 +159,10 @@ private IReadOnlyDictionary MapAnonymousDelegatesWit /// Then the resulting collection shall have the following entries: /// {S' -> {A', B', C, D}, U -> {G, H}, T -> {E, F}} /// - internal ImmutableDictionary> MapSynthesizedMembers( + internal ImmutableDictionary> MapSynthesizedOrDeletedMembers( ImmutableDictionary> previousMembers, - ImmutableDictionary> newMembers) + ImmutableDictionary> newMembers, + bool isDeletedMemberMapping) { // Note: we can't just return previous members if there are no new members, since we still need to map the symbols to the new compilation. @@ -174,11 +175,8 @@ internal ImmutableDictionary> M synthesizedMembersBuilder.AddRange(newMembers); - foreach (var pair in previousMembers) + foreach (var (previousContainer, members) in previousMembers) { - var previousContainer = pair.Key; - var members = pair.Value; - var mappedContainer = MapDefinitionOrNamespace(previousContainer); if (mappedContainer == null) { @@ -207,7 +205,11 @@ internal ImmutableDictionary> M // If the matcher found a member in the current compilation corresponding to previous memberDef, // then the member has to be synthesized and produced as a result of a method update // and thus already contained in newSynthesizedMembers. - Debug.Assert(newSynthesizedMembers.Contains(mappedMember)); + // However, because this method is also used to map deleted members, it's possible that a method + // could be renamed in the previous generation, and renamed back in this generation, which would + // mean it could be mapped, but isn't in the newSynthesizedMembers list, so we allow the flag to + // override this behaviour for deleted methods. + Debug.Assert(isDeletedMemberMapping || newSynthesizedMembers.Contains(mappedMember)); } else { diff --git a/src/Compilers/Core/Portable/Emit/EditAndContinueMethodDebugInformation.cs b/src/Compilers/Core/Portable/Emit/EditAndContinueMethodDebugInformation.cs index 797017298f9a0..0e78c4199d00c 100644 --- a/src/Compilers/Core/Portable/Emit/EditAndContinueMethodDebugInformation.cs +++ b/src/Compilers/Core/Portable/Emit/EditAndContinueMethodDebugInformation.cs @@ -49,7 +49,6 @@ internal EditAndContinueMethodDebugInformation( public static EditAndContinueMethodDebugInformation Create(ImmutableArray compressedSlotMap, ImmutableArray compressedLambdaMap) => Create(compressedSlotMap, compressedLambdaMap, compressedStateMachineStateMap: default); - /// /// Deserializes Edit and Continue method debug information from specified blobs. /// @@ -264,6 +263,9 @@ internal void SerializeLambdaMap(BlobBuilder writer) Debug.Assert(MethodOrdinal >= -1); writer.WriteCompressedInteger(MethodOrdinal + 1); + // Negative syntax offsets are rare - only when the syntax node is in an initializer of a field or property. + // To optimize for size calculate the base offset and adds it to all syntax offsets. In common cases (no negative offsets) + // this base offset will be 0. Otherwise it will be the lowest negative offset. int syntaxOffsetBaseline = -1; foreach (ClosureDebugInfo info in Closures) { @@ -329,7 +331,7 @@ private static unsafe ImmutableArray UncompressState int stateNumber = blobReader.ReadCompressedSignedInteger(); int syntaxOffset = syntaxOffsetBaseline + blobReader.ReadCompressedInteger(); - mapBuilder.Add(new StateMachineStateDebugInfo(syntaxOffset, stateNumber)); + mapBuilder.Add(new StateMachineStateDebugInfo(syntaxOffset, (StateMachineState)stateNumber)); count--; } } @@ -348,12 +350,15 @@ internal void SerializeStateMachineStates(BlobBuilder writer) writer.WriteCompressedInteger(StateMachineStates.Length); if (StateMachineStates.Length > 0) { + // Negative syntax offsets are rare - only when the syntax node is in an initializer of a field or property. + // To optimize for size calculate the base offset and adds it to all syntax offsets. In common cases (no negative offsets) + // this base offset will be 0. Otherwise it will be the lowest negative offset. int syntaxOffsetBaseline = Math.Min(StateMachineStates.Min(state => state.SyntaxOffset), 0); writer.WriteCompressedInteger(-syntaxOffsetBaseline); foreach (StateMachineStateDebugInfo state in StateMachineStates) { - writer.WriteCompressedSignedInteger(state.StateNumber); + writer.WriteCompressedSignedInteger((int)state.StateNumber); writer.WriteCompressedInteger(state.SyntaxOffset - syntaxOffsetBaseline); } } diff --git a/src/Compilers/Core/Portable/Emit/ErrorType.cs b/src/Compilers/Core/Portable/Emit/ErrorType.cs index 79a43e38fc187..83d61eb70c3c3 100644 --- a/src/Compilers/Core/Portable/Emit/ErrorType.cs +++ b/src/Compilers/Core/Portable/Emit/ErrorType.cs @@ -55,6 +55,16 @@ bool Cci.INamedTypeReference.MangleName } } +#nullable enable + string? Cci.INamedTypeReference.AssociatedFileIdentifier + { + get + { + return null; + } + } +#nullable disable + bool Cci.ITypeReference.IsEnum { get diff --git a/src/Compilers/Core/Portable/Emit/NoPia/CommonEmbeddedType.cs b/src/Compilers/Core/Portable/Emit/NoPia/CommonEmbeddedType.cs index c5bf550d98e2a..2ab12dba66c50 100644 --- a/src/Compilers/Core/Portable/Emit/NoPia/CommonEmbeddedType.cs +++ b/src/Compilers/Core/Portable/Emit/NoPia/CommonEmbeddedType.cs @@ -675,6 +675,16 @@ bool Cci.INamedTypeReference.MangleName } } +#nullable enable + string? Cci.INamedTypeReference.AssociatedFileIdentifier + { + get + { + return UnderlyingNamedType.AssociatedFileIdentifier; + } + } +#nullable disable + string Cci.INamedEntity.Name { get diff --git a/src/Compilers/Core/Portable/InternalUtilities/EnumerableExtensions.cs b/src/Compilers/Core/Portable/InternalUtilities/EnumerableExtensions.cs index 869df3804dc9a..c017a55043b25 100644 --- a/src/Compilers/Core/Portable/InternalUtilities/EnumerableExtensions.cs +++ b/src/Compilers/Core/Portable/InternalUtilities/EnumerableExtensions.cs @@ -311,6 +311,18 @@ public static ImmutableArray SelectAsArray(this IEnum return builder.ToImmutableAndFree(); } + public static ImmutableArray SelectAsArray(this IReadOnlyCollection? source, Func selector) + { + if (source == null) + return ImmutableArray.Empty; + + var builder = ArrayBuilder.GetInstance(source.Count); + foreach (var item in source) + builder.Add(selector(item)); + + return builder.ToImmutableAndFree(); + } + /// /// Maps an immutable array through a function that returns ValueTask, returning the new ImmutableArray. /// diff --git a/src/Compilers/Core/Portable/InternalUtilities/Hash.cs b/src/Compilers/Core/Portable/InternalUtilities/Hash.cs index a1ea12a025329..f2d66d5918316 100644 --- a/src/Compilers/Core/Portable/InternalUtilities/Hash.cs +++ b/src/Compilers/Core/Portable/InternalUtilities/Hash.cs @@ -68,6 +68,25 @@ internal static int CombineValues(IEnumerable? values, int maxItemsToHash return hashCode; } + internal static int CombineValues(ImmutableDictionary values, int maxItemsToHash = int.MaxValue) + where TKey : notnull + { + if (values == null) + return 0; + + var hashCode = 0; + var count = 0; + foreach (var value in values) + { + if (count++ >= maxItemsToHash) + break; + + hashCode = Hash.Combine(value.GetHashCode(), hashCode); + } + + return hashCode; + } + internal static int CombineValues(T[]? values, int maxItemsToHash = int.MaxValue) { if (values == null) @@ -143,6 +162,25 @@ internal static int CombineValues(IEnumerable? values, StringComparer s return hashCode; } + internal static int CombineValues(ImmutableArray values, StringComparer stringComparer, int maxItemsToHash = int.MaxValue) + { + if (values == null) + return 0; + + var hashCode = 0; + var count = 0; + foreach (var value in values) + { + if (count++ >= maxItemsToHash) + break; + + if (value != null) + hashCode = Hash.Combine(stringComparer.GetHashCode(value), hashCode); + } + + return hashCode; + } + /// /// The offset bias value used in the FNV-1a algorithm /// See http://en.wikipedia.org/wiki/Fowler%E2%80%93Noll%E2%80%93Vo_hash_function diff --git a/src/Compilers/Core/Portable/InternalUtilities/OneOrMany.cs b/src/Compilers/Core/Portable/InternalUtilities/OneOrMany.cs index bdf29b7f006e7..d953a384bba96 100644 --- a/src/Compilers/Core/Portable/InternalUtilities/OneOrMany.cs +++ b/src/Compilers/Core/Portable/InternalUtilities/OneOrMany.cs @@ -3,10 +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.CodeAnalysis; -using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.PooledObjects; namespace Roslyn.Utilities { @@ -17,7 +18,6 @@ namespace Roslyn.Utilities /// Used when a collection usually contains a single item but sometimes might contain multiple. /// internal readonly struct OneOrMany - where T : notnull { public static readonly OneOrMany Empty = new OneOrMany(ImmutableArray.Empty); @@ -73,7 +73,7 @@ public bool IsEmpty public OneOrMany Add(T one) { - var builder = ArrayBuilder.GetInstance(); + var builder = ArrayBuilder.GetInstance(this.Count + 1); if (HasOne) { builder.Add(_one); @@ -89,19 +89,13 @@ public OneOrMany Add(T one) public bool Contains(T item) { - RoslynDebug.Assert(item != null); if (HasOne) - { - return item.Equals(_one); - } + return EqualityComparer.Default.Equals(item, _one); - var iter = GetEnumerator(); - while (iter.MoveNext()) + foreach (var value in _many) { - if (item.Equals(iter.Current)) - { + if (EqualityComparer.Default.Equals(item, value)) return true; - } } return false; @@ -111,21 +105,20 @@ public OneOrMany RemoveAll(T item) { if (HasOne) { - return item.Equals(_one) ? default : this; + return EqualityComparer.Default.Equals(item, _one) ? default : this; } var builder = ArrayBuilder.GetInstance(); - var iter = GetEnumerator(); - while (iter.MoveNext()) + + foreach (var value in _many) { - if (!item.Equals(iter.Current)) - { - builder.Add(iter.Current); - } + if (!EqualityComparer.Default.Equals(item, value)) + builder.Add(value); } if (builder.Count == 0) { + builder.Free(); return default; } @@ -133,7 +126,6 @@ public OneOrMany RemoveAll(T item) } public OneOrMany Select(Func selector) - where TResult : notnull { return HasOne ? OneOrMany.Create(selector(_one)) : @@ -141,7 +133,6 @@ public OneOrMany Select(Func selector) } public OneOrMany Select(Func selector, TArg arg) - where TResult : notnull { return HasOne ? OneOrMany.Create(selector(_one, arg)) : @@ -204,25 +195,16 @@ public bool MoveNext() return _index < _collection.Count; } - public T Current - { - get { return _collection[_index]; } - } + public T Current => _collection[_index]; } } internal static class OneOrMany { public static OneOrMany Create(T one) - where T : notnull - { - return new OneOrMany(one); - } + => new OneOrMany(one); public static OneOrMany Create(ImmutableArray many) - where T : notnull - { - return new OneOrMany(many); - } + => new OneOrMany(many); } } diff --git a/src/Compilers/Core/Portable/MetadataReader/MetadataHelpers.cs b/src/Compilers/Core/Portable/MetadataReader/MetadataHelpers.cs index 03cfc874b2910..7a042ab03c067 100644 --- a/src/Compilers/Core/Portable/MetadataReader/MetadataHelpers.cs +++ b/src/Compilers/Core/Portable/MetadataReader/MetadataHelpers.cs @@ -470,10 +470,12 @@ internal static string GetAritySuffix(int arity) return (arity <= 9) ? s_aritySuffixesOneToNine[arity - 1] : string.Concat(GenericTypeNameManglingString, arity.ToString(CultureInfo.InvariantCulture)); } - internal static string ComposeAritySuffixedMetadataName(string name, int arity) +#nullable enable + internal static string ComposeAritySuffixedMetadataName(string name, int arity, string? associatedFileIdentifier) { - return arity == 0 ? name : name + GetAritySuffix(arity); + return associatedFileIdentifier + (arity == 0 ? name : name + GetAritySuffix(arity)); } +#nullable disable internal static int InferTypeArityFromMetadataName(string emittedTypeName) { diff --git a/src/Compilers/Core/Portable/MetadataReader/PEModule.cs b/src/Compilers/Core/Portable/MetadataReader/PEModule.cs index 6117c5f32428d..0591e2e8471c4 100644 --- a/src/Compilers/Core/Portable/MetadataReader/PEModule.cs +++ b/src/Compilers/Core/Portable/MetadataReader/PEModule.cs @@ -1087,16 +1087,14 @@ internal bool HasNativeIntegerAttribute(EntityHandle token, out ImmutableArray tupleElementNames) diff --git a/src/Compilers/Core/Portable/MetadataReference/AssemblyMetadata.cs b/src/Compilers/Core/Portable/MetadataReference/AssemblyMetadata.cs index d8ea338e14d25..4b3a1619073cc 100644 --- a/src/Compilers/Core/Portable/MetadataReference/AssemblyMetadata.cs +++ b/src/Compilers/Core/Portable/MetadataReference/AssemblyMetadata.cs @@ -428,7 +428,7 @@ internal bool IsValidAssembly() } /// - /// Returns the metadata kind. + /// Returns the metadata kind. /// public override MetadataImageKind Kind { diff --git a/src/Compilers/Core/Portable/MetadataReference/ModuleMetadata.cs b/src/Compilers/Core/Portable/MetadataReference/ModuleMetadata.cs index e539844d5a146..5119669dc455c 100644 --- a/src/Compilers/Core/Portable/MetadataReference/ModuleMetadata.cs +++ b/src/Compilers/Core/Portable/MetadataReference/ModuleMetadata.cs @@ -9,6 +9,7 @@ using System.IO; using System.Reflection.Metadata; using System.Reflection.PortableExecutable; +using System.Threading; using Roslyn.Utilities; namespace Microsoft.CodeAnalysis @@ -22,47 +23,29 @@ public sealed partial class ModuleMetadata : Metadata private readonly PEModule _module; /// - /// Optional data that should be kept alive as long as this is alive. This can be - /// useful, for example, if there is backing memory that the metadata depends on that should be kept rooted so it - /// doesn't get garbage collected. + /// Optional action to invoke when this metadata is disposed. /// - private readonly IDisposable? _owner; - - /// - /// Whether or not should be 'd when this object is - /// Disposed. Is controlled by the leaveOpen flag in , or - /// the flag in . - /// - private readonly bool _disposeOwner; + private Action? _onDispose; private bool _isDisposed; - private ModuleMetadata(PEReader peReader, IDisposable? owner, bool disposeOwner) + private ModuleMetadata(PEReader peReader, Action? onDispose) : base(isImageOwner: true, id: MetadataId.CreateNewId()) { - // If we've been asked to dispose the owner, then we better have an owner to dispose. - Debug.Assert(!disposeOwner || owner is not null); - _module = new PEModule(this, peReader: peReader, metadataOpt: IntPtr.Zero, metadataSizeOpt: 0, includeEmbeddedInteropTypes: false, ignoreAssemblyRefs: false); - _owner = owner; - _disposeOwner = disposeOwner; + _onDispose = onDispose; } private ModuleMetadata( IntPtr metadata, int size, - IDisposable? owner, - bool disposeOwner, + Action? onDispose, bool includeEmbeddedInteropTypes, bool ignoreAssemblyRefs) : base(isImageOwner: true, id: MetadataId.CreateNewId()) { - // If we've been asked to dispose the owner, then we better have an owner to dispose. - Debug.Assert(!disposeOwner || owner is not null); - _module = new PEModule(this, peReader: null, metadataOpt: metadata, metadataSizeOpt: size, includeEmbeddedInteropTypes: includeEmbeddedInteropTypes, ignoreAssemblyRefs: ignoreAssemblyRefs); - _owner = owner; - _disposeOwner = disposeOwner; + _onDispose = onDispose; } // creates a copy @@ -70,10 +53,11 @@ private ModuleMetadata(ModuleMetadata metadata) : base(isImageOwner: false, id: metadata.Id) { _module = metadata.Module; - // ensure that we keep the owner rooted so that it can't get GC'ed why we're alive. - _owner = metadata._owner; - // however, as we're not the image owner, we will never dispose the owner. Only the single image owner can be responsible for that. - _disposeOwner = false; + + // note: we intentionally do not pass the _onDispose callback to the copy. Only the owner owns the callback + // and controls calling it. This does mean that the callback (and underlying memory it holds onto) may + // disappear once the owner is disposed or GC'd. But that's ok as that is expected semantics. Once an image + // owner is gone, all copies are no longer in a valid state for use. } /// @@ -85,7 +69,7 @@ private ModuleMetadata(ModuleMetadata metadata) /// is null. /// is not positive. public static ModuleMetadata CreateFromMetadata(IntPtr metadata, int size) - => CreateFromMetadataWorker(metadata, size, owner: null, disposeOwner: false); + => CreateFromMetadataWorker(metadata, size, onDispose: null); /// /// Create metadata module from a raw memory pointer to metadata directory of a PE image or .cormeta section of an object file. @@ -93,29 +77,25 @@ public static ModuleMetadata CreateFromMetadata(IntPtr metadata, int size) /// /// Pointer to the start of metadata block. /// The size of the metadata block. - /// Data that should be kept alive as long as this is alive. This can be - /// useful, for example, if there is backing memory that the metadata depends on that should be kept rooted so it - /// doesn't get garbage collected. - /// Whether or not should be 'd when this object is - /// Disposed. - /// is null. + /// Action to run when the metadata module is disposed. This will only be called then + /// this actual metadata instance is disposed. Any instances created from this using will not call this when they are disposed. + /// is null. public static unsafe ModuleMetadata CreateFromMetadata( IntPtr metadata, int size, - IDisposable owner, - bool disposeOwner) + Action onDispose) { - if (owner is null) - throw new ArgumentNullException(nameof(owner)); + if (onDispose is null) + throw new ArgumentNullException(nameof(onDispose)); - return CreateFromMetadataWorker(metadata, size, owner, disposeOwner); + return CreateFromMetadataWorker(metadata, size, onDispose); } private static ModuleMetadata CreateFromMetadataWorker( IntPtr metadata, int size, - IDisposable? owner, - bool disposeOwner) + Action? onDispose) { if (metadata == IntPtr.Zero) { @@ -127,14 +107,14 @@ private static ModuleMetadata CreateFromMetadataWorker( throw new ArgumentOutOfRangeException(CodeAnalysisResources.SizeHasToBePositive, nameof(size)); } - return new ModuleMetadata(metadata, size, owner, disposeOwner, includeEmbeddedInteropTypes: false, ignoreAssemblyRefs: false); + return new ModuleMetadata(metadata, size, onDispose, includeEmbeddedInteropTypes: false, ignoreAssemblyRefs: false); } internal static ModuleMetadata CreateFromMetadata(IntPtr metadata, int size, bool includeEmbeddedInteropTypes, bool ignoreAssemblyRefs = false) { Debug.Assert(metadata != IntPtr.Zero); Debug.Assert(size > 0); - return new ModuleMetadata(metadata, size, owner: null, disposeOwner: false, includeEmbeddedInteropTypes, ignoreAssemblyRefs); + return new ModuleMetadata(metadata, size, onDispose: null, includeEmbeddedInteropTypes, ignoreAssemblyRefs); } /// @@ -145,9 +125,9 @@ internal static ModuleMetadata CreateFromMetadata(IntPtr metadata, int size, boo /// is null. /// is not positive. public static unsafe ModuleMetadata CreateFromImage(IntPtr peImage, int size) - => CreateFromImage((byte*)peImage, size, owner: null, disposeOwner: false); + => CreateFromImage((byte*)peImage, size, onDispose: null); - private static unsafe ModuleMetadata CreateFromImage(byte* peImage, int size, IDisposable? owner, bool disposeOwner) + private static unsafe ModuleMetadata CreateFromImage(byte* peImage, int size, Action? onDispose) { if (peImage == null) { @@ -159,7 +139,7 @@ private static unsafe ModuleMetadata CreateFromImage(byte* peImage, int size, ID throw new ArgumentOutOfRangeException(CodeAnalysisResources.SizeHasToBePositive, nameof(size)); } - return new ModuleMetadata(new PEReader(peImage, size), owner, disposeOwner); + return new ModuleMetadata(new PEReader(peImage, size), onDispose); } /// @@ -189,7 +169,7 @@ public static ModuleMetadata CreateFromImage(ImmutableArray peImage) throw new ArgumentNullException(nameof(peImage)); } - return new ModuleMetadata(new PEReader(peImage), owner: null, disposeOwner: false); + return new ModuleMetadata(new PEReader(peImage), onDispose: null); } /// @@ -249,11 +229,14 @@ public static ModuleMetadata CreateFromStream(Stream peStream, PEStreamOptions o { unsafe { + Action? onDispose = options.HasFlag(PEStreamOptions.LeaveOpen) + ? null + : unmanagedMemoryStream.Dispose; + return CreateFromImage( unmanagedMemoryStream.PositionPointer, (int)Math.Min(unmanagedMemoryStream.Length, int.MaxValue), - owner: unmanagedMemoryStream, - disposeOwner: !options.HasFlag(PEStreamOptions.LeaveOpen)); + onDispose); } } @@ -265,7 +248,7 @@ public static ModuleMetadata CreateFromStream(Stream peStream, PEStreamOptions o } // ownership of the stream is passed on PEReader: - return new ModuleMetadata(new PEReader(peStream, options), owner: null, disposeOwner: false); + return new ModuleMetadata(new PEReader(peStream, options), onDispose: null); } /// @@ -317,8 +300,8 @@ public override void Dispose() { _module.Dispose(); - if (_disposeOwner) - _owner!.Dispose(); + var onDispose = Interlocked.Exchange(ref _onDispose, null); + onDispose?.Invoke(); } } diff --git a/src/Compilers/Core/Portable/Microsoft.CodeAnalysis.csproj b/src/Compilers/Core/Portable/Microsoft.CodeAnalysis.csproj index 4bdef9c9b6641..9cfc181b99223 100644 --- a/src/Compilers/Core/Portable/Microsoft.CodeAnalysis.csproj +++ b/src/Compilers/Core/Portable/Microsoft.CodeAnalysis.csproj @@ -62,6 +62,7 @@ + diff --git a/src/Compilers/Core/Portable/NativePdbWriter/SymWriterMetadataProvider.cs b/src/Compilers/Core/Portable/NativePdbWriter/SymWriterMetadataProvider.cs index bcd9b1cc00509..e306f811888c4 100644 --- a/src/Compilers/Core/Portable/NativePdbWriter/SymWriterMetadataProvider.cs +++ b/src/Compilers/Core/Portable/NativePdbWriter/SymWriterMetadataProvider.cs @@ -45,7 +45,7 @@ public bool TryGetTypeDefinitionInfo(int typeDefinitionToken, out string namespa else { int generation = (t is INamedTypeDefinition namedType) ? _writer.Module.GetTypeDefinitionGeneration(namedType) : 0; - typeName = MetadataWriter.GetMangledName((INamedTypeReference)t, generation); + typeName = MetadataWriter.GetMetadataName((INamedTypeReference)t, generation); INamespaceTypeDefinition namespaceTypeDef; if ((namespaceTypeDef = t.AsNamespaceTypeDefinition(_writer.Context)) != null) diff --git a/src/Compilers/Core/Portable/OutputKind.cs b/src/Compilers/Core/Portable/OutputKind.cs index 09db23ac906cb..e93f494a0b850 100644 --- a/src/Compilers/Core/Portable/OutputKind.cs +++ b/src/Compilers/Core/Portable/OutputKind.cs @@ -40,12 +40,12 @@ public enum OutputKind /// /// An .exe that can run in an app container. - /// - /// + /// /// Equivalent to a WindowsApplication, but with an extra bit set in the Portable Executable file /// so that the application can only be run in an app container. /// Also known as a "Windows Store app". - /// + /// + /// WindowsRuntimeApplication = 5, } diff --git a/src/Compilers/Core/Portable/PEWriter/MetadataWriter.cs b/src/Compilers/Core/Portable/PEWriter/MetadataWriter.cs index 9b0743613eb5a..f952948663bbf 100644 --- a/src/Compilers/Core/Portable/PEWriter/MetadataWriter.cs +++ b/src/Compilers/Core/Portable/PEWriter/MetadataWriter.cs @@ -916,13 +916,13 @@ private static uint GetManagedResourceOffset(BlobBuilder resource, BlobBuilder r return (uint)result; } - public static string GetMangledName(INamedTypeReference namedType, int generation) + public static string GetMetadataName(INamedTypeReference namedType, int generation) { - string unmangledName = (generation == 0) ? namedType.Name : namedType.Name + "#" + generation; - - return namedType.MangleName - ? MetadataHelpers.ComposeAritySuffixedMetadataName(unmangledName, namedType.GenericParameterCount) - : unmangledName; + string nameWithGeneration = (generation == 0) ? namedType.Name : namedType.Name + "#" + generation; + string fileIdentifier = namedType.AssociatedFileIdentifier; + return namedType.MangleName || fileIdentifier != null + ? MetadataHelpers.ComposeAritySuffixedMetadataName(nameWithGeneration, namedType.GenericParameterCount, fileIdentifier) + : nameWithGeneration; } internal MemberReferenceHandle GetMemberReferenceHandle(ITypeMemberReference memberRef) @@ -2219,10 +2219,10 @@ private void PopulateExportedTypeTableRows() if ((namespaceTypeRef = exportedType.Type.AsNamespaceTypeReference) != null) { // exported types are not emitted in EnC deltas (hence generation 0): - string mangledTypeName = GetMangledName(namespaceTypeRef, generation: 0); + string metadataTypeName = GetMetadataName(namespaceTypeRef, generation: 0); - typeName = GetStringHandleForNameAndCheckLength(mangledTypeName, namespaceTypeRef); - typeNamespace = GetStringHandleForNamespaceAndCheckLength(namespaceTypeRef, mangledTypeName); + typeName = GetStringHandleForNameAndCheckLength(metadataTypeName, namespaceTypeRef); + typeNamespace = GetStringHandleForNamespaceAndCheckLength(namespaceTypeRef, metadataTypeName); implementation = GetExportedTypeImplementation(namespaceTypeRef); attributes = exportedType.IsForwarder ? TypeAttributes.NotPublic | Constants.TypeAttributes_TypeForwarder : TypeAttributes.Public; } @@ -2231,9 +2231,9 @@ private void PopulateExportedTypeTableRows() Debug.Assert(exportedType.ParentIndex != -1); // exported types are not emitted in EnC deltas (hence generation 0): - string mangledTypeName = GetMangledName(nestedRef, generation: 0); + string metadataTypeName = GetMetadataName(nestedRef, generation: 0); - typeName = GetStringHandleForNameAndCheckLength(mangledTypeName, nestedRef); + typeName = GetStringHandleForNameAndCheckLength(metadataTypeName, nestedRef); typeNamespace = default(StringHandle); implementation = MetadataTokens.ExportedTypeHandle(exportedType.ParentIndex + 1); attributes = exportedType.IsForwarder ? TypeAttributes.NotPublic : TypeAttributes.NestedPublic; @@ -2710,13 +2710,13 @@ private void PopulateTypeDefTableRows() var moduleBuilder = Context.Module; int generation = moduleBuilder.GetTypeDefinitionGeneration(typeDef); - string mangledTypeName = GetMangledName(typeDef, generation); + string metadataTypeName = GetMetadataName(typeDef, generation); ITypeReference baseType = typeDef.GetBaseClass(Context); metadata.AddTypeDefinition( attributes: GetTypeAttributes(typeDef), - @namespace: (namespaceType != null) ? GetStringHandleForNamespaceAndCheckLength(namespaceType, mangledTypeName) : default(StringHandle), - name: GetStringHandleForNameAndCheckLength(mangledTypeName, typeDef), + @namespace: (namespaceType != null) ? GetStringHandleForNamespaceAndCheckLength(namespaceType, metadataTypeName) : default(StringHandle), + name: GetStringHandleForNameAndCheckLength(metadataTypeName, typeDef), baseType: (baseType != null) ? GetTypeHandle(baseType) : default(EntityHandle), fieldList: GetFirstFieldDefinitionHandle(typeDef), methodList: GetFirstMethodDefinitionHandle(typeDef)); @@ -2785,9 +2785,9 @@ private void PopulateTypeRefTableRows() // It's not possible to reference newer versions of reloadable types from another assembly, hence generation 0: // TODO: https://github.com/dotnet/roslyn/issues/54981 - string mangledTypeName = GetMangledName(nestedTypeRef, generation: 0); + string metadataTypeName = GetMetadataName(nestedTypeRef, generation: 0); - name = this.GetStringHandleForNameAndCheckLength(mangledTypeName, nestedTypeRef); + name = this.GetStringHandleForNameAndCheckLength(metadataTypeName, nestedTypeRef); @namespace = default(StringHandle); } else @@ -2802,10 +2802,10 @@ private void PopulateTypeRefTableRows() // It's not possible to reference newer versions of reloadable types from another assembly, hence generation 0: // TODO: https://github.com/dotnet/roslyn/issues/54981 - string mangledTypeName = GetMangledName(namespaceTypeRef, generation: 0); + string metadataTypeName = GetMetadataName(namespaceTypeRef, generation: 0); - name = this.GetStringHandleForNameAndCheckLength(mangledTypeName, namespaceTypeRef); - @namespace = this.GetStringHandleForNamespaceAndCheckLength(namespaceTypeRef, mangledTypeName); + name = this.GetStringHandleForNameAndCheckLength(metadataTypeName, namespaceTypeRef); + @namespace = this.GetStringHandleForNamespaceAndCheckLength(namespaceTypeRef, metadataTypeName); } metadata.AddTypeReference( diff --git a/src/Compilers/Core/Portable/PEWriter/RootModuleStaticConstructor.cs b/src/Compilers/Core/Portable/PEWriter/RootModuleStaticConstructor.cs index b6001e1a37a07..42c976c9a2d65 100644 --- a/src/Compilers/Core/Portable/PEWriter/RootModuleStaticConstructor.cs +++ b/src/Compilers/Core/Portable/PEWriter/RootModuleStaticConstructor.cs @@ -165,17 +165,16 @@ public RootModuleStaticConstructor(ITypeDefinition containingTypeDefinition, Imm public DynamicAnalysisMethodBodyData DynamicAnalysisData => null; - 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 f90f9f573c9e6..dd6391debef0f 100644 --- a/src/Compilers/Core/Portable/PEWriter/RootModuleType.cs +++ b/src/Compilers/Core/Portable/PEWriter/RootModuleType.cs @@ -58,6 +58,11 @@ public bool MangleName get { return false; } } + public string? AssociatedFileIdentifier + { + get { return null; } + } + public string Name { get { return ""; } diff --git a/src/Compilers/Core/Portable/PEWriter/TypeNameSerializer.cs b/src/Compilers/Core/Portable/PEWriter/TypeNameSerializer.cs index 29115ffdff6a5..8a1639677e959 100644 --- a/src/Compilers/Core/Portable/PEWriter/TypeNameSerializer.cs +++ b/src/Compilers/Core/Portable/PEWriter/TypeNameSerializer.cs @@ -10,6 +10,7 @@ using Microsoft.CodeAnalysis.PooledObjects; using System.Text; using System.Diagnostics; +using System.Linq; namespace Microsoft.Cci { @@ -71,7 +72,7 @@ internal static string GetSerializedTypeName(this ITypeReference typeReference, sb.Append('.'); } - sb.Append(GetMangledAndEscapedName(namespaceType)); + sb.Append(GetEscapedMetadataName(namespaceType)); goto done; } @@ -113,7 +114,7 @@ internal static string GetSerializedTypeName(this ITypeReference typeReference, bool nestedTypeIsAssemblyQualified = false; sb.Append(GetSerializedTypeName(nestedType.GetContainingType(context), context, ref nestedTypeIsAssemblyQualified)); sb.Append('+'); - sb.Append(GetMangledAndEscapedName(nestedType)); + sb.Append(GetEscapedMetadataName(nestedType)); goto done; } @@ -193,12 +194,18 @@ private static void AppendAssemblyQualifierIfNecessary(StringBuilder sb, ITypeRe } } - private static string GetMangledAndEscapedName(INamedTypeReference namedType) + private static string GetEscapedMetadataName(INamedTypeReference namedType) { var pooled = PooledStringBuilder.GetInstance(); StringBuilder mangledName = pooled.Builder; const string needsEscaping = "\\[]*.+,& "; + if (namedType.AssociatedFileIdentifier is string fileIdentifier) + { + Debug.Assert(needsEscaping.All(c => !fileIdentifier.Contains(c))); + mangledName.Append(fileIdentifier); + } + foreach (var ch in namedType.Name) { if (needsEscaping.IndexOf(ch) >= 0) diff --git a/src/Compilers/Core/Portable/PEWriter/Types.cs b/src/Compilers/Core/Portable/PEWriter/Types.cs index 97e957df38f1c..2a4e50b50ac52 100644 --- a/src/Compilers/Core/Portable/PEWriter/Types.cs +++ b/src/Compilers/Core/Portable/PEWriter/Types.cs @@ -253,6 +253,9 @@ internal interface INamedTypeReference : ITypeReference, INamedEntity /// If true, the persisted type name is mangled by appending "`n" where n is the number of type parameters, if the number of type parameters is greater than 0. /// bool MangleName { get; } + + /// Indicates that the type is scoped to the file it is declared in. Used as a prefix for the metadata name. + string? AssociatedFileIdentifier { get; } } /// diff --git a/src/Compilers/Core/Portable/PublicAPI.Unshipped.txt b/src/Compilers/Core/Portable/PublicAPI.Unshipped.txt index 8b137891791fe..f6c8a9c300c3a 100644 --- a/src/Compilers/Core/Portable/PublicAPI.Unshipped.txt +++ b/src/Compilers/Core/Portable/PublicAPI.Unshipped.txt @@ -1 +1,6 @@ - +*REMOVED*override abstract Microsoft.CodeAnalysis.CompilationOptions.GetHashCode() -> int +*REMOVED*static Microsoft.CodeAnalysis.ModuleMetadata.CreateFromMetadata(System.IntPtr metadata, int size, System.IDisposable! owner, bool disposeOwner) -> Microsoft.CodeAnalysis.ModuleMetadata! +Microsoft.CodeAnalysis.GeneratorDriver.ReplaceGenerators(System.Collections.Immutable.ImmutableArray generators) -> Microsoft.CodeAnalysis.GeneratorDriver! +override sealed Microsoft.CodeAnalysis.CompilationOptions.GetHashCode() -> int +static Microsoft.CodeAnalysis.ModuleMetadata.CreateFromMetadata(System.IntPtr metadata, int size, System.Action! onDispose) -> Microsoft.CodeAnalysis.ModuleMetadata! +Microsoft.CodeAnalysis.INamedTypeSymbol.IsFileLocal.get -> bool diff --git a/src/Compilers/Core/Portable/RuleSet/RuleSet.cs b/src/Compilers/Core/Portable/RuleSet/RuleSet.cs index 0f26e5a62ccb3..362da93e25f45 100644 --- a/src/Compilers/Core/Portable/RuleSet/RuleSet.cs +++ b/src/Compilers/Core/Portable/RuleSet/RuleSet.cs @@ -246,7 +246,7 @@ private static bool IsStricterThan(ReportDiagnostic action1, ReportDiagnostic ac /// /// Load the ruleset from the specified file. This ruleset will contain /// all the rules resolved from the includes specified in the ruleset file - /// as well. See also: . + /// as well. See also: . /// /// /// A ruleset that contains resolved rules or null if there were errors. @@ -259,7 +259,7 @@ public static RuleSet LoadEffectiveRuleSetFromFile(string filePath) /// /// Get the paths to all files contributing rules to the ruleset from the specified file. - /// See also: . + /// See also: . /// /// /// The full paths to included files, or an empty array if there were errors. diff --git a/src/Compilers/Core/Portable/SourceGeneration/GeneratorDriver.cs b/src/Compilers/Core/Portable/SourceGeneration/GeneratorDriver.cs index 78e9a34adac57..fd97951e0e3cf 100644 --- a/src/Compilers/Core/Portable/SourceGeneration/GeneratorDriver.cs +++ b/src/Compilers/Core/Portable/SourceGeneration/GeneratorDriver.cs @@ -36,8 +36,8 @@ internal GeneratorDriver(GeneratorDriverState state) internal GeneratorDriver(ParseOptions parseOptions, ImmutableArray generators, AnalyzerConfigOptionsProvider optionsProvider, ImmutableArray additionalTexts, GeneratorDriverOptions driverOptions) { - (var filteredGenerators, var incrementalGenerators) = GetIncrementalGenerators(generators, SourceExtension); - _state = new GeneratorDriverState(parseOptions, optionsProvider, filteredGenerators, incrementalGenerators, additionalTexts, ImmutableArray.Create(new GeneratorState[filteredGenerators.Length]), DriverStateTable.Empty, SyntaxStore.Empty, driverOptions.DisabledOutputs, runtime: TimeSpan.Zero, driverOptions.TrackIncrementalGeneratorSteps); + var incrementalGenerators = GetIncrementalGenerators(generators, SourceExtension); + _state = new GeneratorDriverState(parseOptions, optionsProvider, generators, incrementalGenerators, additionalTexts, ImmutableArray.Create(new GeneratorState[generators.Length]), DriverStateTable.Empty, SyntaxStore.Empty, driverOptions.DisabledOutputs, runtime: TimeSpan.Zero, driverOptions.TrackIncrementalGeneratorSteps); } public GeneratorDriver RunGenerators(Compilation compilation, CancellationToken cancellationToken = default) @@ -67,13 +67,35 @@ public GeneratorDriver RunGeneratorsAndUpdateCompilation(Compilation compilation public GeneratorDriver AddGenerators(ImmutableArray generators) { - (var filteredGenerators, var incrementalGenerators) = GetIncrementalGenerators(generators, SourceExtension); - var newState = _state.With(sourceGenerators: _state.Generators.AddRange(filteredGenerators), + var incrementalGenerators = GetIncrementalGenerators(generators, SourceExtension); + var newState = _state.With(sourceGenerators: _state.Generators.AddRange(generators), incrementalGenerators: _state.IncrementalGenerators.AddRange(incrementalGenerators), - generatorStates: _state.GeneratorStates.AddRange(new GeneratorState[filteredGenerators.Length])); + generatorStates: _state.GeneratorStates.AddRange(new GeneratorState[generators.Length])); return FromState(newState); } + public GeneratorDriver ReplaceGenerators(ImmutableArray generators) + { + var incrementalGenerators = GetIncrementalGenerators(generators, SourceExtension); + var states = ArrayBuilder.GetInstance(generators.Length); + + foreach (var generator in generators) + { + var existingIndex = _state.Generators.IndexOf(generator); + + if (existingIndex >= 0) + { + states.Add(_state.GeneratorStates[existingIndex]); + } + else + { + states.Add(GeneratorState.Empty); + } + } + + return FromState(_state.With(generators, incrementalGenerators, states.ToImmutableAndFree())); + } + public GeneratorDriver RemoveGenerators(ImmutableArray generators) { var newGenerators = _state.Generators; @@ -355,14 +377,14 @@ internal static string GetFilePathPrefixForGenerator(ISourceGenerator generator) return Path.Combine(type.Assembly.GetName().Name ?? string.Empty, type.FullName!); } - private static (ImmutableArray, ImmutableArray) GetIncrementalGenerators(ImmutableArray generators, string sourceExtension) + private static ImmutableArray GetIncrementalGenerators(ImmutableArray generators, string sourceExtension) { - return (generators, generators.SelectAsArray(g => g switch + return generators.SelectAsArray(g => g switch { IncrementalGeneratorWrapper igw => igw.Generator, IIncrementalGenerator ig => ig, _ => new SourceGeneratorAdaptor(g, sourceExtension) - })); + }); } diff --git a/src/Compilers/Core/Portable/SourceGeneration/GlobalAliases.cs b/src/Compilers/Core/Portable/SourceGeneration/GlobalAliases.cs index d4477c455faff..a6939660c46f0 100644 --- a/src/Compilers/Core/Portable/SourceGeneration/GlobalAliases.cs +++ b/src/Compilers/Core/Portable/SourceGeneration/GlobalAliases.cs @@ -31,6 +31,22 @@ public static GlobalAliases Create(ImmutableArray<(string aliasName, string symb return aliasAndSymbolNames.IsEmpty ? Empty : new GlobalAliases(aliasAndSymbolNames); } + public static GlobalAliases Create(ImmutableArray aliasesArray) + { + if (aliasesArray.Length == 0) + return Empty; + + if (aliasesArray.Length == 1) + return aliasesArray[0]; + + var total = ArrayBuilder<(string aliasName, string symbolName)>.GetInstance(aliasesArray.Sum(a => a.AliasAndSymbolNames.Length)); + + foreach (var array in aliasesArray) + total.AddRange(array.AliasAndSymbolNames); + + return Create(total.ToImmutableAndFree()); + } + public static GlobalAliases Concat(GlobalAliases ga1, GlobalAliases ga2) { if (ga1.AliasAndSymbolNames.Length == 0) diff --git a/src/Compilers/Core/Portable/SourceGeneration/ISyntaxHelper.cs b/src/Compilers/Core/Portable/SourceGeneration/ISyntaxHelper.cs index e505d313ada91..6c478d4e2f279 100644 --- a/src/Compilers/Core/Portable/SourceGeneration/ISyntaxHelper.cs +++ b/src/Compilers/Core/Portable/SourceGeneration/ISyntaxHelper.cs @@ -6,9 +6,10 @@ using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using System.Text; +using System.Threading; using Microsoft.CodeAnalysis.PooledObjects; -namespace Microsoft.CodeAnalysis.SourceGeneration +namespace Microsoft.CodeAnalysis { internal interface ISyntaxHelper { @@ -28,22 +29,26 @@ internal interface ISyntaxHelper bool IsLambdaExpression(SyntaxNode node); - SyntaxToken GetUnqualifiedIdentifierOfName(SyntaxNode node); + string GetUnqualifiedIdentifierOfName(SyntaxNode node); /// /// must be a compilation unit or namespace block. /// - void AddAliases(SyntaxNode node, ArrayBuilder<(string aliasName, string symbolName)> aliases, bool global); + void AddAliases(GreenNode node, ArrayBuilder<(string aliasName, string symbolName)> aliases, bool global); void AddAliases(CompilationOptions options, ArrayBuilder<(string aliasName, string symbolName)> aliases); + + bool ContainsAttributeList(SyntaxNode root); + bool ContainsGlobalAliases(SyntaxNode root); } internal abstract class AbstractSyntaxHelper : ISyntaxHelper { public abstract bool IsCaseSensitive { get; } + protected abstract int AttributeListKind { get; } public abstract bool IsValidIdentifier(string name); - public abstract SyntaxToken GetUnqualifiedIdentifierOfName(SyntaxNode name); + public abstract string GetUnqualifiedIdentifierOfName(SyntaxNode name); public abstract bool IsAnyNamespaceBlock(SyntaxNode node); @@ -56,7 +61,31 @@ internal abstract class AbstractSyntaxHelper : ISyntaxHelper public abstract bool IsLambdaExpression(SyntaxNode node); - public abstract void AddAliases(SyntaxNode node, ArrayBuilder<(string aliasName, string symbolName)> aliases, bool global); + public abstract void AddAliases(GreenNode node, ArrayBuilder<(string aliasName, string symbolName)> aliases, bool global); public abstract void AddAliases(CompilationOptions options, ArrayBuilder<(string aliasName, string symbolName)> aliases); + + public abstract bool ContainsGlobalAliases(SyntaxNode root); + + public bool ContainsAttributeList(SyntaxNode root) + => ContainsAttributeList(root.Green, this.AttributeListKind); + + private static bool ContainsAttributeList(GreenNode node, int attributeListKind) + { + if (node.RawKind == attributeListKind) + return true; + + for (int i = 0, n = node.SlotCount; i < n; i++) + { + var child = node.GetSlot(i); + + if (child is null || child.IsToken) + continue; + + if (ContainsAttributeList(child, attributeListKind)) + return true; + } + + return false; + } } } diff --git a/src/Compilers/Core/Portable/SourceGeneration/Nodes/BatchNode.cs b/src/Compilers/Core/Portable/SourceGeneration/Nodes/BatchNode.cs index 0b2604db436e3..1e5b1a60045a5 100644 --- a/src/Compilers/Core/Portable/SourceGeneration/Nodes/BatchNode.cs +++ b/src/Compilers/Core/Portable/SourceGeneration/Nodes/BatchNode.cs @@ -2,8 +2,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; using System.Collections.Immutable; using System.Diagnostics; @@ -30,6 +28,81 @@ public BatchNode(IIncrementalGeneratorNode sourceNode, IEqualityComparer public IIncrementalGeneratorNode> WithTrackingName(string name) => new BatchNode(_sourceNode, _comparer, name); + private (ImmutableArray, ImmutableArray<(IncrementalGeneratorRunStep InputStep, int OutputIndex)>) GetValuesAndInputs( + NodeStateTable sourceTable, + NodeStateTable> previousTable, + NodeStateTable>.Builder newTable) + { + // Do an initial pass to both get the steps, and determine how many entries we'll have. + var sourceInputsBuilder = newTable.TrackIncrementalSteps ? ArrayBuilder<(IncrementalGeneratorRunStep InputStep, int OutputIndex)>.GetInstance() : null; + + var entryCount = 0; + foreach (var entry in sourceTable) + { + // Always keep track of its step information, regardless of if the entry was removed or not, so we + // can accurately report how long it took and what actually happened (for testing validation). + sourceInputsBuilder?.Add((entry.Step!, entry.OutputIndex)); + + if (entry.State != EntryState.Removed) + entryCount++; + } + + var sourceInputs = sourceInputsBuilder != null ? sourceInputsBuilder.ToImmutableAndFree() : default; + + // First, see if we can reuse the entries from previousTable. + // If not, produce the actual values we need from sourceTable. + var result = tryReusePreviousTableValues(entryCount) ?? computeCurrentTableValues(entryCount); + return (result, sourceInputs); + + ImmutableArray? tryReusePreviousTableValues(int entryCount) + { + if (previousTable.Count != 1) + return null; + + var previousItems = previousTable.Single().item; + + // If they don't have the same length, we clearly can't reuse them. + if (previousItems.Length != entryCount) + return null; + + var indexInPrevious = 0; + foreach (var entry in sourceTable) + { + if (entry.State == EntryState.Removed) + continue; + + // If the entries aren't the same, we can't reuse. + if (!EqualityComparer.Default.Equals(entry.Item, previousItems[indexInPrevious])) + return null; + + indexInPrevious++; + } + + // We better have the exact same count as previousItems as we checked that above. + Debug.Assert(indexInPrevious == previousItems.Length); + + // Looks good, we can reuse this. + return previousItems; + } + + ImmutableArray computeCurrentTableValues(int entryCount) + { + // Important: we initialize with the exact capacity we need here so that we don't make a pointless + // scratch array that may be very large and may cause GC churn when it cannot be returned to the pool. + var builder = ArrayBuilder.GetInstance(entryCount); + foreach (var entry in sourceTable) + { + if (entry.State == EntryState.Removed) + continue; + + builder.Add(entry.Item); + } + + Debug.Assert(builder.Count == entryCount); + return builder.ToImmutableAndFree(); + } + } + public NodeStateTable> UpdateStateTable(DriverStateTable.Builder builder, NodeStateTable> previousTable, CancellationToken cancellationToken) { // grab the source inputs @@ -43,29 +116,14 @@ public NodeStateTable> UpdateStateTable(DriverStateTable. // - Modified otherwise // update the table - var newTable = builder.CreateTableBuilder(previousTable, _name); + var newTable = builder.CreateTableBuilder(previousTable, _name, _comparer); // If this execution is tracking steps, then the source table should have also tracked steps or be the empty table. Debug.Assert(!newTable.TrackIncrementalSteps || (sourceTable.HasTrackedSteps || sourceTable.IsEmpty)); var stopwatch = SharedStopwatch.StartNew(); - var sourceValuesBuilder = ArrayBuilder.GetInstance(); - var sourceInputsBuilder = newTable.TrackIncrementalSteps ? ArrayBuilder<(IncrementalGeneratorRunStep InputStep, int OutputIndex)>.GetInstance() : null; - - foreach (var entry in sourceTable) - { - // At this point, we can remove any 'Removed' items and ensure they're not in our list of states. - if (entry.State != EntryState.Removed) - sourceValuesBuilder.Add(entry.Item); - - // However, regardless of if the entry was removed or not, we still keep track of its step information - // so we can accurately report how long it took and what actually happened (for testing validation). - sourceInputsBuilder?.Add((entry.Step!, entry.OutputIndex)); - } - - var sourceValues = sourceValuesBuilder.ToImmutableAndFree(); - var sourceInputs = newTable.TrackIncrementalSteps ? sourceInputsBuilder!.ToImmutableAndFree() : default; + var (sourceValues, sourceInputs) = GetValuesAndInputs(sourceTable, previousTable, newTable); if (previousTable.IsEmpty) { diff --git a/src/Compilers/Core/Portable/SourceGeneration/Nodes/CombineNode.cs b/src/Compilers/Core/Portable/SourceGeneration/Nodes/CombineNode.cs index aef82e0a84744..732f6708669b3 100644 --- a/src/Compilers/Core/Portable/SourceGeneration/Nodes/CombineNode.cs +++ b/src/Compilers/Core/Portable/SourceGeneration/Nodes/CombineNode.cs @@ -41,7 +41,8 @@ public CombineNode(IIncrementalGeneratorNode input1, IIncrementalGenera return previousTable; } - var builder = graphState.CreateTableBuilder(previousTable, _name); + var totalEntryItemCount = input1Table.GetTotalEntryItemCount(); + var builder = graphState.CreateTableBuilder(previousTable, _name, _comparer, totalEntryItemCount); // Semantics of a join: // @@ -75,13 +76,14 @@ public CombineNode(IIncrementalGeneratorNode input1, IIncrementalGenera } } + Debug.Assert(builder.Count == totalEntryItemCount); return builder.ToImmutableAndFree(); } private NodeStateTable<(TInput1, TInput2)> RecordStepsForCachedTable(DriverStateTable.Builder graphState, NodeStateTable<(TInput1, TInput2)> previousTable, NodeStateTable input1Table, NodeStateTable input2Table) { Debug.Assert(input1Table.HasTrackedSteps && input2Table.IsCached); - var builder = graphState.CreateTableBuilder(previousTable, _name); + var builder = graphState.CreateTableBuilder(previousTable, _name, _comparer); (_, IncrementalGeneratorRunStep? input2Step) = input2Table.Single(); foreach (var entry in input1Table) { diff --git a/src/Compilers/Core/Portable/SourceGeneration/Nodes/DriverStateTable.cs b/src/Compilers/Core/Portable/SourceGeneration/Nodes/DriverStateTable.cs index edf3b8a681ef8..e465690fcbda8 100644 --- a/src/Compilers/Core/Portable/SourceGeneration/Nodes/DriverStateTable.cs +++ b/src/Compilers/Core/Portable/SourceGeneration/Nodes/DriverStateTable.cs @@ -3,6 +3,7 @@ // See the LICENSE file in the project root for more information. using System; +using System.Collections.Generic; using System.Collections.Immutable; using System.Diagnostics; using System.Linq; @@ -61,9 +62,10 @@ public NodeStateTable GetLatestStateTableForNode(IIncrementalGeneratorNode return newTable; } - public NodeStateTable.Builder CreateTableBuilder(NodeStateTable previousTable, string? stepName) + public NodeStateTable.Builder CreateTableBuilder( + NodeStateTable previousTable, string? stepName, IEqualityComparer? equalityComparer, int? tableCapacity = null) { - return previousTable.ToBuilder(stepName, DriverState.TrackIncrementalSteps); + return previousTable.ToBuilder(stepName, DriverState.TrackIncrementalSteps, equalityComparer, tableCapacity); } public DriverStateTable ToImmutable() diff --git a/src/Compilers/Core/Portable/SourceGeneration/Nodes/InputNode.cs b/src/Compilers/Core/Portable/SourceGeneration/Nodes/InputNode.cs index 96af759a55bb0..8d7b13f033bec 100644 --- a/src/Compilers/Core/Portable/SourceGeneration/Nodes/InputNode.cs +++ b/src/Compilers/Core/Portable/SourceGeneration/Nodes/InputNode.cs @@ -52,7 +52,7 @@ public NodeStateTable UpdateStateTable(DriverStateTable.Builder graphState, N Debug.Assert(added); } - var builder = graphState.CreateTableBuilder(previousTable, _name); + var builder = graphState.CreateTableBuilder(previousTable, _name, _comparer); // We always have no inputs steps into an InputNode, but we track the difference between "no inputs" (empty collection) and "no step information" (default value) var noInputStepsStepInfo = builder.TrackIncrementalSteps ? ImmutableArray<(IncrementalGeneratorRunStep, int)>.Empty : default; diff --git a/src/Compilers/Core/Portable/SourceGeneration/Nodes/NodeStateTable.cs b/src/Compilers/Core/Portable/SourceGeneration/Nodes/NodeStateTable.cs index e8ca334d762db..c5c2aef5546fe 100644 --- a/src/Compilers/Core/Portable/SourceGeneration/Nodes/NodeStateTable.cs +++ b/src/Compilers/Core/Portable/SourceGeneration/Nodes/NodeStateTable.cs @@ -64,7 +64,6 @@ internal sealed class NodeStateTable : IStateTable private readonly ImmutableArray _states; - private NodeStateTable(ImmutableArray states, ImmutableArray steps, bool hasTrackedSteps) { Debug.Assert(!hasTrackedSteps || steps.Length == states.Length); @@ -75,7 +74,7 @@ private NodeStateTable(ImmutableArray states, ImmutableArray _states.Length; } + public int Count => _states.Length; /// /// Indicates if every entry in this table has a state of @@ -88,6 +87,9 @@ private NodeStateTable(ImmutableArray states, ImmutableArray Steps { get; } + public int GetTotalEntryItemCount() + => _states.Sum(static e => e.Count); + public IEnumerator> GetEnumerator() { for (int i = 0; i < _states.Length; i++) @@ -106,16 +108,20 @@ public NodeStateTable AsCached() if (IsCached) return this; - var compacted = ArrayBuilder.GetInstance(); + var nonRemovedCount = _states.Count(static e => !e.IsRemoved); + + var compacted = ArrayBuilder.GetInstance(nonRemovedCount); foreach (var entry in _states) { if (!entry.IsRemoved) - { compacted.Add(entry.AsCached()); - } } + // When we're preparing a table for caching between runs, we drop the step information as we cannot guarantee the graph structure while also updating // the input states + + // Ensure we are completely full so that ToImmutable translates to a MoveToImmutable + Debug.Assert(compacted.Count == nonRemovedCount); return new NodeStateTable(compacted.ToImmutableAndFree(), ImmutableArray.Empty, hasTrackedSteps: false); } @@ -127,19 +133,20 @@ public NodeStateTable AsCached() return (_states[^1].GetItem(0), HasTrackedSteps ? Steps[^1] : null); } - public Builder ToBuilder(string? stepName, bool stepTrackingEnabled) - => new Builder(this, stepName, stepTrackingEnabled); + public Builder ToBuilder(string? stepName, bool stepTrackingEnabled, IEqualityComparer? equalityComparer = null, int? tableCapacity = null) + => new(this, stepName, stepTrackingEnabled, equalityComparer, tableCapacity); - public NodeStateTable CreateCachedTableWithUpdatedSteps(NodeStateTable inputTable, string? stepName) + public NodeStateTable CreateCachedTableWithUpdatedSteps(NodeStateTable inputTable, string? stepName, IEqualityComparer equalityComparer) { Debug.Assert(inputTable.HasTrackedSteps && inputTable.IsCached); - NodeStateTable.Builder builder = ToBuilder(stepName, stepTrackingEnabled: true); + NodeStateTable.Builder builder = ToBuilder(stepName, stepTrackingEnabled: true, equalityComparer); foreach (var entry in inputTable) { var inputs = ImmutableArray.Create((entry.Step!, entry.OutputIndex)); bool usedCachedEntry = builder.TryUseCachedEntries(TimeSpan.Zero, inputs); Debug.Assert(usedCachedEntry); } + return builder.ToImmutableAndFree(); } @@ -149,22 +156,40 @@ public sealed class Builder private readonly NodeStateTable _previous; private readonly string? _name; + private readonly IEqualityComparer _equalityComparer; private readonly ArrayBuilder? _steps; [MemberNotNullWhen(true, nameof(_steps))] public bool TrackIncrementalSteps => _steps is not null; - internal Builder(NodeStateTable previous, string? name, bool stepTrackingEnabled) +#if DEBUG + private readonly int? _requestedTableCapacity; +#endif + + internal Builder( + NodeStateTable previous, + string? name, + bool stepTrackingEnabled, + IEqualityComparer? equalityComparer, + int? tableCapacity) { - _states = ArrayBuilder.GetInstance(previous._states.Length); +#if DEBUG + _requestedTableCapacity = tableCapacity; +#endif + // If the caller specified a desired capacity, then use that. Otherwise, use the previous table's total + // entry count as a reasonable approximation for what we will need. + _states = ArrayBuilder.GetInstance(tableCapacity ?? previous.GetTotalEntryItemCount()); _previous = previous; _name = name; + _equalityComparer = equalityComparer ?? EqualityComparer.Default; if (stepTrackingEnabled) { _steps = ArrayBuilder.GetInstance(); } } + public int Count => _states.Count; + public bool TryRemoveEntries(TimeSpan elapsedTime, ImmutableArray<(IncrementalGeneratorRunStep InputStep, int OutputIndex)> stepInputs) { if (_previous._states.Length <= _states.Count) @@ -180,7 +205,7 @@ public bool TryRemoveEntries(TimeSpan elapsedTime, ImmutableArray<(IncrementalGe return true; } - public bool TryRemoveEntries(TimeSpan elapsedTime, ImmutableArray<(IncrementalGeneratorRunStep InputStep, int OutputIndex)> stepInputs, out ImmutableArray entries) + public bool TryRemoveEntries(TimeSpan elapsedTime, ImmutableArray<(IncrementalGeneratorRunStep InputStep, int OutputIndex)> stepInputs, out OneOrMany entries) { if (!TryRemoveEntries(elapsedTime, stepInputs)) { @@ -188,7 +213,7 @@ public bool TryRemoveEntries(TimeSpan elapsedTime, ImmutableArray<(IncrementalGe return false; } - entries = _states[^1].ToImmutableArray(); + entries = _states[^1].Items; return true; } @@ -229,8 +254,8 @@ public bool TryModifyEntry(T value, IEqualityComparer comparer, TimeSpan elap } Debug.Assert(_previous._states[_states.Count].Count == 1); - var (chosen, state) = GetModifiedItemAndState(_previous._states[_states.Count].GetItem(0), value, comparer); - _states.Add(new TableEntry(chosen, state)); + var (chosen, state, _) = GetModifiedItemAndState(_previous._states[_states.Count].GetItem(0), value, comparer); + _states.Add(new TableEntry(OneOrMany.Create(chosen), state)); RecordStepInfoForLastEntry(elapsedTime, stepInputs, overallInputState); return true; } @@ -259,48 +284,85 @@ public bool TryModifyEntries(ImmutableArray outputs, IEqualityComparer com { RecordStepInfoForLastEntry(elapsedTime, stepInputs, EntryState.Cached); } + return true; } - var modified = new TableEntry.Builder(); + // We may be able to move the previous entry over wholesale. So avoid creating an builder and doing any + // expensive work there until necessary (e.g. we detected either a different item or a different state). + // We can only do this if the counts of before/after are the same. If not, then obviously something + // changed and we can't reuse the before item. + + var totalBuilderItems = Math.Max(previousEntry.Count, outputs.Length); + var builder = previousEntry.Count == outputs.Length ? null : new TableEntry.Builder(capacity: totalBuilderItems); + var sharedCount = Math.Min(previousEntry.Count, outputs.Length); // cached or modified items for (int i = 0; i < sharedCount; i++) { - var previous = previousEntry.GetItem(i); - var replacement = outputs[i]; + var previousItem = previousEntry.GetItem(i); + var previousState = previousEntry.GetState(i); + var replacementItem = outputs[i]; - (var chosen, var state) = GetModifiedItemAndState(previous, replacement, comparer); - modified.Add(chosen, state); + var (chosenItem, state, chosePrevious) = GetModifiedItemAndState(previousItem, replacementItem, comparer); + + if (builder != null) + { + // if we have a builder, then we're keeping track of all entries no matter what. + builder.Add(chosenItem, state); + continue; + } + + if (!chosePrevious || state != previousState) + { + // We don't have a builder, but we also can't use the previous entry. Make a builder, copy + // everything prior to this point to it, and then add the latest entry. + builder = new TableEntry.Builder(capacity: totalBuilderItems); + for (int j = 0; j < i; j++) + builder.Add(previousEntry.GetItem(j), previousEntry.GetState(j)); + + builder.Add(chosenItem, state); + continue; + } + + // otherwise, we don't have a builder and we are still able to use the previous entry. Keep going + // without constructing anything. } // removed for (int i = sharedCount; i < previousEntry.Count; i++) { - modified.Add(previousEntry.GetItem(i), EntryState.Removed); + // We know we must have a builder because we only get into this path when the counts are different + // (and thus we created a builder at the start). + builder!.Add(previousEntry.GetItem(i), EntryState.Removed); } // added for (int i = sharedCount; i < outputs.Length; i++) { - modified.Add(outputs[i], EntryState.Added); + // We know we must have a builder because we only get into this path when the counts are different + // (and thus we created a builder at the start). + builder!.Add(outputs[i], EntryState.Added); } - _states.Add(modified.ToImmutableAndFree()); + // If we still don't have a builder, then we can reuse the previous table entry entirely. Otherwise, + // construct the new one from the values collected. + _states.Add(builder == null ? previousEntry : builder.ToImmutableAndFree()); + RecordStepInfoForLastEntry(elapsedTime, stepInputs, overallInputState); return true; } public void AddEntry(T value, EntryState state, TimeSpan elapsedTime, ImmutableArray<(IncrementalGeneratorRunStep InputStep, int OutputIndex)> stepInputs, EntryState overallInputState) { - _states.Add(new TableEntry(value, state)); + _states.Add(new TableEntry(OneOrMany.Create(value), state)); RecordStepInfoForLastEntry(elapsedTime, stepInputs, overallInputState); } public TableEntry AddEntries(ImmutableArray values, EntryState state, TimeSpan elapsedTime, ImmutableArray<(IncrementalGeneratorRunStep InputStep, int OutputIndex)> stepInputs, EntryState overallInputState) { - var tableEntry = new TableEntry(values, state); + var tableEntry = new TableEntry(OneOrMany.Create(values), state); _states.Add(tableEntry); RecordStepInfoForLastEntry(elapsedTime, stepInputs, overallInputState); return tableEntry; @@ -359,19 +421,41 @@ public NodeStateTable ToImmutableAndFree() return NodeStateTable.Empty; } +#if DEBUG + // If the caller requested a specific capacity, then we should have added either that amount, or some + // amount less than that. It's possible to have added less as a Where clause will mean some amount of + // states are filtered out. + Debug.Assert(_requestedTableCapacity == null || _states.Count <= _requestedTableCapacity); +#endif + + // if we added the exact same entries as before, then we can directly embed previous' entry array, + // avoiding a costly allocation of the same data. + ImmutableArray finalStates; + if (_states.Count == _previous.Count && _states.SequenceEqual(_previous._states, (e1, e2) => e1.Matches(e2, _equalityComparer))) + { + finalStates = _previous._states; + _states.Free(); + } + else + { + // Important to use ToImmutableAndFree so that we will MoveToImmutable when the requested capacity + // equals the count. + finalStates = _states.ToImmutableAndFree(); + } + return new NodeStateTable( - _states.ToImmutableAndFree(), + finalStates, TrackIncrementalSteps ? _steps.ToImmutableAndFree() : default, hasTrackedSteps: TrackIncrementalSteps); } - private static (T chosen, EntryState state) GetModifiedItemAndState(T previous, T replacement, IEqualityComparer comparer) + private static (T chosen, EntryState state, bool chosePrevious) GetModifiedItemAndState(T previous, T replacement, IEqualityComparer comparer) { // when comparing an item to check if its modified we explicitly cache the *previous* item in the case where its // considered to be equal. This ensures that subsequent comparisons are stable across future generation passes. return comparer.Equals(previous, replacement) - ? (previous, EntryState.Cached) - : (replacement, EntryState.Modified); + ? (previous, EntryState.Cached, chosePrevious: true) + : (replacement, EntryState.Modified, chosePrevious: false); } } @@ -382,53 +466,58 @@ internal readonly struct TableEntry private static readonly ImmutableArray s_allModifiedEntries = ImmutableArray.Create(EntryState.Modified); private static readonly ImmutableArray s_allRemovedEntries = ImmutableArray.Create(EntryState.Removed); - private readonly ImmutableArray _items; - private readonly T? _item; + private readonly OneOrMany _items; /// - /// Represents the corresponding state of each item in , - /// or contains a single state when is populated or when every state of has the same value. + /// Represents the corresponding state of each item in , or contains a single state when + /// is populated or when every state of has the same value. /// private readonly ImmutableArray _states; - public TableEntry(T item, EntryState state) - : this(item, default, GetSingleArray(state)) { } + public TableEntry(OneOrMany items, EntryState state) + : this(items, GetSingleArray(state)) { } - public TableEntry(ImmutableArray items, EntryState state) - : this(default, items, GetSingleArray(state)) { } - - private TableEntry(T? item, ImmutableArray items, ImmutableArray states) + private TableEntry(OneOrMany items, ImmutableArray states) { Debug.Assert(!states.IsDefault); - Debug.Assert(states.Length == 1 || states.Distinct().Count() > 1); + Debug.Assert(states.Length == 1 || states.Distinct().Length > 1); + + _items = items; + _states = states; + } + + public bool Matches(TableEntry entry, IEqualityComparer equalityComparer) + { + if (!_states.SequenceEqual(entry._states)) + return false; - this._item = item; - this._items = items; - this._states = states; + if (this.Count != entry.Count) + return false; + + for (int i = 0, n = this.Count; i < n; i++) + { + if (!equalityComparer.Equals(this.GetItem(i), entry.GetItem(i))) + return false; + } + + return true; } public bool IsCached => this._states == s_allCachedEntries || this._states.All(s => s == EntryState.Cached); public bool IsRemoved => this._states == s_allRemovedEntries || this._states.All(s => s == EntryState.Removed); - public int Count => IsSingle ? 1 : _items.Length; + public int Count => _items.Count; - public T GetItem(int index) - { - Debug.Assert(!IsSingle || index == 0); - return IsSingle ? _item : _items[index]; - } + public T GetItem(int index) => _items[index]; public EntryState GetState(int index) => _states.Length == 1 ? _states[0] : _states[index]; - public ImmutableArray ToImmutableArray() => IsSingle ? ImmutableArray.Create(_item) : _items; + public OneOrMany Items => _items; - public TableEntry AsCached() => new(_item, _items, s_allCachedEntries); + public TableEntry AsCached() => new(_items, s_allCachedEntries); - public TableEntry AsRemoved() => new(_item, _items, s_allRemovedEntries); - - [MemberNotNullWhen(true, nameof(_item))] - private bool IsSingle => this._items.IsDefault; + public TableEntry AsRemoved() => new(_items, s_allRemovedEntries); private static ImmutableArray GetSingleArray(EntryState state) => state switch { @@ -465,26 +554,28 @@ public bool MoveNext() #if DEBUG public override string ToString() { - if (IsSingle) + if (this.Count == 1) { return $"{GetItem(0)}: {GetState(0)}"; } else { var sb = PooledStringBuilder.GetInstance(); - sb.Builder.Append("{"); + sb.Builder.Append('{'); for (int i = 0; i < Count; i++) { if (i > 0) { sb.Builder.Append(','); } + sb.Builder.Append(" ("); sb.Builder.Append(GetItem(i)); sb.Builder.Append(':'); sb.Builder.Append(GetState(i)); sb.Builder.Append(')'); } + sb.Builder.Append(" }"); return sb.ToStringAndFree(); } @@ -493,12 +584,19 @@ public override string ToString() public sealed class Builder { - private readonly ArrayBuilder _items = ArrayBuilder.GetInstance(); + private readonly ArrayBuilder _items; private ArrayBuilder? _states; - private EntryState? _currentState; + private readonly int _requestedCapacity; + + public Builder(int capacity) + { + _items = ArrayBuilder.GetInstance(capacity); + _requestedCapacity = capacity; + } + public void Add(T item, EntryState state) { _items.Add(item); @@ -506,13 +604,19 @@ public void Add(T item, EntryState state) { _currentState = state; } - else if (_states is object) + else if (_states is not null) { _states.Add(state); } else if (_currentState != state) { - _states = ArrayBuilder.GetInstance(_items.Count - 1, _currentState.Value); + // Create a builder with the right capacity (so we don't waste scratch space). Copy all the same + // prior values all the way up to the last item we're about to add. + _states = ArrayBuilder.GetInstance(_requestedCapacity); + for (int i = 0, n = _items.Count - 1; i < n; i++) + _states.Add(_currentState.Value); + + // then finally add the new value at the end. _states.Add(state); } } @@ -520,8 +624,24 @@ public void Add(T item, EntryState state) public TableEntry ToImmutableAndFree() { Debug.Assert(_currentState.HasValue, "Created a builder with no values?"); - int numItems = _items.Count; - return new TableEntry(item: default, _items.ToImmutableAndFree(), _states?.ToImmutableAndFree() ?? GetSingleArray(_currentState.Value)); + Debug.Assert(_items.Count >= 1, "Created a builder with no values?"); + + Debug.Assert(_items.Count == _requestedCapacity); + Debug.Assert(_states == null || _states.Count == _requestedCapacity); + + OneOrMany items; + if (_items.Count == 1) + { + var item = _items[0]; + _items.Free(); + items = OneOrMany.Create(item); + } + else + { + items = OneOrMany.Create(_items.ToImmutableAndFree()); + } + + return new TableEntry(items, _states?.ToImmutableAndFree() ?? GetSingleArray(_currentState.Value)); } } } diff --git a/src/Compilers/Core/Portable/SourceGeneration/Nodes/PredicateSyntaxStrategy.cs b/src/Compilers/Core/Portable/SourceGeneration/Nodes/PredicateSyntaxStrategy.cs index 7f5aab8e66ff4..fc366730dc8af 100644 --- a/src/Compilers/Core/Portable/SourceGeneration/Nodes/PredicateSyntaxStrategy.cs +++ b/src/Compilers/Core/Portable/SourceGeneration/Nodes/PredicateSyntaxStrategy.cs @@ -49,7 +49,7 @@ public Builder(PredicateSyntaxStrategy owner, object key, StateTableStore tab _comparer = comparer; _key = key; _filterTable = table.GetStateTableOrEmpty(_owner._filterKey).ToBuilder(stepName: null, trackIncrementalSteps); - _transformTable = table.GetStateTableOrEmpty(_key).ToBuilder(_name, trackIncrementalSteps); + _transformTable = table.GetStateTableOrEmpty(_key).ToBuilder(_name, trackIncrementalSteps, _comparer); } public void SaveStateAndFree(StateTableStore.Builder tables) @@ -69,12 +69,10 @@ public void VisitTree( if (state == EntryState.Removed) { // mark both syntax *and* transform nodes removed - if (_filterTable.TryRemoveEntries(TimeSpan.Zero, noInputStepsStepInfo, out ImmutableArray removedNodes)) + if (_filterTable.TryRemoveEntries(TimeSpan.Zero, noInputStepsStepInfo, out var removedNodes)) { - for (int i = 0; i < removedNodes.Length; i++) - { + for (int i = 0; i < removedNodes.Count; i++) _transformTable.TryRemoveEntries(TimeSpan.Zero, noInputStepsStepInfo); - } } } else diff --git a/src/Compilers/Core/Portable/SourceGeneration/Nodes/SharedInputNodes.cs b/src/Compilers/Core/Portable/SourceGeneration/Nodes/SharedInputNodes.cs index 390c2299e4dd4..31cef60cb7db9 100644 --- a/src/Compilers/Core/Portable/SourceGeneration/Nodes/SharedInputNodes.cs +++ b/src/Compilers/Core/Portable/SourceGeneration/Nodes/SharedInputNodes.cs @@ -4,6 +4,7 @@ using System.Collections.Immutable; using Microsoft.CodeAnalysis.Diagnostics; +using Roslyn.Utilities; namespace Microsoft.CodeAnalysis { @@ -14,7 +15,7 @@ internal static class SharedInputNodes { public static readonly InputNode Compilation = new InputNode(b => ImmutableArray.Create(b.Compilation)); - public static readonly InputNode CompilationOptions = new(b => ImmutableArray.Create(b.Compilation.Options)); + public static readonly InputNode CompilationOptions = new(b => ImmutableArray.Create(b.Compilation.Options), ReferenceEqualityComparer.Instance); public static readonly InputNode ParseOptions = new InputNode(b => ImmutableArray.Create(b.DriverState.ParseOptions)); diff --git a/src/Compilers/Core/Portable/SourceGeneration/Nodes/SourceOutputNode.cs b/src/Compilers/Core/Portable/SourceGeneration/Nodes/SourceOutputNode.cs index b6b715f807af5..805b2494a179f 100644 --- a/src/Compilers/Core/Portable/SourceGeneration/Nodes/SourceOutputNode.cs +++ b/src/Compilers/Core/Portable/SourceGeneration/Nodes/SourceOutputNode.cs @@ -43,12 +43,12 @@ public NodeStateTable UpdateStateTable(DriverStateTable.Builder graphSt { if (graphState.DriverState.TrackIncrementalSteps) { - return previousTable.CreateCachedTableWithUpdatedSteps(sourceTable, stepName); + return previousTable.CreateCachedTableWithUpdatedSteps(sourceTable, stepName, EqualityComparer.Default); } return previousTable; } - var nodeTable = graphState.CreateTableBuilder(previousTable, stepName); + var nodeTable = graphState.CreateTableBuilder(previousTable, stepName, EqualityComparer.Default); foreach (var entry in sourceTable) { var inputs = nodeTable.TrackIncrementalSteps ? ImmutableArray.Create((entry.Step!, entry.OutputIndex)) : default; diff --git a/src/Compilers/Core/Portable/SourceGeneration/Nodes/SyntaxNodeGrouping.cs b/src/Compilers/Core/Portable/SourceGeneration/Nodes/SyntaxNodeGrouping.cs deleted file mode 100644 index d138b6d166de5..0000000000000 --- a/src/Compilers/Core/Portable/SourceGeneration/Nodes/SyntaxNodeGrouping.cs +++ /dev/null @@ -1,43 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using System; -using System.Collections.Immutable; -using System.Linq; -using Roslyn.Utilities; - -namespace Microsoft.CodeAnalysis; - -public partial struct SyntaxValueProvider -{ - /// - /// Wraps a grouping of nodes within a syntax tree so we can have value-semantics around them usable by the - /// incremental driver. Note: we do something very sneaky here. Specifically, as long as we have the same from before, then we know we must have the same nodes as before (since the nodes are - /// entirely determined from the text+options which is exactly what the syntax tree represents). Similarly, if the - /// syntax tree changes, we will always get different nodes (since they point back at the syntax tree). So we can - /// just use the syntax tree itself to determine value semantics here. - /// - private class SyntaxNodeGrouping : IEquatable> - where TSyntaxNode : SyntaxNode - { - public readonly SyntaxTree SyntaxTree; - public readonly ImmutableArray SyntaxNodes; - - public SyntaxNodeGrouping(IGrouping grouping) - { - SyntaxTree = grouping.Key; - SyntaxNodes = grouping.OrderBy(static n => n.FullSpan.Start).ToImmutableArray(); - } - - public override int GetHashCode() - => SyntaxTree.GetHashCode(); - - public override bool Equals(object? obj) - => Equals(obj as SyntaxNodeGrouping); - - public bool Equals(SyntaxNodeGrouping? obj) - => this.SyntaxTree == obj?.SyntaxTree; - } -} diff --git a/src/Compilers/Core/Portable/SourceGeneration/Nodes/SyntaxValueProvider_ForAttributeWithMetadataName.cs b/src/Compilers/Core/Portable/SourceGeneration/Nodes/SyntaxValueProvider_ForAttributeWithMetadataName.cs index 4fd4fc272b937..ce3ce7d5ecdc2 100644 --- a/src/Compilers/Core/Portable/SourceGeneration/Nodes/SyntaxValueProvider_ForAttributeWithMetadataName.cs +++ b/src/Compilers/Core/Portable/SourceGeneration/Nodes/SyntaxValueProvider_ForAttributeWithMetadataName.cs @@ -4,20 +4,14 @@ using System; using System.Collections.Immutable; +using System.Diagnostics; using System.Linq; -using System.Xml.Serialization; +using System.Threading; using Microsoft.CodeAnalysis.PooledObjects; using Roslyn.Utilities; -using System.Collections; -using System.Collections.Generic; -using System.Diagnostics.CodeAnalysis; -using Microsoft.CodeAnalysis.SourceGeneration; -using System.Threading; namespace Microsoft.CodeAnalysis; -using Aliases = ArrayBuilder<(string aliasName, string symbolName)>; - public readonly struct GeneratorAttributeSyntaxContext { /// @@ -92,51 +86,41 @@ public IncrementalValuesProvider ForAttributeWithMetadataName( var nodesWithAttributesMatchingSimpleName = this.ForAttributeWithSimpleName(metadataName.UnmangledTypeName, predicate); - var collectedNodes = nodesWithAttributesMatchingSimpleName - .Collect() - .WithComparer(ImmutableArrayValueComparer.Instance) - .WithTrackingName("collectedNodes_ForAttributeWithMetadataName"); - - // Group all the nodes by syntax tree, so we can process a whole syntax tree at a time. This will let us make - // the required semantic model for it once, instead of potentially many times (in the rare, but possible case of - // a single file with a ton of matching nodes in it). - var groupedNodes = collectedNodes.SelectMany( - static (array, cancellationToken) => - array.GroupBy(static n => n.SyntaxTree) - .Select(static g => new SyntaxNodeGrouping(g))).WithTrackingName("groupedNodes_ForAttributeWithMetadataName"); - - var compilationAndGroupedNodesProvider = groupedNodes + var compilationAndGroupedNodesProvider = nodesWithAttributesMatchingSimpleName .Combine(_context.CompilationProvider) .WithTrackingName("compilationAndGroupedNodes_ForAttributeWithMetadataName"); var syntaxHelper = _context.SyntaxHelper; var finalProvider = compilationAndGroupedNodesProvider.SelectMany((tuple, cancellationToken) => { - var (grouping, compilation) = tuple; + var ((syntaxTree, syntaxNodes), compilation) = tuple; + Debug.Assert(syntaxNodes.All(n => n.SyntaxTree == syntaxTree)); var result = ArrayBuilder.GetInstance(); try { - var syntaxTree = grouping.SyntaxTree; - var semanticModel = compilation.GetSemanticModel(syntaxTree); - - foreach (var targetNode in grouping.SyntaxNodes) + if (!syntaxNodes.IsEmpty) { - cancellationToken.ThrowIfCancellationRequested(); - - var targetSymbol = - targetNode is ICompilationUnitSyntax compilationUnit ? semanticModel.Compilation.Assembly : - syntaxHelper.IsLambdaExpression(targetNode) ? semanticModel.GetSymbolInfo(targetNode, cancellationToken).Symbol : - semanticModel.GetDeclaredSymbol(targetNode, cancellationToken); - if (targetSymbol is null) - continue; + var semanticModel = compilation.GetSemanticModel(syntaxTree); - var attributes = getMatchingAttributes(targetNode, targetSymbol, fullyQualifiedMetadataName); - if (attributes.Length > 0) + foreach (var targetNode in syntaxNodes) { - result.Add(transform( - new GeneratorAttributeSyntaxContext(targetNode, targetSymbol, semanticModel, attributes), - cancellationToken)); + cancellationToken.ThrowIfCancellationRequested(); + + var targetSymbol = + targetNode is ICompilationUnitSyntax compilationUnit ? semanticModel.Compilation.Assembly : + syntaxHelper.IsLambdaExpression(targetNode) ? semanticModel.GetSymbolInfo(targetNode, cancellationToken).Symbol : + semanticModel.GetDeclaredSymbol(targetNode, cancellationToken); + if (targetSymbol is null) + continue; + + var attributes = getMatchingAttributes(targetNode, targetSymbol, fullyQualifiedMetadataName); + if (attributes.Length > 0) + { + result.Add(transform( + new GeneratorAttributeSyntaxContext(targetNode, targetSymbol, semanticModel, attributes), + cancellationToken)); + } } } diff --git a/src/Compilers/Core/Portable/SourceGeneration/Nodes/SyntaxValueProvider_ForAttributeWithSimpleName.cs b/src/Compilers/Core/Portable/SourceGeneration/Nodes/SyntaxValueProvider_ForAttributeWithSimpleName.cs index 9c3b9dad0afc9..9954e7c6e0eee 100644 --- a/src/Compilers/Core/Portable/SourceGeneration/Nodes/SyntaxValueProvider_ForAttributeWithSimpleName.cs +++ b/src/Compilers/Core/Portable/SourceGeneration/Nodes/SyntaxValueProvider_ForAttributeWithSimpleName.cs @@ -6,10 +6,7 @@ using System.Collections.Generic; using System.Collections.Immutable; using System.Diagnostics; -using System.Linq; -using System.Text; using System.Threading; -using System.Transactions; using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.SourceGeneration; using Roslyn.Utilities; @@ -18,9 +15,20 @@ namespace Microsoft.CodeAnalysis; using Aliases = ArrayBuilder<(string aliasName, string symbolName)>; +[Flags] +internal enum SourceGeneratorSyntaxTreeInfo +{ + NotComputedYet, + None = 1 << 0, + ContainsGlobalAliases = 1 << 1, + ContainsAttributeList = 1 << 2, + + ContainsGlobalAliasesOrAttributeList = ContainsGlobalAliases | ContainsAttributeList, +} + public partial struct SyntaxValueProvider { - private static readonly ObjectPool> s_stackPool = new(static () => new()); + private static readonly ObjectPool> s_stackPool = new ObjectPool>(static () => new Stack()); /// /// Returns all syntax nodes of that match if that node has an attribute on it that @@ -39,7 +47,11 @@ public partial struct SyntaxValueProvider /// context.SyntaxProvider.CreateSyntaxProviderForAttribute(nameof(CLSCompliantAttribute), (node, c) => node is ClassDeclarationSyntax) /// will find the C class. /// - internal IncrementalValuesProvider ForAttributeWithSimpleName( + /// + /// Note: a 'Values'-provider of arrays are returned. Each array provides all the matching nodes from a single . + /// + internal IncrementalValuesProvider<(SyntaxTree tree, ImmutableArray matches)> ForAttributeWithSimpleName( string simpleName, Func predicate) { @@ -50,12 +62,14 @@ internal IncrementalValuesProvider ForAttributeWithSimpleName( // changed. CreateSyntaxProvider will have to rerun all incremental nodes since it passes along the // SemanticModel, and that model is updated whenever any tree changes (since it is tied to the compilation). var syntaxTreesProvider = _context.CompilationProvider - .SelectMany(static (c, _) => c.SyntaxTrees) + .SelectMany((compilation, cancellationToken) => GetSourceGeneratorInfo(syntaxHelper, compilation, cancellationToken)) .WithTrackingName("compilationUnit_ForAttribute"); // Create a provider that provides (and updates) the global aliases for any particular file when it is edited. - var individualFileGlobalAliasesProvider = syntaxTreesProvider.Select( - (s, c) => getGlobalAliasesInCompilationUnit(syntaxHelper, s.GetRoot(c))).WithTrackingName("individualFileGlobalAliases_ForAttribute"); + var individualFileGlobalAliasesProvider = syntaxTreesProvider + .Where((info, _) => info.Info.HasFlag(SourceGeneratorSyntaxTreeInfo.ContainsGlobalAliases)) + .Select((info, cancellationToken) => getGlobalAliasesInCompilationUnit(syntaxHelper, info.Tree.GetRoot(cancellationToken))) + .WithTrackingName("individualFileGlobalAliases_ForAttribute"); // Create an aggregated view of all global aliases across all files. This should only update when an individual // file changes its global aliases or a file is added / removed from the compilation @@ -65,7 +79,7 @@ internal IncrementalValuesProvider ForAttributeWithSimpleName( .WithTrackingName("collectedGlobalAliases_ForAttribute"); var allUpGlobalAliasesProvider = collectedGlobalAliasesProvider - .Select(static (arrays, _) => GlobalAliases.Create(arrays.SelectMany(a => a.AliasAndSymbolNames).ToImmutableArray())) + .Select(static (arrays, _) => GlobalAliases.Create(arrays)) .WithTrackingName("allUpGlobalAliases_ForAttribute"); // Regenerate our data if the compilation options changed. VB can supply global aliases with compilation options, @@ -86,16 +100,14 @@ internal IncrementalValuesProvider ForAttributeWithSimpleName( // Combine the two providers so that we reanalyze every file if the global aliases change, or we reanalyze a // particular file when it's compilation unit changes. var syntaxTreeAndGlobalAliasesProvider = syntaxTreesProvider + .Where((info, _) => info.Info.HasFlag(SourceGeneratorSyntaxTreeInfo.ContainsAttributeList)) .Combine(allUpGlobalAliasesProvider) .WithTrackingName("compilationUnitAndGlobalAliases_ForAttribute"); - // For each pair of compilation unit + global aliases, walk the compilation unit - var result = syntaxTreeAndGlobalAliasesProvider - .SelectMany((globalAliasesAndCompilationUnit, cancellationToken) => GetMatchingNodes( - syntaxHelper, globalAliasesAndCompilationUnit.Right, globalAliasesAndCompilationUnit.Left, simpleName, predicate, cancellationToken)) - .WithTrackingName("result_ForAttribute"); - - return result; + return syntaxTreeAndGlobalAliasesProvider + .Select((tuple, c) => (tuple.Left.Tree, GetMatchingNodes(syntaxHelper, tuple.Right, tuple.Left.Tree, simpleName, predicate, c))) + .Where(tuple => tuple.Item2.Length > 0) + .WithTrackingName("result_ForAttributeInternal"); static GlobalAliases getGlobalAliasesInCompilationUnit( ISyntaxHelper syntaxHelper, @@ -104,12 +116,38 @@ static GlobalAliases getGlobalAliasesInCompilationUnit( Debug.Assert(compilationUnit is ICompilationUnitSyntax); var globalAliases = Aliases.GetInstance(); - syntaxHelper.AddAliases(compilationUnit, globalAliases, global: true); + syntaxHelper.AddAliases(compilationUnit.Green, globalAliases, global: true); return GlobalAliases.Create(globalAliases.ToImmutableAndFree()); } } + private static ImmutableArray<(SyntaxTree Tree, SourceGeneratorSyntaxTreeInfo Info)> GetSourceGeneratorInfo( + ISyntaxHelper syntaxHelper, Compilation compilation, CancellationToken cancellationToken) + { + // Get the count up front so we can allocate without waste. + var count = 0; + foreach (var tree in compilation.CommonSyntaxTrees) + { + cancellationToken.ThrowIfCancellationRequested(); + var info = tree.GetSourceGeneratorInfo(syntaxHelper, cancellationToken); + if ((info & SourceGeneratorSyntaxTreeInfo.ContainsGlobalAliasesOrAttributeList) != 0) + count++; + } + + var builder = ImmutableArray.CreateBuilder<(SyntaxTree Tree, SourceGeneratorSyntaxTreeInfo Info)>(count); + + // Iterate again. This will be free as the values from before will already be cached on the syntax tree. + foreach (var tree in compilation.CommonSyntaxTrees) + { + var info = tree.GetSourceGeneratorInfo(syntaxHelper, cancellationToken); + if ((info & SourceGeneratorSyntaxTreeInfo.ContainsGlobalAliasesOrAttributeList) != 0) + builder.Add((tree, info)); + } + + return builder.MoveToImmutable(); + } + private static ImmutableArray GetMatchingNodes( ISyntaxHelper syntaxHelper, GlobalAliases globalAliases, @@ -119,7 +157,6 @@ private static ImmutableArray GetMatchingNodes( CancellationToken cancellationToken) { var compilationUnit = syntaxTree.GetRoot(cancellationToken); - Debug.Assert(compilationUnit is ICompilationUnitSyntax); var isCaseSensitive = syntaxHelper.IsCaseSensitive; @@ -158,14 +195,14 @@ void recurse(SyntaxNode node) if (node is ICompilationUnitSyntax) { - syntaxHelper.AddAliases(node, localAliases, global: false); + syntaxHelper.AddAliases(node.Green, localAliases, global: false); recurseChildren(node); } else if (syntaxHelper.IsAnyNamespaceBlock(node)) { var localAliasCount = localAliases.Count; - syntaxHelper.AddAliases(node, localAliases, global: false); + syntaxHelper.AddAliases(node.Green, localAliases, global: false); recurseChildren(node); @@ -178,8 +215,7 @@ void recurse(SyntaxNode node) { // Have to lookup both with the name in the attribute, as well as adding the 'Attribute' suffix. // e.g. if there is [X] then we have to lookup with X and with XAttribute. - var simpleAttributeName = syntaxHelper.GetUnqualifiedIdentifierOfName( - syntaxHelper.GetNameOfAttribute(attribute)).ValueText; + var simpleAttributeName = syntaxHelper.GetUnqualifiedIdentifierOfName(syntaxHelper.GetNameOfAttribute(attribute)); if (matchesAttributeName(simpleAttributeName, withAttributeSuffix: false) || matchesAttributeName(simpleAttributeName, withAttributeSuffix: true)) { diff --git a/src/Compilers/Core/Portable/SourceGeneration/Nodes/TransformNode.cs b/src/Compilers/Core/Portable/SourceGeneration/Nodes/TransformNode.cs index c0bfdfe19b624..76f0903abbf6b 100644 --- a/src/Compilers/Core/Portable/SourceGeneration/Nodes/TransformNode.cs +++ b/src/Compilers/Core/Portable/SourceGeneration/Nodes/TransformNode.cs @@ -33,9 +33,11 @@ public TransformNode(IIncrementalGeneratorNode sourceNode, Func WithComparer(IEqualityComparer comparer) => new TransformNode(_sourceNode, _func, comparer, _name); + public IIncrementalGeneratorNode WithComparer(IEqualityComparer comparer) + => new TransformNode(_sourceNode, _func, comparer, _name); - public IIncrementalGeneratorNode WithTrackingName(string name) => new TransformNode(_sourceNode, _func, _comparer, name); + public IIncrementalGeneratorNode WithTrackingName(string name) + => new TransformNode(_sourceNode, _func, _comparer, name); public NodeStateTable UpdateStateTable(DriverStateTable.Builder builder, NodeStateTable previousTable, CancellationToken cancellationToken) { @@ -45,7 +47,7 @@ public NodeStateTable UpdateStateTable(DriverStateTable.Builder builder { if (builder.DriverState.TrackIncrementalSteps) { - return previousTable.CreateCachedTableWithUpdatedSteps(sourceTable, _name); + return previousTable.CreateCachedTableWithUpdatedSteps(sourceTable, _name, _comparer); } return previousTable; } @@ -56,7 +58,8 @@ public NodeStateTable UpdateStateTable(DriverStateTable.Builder builder // - Added: perform transform and add // - Modified: perform transform and do element wise comparison with previous results - var newTable = builder.CreateTableBuilder(previousTable, _name); + var totalEntryItemCount = sourceTable.GetTotalEntryItemCount(); + var newTable = builder.CreateTableBuilder(previousTable, _name, _comparer, totalEntryItemCount); foreach (var entry in sourceTable) { @@ -77,6 +80,9 @@ public NodeStateTable UpdateStateTable(DriverStateTable.Builder builder } } } + + // Can't assert anything about the count of items. _func may have produced a different amount of items if + // it's not a 1:1 function. return newTable.ToImmutableAndFree(); } diff --git a/src/Compilers/Core/Portable/SourceGeneration/Nodes/ValueSourceExtensions.cs b/src/Compilers/Core/Portable/SourceGeneration/Nodes/ValueSourceExtensions.cs index 83b654050ecdd..8d033798bd06f 100644 --- a/src/Compilers/Core/Portable/SourceGeneration/Nodes/ValueSourceExtensions.cs +++ b/src/Compilers/Core/Portable/SourceGeneration/Nodes/ValueSourceExtensions.cs @@ -35,6 +35,8 @@ public static class IncrementalValueProviderExtensions // helper for filtering public static IncrementalValuesProvider Where(this IncrementalValuesProvider source, Func predicate) => source.SelectMany((item, _) => predicate(item) ? ImmutableArray.Create(item) : ImmutableArray.Empty); + internal static IncrementalValuesProvider Where(this IncrementalValuesProvider source, Func predicate) => source.SelectMany((item, c) => predicate(item, c) ? ImmutableArray.Create(item) : ImmutableArray.Empty); + // custom comparer for given node public static IncrementalValueProvider WithComparer(this IncrementalValueProvider source, IEqualityComparer comparer) => new IncrementalValueProvider(source.Node.WithComparer(comparer)); diff --git a/src/Compilers/Core/Portable/SourceGeneration/UserFunction.cs b/src/Compilers/Core/Portable/SourceGeneration/UserFunction.cs index 72ee87619702f..41cb7a0b63897 100644 --- a/src/Compilers/Core/Portable/SourceGeneration/UserFunction.cs +++ b/src/Compilers/Core/Portable/SourceGeneration/UserFunction.cs @@ -39,7 +39,7 @@ internal static Func WrapUserFunction> WrapUserFunctionAsImmutableArray(this Func> userFunction) { - return (input, token) => userFunction.WrapUserFunction()(input, token).ToImmutableArray(); + return (input, token) => userFunction.WrapUserFunction()(input, token).ToImmutableArrayOrEmpty(); } internal static Action WrapUserAction(this Action userAction) diff --git a/src/Compilers/Core/Portable/SymbolDisplay/SymbolDisplayCompilerInternalOptions.cs b/src/Compilers/Core/Portable/SymbolDisplay/SymbolDisplayCompilerInternalOptions.cs index 14346d9edbf25..d5b83d44d8fbc 100644 --- a/src/Compilers/Core/Portable/SymbolDisplay/SymbolDisplayCompilerInternalOptions.cs +++ b/src/Compilers/Core/Portable/SymbolDisplay/SymbolDisplayCompilerInternalOptions.cs @@ -72,5 +72,10 @@ internal enum SymbolDisplayCompilerInternalOptions /// Includes the scoped keyword. /// IncludeScoped = 1 << 9, + + /// + /// Display `MyType@File.cs` instead of `MyType`. + /// + IncludeContainingFileForFileTypes = 1 << 10, } } diff --git a/src/Compilers/Core/Portable/SymbolDisplay/SymbolDisplayDelegateStyle.cs b/src/Compilers/Core/Portable/SymbolDisplay/SymbolDisplayDelegateStyle.cs index 348e94a581058..aa215920edebb 100644 --- a/src/Compilers/Core/Portable/SymbolDisplay/SymbolDisplayDelegateStyle.cs +++ b/src/Compilers/Core/Portable/SymbolDisplay/SymbolDisplayDelegateStyle.cs @@ -16,18 +16,18 @@ public enum SymbolDisplayDelegateStyle /// /// Shows the name and the parameters of the delegate (e.g. "SomeDelegate(int x)"). - /// - /// + /// /// The format of the parameters will be determined by the other flags passed. - /// + /// + /// NameAndParameters = 1, /// - /// Shows the name and the signature of the delegate (e.g. "void SomeDelegate(int x)"). - /// - /// + /// Shows the name and the signature of the delegate (e.g. "void SomeDelegate(int x)"). + /// /// The format of the signature will be determined by the other flags passed. - /// + /// + /// NameAndSignature = 2, } } diff --git a/src/Compilers/Core/Portable/SymbolDisplay/SymbolDisplayFormat.cs b/src/Compilers/Core/Portable/SymbolDisplay/SymbolDisplayFormat.cs index d8a5dc6aba65e..70928557f49e7 100644 --- a/src/Compilers/Core/Portable/SymbolDisplay/SymbolDisplayFormat.cs +++ b/src/Compilers/Core/Portable/SymbolDisplay/SymbolDisplayFormat.cs @@ -202,7 +202,8 @@ public class SymbolDisplayFormat SymbolDisplayCompilerInternalOptions.IncludeScriptType | SymbolDisplayCompilerInternalOptions.UseMetadataMethodNames | SymbolDisplayCompilerInternalOptions.FlagMissingMetadataTypes | - SymbolDisplayCompilerInternalOptions.IncludeCustomModifiers); + SymbolDisplayCompilerInternalOptions.IncludeCustomModifiers | + SymbolDisplayCompilerInternalOptions.IncludeContainingFileForFileTypes); /// /// A verbose format for displaying symbols (useful for testing). @@ -426,12 +427,12 @@ internal SymbolDisplayFormat( } /// - /// Creates a copy of the SymbolDisplayFormat but with replaced set of . + /// Creates a copy of the SymbolDisplayFormat but with replaced set of . /// /// /// An object representing how miscellaneous symbols will be formatted. /// - /// A duplicate of the SymbolDisplayFormat, with a replaced set of . + /// A duplicate of the SymbolDisplayFormat, with a replaced set of . public SymbolDisplayFormat WithMiscellaneousOptions(SymbolDisplayMiscellaneousOptions options) { return new SymbolDisplayFormat( @@ -451,36 +452,36 @@ public SymbolDisplayFormat WithMiscellaneousOptions(SymbolDisplayMiscellaneousOp } /// - /// Creates a copy of the SymbolDisplayFormat but with an additional set of . + /// Creates a copy of the SymbolDisplayFormat but with an additional set of . /// /// /// An object specifying additional parameters for how miscellaneous symbols will be formatted. /// - /// A duplicate of the SymbolDisplayFormat, with an additional set of . + /// A duplicate of the SymbolDisplayFormat, with an additional set of . public SymbolDisplayFormat AddMiscellaneousOptions(SymbolDisplayMiscellaneousOptions options) { return this.WithMiscellaneousOptions(this.MiscellaneousOptions | options); } /// - /// Creates a copy of the SymbolDisplayFormat without the specified . + /// Creates a copy of the SymbolDisplayFormat without the specified . /// /// /// An object specifying which parameters should not be applied to how miscellaneous symbols will be formatted. /// - /// A duplicate of the SymbolDisplayFormat, without the specified . + /// A duplicate of the SymbolDisplayFormat, without the specified . public SymbolDisplayFormat RemoveMiscellaneousOptions(SymbolDisplayMiscellaneousOptions options) { return this.WithMiscellaneousOptions(this.MiscellaneousOptions & ~options); } /// - /// Creates a copy of the SymbolDisplayFormat but with replaced set of . + /// Creates a copy of the SymbolDisplayFormat but with replaced set of . /// /// /// An object specifying how generic symbols will be formatted. /// - /// A duplicate of the SymbolDisplayFormat, with a replaced set of . + /// A duplicate of the SymbolDisplayFormat, with a replaced set of . public SymbolDisplayFormat WithGenericsOptions(SymbolDisplayGenericsOptions options) { return new SymbolDisplayFormat( @@ -499,25 +500,25 @@ public SymbolDisplayFormat WithGenericsOptions(SymbolDisplayGenericsOptions opti } /// - /// Creates a copy of the SymbolDisplayFormat but with an additional set of . + /// Creates a copy of the SymbolDisplayFormat but with an additional set of . /// /// /// An object specifying additional parameters for how generic symbols will be formatted. /// - /// A duplicate of the SymbolDisplayFormat, with an additional set of . + /// A duplicate of the SymbolDisplayFormat, with an additional set of . public SymbolDisplayFormat AddGenericsOptions(SymbolDisplayGenericsOptions options) { return this.WithGenericsOptions(this.GenericsOptions | options); } /// - /// Creates a copy of the SymbolDisplayFormat but with a set of stripped away from the original object. + /// Creates a copy of the SymbolDisplayFormat but with a set of stripped away from the original object. /// /// /// An object specifying which parameters should not be applied to how generic symbols will be formatted. /// /// - /// A duplicate of the SymbolDisplayFormat, with a set of stripped away from the original object. + /// A duplicate of the SymbolDisplayFormat, with a set of stripped away from the original object. /// public SymbolDisplayFormat RemoveGenericsOptions(SymbolDisplayGenericsOptions options) { @@ -525,12 +526,12 @@ public SymbolDisplayFormat RemoveGenericsOptions(SymbolDisplayGenericsOptions op } /// - /// Creates a copy of the SymbolDisplayFormat but with replaced set of . + /// Creates a copy of the SymbolDisplayFormat but with replaced set of . /// /// /// An object specifying how members will be formatted. /// - /// A duplicate of the SymbolDisplayFormat, with a replaced set of . + /// A duplicate of the SymbolDisplayFormat, with a replaced set of . public SymbolDisplayFormat WithMemberOptions(SymbolDisplayMemberOptions options) { return new SymbolDisplayFormat( @@ -549,13 +550,13 @@ public SymbolDisplayFormat WithMemberOptions(SymbolDisplayMemberOptions options) } /// - /// Creates a copy of the SymbolDisplayFormat but with an additional set of . + /// Creates a copy of the SymbolDisplayFormat but with an additional set of . /// /// /// An object specifying additional parameters for how members will be formatted. /// /// - /// A duplicate of the SymbolDisplayFormat, with an additional set of . + /// A duplicate of the SymbolDisplayFormat, with an additional set of . /// public SymbolDisplayFormat AddMemberOptions(SymbolDisplayMemberOptions options) { @@ -563,13 +564,13 @@ public SymbolDisplayFormat AddMemberOptions(SymbolDisplayMemberOptions options) } /// - /// Creates a copy of the SymbolDisplayFormat but with a set of stripped away from the original object. + /// Creates a copy of the SymbolDisplayFormat but with a set of stripped away from the original object. /// /// /// An object specifying which parameters should not be applied to how members will be formatted. /// /// - /// A duplicate of the SymbolDisplayFormat, with a set of stripped away from the original object. + /// A duplicate of the SymbolDisplayFormat, with a set of stripped away from the original object. /// public SymbolDisplayFormat RemoveMemberOptions(SymbolDisplayMemberOptions options) { @@ -577,13 +578,13 @@ public SymbolDisplayFormat RemoveMemberOptions(SymbolDisplayMemberOptions option } /// - /// Creates a copy of the SymbolDisplayFormat but with replaced set of . + /// Creates a copy of the SymbolDisplayFormat but with replaced set of . /// /// /// An object specifying parameters with which symbols belonging to kind keywords should be formatted. /// /// - /// A duplicate of the SymbolDisplayFormat, with a replaced set of . + /// A duplicate of the SymbolDisplayFormat, with a replaced set of . /// public SymbolDisplayFormat WithKindOptions(SymbolDisplayKindOptions options) { @@ -603,13 +604,13 @@ public SymbolDisplayFormat WithKindOptions(SymbolDisplayKindOptions options) } /// - /// Creates a copy of the SymbolDisplayFormat but with an additional set of . + /// Creates a copy of the SymbolDisplayFormat but with an additional set of . /// /// /// An object specifying additional parameters with which symbols belonging to kind keywords should be formatted. /// /// - /// A duplicate of the SymbolDisplayFormat, with an additional set of . + /// A duplicate of the SymbolDisplayFormat, with an additional set of . /// public SymbolDisplayFormat AddKindOptions(SymbolDisplayKindOptions options) { @@ -617,13 +618,13 @@ public SymbolDisplayFormat AddKindOptions(SymbolDisplayKindOptions options) } /// - /// Creates a copy of the SymbolDisplayFormat but with a set of stripped away from the original object. + /// Creates a copy of the SymbolDisplayFormat but with a set of stripped away from the original object. /// /// /// The settings that determine other characteristics of how symbols are displayed. /// /// - /// A duplicate of the SymbolDisplayFormat, with a set of stripped away from the original object. + /// A duplicate of the SymbolDisplayFormat, with a set of stripped away from the original object. /// public SymbolDisplayFormat RemoveKindOptions(SymbolDisplayKindOptions options) { @@ -631,12 +632,12 @@ public SymbolDisplayFormat RemoveKindOptions(SymbolDisplayKindOptions options) } /// - /// Creates a copy of the SymbolDisplayFormat but with replaced set of . + /// Creates a copy of the SymbolDisplayFormat but with replaced set of . /// /// /// An object specifying how parameters should be formatted. /// - /// A duplicate of the SymbolDisplayFormat, with a replaced set of . + /// A duplicate of the SymbolDisplayFormat, with a replaced set of . public SymbolDisplayFormat WithParameterOptions(SymbolDisplayParameterOptions options) { return new SymbolDisplayFormat( @@ -655,13 +656,13 @@ public SymbolDisplayFormat WithParameterOptions(SymbolDisplayParameterOptions op } /// - /// Creates a copy of the SymbolDisplayFormat but with an additional set of . + /// Creates a copy of the SymbolDisplayFormat but with an additional set of . /// /// /// An object specifying additional parameters on how parameters should be formatted. /// /// - /// A duplicate of the SymbolDisplayFormat, with an additional set of . + /// A duplicate of the SymbolDisplayFormat, with an additional set of . /// public SymbolDisplayFormat AddParameterOptions(SymbolDisplayParameterOptions options) { @@ -669,13 +670,13 @@ public SymbolDisplayFormat AddParameterOptions(SymbolDisplayParameterOptions opt } /// - /// Creates a copy of the SymbolDisplayFormat but with a set of stripped away from the original object. + /// Creates a copy of the SymbolDisplayFormat but with a set of stripped away from the original object. /// /// /// An object specifying parameters that should not be applied when formatting parameters. /// /// - /// A duplicate of the SymbolDisplayFormat, with a set of stripped away from the original object. + /// A duplicate of the SymbolDisplayFormat, with a set of stripped away from the original object. /// public SymbolDisplayFormat RemoveParameterOptions(SymbolDisplayParameterOptions options) { @@ -683,12 +684,12 @@ public SymbolDisplayFormat RemoveParameterOptions(SymbolDisplayParameterOptions } /// - /// Creates a copy of the SymbolDisplayFormat but with replaced . + /// Creates a copy of the SymbolDisplayFormat but with replaced . /// /// /// An object specifying parameters on how namespace symbols should be formatted. /// - /// A duplicate of the SymbolDisplayFormat, with a replaced set of . + /// A duplicate of the SymbolDisplayFormat, with a replaced set of . public SymbolDisplayFormat WithGlobalNamespaceStyle(SymbolDisplayGlobalNamespaceStyle style) { return new SymbolDisplayFormat( @@ -707,12 +708,12 @@ public SymbolDisplayFormat WithGlobalNamespaceStyle(SymbolDisplayGlobalNamespace } /// - /// Creates a copy of the SymbolDisplayFormat but with replaced set of . + /// Creates a copy of the SymbolDisplayFormat but with replaced set of . /// /// /// An object specifying parameters on how symbols belonging to locals should be formatted. /// - /// A duplicate of the SymbolDisplayFormat, with a replaced set of . + /// A duplicate of the SymbolDisplayFormat, with a replaced set of . public SymbolDisplayFormat WithLocalOptions(SymbolDisplayLocalOptions options) { return new SymbolDisplayFormat( @@ -731,13 +732,13 @@ public SymbolDisplayFormat WithLocalOptions(SymbolDisplayLocalOptions options) } /// - /// Creates a copy of the SymbolDisplayFormat but with an additional set of . + /// Creates a copy of the SymbolDisplayFormat but with an additional set of . /// /// /// An object specifying additional parameters on how symbols belonging to locals should be formatted. /// /// - /// A duplicate of the SymbolDisplayFormat, with an additional set of . + /// A duplicate of the SymbolDisplayFormat, with an additional set of . /// public SymbolDisplayFormat AddLocalOptions(SymbolDisplayLocalOptions options) { @@ -745,13 +746,13 @@ public SymbolDisplayFormat AddLocalOptions(SymbolDisplayLocalOptions options) } /// - /// Creates a copy of the SymbolDisplayFormat but with a set of stripped away from the original object. + /// Creates a copy of the SymbolDisplayFormat but with a set of stripped away from the original object. /// /// /// An object specifying parameters that should not be applied when formatting symbols belonging to locals. /// /// - /// A duplicate of the SymbolDisplayFormat, with a set of stripped away from the original object. + /// A duplicate of the SymbolDisplayFormat, with a set of stripped away from the original object. /// public SymbolDisplayFormat RemoveLocalOptions(SymbolDisplayLocalOptions options) { @@ -759,13 +760,13 @@ public SymbolDisplayFormat RemoveLocalOptions(SymbolDisplayLocalOptions options) } /// - /// Creates a copy of the SymbolDisplayFormat but with added set of . + /// Creates a copy of the SymbolDisplayFormat but with added set of . /// internal SymbolDisplayFormat AddCompilerInternalOptions(SymbolDisplayCompilerInternalOptions options) => WithCompilerInternalOptions(this.CompilerInternalOptions | options); /// - /// Creates a copy of the SymbolDisplayFormat but with replaced set of . + /// Creates a copy of the SymbolDisplayFormat but with replaced set of . /// internal SymbolDisplayFormat WithCompilerInternalOptions(SymbolDisplayCompilerInternalOptions options) { diff --git a/src/Compilers/Core/Portable/SymbolDisplay/SymbolDisplayMemberOptions.cs b/src/Compilers/Core/Portable/SymbolDisplay/SymbolDisplayMemberOptions.cs index ec104fea83d06..563665466e7cc 100644 --- a/src/Compilers/Core/Portable/SymbolDisplay/SymbolDisplayMemberOptions.cs +++ b/src/Compilers/Core/Portable/SymbolDisplay/SymbolDisplayMemberOptions.cs @@ -23,44 +23,40 @@ public enum SymbolDisplayMemberOptions IncludeType = 1 << 0, /// - /// Includes the modifiers of the member. - /// For example, "static readonly" in C# or "Shared ReadOnly" in Visual Basic. - /// - /// + /// Includes the modifiers of the member. For example, "static readonly" in C# or "Shared ReadOnly" in Visual Basic. + /// /// Accessibility modifiers are controlled separately by . - /// + /// + /// IncludeModifiers = 1 << 1, /// - /// Includes the accessibility modifiers of the member. - /// For example, "public" in C# or "Public" in Visual Basic. + /// Includes the accessibility modifiers of the member. For example, "public" in C# or "Public" in Visual Basic. /// IncludeAccessibility = 1 << 2, /// - /// Includes the name of corresponding interface on members that explicitly implement - /// interface members. - /// For example, "IGoo.Bar { get; }". - /// - /// + /// Includes the name of corresponding interface on members that explicitly implement interface members. For example, "IGoo.Bar { get; }". + /// /// This option has no effect in Visual Basic. - /// + /// + /// IncludeExplicitInterface = 1 << 3, /// - /// Includes the parameters of methods and properties/indexers. - /// - /// + /// Includes the parameters of methods and properties/indexers. + /// /// See for finer-grained settings. - /// + /// + /// IncludeParameters = 1 << 4, /// - /// Includes the name of the type containing the member. - /// - /// + /// Includes the name of the type containing the member. + /// /// The format of the containing type is determined by . - /// + /// + /// IncludeContainingType = 1 << 5, /// diff --git a/src/Compilers/Core/Portable/SymbolDisplay/SymbolDisplayMiscellaneousOptions.cs b/src/Compilers/Core/Portable/SymbolDisplay/SymbolDisplayMiscellaneousOptions.cs index dc26669cfbe3c..f54c6e66f3786 100644 --- a/src/Compilers/Core/Portable/SymbolDisplay/SymbolDisplayMiscellaneousOptions.cs +++ b/src/Compilers/Core/Portable/SymbolDisplay/SymbolDisplayMiscellaneousOptions.cs @@ -45,11 +45,11 @@ public enum SymbolDisplayMiscellaneousOptions /// /// Displays attributes names without the "Attribute" suffix, if possible. - /// - /// + /// /// Has no effect outside and only applies /// if the context location is one where an attribute ca be referenced without the suffix. - /// + /// + /// RemoveAttributeSuffix = 1 << 4, /// diff --git a/src/Compilers/Core/Portable/SymbolDisplay/SymbolDisplayParameterOptions.cs b/src/Compilers/Core/Portable/SymbolDisplay/SymbolDisplayParameterOptions.cs index 8d6105a54e98c..b17abe5e66782 100644 --- a/src/Compilers/Core/Portable/SymbolDisplay/SymbolDisplayParameterOptions.cs +++ b/src/Compilers/Core/Portable/SymbolDisplay/SymbolDisplayParameterOptions.cs @@ -13,20 +13,20 @@ namespace Microsoft.CodeAnalysis public enum SymbolDisplayParameterOptions { /// - /// Omits parameters from symbol descriptions. - /// - /// + /// Omits parameters from symbol descriptions. + /// /// If this option is combined with , then only /// the parentheses will be shown (e.g. M()). - /// + /// + /// None = 0, /// /// Includes the this keyword before the first parameter of an extension method in C#. - /// - /// + /// /// This option has no effect in Visual Basic. - /// + /// + /// IncludeExtensionThis = 1 << 0, /// @@ -46,8 +46,9 @@ public enum SymbolDisplayParameterOptions /// /// Includes parameter default values in symbol descriptions. + /// Ignored if is not set. + /// /// - /// Ignored if is not set. IncludeDefaultValue = 1 << 4, /// diff --git a/src/Compilers/Core/Portable/SymbolDisplay/SymbolDisplayPartKind.cs b/src/Compilers/Core/Portable/SymbolDisplay/SymbolDisplayPartKind.cs index 017e2eac861ee..d82214664fce4 100644 --- a/src/Compilers/Core/Portable/SymbolDisplay/SymbolDisplayPartKind.cs +++ b/src/Compilers/Core/Portable/SymbolDisplay/SymbolDisplayPartKind.cs @@ -34,11 +34,15 @@ public enum SymbolDisplayPartKind LabelName = 10, /// A line-break (i.e. whitespace). LineBreak = 11, - /// A numeric literal. - /// Typically for the default values of parameters and the constant values of fields. + /// A numeric literal. + /// Typically for the default values of parameters and the constant values of fields. + /// + /// NumericLiteral = 12, - /// A string literal. - /// Typically for the default values of parameters and the constant values of fields. + /// A string literal. + /// Typically for the default values of parameters and the constant values of fields. + /// + /// StringLiteral = 13, /// The name of a local. LocalName = 14, @@ -62,8 +66,10 @@ public enum SymbolDisplayPartKind StructName = 23, /// A keyword-like part for anonymous types (not actually a keyword). AnonymousTypeIndicator = 24, - /// An unclassified part. - /// Never returned - only set in user-constructed parts. + /// An unclassified part. + /// Never returned - only set in user-constructed parts. + /// + /// Text = 25, /// The name of a type parameter. TypeParameterName = 26, @@ -71,10 +77,11 @@ public enum SymbolDisplayPartKind RangeVariableName = 27, /// The name of an enum member. EnumMemberName = 28, - /// The name of a reduced extension method. - /// + /// The name of a reduced extension method. + /// /// When an extension method is in it's non-reduced form it will be will be marked as MethodName. - /// + /// + /// ExtensionMethodName = 29, /// The name of a field or local constant. ConstantName = 30, diff --git a/src/Compilers/Core/Portable/SymbolDisplay/SymbolDisplayPropertyStyle.cs b/src/Compilers/Core/Portable/SymbolDisplay/SymbolDisplayPropertyStyle.cs index 009fa22bc5126..2cc5a3dbc49df 100644 --- a/src/Compilers/Core/Portable/SymbolDisplay/SymbolDisplayPropertyStyle.cs +++ b/src/Compilers/Core/Portable/SymbolDisplay/SymbolDisplayPropertyStyle.cs @@ -11,7 +11,7 @@ public enum SymbolDisplayPropertyStyle { /// /// Shows only the names of properties. - /// + /// /// NameOnly = 0, diff --git a/src/Compilers/Core/Portable/Symbols/Attributes/AttributeDescription.cs b/src/Compilers/Core/Portable/Symbols/Attributes/AttributeDescription.cs index abe6c5d039722..cfe61b5453111 100644 --- a/src/Compilers/Core/Portable/Symbols/Attributes/AttributeDescription.cs +++ b/src/Compilers/Core/Portable/Symbols/Attributes/AttributeDescription.cs @@ -334,7 +334,6 @@ static AttributeDescription() private static readonly byte[][] s_signaturesOfNullableAttribute = { s_signature_HasThis_Void_Byte, s_signature_HasThis_Void_SzArray_Byte }; private static readonly byte[][] s_signaturesOfNullableContextAttribute = { s_signature_HasThis_Void_Byte }; private static readonly byte[][] s_signaturesOfNativeIntegerAttribute = { s_signature_HasThis_Void, s_signature_HasThis_Void_SzArray_Boolean }; - private static readonly byte[][] s_signaturesOfLifetimeAnnotationAttribute = { s_signature_HasThis_Void_Boolean_Boolean }; private static readonly byte[][] s_signaturesOfInterpolatedStringArgumentAttribute = { s_signature_HasThis_Void_String, s_signature_HasThis_Void_SzArray_String }; // early decoded attributes: @@ -470,7 +469,7 @@ static AttributeDescription() internal static readonly AttributeDescription EnumeratorCancellationAttribute = new AttributeDescription("System.Runtime.CompilerServices", "EnumeratorCancellationAttribute", s_signatures_HasThis_Void_Only); internal static readonly AttributeDescription SkipLocalsInitAttribute = new AttributeDescription("System.Runtime.CompilerServices", "SkipLocalsInitAttribute", s_signatures_HasThis_Void_Only); internal static readonly AttributeDescription NativeIntegerAttribute = new AttributeDescription("System.Runtime.CompilerServices", "NativeIntegerAttribute", s_signaturesOfNativeIntegerAttribute); - internal static readonly AttributeDescription LifetimeAnnotationAttribute = new AttributeDescription("System.Runtime.CompilerServices", "LifetimeAnnotationAttribute", s_signaturesOfLifetimeAnnotationAttribute); + internal static readonly AttributeDescription ScopedRefAttribute = new AttributeDescription("System.Runtime.CompilerServices", "ScopedRefAttribute", s_signatures_HasThis_Void_Only); internal static readonly AttributeDescription ModuleInitializerAttribute = new AttributeDescription("System.Runtime.CompilerServices", "ModuleInitializerAttribute", s_signatures_HasThis_Void_Only); internal static readonly AttributeDescription UnmanagedCallersOnlyAttribute = new AttributeDescription("System.Runtime.InteropServices", "UnmanagedCallersOnlyAttribute", s_signatures_HasThis_Void_Only); internal static readonly AttributeDescription InterpolatedStringHandlerAttribute = new AttributeDescription("System.Runtime.CompilerServices", "InterpolatedStringHandlerAttribute", s_signatures_HasThis_Void_Only); @@ -478,5 +477,6 @@ static AttributeDescription() internal static readonly AttributeDescription RequiredMemberAttribute = new AttributeDescription("System.Runtime.CompilerServices", "RequiredMemberAttribute", s_signatures_HasThis_Void_Only); internal static readonly AttributeDescription SetsRequiredMembersAttribute = new AttributeDescription("System.Diagnostics.CodeAnalysis", "SetsRequiredMembersAttribute", s_signatures_HasThis_Void_Only); internal static readonly AttributeDescription CompilerFeatureRequiredAttribute = new AttributeDescription("System.Runtime.CompilerServices", "CompilerFeatureRequiredAttribute", s_signatures_HasThis_Void_String_Only); + internal static readonly AttributeDescription UnscopedRefAttribute = new AttributeDescription("System.Diagnostics.CodeAnalysis", "UnscopedRefAttribute", s_signatures_HasThis_Void_Only); } } diff --git a/src/Compilers/Core/Portable/Symbols/INamedTypeSymbol.cs b/src/Compilers/Core/Portable/Symbols/INamedTypeSymbol.cs index 3ba82acb88738..2a6a9ceb1ff8c 100644 --- a/src/Compilers/Core/Portable/Symbols/INamedTypeSymbol.cs +++ b/src/Compilers/Core/Portable/Symbols/INamedTypeSymbol.cs @@ -56,6 +56,11 @@ public interface INamedTypeSymbol : ITypeSymbol /// bool IsComImport { get; } + /// + /// Indicates the type is declared in source and is only visible in the file it is declared in. + /// + bool IsFileLocal { get; } + /// /// Returns collection of names of members declared within this type. /// diff --git a/src/Compilers/Core/Portable/Symbols/NullableAnnotation.cs b/src/Compilers/Core/Portable/Symbols/NullableAnnotation.cs index f1543b847d14e..2862aad76ec8e 100644 --- a/src/Compilers/Core/Portable/Symbols/NullableAnnotation.cs +++ b/src/Compilers/Core/Portable/Symbols/NullableAnnotation.cs @@ -14,18 +14,13 @@ public enum NullableAnnotation : byte /// /// The expression has not been analyzed, or the syntax is /// not an expression (such as a statement). + /// There are a few different reasons the expression could have not been analyzed: + /// + /// + /// The symbol producing the expression comes from a method that has not been annotated, such as invoking a C# 7.3 or earlier method, or a method in this compilation that is in a disabled context. + /// Nullable is completely disabled in this compilation. + /// /// - /// - /// There are a few different reasons the expression could - /// have not been analyzed: - /// 1) The symbol producing the expression comes from - /// a method that has not been annotated, such as - /// invoking a C# 7.3 or earlier method, or a - /// method in this compilation that is in a disabled - /// context. - /// 2) Nullable is completely disabled in this - /// compilation. - /// None = 0, /// /// The expression is not annotated (does not have a ?). diff --git a/src/Compilers/Core/Portable/Syntax/SyntaxTree.cs b/src/Compilers/Core/Portable/Syntax/SyntaxTree.cs index e442158832c52..3f88a773c542e 100644 --- a/src/Compilers/Core/Portable/Syntax/SyntaxTree.cs +++ b/src/Compilers/Core/Portable/Syntax/SyntaxTree.cs @@ -102,6 +102,13 @@ public ParseOptions Options /// public abstract Encoding? Encoding { get; } + /// + /// Useful information about this tree that is stored for source-generator scenarios. Allows the incremental + /// generation framework to compute and cache data once against a tree so it does not have to go back to source + /// for untouched trees when other trees in the compilation are modified. + /// + private SourceGeneratorSyntaxTreeInfo _sourceGeneratorInfo = SourceGeneratorSyntaxTreeInfo.NotComputedYet; + /// /// Gets the text of the source document asynchronously. /// @@ -399,5 +406,26 @@ internal virtual bool SupportsLocations { get { return this.HasCompilationUnitRoot; } } + + internal SourceGeneratorSyntaxTreeInfo GetSourceGeneratorInfo( + ISyntaxHelper syntaxHelper, CancellationToken cancellationToken) + { + if (_sourceGeneratorInfo is SourceGeneratorSyntaxTreeInfo.NotComputedYet) + { + var root = this.GetRoot(cancellationToken); + + var result = SourceGeneratorSyntaxTreeInfo.None; + + if (syntaxHelper.ContainsGlobalAliases(root)) + result |= SourceGeneratorSyntaxTreeInfo.ContainsGlobalAliases; + + if (syntaxHelper.ContainsAttributeList(root)) + result |= SourceGeneratorSyntaxTreeInfo.ContainsAttributeList; + + _sourceGeneratorInfo = result; + } + + return _sourceGeneratorInfo; + } } } diff --git a/src/Compilers/Core/Portable/Text/SourceText.cs b/src/Compilers/Core/Portable/Text/SourceText.cs index f735355ac1ab9..a98f26ff26141 100644 --- a/src/Compilers/Core/Portable/Text/SourceText.cs +++ b/src/Compilers/Core/Portable/Text/SourceText.cs @@ -732,13 +732,13 @@ orderby c.Span /// /// Constructs a new SourceText from this text with the specified changes. - /// If any changes are not in bounds of this . - /// If any changes overlap other changes. - /// + /// /// /// Changes do not have to be in sorted order. However, will /// perform better if they are. /// + /// If any changes are not in bounds of this . + /// If any changes overlap other changes. public SourceText WithChanges(params TextChange[] changes) { return this.WithChanges((IEnumerable)changes); diff --git a/src/Compilers/Core/Portable/WellKnownMember.cs b/src/Compilers/Core/Portable/WellKnownMember.cs index e32700fdbd918..6c918ede9dda6 100644 --- a/src/Compilers/Core/Portable/WellKnownMember.cs +++ b/src/Compilers/Core/Portable/WellKnownMember.cs @@ -522,15 +522,17 @@ internal enum WellKnownMember System_Runtime_CompilerServices_DefaultInterpolatedStringHandler__ToStringAndClear, System_Runtime_CompilerServices_RequiredMemberAttribute__ctor, System_Diagnostics_CodeAnalysis_SetsRequiredMembersAttribute__ctor, - System_Runtime_CompilerServices_LifetimeAnnotationAttribute__ctor, + System_Runtime_CompilerServices_ScopedRefAttribute__ctor, System_MemoryExtensions__SequenceEqual_Span_T, System_MemoryExtensions__SequenceEqual_ReadOnlySpan_T, System_MemoryExtensions__AsSpan_String, System_Runtime_CompilerServices_CompilerFeatureRequiredAttribute__ctor, + System_Diagnostics_CodeAnalysis_UnscopedRefAttribute__ctor, System_MissingMethodException__ctor, + System_Runtime_CompilerServices_MetadataUpdateOriginalTypeAttribute__ctor, Count diff --git a/src/Compilers/Core/Portable/WellKnownMembers.cs b/src/Compilers/Core/Portable/WellKnownMembers.cs index 66117afc0bbae..96b50b609133b 100644 --- a/src/Compilers/Core/Portable/WellKnownMembers.cs +++ b/src/Compilers/Core/Portable/WellKnownMembers.cs @@ -3583,14 +3583,12 @@ static WellKnownMembers() 0, // Method Signature (byte)SignatureTypeCode.TypeHandle, (byte)SpecialType.System_Void, // Return Type - // System_Runtime_CompilerServices_LifetimeAnnotationAttribute__ctor + // System_Runtime_CompilerServices_ScopedRefAttribute__ctor (byte)MemberFlags.Constructor, // Flags - (byte)WellKnownType.ExtSentinel, (byte)(WellKnownType.System_Runtime_CompilerServices_LifetimeAnnotationAttribute - WellKnownType.ExtSentinel), // DeclaringTypeId + (byte)WellKnownType.ExtSentinel, (byte)(WellKnownType.System_Runtime_CompilerServices_ScopedRefAttribute - WellKnownType.ExtSentinel), // DeclaringTypeId 0, // Arity - 2, // Method Signature + 0, // Method Signature (byte)SignatureTypeCode.TypeHandle, (byte)SpecialType.System_Void, // Return Type - (byte)SignatureTypeCode.TypeHandle, (byte)SpecialType.System_Boolean, - (byte)SignatureTypeCode.TypeHandle, (byte)SpecialType.System_Boolean, // System_MemoryExtensions__SequenceEqual_Span_T (byte)(MemberFlags.Method | MemberFlags.Static), // Flags @@ -3640,6 +3638,13 @@ static WellKnownMembers() 1, // Method Signature (byte)SignatureTypeCode.TypeHandle, (byte)SpecialType.System_Void, // Return Type (byte)SignatureTypeCode.TypeHandle, (byte)SpecialType.System_String, + + // System_Diagnostics_CodeAnalysis_UnscopedRefAttribute__ctor + (byte)MemberFlags.Constructor, // Flags + (byte)WellKnownType.ExtSentinel, (byte)(WellKnownType.System_Diagnostics_CodeAnalysis_UnscopedRefAttribute - WellKnownType.ExtSentinel), // DeclaringTypeId + 0, // Arity + 0, // Method Signature + (byte)SignatureTypeCode.TypeHandle, (byte)SpecialType.System_Void, // Return Type // System_MissingMethodException__ctor (byte)MemberFlags.Constructor, // Flags @@ -3648,6 +3653,13 @@ static WellKnownMembers() 0, // Method Signature (byte)SignatureTypeCode.TypeHandle, (byte)SpecialType.System_Void, + // MetadataUpdateOriginalTypeAttribute__ctor + (byte)MemberFlags.Constructor, // Flags + (byte)WellKnownType.ExtSentinel, (byte)(WellKnownType.System_Runtime_CompilerServices_MetadataUpdateOriginalTypeAttribute - WellKnownType.ExtSentinel), // DeclaringTypeId + 0, // Arity + 1, // Method Signature + (byte)SignatureTypeCode.TypeHandle, (byte)SpecialType.System_Void, // Return Type + (byte)SignatureTypeCode.TypeHandle, (byte)WellKnownType.System_Type, }; string[] allNames = new string[(int)WellKnownMember.Count] @@ -4098,12 +4110,14 @@ static WellKnownMembers() "ToStringAndClear", // System_Runtime_CompilerServices_DefaultInterpolatedStringHandler__ToStringAndClear ".ctor", // System_Runtime_CompilerServices_RequiredMemberAttribute__ctor ".ctor", // System_Diagnostics_CodeAnalysis_SetsRequiredMembersAttribute__ctor - ".ctor", // System_Runtime_CompilerServices_LifetimeAttribute__ctor + ".ctor", // System_Runtime_CompilerServices_LifetimeAttribute__ctor "SequenceEqual", // System_MemoryExtensions__SequenceEqual_Span_T "SequenceEqual", // System_MemoryExtensions__SequenceEqual_ReadOnlySpan_T "AsSpan", // System_MemoryExtensions__AsSpan_String ".ctor", // System_Runtime_CompilerServices_CompilerFeatureRequiredAttribute_ctor + ".ctor", // System_Diagnostics_CodeAnalysis_UnscopedRefAttribute__ctor ".ctor", // System_MissingMethodException__ctor + ".ctor", // System_Runtime_CompilerServices_MetadataUpdateOriginalTypeAttribute }; s_descriptors = MemberDescriptor.InitializeFromStream(new System.IO.MemoryStream(initializationBytes, writable: false), allNames); diff --git a/src/Compilers/Core/Portable/WellKnownTypes.cs b/src/Compilers/Core/Portable/WellKnownTypes.cs index 41bf3dc7e746d..199b7d442e6cf 100644 --- a/src/Compilers/Core/Portable/WellKnownTypes.cs +++ b/src/Compilers/Core/Portable/WellKnownTypes.cs @@ -314,7 +314,7 @@ internal enum WellKnownType System_Text_StringBuilder, System_Runtime_CompilerServices_DefaultInterpolatedStringHandler, - System_Runtime_CompilerServices_LifetimeAnnotationAttribute, + System_Runtime_CompilerServices_ScopedRefAttribute, System_ArgumentNullException, @@ -323,8 +323,10 @@ internal enum WellKnownType System_MemoryExtensions, System_Runtime_CompilerServices_CompilerFeatureRequiredAttribute, + System_Diagnostics_CodeAnalysis_UnscopedRefAttribute, System_MissingMethodException, + System_Runtime_CompilerServices_MetadataUpdateOriginalTypeAttribute, NextAvailable, // Remember to update the AllWellKnownTypes tests when making changes here @@ -633,14 +635,16 @@ internal static class WellKnownTypes "System.Text.StringBuilder", "System.Runtime.CompilerServices.DefaultInterpolatedStringHandler", - "System.Runtime.CompilerServices.LifetimeAnnotationAttribute", + "System.Runtime.CompilerServices.ScopedRefAttribute", "System.ArgumentNullException", "System.Runtime.CompilerServices.RequiredMemberAttribute", "System.Diagnostics.CodeAnalysis.SetsRequiredMembersAttribute", "System.MemoryExtensions", "System.Runtime.CompilerServices.CompilerFeatureRequiredAttribute", + "System.Diagnostics.CodeAnalysis.UnscopedRefAttribute", "System.MissingMethodException", + "System.Runtime.CompilerServices.MetadataUpdateOriginalTypeAttribute", }; private static readonly Dictionary s_nameToTypeIdMap = new Dictionary((int)Count); diff --git a/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.cs.xlf b/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.cs.xlf index d5ddd74aeaa77..1595df5f6198c 100644 --- a/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.cs.xlf +++ b/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.cs.xlf @@ -49,6 +49,16 @@ Funkce Upravit a pokračovat nemůže obnovit pozastavený iterátor, protože odpovídající příkaz yield return byl odstraněn. + + Generator + Generator + + + + Total generator execution time: {0} seconds. + Total generator execution time: {0} seconds. + + The hintName '{0}' contains an invalid character '{1}' at position {2}. {0} hintName obsahuje neplatný znak {1} na pozici {2}. diff --git a/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.de.xlf b/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.de.xlf index 0d1b952dba1ae..02a6c35b72c4f 100644 --- a/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.de.xlf +++ b/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.de.xlf @@ -49,6 +49,16 @@ "Bearbeiten und Fortfahren" kann den angehaltenen Iterator nicht fortsetzen, da die entsprechende yield return-Anweisung gelöscht wurde + + Generator + Generator + + + + Total generator execution time: {0} seconds. + Total generator execution time: {0} seconds. + + The hintName '{0}' contains an invalid character '{1}' at position {2}. Der hintName "{0}" enthält ein ungültiges Zeichen "{1}" an Position {2}. diff --git a/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.es.xlf b/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.es.xlf index 3313141ef1385..1fa2ec04a7df6 100644 --- a/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.es.xlf +++ b/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.es.xlf @@ -49,6 +49,16 @@ Editar y continuar no puede reanudar el iterador suspendido porque se ha eliminado la instrucción yield return correspondiente + + Generator + Generator + + + + Total generator execution time: {0} seconds. + Total generator execution time: {0} seconds. + + The hintName '{0}' contains an invalid character '{1}' at position {2}. El elemento hintName "{0}" contiene un carácter no válido "{1}" en la posición {2}. diff --git a/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.fr.xlf b/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.fr.xlf index dc71f8b68b575..6e0eb2c31e51d 100644 --- a/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.fr.xlf +++ b/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.fr.xlf @@ -49,6 +49,16 @@ Modifier et continuer ne peut pas reprendre l’itérateur suspendu, car l’instruction yield return correspondante a été supprimée + + Generator + Generator + + + + Total generator execution time: {0} seconds. + Total generator execution time: {0} seconds. + + The hintName '{0}' contains an invalid character '{1}' at position {2}. Le hintName « {0} » contient un caractère non valide « {1} » à la position {2}. diff --git a/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.it.xlf b/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.it.xlf index a066d93fa3b0a..0fa79eca3cf7e 100644 --- a/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.it.xlf +++ b/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.it.xlf @@ -49,6 +49,16 @@ Modifica e Continua non sono in grado di riprendere l'enumeratore sospeso perché l'istruzione yield return corrispondente è stata eliminata + + Generator + Generator + + + + Total generator execution time: {0} seconds. + Total generator execution time: {0} seconds. + + The hintName '{0}' contains an invalid character '{1}' at position {2}. L'elemento hintName '{0}' contiene un carattere non valido '{1}' alla posizione {2}. diff --git a/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.ja.xlf b/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.ja.xlf index f85497a3fce75..f8c1d8e7002bf 100644 --- a/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.ja.xlf +++ b/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.ja.xlf @@ -49,6 +49,16 @@ 対応する yield return ステートメントが削除されているため、エディット コンティニュは中断された反復子を再開できません + + Generator + Generator + + + + Total generator execution time: {0} seconds. + Total generator execution time: {0} seconds. + + The hintName '{0}' contains an invalid character '{1}' at position {2}. hintName {0} の位置 {2} に無効な文字 '{1}' が含まれています。 diff --git a/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.ko.xlf b/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.ko.xlf index 60e4aa566cdf7..b35ac8df5b641 100644 --- a/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.ko.xlf +++ b/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.ko.xlf @@ -49,6 +49,16 @@ 해당 yield return 문이 삭제되었으므로 편집하고 계속하기가 일시 중단된 반복기를 다시 시작할 수 없습니다. + + Generator + Generator + + + + Total generator execution time: {0} seconds. + Total generator execution time: {0} seconds. + + The hintName '{0}' contains an invalid character '{1}' at position {2}. hintName의 {0} 위치 {2}에 잘못된 문자 '{1}'이(가) 있습니다. diff --git a/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.pl.xlf b/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.pl.xlf index 58617372883b4..d47b9d2f2daf3 100644 --- a/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.pl.xlf +++ b/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.pl.xlf @@ -49,6 +49,16 @@ Funkcja Edytuj i kontynuuj nie może wznowić wstrzymanego iteratora, ponieważ odpowiadająca jej instrukcja yield return została usunięta + + Generator + Generator + + + + Total generator execution time: {0} seconds. + Total generator execution time: {0} seconds. + + The hintName '{0}' contains an invalid character '{1}' at position {2}. Element hintName „{0}” zawiera nieprawidłowy znak „{1}” na pozycji {2}. diff --git a/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.pt-BR.xlf b/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.pt-BR.xlf index 47e06314e8d34..793b0ee7284ca 100644 --- a/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.pt-BR.xlf +++ b/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.pt-BR.xlf @@ -49,6 +49,16 @@ Editar e Continuar não pode retomar o iterador suspenso já que a instrução yield return correspondente foi excluída + + Generator + Generator + + + + Total generator execution time: {0} seconds. + Total generator execution time: {0} seconds. + + The hintName '{0}' contains an invalid character '{1}' at position {2}. O hintName '{0}' contém um caractere inválido '{1}' na posição {2}. diff --git a/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.ru.xlf b/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.ru.xlf index 7ab722c73869b..b7b60816a0fa3 100644 --- a/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.ru.xlf +++ b/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.ru.xlf @@ -49,6 +49,16 @@ Операция "Изменить и продолжить" не может возобновить приостановленный итератор, поскольку соответствующий оператор yield return удален + + Generator + Generator + + + + Total generator execution time: {0} seconds. + Total generator execution time: {0} seconds. + + The hintName '{0}' contains an invalid character '{1}' at position {2}. hintName "{0}" содержит недопустимый символ "{1}" в позиции {2}. diff --git a/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.tr.xlf b/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.tr.xlf index dc07e7b89bc62..f0f038f115f12 100644 --- a/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.tr.xlf +++ b/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.tr.xlf @@ -49,6 +49,16 @@ İlgili yield return deyimi silindiğinden Düzenle ve Devam Et, askıya alınmış yineleyiciyi sürdüremiyor + + Generator + Generator + + + + Total generator execution time: {0} seconds. + Total generator execution time: {0} seconds. + + The hintName '{0}' contains an invalid character '{1}' at position {2}. hintName '{0}', {2} konumunda geçersiz bir '{1}' karakteri içeriyor. diff --git a/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.zh-Hans.xlf b/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.zh-Hans.xlf index 33d656da37269..d0930b72a274e 100644 --- a/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.zh-Hans.xlf +++ b/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.zh-Hans.xlf @@ -49,6 +49,16 @@ 编辑并继续无法恢复挂起的迭代器,因为相应的 yield return 语句已被删除 + + Generator + Generator + + + + Total generator execution time: {0} seconds. + Total generator execution time: {0} seconds. + + The hintName '{0}' contains an invalid character '{1}' at position {2}. hintName“{0}”在位置 {2} 处包含无效字符“{1}”。 diff --git a/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.zh-Hant.xlf b/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.zh-Hant.xlf index 7ae5c4ae799dc..a3b308e31afaa 100644 --- a/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.zh-Hant.xlf +++ b/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.zh-Hant.xlf @@ -49,6 +49,16 @@ 編輯和繼續無法繼續暫停的列舉程式,因為對應的 yield return 陳述式已刪除 + + Generator + Generator + + + + Total generator execution time: {0} seconds. + Total generator execution time: {0} seconds. + + The hintName '{0}' contains an invalid character '{1}' at position {2}. 位置 {2} 的 hintName {0} 包含無效的字元 '{1}'。 diff --git a/src/Compilers/Core/RebuildTest/BasicDeterministicKeyBuilderTests.cs b/src/Compilers/Core/RebuildTest/BasicDeterministicKeyBuilderTests.cs index 887a382cc2d3d..77b719b1c0abe 100644 --- a/src/Compilers/Core/RebuildTest/BasicDeterministicKeyBuilderTests.cs +++ b/src/Compilers/Core/RebuildTest/BasicDeterministicKeyBuilderTests.cs @@ -57,7 +57,7 @@ public void VerifyUpToDate() { verifyCount(11); verifyCount(10); - verifyCount(62); + verifyCount(63); verifyCount(22); static void verifyCount(int expected) diff --git a/src/Compilers/Core/RebuildTest/CSharpDeterministicKeyBuilderTests.cs b/src/Compilers/Core/RebuildTest/CSharpDeterministicKeyBuilderTests.cs index 59a433c74987d..248377e55db51 100644 --- a/src/Compilers/Core/RebuildTest/CSharpDeterministicKeyBuilderTests.cs +++ b/src/Compilers/Core/RebuildTest/CSharpDeterministicKeyBuilderTests.cs @@ -62,7 +62,7 @@ public void VerifyUpToDate() { verifyCount(11); verifyCount(10); - verifyCount(62); + verifyCount(63); verifyCount(9); static void verifyCount(int expected) @@ -552,7 +552,7 @@ public void FeatureFlag() ""features"": {{ ""debug-determinism"": ""true"" }}, - ""languageVersion"": ""CSharp10"", + ""languageVersion"": ""CSharp11"", ""specifiedLanguageVersion"": ""Default"", ""preprocessorSymbols"": [] }} diff --git a/src/Compilers/Server/VBCSCompiler/VBCSCompilerCommandLine.shproj b/src/Compilers/Server/VBCSCompiler/VBCSCompilerCommandLine.shproj index dfd128d203cfa..0ba8351d4499b 100644 --- a/src/Compilers/Server/VBCSCompiler/VBCSCompilerCommandLine.shproj +++ b/src/Compilers/Server/VBCSCompiler/VBCSCompilerCommandLine.shproj @@ -11,6 +11,7 @@ Condition="Exists('$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\CodeSharing\Microsoft.CodeSharing.Common.Default.props')" /> + \ No newline at end of file diff --git a/src/Compilers/Server/VBCSCompilerTests/CompilerServerTests.cs b/src/Compilers/Server/VBCSCompilerTests/CompilerServerTests.cs index 7d3727a204824..084293f127f64 100644 --- a/src/Compilers/Server/VBCSCompilerTests/CompilerServerTests.cs +++ b/src/Compilers/Server/VBCSCompilerTests/CompilerServerTests.cs @@ -235,7 +235,7 @@ private static (T Result, string Output) UseTextWriter(Encoding encoding, Fun currentDirectory: tempDir); if (result.ExitCode != 0) { - AssertEx.Fail($"Deterministic compile failed \n stdout: { result.Output }"); + AssertEx.Fail($"Deterministic compile failed \n stdout: {result.Output}"); } var listener = await serverData.Complete(); Assert.Equal(CompletionData.RequestCompleted, listener.CompletionDataList.Single()); @@ -1503,7 +1503,7 @@ private async Task RunDeterministicTest(string source) { if (first[i] != second[i]) { - AssertEx.Fail($"Bytes were different at position { i } ({ first[i] } vs { second[i] }). Flags used were (\"{ finalFlags1 }\" vs \"{ finalFlags2 }\")"); + AssertEx.Fail($"Bytes were different at position {i} ({first[i]} vs {second[i]}). Flags used were (\"{finalFlags1}\" vs \"{finalFlags2}\")"); } } } diff --git a/src/Compilers/Server/VBCSCompilerTests/VBCSCompiler.UnitTests.csproj b/src/Compilers/Server/VBCSCompilerTests/VBCSCompiler.UnitTests.csproj index fd0181fddd306..8ee6e9160de67 100644 --- a/src/Compilers/Server/VBCSCompilerTests/VBCSCompiler.UnitTests.csproj +++ b/src/Compilers/Server/VBCSCompilerTests/VBCSCompiler.UnitTests.csproj @@ -7,7 +7,7 @@ true net6.0;net472 - @@ -33,6 +33,7 @@ + diff --git a/src/Compilers/Test/Core/Assert/AssertEx.cs b/src/Compilers/Test/Core/Assert/AssertEx.cs index 7cdcdded82c88..66a4af48e0267 100644 --- a/src/Compilers/Test/Core/Assert/AssertEx.cs +++ b/src/Compilers/Test/Core/Assert/AssertEx.cs @@ -555,7 +555,7 @@ public static void AssertEqualToleratingWhitespaceDifferences( string expected, string actual, string message = null, - bool escapeQuotes = true, + bool escapeQuotes = false, [CallerFilePath] string expectedValueSourcePath = null, [CallerLineNumber] int expectedValueSourceLine = 0) { diff --git a/src/Compilers/Test/Core/Compilation/CompilationDifference.cs b/src/Compilers/Test/Core/Compilation/CompilationDifference.cs index 1c2ba92547a86..f47c3972f4c15 100644 --- a/src/Compilers/Test/Core/Compilation/CompilationDifference.cs +++ b/src/Compilers/Test/Core/Compilation/CompilationDifference.cs @@ -62,7 +62,7 @@ public void VerifyIL( [CallerFilePath] string callerPath = null) { string actualIL = ILDelta.GetMethodIL(); - AssertEx.AssertEqualToleratingWhitespaceDifferences(expectedIL, actualIL, escapeQuotes: true, expectedValueSourcePath: callerPath, expectedValueSourceLine: callerLine); + AssertEx.AssertEqualToleratingWhitespaceDifferences(expectedIL, actualIL, escapeQuotes: false, expectedValueSourcePath: callerPath, expectedValueSourceLine: callerLine); } public void VerifyLocalSignature( @@ -96,7 +96,7 @@ internal void VerifyIL( } string actualIL = ILBuilderVisualizer.ILBuilderToString(ilBuilder, mapLocal ?? ToLocalInfo, sequencePointMarkers); - AssertEx.AssertEqualToleratingWhitespaceDifferences(expectedIL, actualIL, escapeQuotes: true, expectedValueSourcePath: callerPath, expectedValueSourceLine: callerLine); + AssertEx.AssertEqualToleratingWhitespaceDifferences(expectedIL, actualIL, escapeQuotes: false, expectedValueSourcePath: callerPath, expectedValueSourceLine: callerLine); } internal string GetMethodIL(string qualifiedMethodName) diff --git a/src/Compilers/Test/Core/Compilation/CompilationTestDataExtensions.cs b/src/Compilers/Test/Core/Compilation/CompilationTestDataExtensions.cs index 0a7d4b5916ba8..f814fe58625cc 100644 --- a/src/Compilers/Test/Core/Compilation/CompilationTestDataExtensions.cs +++ b/src/Compilers/Test/Core/Compilation/CompilationTestDataExtensions.cs @@ -37,7 +37,7 @@ internal static void VerifyIL( expectedIL = expectedIL.Replace(moduleNamePlaceholder, moduleName); } - AssertEx.AssertEqualToleratingWhitespaceDifferences(expectedIL, actualIL, escapeQuotes: true, expectedValueSourcePath: expectedValueSourcePath, expectedValueSourceLine: expectedValueSourceLine); + AssertEx.AssertEqualToleratingWhitespaceDifferences(expectedIL, actualIL, escapeQuotes: false, expectedValueSourcePath: expectedValueSourcePath, expectedValueSourceLine: expectedValueSourceLine); } internal static ImmutableArray> GetExplicitlyDeclaredMethods(this CompilationTestData data) diff --git a/src/Compilers/Test/Core/Compilation/RuntimeUtilities.cs b/src/Compilers/Test/Core/Compilation/RuntimeUtilities.cs index eb0da6d988aec..1af25509283b0 100644 --- a/src/Compilers/Test/Core/Compilation/RuntimeUtilities.cs +++ b/src/Compilers/Test/Core/Compilation/RuntimeUtilities.cs @@ -27,6 +27,9 @@ public static partial class RuntimeUtilities #endif internal static bool IsCoreClrRuntime => !IsDesktopRuntime; + internal static bool IsCoreClr6Runtime + => IsCoreClrRuntime && RuntimeInformation.FrameworkDescription.StartsWith(".NET 6.", StringComparison.Ordinal); + internal static BuildPaths CreateBuildPaths(string workingDirectory, string sdkDirectory = null, string tempDirectory = null) { tempDirectory ??= Path.GetTempPath(); diff --git a/src/Compilers/Test/Core/CompilationVerifier.cs b/src/Compilers/Test/Core/CompilationVerifier.cs index d22002f2ab12d..82a5f9c2209b5 100644 --- a/src/Compilers/Test/Core/CompilationVerifier.cs +++ b/src/Compilers/Test/Core/CompilationVerifier.cs @@ -435,7 +435,7 @@ public CompilationVerifier VerifyIL( [CallerLineNumber] int callerLine = 0, string source = null) { - return VerifyILImpl(qualifiedMethodName, expectedIL, realIL, sequencePoints, callerPath, callerLine, escapeQuotes: true, source: source); + return VerifyILImpl(qualifiedMethodName, expectedIL, realIL, sequencePoints, callerPath, callerLine, escapeQuotes: false, source: source); } public void VerifyILMultiple(params string[] qualifiedMethodNamesAndExpectedIL) diff --git a/src/Compilers/Test/Core/Diagnostics/CommonDiagnosticAnalyzers.cs b/src/Compilers/Test/Core/Diagnostics/CommonDiagnosticAnalyzers.cs index 90cb65fdba517..37f00075a7655 100644 --- a/src/Compilers/Test/Core/Diagnostics/CommonDiagnosticAnalyzers.cs +++ b/src/Compilers/Test/Core/Diagnostics/CommonDiagnosticAnalyzers.cs @@ -2368,5 +2368,42 @@ public override void Initialize(AnalysisContext context) }); } } + + [DiagnosticAnalyzer(LanguageNames.CSharp)] + public sealed class VariableDeclarationAnalyzer : DiagnosticAnalyzer + { + private readonly bool _testSyntaxNodeAction; + public VariableDeclarationAnalyzer(string diagnosticId, bool testSyntaxNodeAction) + { + _testSyntaxNodeAction = testSyntaxNodeAction; + Descriptor = new DiagnosticDescriptor( + diagnosticId, + "Title", + "Message", + "Category", + defaultSeverity: DiagnosticSeverity.Warning, + isEnabledByDefault: true); + } + + public DiagnosticDescriptor Descriptor { get; } + + public override ImmutableArray SupportedDiagnostics => ImmutableArray.Create(Descriptor); + + public override void Initialize(AnalysisContext context) + { + if (_testSyntaxNodeAction) + { + context.RegisterSyntaxNodeAction( + context => context.ReportDiagnostic(Diagnostic.Create(Descriptor, context.Node.GetLocation())), + SyntaxKind.VariableDeclaration); + } + else + { + context.RegisterOperationAction( + context => context.ReportDiagnostic(Diagnostic.Create(Descriptor, context.Operation.Syntax.GetLocation())), + OperationKind.VariableDeclaration); + } + } + } } } diff --git a/src/Compilers/Test/Core/Microsoft.CodeAnalysis.Test.Utilities.csproj b/src/Compilers/Test/Core/Microsoft.CodeAnalysis.Test.Utilities.csproj index e8a0ae1276475..388527ae94ecb 100644 --- a/src/Compilers/Test/Core/Microsoft.CodeAnalysis.Test.Utilities.csproj +++ b/src/Compilers/Test/Core/Microsoft.CodeAnalysis.Test.Utilities.csproj @@ -17,6 +17,7 @@ + diff --git a/src/Compilers/Test/Core/RunInSinglePartitionAssemblyAttribute.cs b/src/Compilers/Test/Core/RunInSinglePartitionAssemblyAttribute.cs new file mode 100644 index 0000000000000..684d2674d5648 --- /dev/null +++ b/src/Compilers/Test/Core/RunInSinglePartitionAssemblyAttribute.cs @@ -0,0 +1,19 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; + +namespace Microsoft.CodeAnalysis.Test.Utilities; + +/// +/// This is a marker attribute used to define that all tests in this assembly +/// should run in a single partition without other assemblies due to state sharing concerns. +/// For example, Microsoft.CodeAnalysis.CSharp.EndToEnd.UnitTests +/// +/// RunTests uses this attribute when partitioning tests. +/// +[AttributeUsage(AttributeTargets.Assembly)] +public sealed class RunTestsInSinglePartitionAttribute : Attribute +{ +} diff --git a/src/Compilers/Test/Core/SourceGeneration/TestSourceGenerator.cs b/src/Compilers/Test/Core/SourceGeneration/TestSourceGenerator.cs new file mode 100644 index 0000000000000..9494741e223b1 --- /dev/null +++ b/src/Compilers/Test/Core/SourceGeneration/TestSourceGenerator.cs @@ -0,0 +1,22 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Collections.Immutable; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.Diagnostics; + +namespace Roslyn.Test.Utilities.TestGenerators; + +internal class TestSourceGenerator : ISourceGenerator +{ + public Action? InitializeImpl; + public Action? ExecuteImpl; + + public void Execute(GeneratorExecutionContext context) + => (ExecuteImpl ?? throw new NotImplementedException()).Invoke(context); + + public void Initialize(GeneratorInitializationContext context) + => InitializeImpl?.Invoke(context); +} diff --git a/src/Compilers/Test/Core/Traits/Traits.cs b/src/Compilers/Test/Core/Traits/Traits.cs index 88fd8881b014f..377ad68409d05 100644 --- a/src/Compilers/Test/Core/Traits/Traits.cs +++ b/src/Compilers/Test/Core/Traits/Traits.cs @@ -236,6 +236,7 @@ public static class Features public const string DisposeAnalysis = nameof(DisposeAnalysis); public const string DocCommentFormatting = nameof(DocCommentFormatting); public const string DocumentationComments = nameof(DocumentationComments); + public const string DocumentOutline = nameof(DocumentOutline); public const string EditorConfig = nameof(EditorConfig); public const string EditorConfigUI = nameof(EditorConfigUI); public const string EncapsulateField = nameof(EncapsulateField); @@ -291,6 +292,7 @@ public static class Features public const string RemoveUnnecessaryLineContinuation = nameof(RemoveUnnecessaryLineContinuation); public const string Rename = nameof(Rename); public const string RenameTracking = nameof(RenameTracking); + public const string RoslynLSPSnippetConverter = nameof(RoslynLSPSnippetConverter); public const string SignatureHelp = nameof(SignatureHelp); public const string Simplification = nameof(Simplification); public const string SmartIndent = nameof(SmartIndent); diff --git a/src/Compilers/Test/Resources/Core/Analyzers/DoNothingAnalyzer.cs b/src/Compilers/Test/Resources/Core/Analyzers/DoNothingAnalyzer.cs new file mode 100644 index 0000000000000..811b1d4afb201 --- /dev/null +++ b/src/Compilers/Test/Resources/Core/Analyzers/DoNothingAnalyzer.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 Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.Diagnostics; + +namespace TestResources.Analyzers; + +[DiagnosticAnalyzer(LanguageNames.CSharp, LanguageNames.VisualBasic)] +public sealed class DoNothingAnalyzer : DiagnosticAnalyzer +{ + public override ImmutableArray SupportedDiagnostics => ImmutableArray.Empty; + + public override void Initialize(AnalysisContext context) + { + } +} diff --git a/src/Compilers/Test/Resources/Core/Analyzers/DoNothingGenerator.cs b/src/Compilers/Test/Resources/Core/Analyzers/DoNothingGenerator.cs new file mode 100644 index 0000000000000..01438b14246ac --- /dev/null +++ b/src/Compilers/Test/Resources/Core/Analyzers/DoNothingGenerator.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; + +namespace TestResources.Analyzers; + +[Generator(LanguageNames.CSharp, LanguageNames.VisualBasic)] +public sealed class DoNothingGenerator : IIncrementalGenerator +{ + public void Initialize(IncrementalGeneratorInitializationContext context) + { + + } +} diff --git a/src/Compilers/Test/Resources/Core/Analyzers/DoNothingSuppressor.cs b/src/Compilers/Test/Resources/Core/Analyzers/DoNothingSuppressor.cs new file mode 100644 index 0000000000000..eb09d12c8d2e3 --- /dev/null +++ b/src/Compilers/Test/Resources/Core/Analyzers/DoNothingSuppressor.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 Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.Diagnostics; + +namespace TestResources.Analyzers; + +[DiagnosticAnalyzer(LanguageNames.CSharp, LanguageNames.VisualBasic)] +public sealed class DoNothingSuppressor : DiagnosticSuppressor +{ + public override ImmutableArray SupportedSuppressions => ImmutableArray.Empty; + + public override void ReportSuppressions(SuppressionAnalysisContext context) + { + } +} diff --git a/src/Compilers/Test/Resources/Core/Analyzers/README.md b/src/Compilers/Test/Resources/Core/Analyzers/README.md new file mode 100644 index 0000000000000..575fbd77f5356 --- /dev/null +++ b/src/Compilers/Test/Resources/Core/Analyzers/README.md @@ -0,0 +1,6 @@ +Analyzers / Generators +=== + +Many of our unit tests need to define and consume custom analyzers and generators. This is a problem because most of our unit test assemblies multi-target between `net472` and the latest .NET Core. The compiler pushes customers to define their analyzers / generators against `netstandard2.0`. For generators the compiler actually issues a diagnostic when targeting `net472` and eventually this will be an error. + +Analyzers and Generators that are defined for testing purposes therefore should be defined in this project. It is the only project in our test set that actually targets `netstandard2.0` hence the only place we can safely define analyzers / generators going forward. diff --git a/src/Compilers/Test/Resources/Core/Microsoft.CodeAnalysis.Compiler.Test.Resources.csproj b/src/Compilers/Test/Resources/Core/Microsoft.CodeAnalysis.Compiler.Test.Resources.csproj index 24da3b2a86e2f..28bb8dc578b26 100644 --- a/src/Compilers/Test/Resources/Core/Microsoft.CodeAnalysis.Compiler.Test.Resources.csproj +++ b/src/Compilers/Test/Resources/Core/Microsoft.CodeAnalysis.Compiler.Test.Resources.csproj @@ -374,6 +374,10 @@ + + + + diff --git a/src/Compilers/Test/Utilities/CSharp/CSharpTestBase.cs b/src/Compilers/Test/Utilities/CSharp/CSharpTestBase.cs index 43b4045dd195c..eee1f2e5b06ea 100644 --- a/src/Compilers/Test/Utilities/CSharp/CSharpTestBase.cs +++ b/src/Compilers/Test/Utilities/CSharp/CSharpTestBase.cs @@ -37,6 +37,12 @@ namespace Microsoft.CodeAnalysis.CSharp.Test.Utilities { public abstract class CSharpTestBase : CommonTestBase { + public enum RuntimeFlag + { + None, + ByRefFields, + } + protected const string NullableAttributeDefinition = @" namespace System.Runtime.CompilerServices { @@ -625,6 +631,15 @@ public UnmanagedCallersOnlyAttribute() { } } }"; + protected const string UnscopedRefAttributeDefinition = +@"namespace System.Diagnostics.CodeAnalysis +{ + [AttributeUsage(AttributeTargets.All, AllowMultiple = false, Inherited = false)] + public sealed class UnscopedRefAttribute : Attribute + { + } +}"; + protected const string RequiredMemberAttribute = @" namespace System.Runtime.CompilerServices { @@ -1197,7 +1212,36 @@ public static CSharpCompilation CreateCompilation( TargetFramework targetFramework = TargetFramework.Standard, string assemblyName = "", string sourceFileName = "", - bool skipUsesIsNullable = false) => CreateEmptyCompilation(source, TargetFrameworkUtil.GetReferences(targetFramework, references), options, parseOptions, assemblyName, sourceFileName, skipUsesIsNullable); + bool skipUsesIsNullable = false, + RuntimeFlag runtimeFeature = RuntimeFlag.None) + { + Debug.Assert(targetFramework == TargetFramework.Standard || runtimeFeature == RuntimeFlag.None); + if (runtimeFeature == RuntimeFlag.ByRefFields) + { + // Avoid sharing mscorlib symbols with other tests since we are about to change + // RuntimeSupportsByRefFields property for it. + var mscorlibWithoutSharing = new[] { GetMscorlibRefWithoutSharingCachedSymbols() }; + + // Note: we use skipExtraValidation so that nobody pulls + // on the compilation or its references before we set the RuntimeSupportsByRefFields flag. + var comp = CreateCompilationCore(source, references is not null ? references.Concat(mscorlibWithoutSharing) : mscorlibWithoutSharing, + options, parseOptions, assemblyName, sourceFileName, skipUsesIsNullable, experimentalFeature: null, skipExtraValidation: true); + + comp.Assembly.RuntimeSupportsByRefFields = true; + return comp; + } + + return CreateEmptyCompilation(source, TargetFrameworkUtil.GetReferences(targetFramework, references), options, parseOptions, assemblyName, sourceFileName, skipUsesIsNullable); + } + + public static MetadataReference GetMscorlibRefWithoutSharingCachedSymbols() + { + // Avoid sharing mscorlib symbols with other tests since we are about to change + // RuntimeSupportsByRefFields property for it. + + return ((AssemblyMetadata)((MetadataImageReference)MscorlibRef).GetMetadata()).CopyWithoutSharingCachedSymbols(). + GetReference(display: "mscorlib.v4_0_30319.dll"); + } public static CSharpCompilation CreateEmptyCompilation( CSharpTestSource source, @@ -1206,7 +1250,8 @@ public static CSharpCompilation CreateEmptyCompilation( CSharpParseOptions parseOptions = null, string assemblyName = "", string sourceFileName = "", - bool skipUsesIsNullable = false) => CreateCompilationCore(source, references, options, parseOptions, assemblyName, sourceFileName, skipUsesIsNullable, experimentalFeature: null); + bool skipUsesIsNullable = false, + bool skipExtraValidation = false) => CreateCompilationCore(source, references, options, parseOptions, assemblyName, sourceFileName, skipUsesIsNullable, experimentalFeature: null, skipExtraValidation: skipExtraValidation); private static CSharpCompilation CreateCompilationCore( CSharpTestSource source, @@ -2190,7 +2235,7 @@ protected static CSharpCompilation CreateCompilationWithSpan(CSharpTestSource tr return comp; } - protected static CSharpCompilation CreateCompilationWithMscorlibAndSpan(string text, CSharpCompilationOptions options = null, CSharpParseOptions parseOptions = null) + protected static CSharpCompilation CreateCompilationWithMscorlibAndSpan(CSharpTestSource text, CSharpCompilationOptions options = null, CSharpParseOptions parseOptions = null) { var reference = CreateEmptyCompilation( SpanSource, diff --git a/src/Compilers/Test/Utilities/CSharp/LifetimeAnnotationAttributesVisitor.cs b/src/Compilers/Test/Utilities/CSharp/LifetimeAnnotationAttributesVisitor.cs index 6b967d09b0193..d6dd72234b633 100644 --- a/src/Compilers/Test/Utilities/CSharp/LifetimeAnnotationAttributesVisitor.cs +++ b/src/Compilers/Test/Utilities/CSharp/LifetimeAnnotationAttributesVisitor.cs @@ -14,19 +14,19 @@ namespace Microsoft.CodeAnalysis.CSharp.Test.Utilities { - internal sealed class LifetimeAnnotationAttributesVisitor : CSharpSymbolVisitor + internal sealed class ScopedRefAttributesVisitor : CSharpSymbolVisitor { internal static string GetString(PEModuleSymbol module) { var builder = new StringBuilder(); - var visitor = new LifetimeAnnotationAttributesVisitor(builder); + var visitor = new ScopedRefAttributesVisitor(builder); visitor.Visit(module); return builder.ToString(); } private readonly StringBuilder _builder; - private LifetimeAnnotationAttributesVisitor(StringBuilder builder) + private ScopedRefAttributesVisitor(StringBuilder builder) { _builder = builder; } @@ -73,7 +73,7 @@ public override void VisitProperty(PropertySymbol property) public override void VisitMethod(MethodSymbol method) { var parameters = method.Parameters; - if (!parameters.Any(p => TryGetLifetimeAnnotationAttribute((PEParameterSymbol)p, out _))) + if (!parameters.Any(p => TryGetScopedRefAttribute((PEParameterSymbol)p))) { return; } @@ -81,18 +81,18 @@ public override void VisitMethod(MethodSymbol method) foreach (var parameter in parameters) { _builder.Append(" "); - if (TryGetLifetimeAnnotationAttribute((PEParameterSymbol)parameter, out var pair)) + if (TryGetScopedRefAttribute((PEParameterSymbol)parameter)) { - _builder.Append($"[LifetimeAnnotation({pair.IsRefScoped}, {pair.IsValueScoped})] "); + _builder.Append($"[ScopedRef] "); } _builder.AppendLine(parameter.ToTestDisplayString()); } } - private bool TryGetLifetimeAnnotationAttribute(PEParameterSymbol parameter, out (bool IsRefScoped, bool IsValueScoped) pair) + private bool TryGetScopedRefAttribute(PEParameterSymbol parameter) { var module = ((PEModuleSymbol)parameter.ContainingModule).Module; - return module.HasLifetimeAnnotationAttribute(parameter.Handle, out pair); + return module.HasScopedRefAttribute(parameter.Handle); } } } diff --git a/src/Compilers/Test/Utilities/CSharp/Microsoft.CodeAnalysis.CSharp.Test.Utilities.csproj b/src/Compilers/Test/Utilities/CSharp/Microsoft.CodeAnalysis.CSharp.Test.Utilities.csproj index cf35d6f3befac..7dfd3162da348 100644 --- a/src/Compilers/Test/Utilities/CSharp/Microsoft.CodeAnalysis.CSharp.Test.Utilities.csproj +++ b/src/Compilers/Test/Utilities/CSharp/Microsoft.CodeAnalysis.CSharp.Test.Utilities.csproj @@ -22,6 +22,7 @@ + diff --git a/src/Compilers/Test/Utilities/CSharp/MockCSharpCompiler.cs b/src/Compilers/Test/Utilities/CSharp/MockCSharpCompiler.cs index be90ad0ef1d3b..059b14b1b08b3 100644 --- a/src/Compilers/Test/Utilities/CSharp/MockCSharpCompiler.cs +++ b/src/Compilers/Test/Utilities/CSharp/MockCSharpCompiler.cs @@ -53,6 +53,16 @@ protected override void ResolveAnalyzersFromArguments( } } + public void ResolveAnalyzersFromArguments( + bool skipAnalyzers, + out List diagnostics, + out ImmutableArray analyzers, + out ImmutableArray generators) + { + diagnostics = new List(); + ResolveAnalyzersFromArguments(diagnostics, this.MessageProvider, skipAnalyzers, out analyzers, out generators); + } + public Compilation CreateCompilation( TextWriter consoleOutput, TouchedFileLogger touchedFilesLogger, diff --git a/src/Compilers/Test/Utilities/CSharp/RequiredMemberAttributesVisitor.cs b/src/Compilers/Test/Utilities/CSharp/RequiredMemberAttributesVisitor.cs index 00c93aa972ba1..cf5d1f0023457 100644 --- a/src/Compilers/Test/Utilities/CSharp/RequiredMemberAttributesVisitor.cs +++ b/src/Compilers/Test/Utilities/CSharp/RequiredMemberAttributesVisitor.cs @@ -3,6 +3,7 @@ // See the LICENSE file in the project root for more information. using System.Collections.Immutable; +using System.Reflection.Metadata; using System.Text; using Microsoft.CodeAnalysis.CSharp.Symbols; using Microsoft.CodeAnalysis.CSharp.Symbols.Metadata.PE; @@ -25,6 +26,50 @@ private RequiredMemberAttributesVisitor(StringBuilder builder) : base(builder) protected override SymbolDisplayFormat DisplayFormat => SymbolDisplayFormat.TestFormat; + protected override void ReportSymbol(Symbol symbol) + { + EntityHandle handle; + PEModule module; + + switch (symbol) + { + case PENamedTypeSymbol namedType: + handle = namedType.Handle; + module = ((PEModuleSymbol)namedType.ContainingModule).Module; + break; + + case PEFieldSymbol field: + handle = field.Handle; + module = ((PEModuleSymbol)field.ContainingModule).Module; + break; + + case PEPropertySymbol property: + handle = property.Handle; + module = ((PEModuleSymbol)property.ContainingModule).Module; + break; + + default: + base.ReportSymbol(symbol); + return; + } + + var attribute = module.GetAttributeHandle(handle, AttributeDescription.RequiredMemberAttribute); + + if (attribute.IsNil) + { + return; + } + + ReportContainingSymbols(symbol); + _builder.Append(GetIndentString(symbol)); + _builder.Append("[RequiredMember] "); + _builder.AppendLine(symbol.ToDisplayString(DisplayFormat)); + _reported.Add(symbol); + + // If attributes aren't filtered out, this will print extra data and cause an error in test assertion. + base.ReportSymbol(symbol); + } + protected override CSharpAttributeData? GetTargetAttribute(ImmutableArray attributes) => GetAttribute(attributes, "System.Runtime.CompilerServices", "RequiredMemberAttribute"); diff --git a/src/Compilers/Test/Utilities/CSharp/TestOptions.cs b/src/Compilers/Test/Utilities/CSharp/TestOptions.cs index 1ed081da0a327..158135487da2f 100644 --- a/src/Compilers/Test/Utilities/CSharp/TestOptions.cs +++ b/src/Compilers/Test/Utilities/CSharp/TestOptions.cs @@ -25,7 +25,7 @@ public static class TestOptions public static readonly CSharpParseOptions RegularDefault = Regular.WithLanguageVersion(LanguageVersion.Default); /// - /// Usages of and + /// Usages of and /// will be replaced with TestOptions.RegularN and LanguageVersion.CSharpN when language version N is introduced. /// public static readonly CSharpParseOptions RegularNext = Regular.WithLanguageVersion(LanguageVersion.Preview); @@ -34,6 +34,7 @@ public static class TestOptions public static readonly CSharpParseOptions Regular8 = Regular.WithLanguageVersion(LanguageVersion.CSharp8); public static readonly CSharpParseOptions Regular9 = Regular.WithLanguageVersion(LanguageVersion.CSharp9); public static readonly CSharpParseOptions Regular10 = Regular.WithLanguageVersion(LanguageVersion.CSharp10); + public static readonly CSharpParseOptions Regular11 = Regular.WithLanguageVersion(LanguageVersion.CSharp11); public static readonly CSharpParseOptions RegularWithDocumentationComments = Regular.WithDocumentationMode(DocumentationMode.Diagnose); public static readonly CSharpParseOptions RegularWithLegacyStrongName = Regular.WithFeature("UseLegacyStrongNameProvider"); public static readonly CSharpParseOptions WithoutImprovedOverloadCandidates = Regular.WithLanguageVersion(MessageID.IDS_FeatureImprovedOverloadCandidates.RequiredVersion() - 1); @@ -69,6 +70,9 @@ public static class TestOptions public static readonly CSharpCompilationOptions DebugDll = CreateTestOptions(OutputKind.DynamicallyLinkedLibrary, OptimizationLevel.Debug); public static readonly CSharpCompilationOptions DebugExe = CreateTestOptions(OutputKind.ConsoleApplication, OptimizationLevel.Debug); + public static readonly CSharpCompilationOptions DebugDllThrowing = DebugDll.WithMetadataReferenceResolver(new ThrowingMetadataReferenceResolver()); + public static readonly CSharpCompilationOptions DebugExeThrowing = DebugExe.WithMetadataReferenceResolver(new ThrowingMetadataReferenceResolver()); + public static readonly CSharpCompilationOptions ReleaseWinMD = CreateTestOptions(OutputKind.WindowsRuntimeMetadata, OptimizationLevel.Release); public static readonly CSharpCompilationOptions DebugWinMD = CreateTestOptions(OutputKind.WindowsRuntimeMetadata, OptimizationLevel.Debug); diff --git a/src/Compilers/Test/Utilities/CSharp/ThrowingMetadataReferenceResolver.cs b/src/Compilers/Test/Utilities/CSharp/ThrowingMetadataReferenceResolver.cs new file mode 100644 index 0000000000000..57e382ab5146d --- /dev/null +++ b/src/Compilers/Test/Utilities/CSharp/ThrowingMetadataReferenceResolver.cs @@ -0,0 +1,41 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Microsoft.CodeAnalysis.CSharp.Test.Utilities; + +/// +/// This simulates our default command line compilation experience where the +/// throws on equality checks via +/// +public sealed class ThrowingMetadataReferenceResolver : MetadataReferenceResolver +{ + public MetadataReferenceResolver? Resolver { get; } + + public ThrowingMetadataReferenceResolver(MetadataReferenceResolver? resolver = null) + { + Resolver = resolver; + } + + public override bool Equals(object? other) => throw new NotImplementedException(); + + public override int GetHashCode() => throw new NotImplementedException(); + + public override ImmutableArray ResolveReference(string reference, string? baseFilePath, MetadataReferenceProperties properties) + { + if (Resolver is null) + { + throw new NotImplementedException(); + } + + return Resolver.ResolveReference(reference, baseFilePath, properties); + } + +} diff --git a/src/Compilers/Test/Utilities/VisualBasic/MockVisualBasicCompiler.vb b/src/Compilers/Test/Utilities/VisualBasic/MockVisualBasicCompiler.vb index 79d7450e56a55..e15a4b3f084e6 100644 --- a/src/Compilers/Test/Utilities/VisualBasic/MockVisualBasicCompiler.vb +++ b/src/Compilers/Test/Utilities/VisualBasic/MockVisualBasicCompiler.vb @@ -12,6 +12,7 @@ Friend Class MockVisualBasicCompiler Inherits VisualBasicCompiler Private ReadOnly _analyzers As ImmutableArray(Of DiagnosticAnalyzer) + Private ReadOnly _generators As ImmutableArray(Of ISourceGenerator) Public Compilation As Compilation Public AnalyzerOptions As AnalyzerOptions @@ -19,22 +20,23 @@ Friend Class MockVisualBasicCompiler MyClass.New(Nothing, baseDirectory, args, analyzer) End Sub - Public Sub New(responseFile As String, baseDirectory As String, args As String(), Optional analyzer As DiagnosticAnalyzer = Nothing) + Public Sub New(responseFile As String, baseDirectory As String, args As String(), analyzer As DiagnosticAnalyzer) MyClass.New(responseFile, CreateBuildPaths(baseDirectory, Path.GetTempPath()), args, analyzer) End Sub - Public Sub New(responseFile As String, buildPaths As BuildPaths, args As String(), Optional analyzer As DiagnosticAnalyzer = Nothing) - MyClass.New(responseFile, buildPaths, args, If(analyzer Is Nothing, ImmutableArray(Of DiagnosticAnalyzer).Empty, ImmutableArray.Create(analyzer))) + Public Sub New(responseFile As String, buildPaths As BuildPaths, args As String(), analyzer As DiagnosticAnalyzer) + MyClass.New(responseFile, buildPaths, args, If(analyzer Is Nothing, Nothing, {analyzer})) End Sub - Public Sub New(responseFile As String, workingDirectory As String, args As String(), analyzers As ImmutableArray(Of DiagnosticAnalyzer)) - MyClass.New(responseFile, CreateBuildPaths(workingDirectory, Path.GetTempPath()), args, analyzers) + Public Sub New(responseFile As String, workingDirectory As String, args As String(), Optional analyzers As DiagnosticAnalyzer() = Nothing, Optional generators As ISourceGenerator() = Nothing) + MyClass.New(responseFile, CreateBuildPaths(workingDirectory, Path.GetTempPath()), args, analyzers, generators) End Sub - Public Sub New(responseFile As String, buildPaths As BuildPaths, args As String(), analyzers As ImmutableArray(Of DiagnosticAnalyzer)) + Public Sub New(responseFile As String, buildPaths As BuildPaths, args As String(), Optional analyzers As DiagnosticAnalyzer() = Nothing, Optional generators As ISourceGenerator() = Nothing) MyBase.New(VisualBasicCommandLineParser.Default, responseFile, args, buildPaths, Environment.GetEnvironmentVariable("LIB"), New DefaultAnalyzerAssemblyLoader()) - _analyzers = analyzers + _analyzers = analyzers.AsImmutableOrEmpty() + _generators = generators.AsImmutableOrEmpty() End Sub Private Shared Function CreateBuildPaths(workingDirectory As String, tempDirectory As String) As BuildPaths @@ -52,6 +54,10 @@ Friend Class MockVisualBasicCompiler If Not _analyzers.IsDefaultOrEmpty Then analyzers = analyzers.InsertRange(0, _analyzers) End If + + If Not _generators.IsDefaultOrEmpty Then + generators = generators.InsertRange(0, _generators) + End If End Sub Public Overloads Function CreateCompilation(consoleOutput As TextWriter, touchedFilesLogger As TouchedFileLogger, errorLogger As ErrorLogger, syntaxTreeDiagnosticOptionsOpt As ImmutableArray(Of AnalyzerConfigOptionsResult)) As Compilation diff --git a/src/Compilers/VisualBasic/Portable/Binding/Binder_Symbols.vb b/src/Compilers/VisualBasic/Portable/Binding/Binder_Symbols.vb index 22f8d32a16009..0ea8e1ba9b275 100644 --- a/src/Compilers/VisualBasic/Portable/Binding/Binder_Symbols.vb +++ b/src/Compilers/VisualBasic/Portable/Binding/Binder_Symbols.vb @@ -375,7 +375,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic If rightPart.Kind = SyntaxKind.GenericName Then arity = DirectCast(rightPart, GenericNameSyntax).Arity - fullName = MetadataHelpers.ComposeAritySuffixedMetadataName(currDiagName, arity) + fullName = MetadataHelpers.ComposeAritySuffixedMetadataName(currDiagName, arity, associatedFileIdentifier:=Nothing) End If forwardedToAssembly = GetForwardedToAssembly(containingAssembly, fullName, arity, typeSyntax, diagBag) diff --git a/src/Compilers/VisualBasic/Portable/BoundTree/BoundBinaryOperator.vb b/src/Compilers/VisualBasic/Portable/BoundTree/BoundBinaryOperator.vb index 68808e9fee0d0..1e5b25126e3af 100644 --- a/src/Compilers/VisualBasic/Portable/BoundTree/BoundBinaryOperator.vb +++ b/src/Compilers/VisualBasic/Portable/BoundTree/BoundBinaryOperator.vb @@ -39,20 +39,24 @@ Namespace Microsoft.CodeAnalysis.VisualBasic Public Overrides ReadOnly Property ExpressionSymbol As Symbol Get If (OperatorKind And BinaryOperatorKind.Error) = 0 Then - Dim opName As String = OverloadResolution.TryGetOperatorName(OperatorKind) + Dim op As BinaryOperatorKind = (OperatorKind And BinaryOperatorKind.OpMask) + Dim leftType = TryCast(Left.Type.GetNullableUnderlyingTypeOrSelf(), NamedTypeSymbol) - If opName IsNot Nothing Then - Dim op As BinaryOperatorKind = (OperatorKind And BinaryOperatorKind.OpMask) - Dim leftType = DirectCast(Left.Type.GetNullableUnderlyingTypeOrSelf(), NamedTypeSymbol) - Return New SynthesizedIntrinsicOperatorSymbol(leftType, - opName, - Right.Type.GetNullableUnderlyingTypeOrSelf(), - Type.GetNullableUnderlyingTypeOrSelf(), - Checked AndAlso leftType.IsIntegralType() AndAlso - (op = BinaryOperatorKind.Multiply OrElse - op = BinaryOperatorKind.Add OrElse - op = BinaryOperatorKind.Subtract OrElse - op = BinaryOperatorKind.IntegerDivide)) + If leftType IsNot Nothing Then + Dim isChecked = Checked AndAlso leftType.IsIntegralType() AndAlso + (op = BinaryOperatorKind.Multiply OrElse + op = BinaryOperatorKind.Add OrElse + op = BinaryOperatorKind.Subtract OrElse + op = BinaryOperatorKind.IntegerDivide) + Dim opName As String = OverloadResolution.TryGetOperatorName(OperatorKind, isChecked) + + If opName IsNot Nothing Then + Return New SynthesizedIntrinsicOperatorSymbol( + leftType, + opName, + Right.Type.GetNullableUnderlyingTypeOrSelf(), + Type.GetNullableUnderlyingTypeOrSelf()) + End If End If End If diff --git a/src/Compilers/VisualBasic/Portable/BoundTree/BoundUnaryOperator.vb b/src/Compilers/VisualBasic/Portable/BoundTree/BoundUnaryOperator.vb index 177c16deab715..cd1bfbb35bfa8 100644 --- a/src/Compilers/VisualBasic/Portable/BoundTree/BoundUnaryOperator.vb +++ b/src/Compilers/VisualBasic/Portable/BoundTree/BoundUnaryOperator.vb @@ -32,16 +32,19 @@ Namespace Microsoft.CodeAnalysis.VisualBasic Public Overrides ReadOnly Property ExpressionSymbol As Symbol Get If (OperatorKind And UnaryOperatorKind.Error) = 0 Then - Dim opName As String = OverloadResolution.TryGetOperatorName(OperatorKind) - - If opName IsNot Nothing Then - Dim op As UnaryOperatorKind = (OperatorKind And UnaryOperatorKind.OpMask) - Dim operandType = DirectCast(Operand.Type.GetNullableUnderlyingTypeOrSelf(), NamedTypeSymbol) - Return New SynthesizedIntrinsicOperatorSymbol(operandType, - opName, - Type.GetNullableUnderlyingTypeOrSelf(), - Checked AndAlso operandType.IsIntegralType() AndAlso - op = UnaryOperatorKind.Minus) + Dim op As UnaryOperatorKind = (OperatorKind And UnaryOperatorKind.OpMask) + Dim operandType = TryCast(Operand.Type.GetNullableUnderlyingTypeOrSelf(), NamedTypeSymbol) + + If operandType IsNot Nothing Then + Dim isChecked = Checked AndAlso operandType.IsIntegralType() AndAlso op = UnaryOperatorKind.Minus + Dim opName As String = OverloadResolution.TryGetOperatorName(OperatorKind, isChecked) + + If opName IsNot Nothing Then + Return New SynthesizedIntrinsicOperatorSymbol( + operandType, + opName, + Type.GetNullableUnderlyingTypeOrSelf()) + End If End If End If diff --git a/src/Compilers/VisualBasic/Portable/CodeGen/ResumableStateMachineStateAllocator.vb b/src/Compilers/VisualBasic/Portable/CodeGen/ResumableStateMachineStateAllocator.vb index 59735a2f203c4..0b5ea39ab7e2b 100644 --- a/src/Compilers/VisualBasic/Portable/CodeGen/ResumableStateMachineStateAllocator.vb +++ b/src/Compilers/VisualBasic/Portable/CodeGen/ResumableStateMachineStateAllocator.vb @@ -20,7 +20,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic ''' ''' The number of the next generated resumable state (i.e. state that resumes execution of the state machine after await expression or yield return). ''' - Private _nextState As Integer + Private _nextState As StateMachineState #If DEBUG Then ''' @@ -33,7 +33,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic ''' Private _matchedStateCount As Integer - Public Sub New(slotAllocator As VariableSlotAllocator, firstState As Integer, increasing As Boolean) + Public Sub New(slotAllocator As VariableSlotAllocator, firstState As StateMachineState, increasing As Boolean) _increasing = increasing _slotAllocator = slotAllocator _matchedStateCount = 0 @@ -41,25 +41,25 @@ Namespace Microsoft.CodeAnalysis.VisualBasic _nextState = If(slotAllocator?.GetFirstUnusedStateMachineState(increasing), firstState) End Sub - Public Function AllocateState(awaitOrYieldReturnSyntax As SyntaxNode) As Integer + Public Function AllocateState(awaitOrYieldReturnSyntax As SyntaxNode) As StateMachineState Debug.Assert(SyntaxBindingUtilities.BindsToResumableStateMachineState(awaitOrYieldReturnSyntax)) Dim direction = If(_increasing, +1, -1) - Dim stateNumber As Integer + Dim state As StateMachineState - If _slotAllocator?.TryGetPreviousStateMachineState(awaitOrYieldReturnSyntax, stateNumber) = True Then + If _slotAllocator?.TryGetPreviousStateMachineState(awaitOrYieldReturnSyntax, state) = True Then #If DEBUG Then ' two states of the new state machine should not match the same state of the previous machine - Debug.Assert(Not _matchedStates(stateNumber * direction)) - _matchedStates(stateNumber * direction) = True + Debug.Assert(Not _matchedStates(state * direction)) + _matchedStates(state * direction) = True #End If _matchedStateCount += 1 Else - stateNumber = _nextState - _nextState += direction + state = _nextState + _nextState = CType(_nextState + direction, StateMachineState) End If - Return stateNumber + Return state End Function ''' diff --git a/src/Compilers/VisualBasic/Portable/Compilation/VisualBasicCompilerDiagnosticAnalyzer.vb b/src/Compilers/VisualBasic/Portable/Compilation/VisualBasicCompilerDiagnosticAnalyzer.vb index 57743107a0bc3..2b5c2b2e4b21d 100644 --- a/src/Compilers/VisualBasic/Portable/Compilation/VisualBasicCompilerDiagnosticAnalyzer.vb +++ b/src/Compilers/VisualBasic/Portable/Compilation/VisualBasicCompilerDiagnosticAnalyzer.vb @@ -24,14 +24,11 @@ Namespace Microsoft.CodeAnalysis.Diagnostics.VisualBasic Dim builder = ImmutableArray.CreateBuilder(Of Integer) For Each errorCode As Integer In errorCodes - ' these errors are not supported by live analysis - If errorCode = ERRID.ERR_TypeRefResolutionError3 OrElse - errorCode = ERRID.ERR_MissingRuntimeHelper OrElse - errorCode = ERRID.ERR_CannotGotoNonScopeBlocksWithClosure Then - Continue For - End If + ' Compiler diagnostic analyzer does not support build-only diagnostics. + If Not ErrorFacts.IsBuildOnlyDiagnostic(DirectCast(errorCode, ERRID)) AndAlso + errorCode > ERRID.ERR_None AndAlso + errorCode < ERRID.WRN_NextAvailable Then - If errorCode > ERRID.ERR_None AndAlso errorCode < ERRID.WRN_NextAvailable Then builder.Add(errorCode) End If Next diff --git a/src/Compilers/VisualBasic/Portable/Emit/EditAndContinue/EmitHelpers.vb b/src/Compilers/VisualBasic/Portable/Emit/EditAndContinue/EmitHelpers.vb index 314f80a0c169f..6fb3c556862c8 100644 --- a/src/Compilers/VisualBasic/Portable/Emit/EditAndContinue/EmitHelpers.vb +++ b/src/Compilers/VisualBasic/Portable/Emit/EditAndContinue/EmitHelpers.vb @@ -135,8 +135,8 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Emit currentSynthesizedMembers, currentDeletedMembers) - Dim mappedSynthesizedMembers = matcher.MapSynthesizedMembers(previousGeneration.SynthesizedMembers, currentSynthesizedMembers) - Dim mappedDeletedMembers = matcher.MapSynthesizedMembers(previousGeneration.DeletedMembers, currentDeletedMembers) + Dim mappedSynthesizedMembers = matcher.MapSynthesizedOrDeletedMembers(previousGeneration.SynthesizedMembers, currentSynthesizedMembers, isDeletedMemberMapping:=False) + Dim mappedDeletedMembers = matcher.MapSynthesizedOrDeletedMembers(previousGeneration.DeletedMembers, currentDeletedMembers, isDeletedMemberMapping:=True) ' TODO can we reuse some data from the previous matcher? Dim matcherWithAllSynthesizedMembers = New VisualBasicSymbolMatcher( diff --git a/src/Compilers/VisualBasic/Portable/Emit/EditAndContinue/VisualBasicDefinitionMap.vb b/src/Compilers/VisualBasic/Portable/Emit/EditAndContinue/VisualBasicDefinitionMap.vb index 98b2a823c3454..f7d1d1527abb6 100644 --- a/src/Compilers/VisualBasic/Portable/Emit/EditAndContinue/VisualBasicDefinitionMap.vb +++ b/src/Compilers/VisualBasic/Portable/Emit/EditAndContinue/VisualBasicDefinitionMap.vb @@ -165,11 +165,13 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Emit End If Case GeneratedNameKind.HoistedSynthesizedLocalField, - GeneratedNameKind.StateMachineHoistedUserVariableField + GeneratedNameKind.HoistedWithLocalPrefix, + GeneratedNameKind.StateMachineHoistedUserVariableOrDisplayClassField - Dim _name As String = Nothing + Dim variableName As String = Nothing If GeneratedNameParser.TryParseSlotIndex(GeneratedNameConstants.HoistedSynthesizedLocalPrefix, name, slotIndex) OrElse - GeneratedNameParser.TryParseStateMachineHoistedUserVariableName(name, _name, slotIndex) Then + GeneratedNameParser.TryParseSlotIndex(GeneratedNameConstants.HoistedWithLocalPrefix, name, slotIndex) OrElse + GeneratedNameParser.TryParseStateMachineHoistedUserVariableOrDisplayClassName(name, variableName, slotIndex) Then Dim field = DirectCast(member, FieldSymbol) If slotIndex >= localSlotDebugInfo.Length Then ' Invalid metadata diff --git a/src/Compilers/VisualBasic/Portable/Emit/NamedTypeReference.vb b/src/Compilers/VisualBasic/Portable/Emit/NamedTypeReference.vb index bafab6592ced3..30f4422a89728 100644 --- a/src/Compilers/VisualBasic/Portable/Emit/NamedTypeReference.vb +++ b/src/Compilers/VisualBasic/Portable/Emit/NamedTypeReference.vb @@ -30,6 +30,12 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Emit End Get End Property + Private ReadOnly Property INamedTypeReferenceAssociatedFileIdentifier As String Implements Cci.INamedTypeReference.AssociatedFileIdentifier + Get + Return Nothing + End Get + End Property + Private ReadOnly Property INamedEntityName As String Implements Cci.INamedEntity.Name Get ' CCI automatically handles type suffix, so use Name instead of MetadataName diff --git a/src/Compilers/VisualBasic/Portable/Emit/NamedTypeSymbolAdapter.vb b/src/Compilers/VisualBasic/Portable/Emit/NamedTypeSymbolAdapter.vb index 7e5181c4d4a07..c857d34202f5a 100644 --- a/src/Compilers/VisualBasic/Portable/Emit/NamedTypeSymbolAdapter.vb +++ b/src/Compilers/VisualBasic/Portable/Emit/NamedTypeSymbolAdapter.vb @@ -758,6 +758,12 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols End Get End Property + Private ReadOnly Property INamedTypeReferenceAssociatedFileIdentifier As String Implements INamedTypeReference.AssociatedFileIdentifier + Get + Return Nothing + End Get + End Property + Private ReadOnly Property INamedEntityName As String Implements INamedEntity.Name Get ' CCI automatically adds the arity suffix, so we return Name, not MetadataName here. diff --git a/src/Compilers/VisualBasic/Portable/Emit/NoPia/EmbeddedEvent.vb b/src/Compilers/VisualBasic/Portable/Emit/NoPia/EmbeddedEvent.vb index 240e191bac19f..4609e353ea436 100644 --- a/src/Compilers/VisualBasic/Portable/Emit/NoPia/EmbeddedEvent.vb +++ b/src/Compilers/VisualBasic/Portable/Emit/NoPia/EmbeddedEvent.vb @@ -19,7 +19,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Emit.NoPia End Sub Protected Overrides Function GetCustomAttributesToEmit(moduleBuilder As PEModuleBuilder) As IEnumerable(Of VisualBasicAttributeData) - Return UnderlyingEvent.AdaptedEventSymbol.GetCustomAttributesToEmit(moduleBuilder.CompilationState) + Return UnderlyingEvent.AdaptedEventSymbol.GetCustomAttributesToEmit(moduleBuilder) End Function Protected Overrides ReadOnly Property IsRuntimeSpecial As Boolean diff --git a/src/Compilers/VisualBasic/Portable/Emit/NoPia/EmbeddedField.vb b/src/Compilers/VisualBasic/Portable/Emit/NoPia/EmbeddedField.vb index bb41d7ed33754..dc5d0ca0949bc 100644 --- a/src/Compilers/VisualBasic/Portable/Emit/NoPia/EmbeddedField.vb +++ b/src/Compilers/VisualBasic/Portable/Emit/NoPia/EmbeddedField.vb @@ -27,7 +27,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Emit.NoPia End Property Protected Overrides Function GetCustomAttributesToEmit(moduleBuilder As PEModuleBuilder) As IEnumerable(Of VisualBasicAttributeData) - Return UnderlyingField.AdaptedFieldSymbol.GetCustomAttributesToEmit(moduleBuilder.CompilationState) + Return UnderlyingField.AdaptedFieldSymbol.GetCustomAttributesToEmit(moduleBuilder) End Function Protected Overrides Function GetCompileTimeValue(context As EmitContext) As MetadataConstant diff --git a/src/Compilers/VisualBasic/Portable/Emit/NoPia/EmbeddedMethod.vb b/src/Compilers/VisualBasic/Portable/Emit/NoPia/EmbeddedMethod.vb index b5338760bf206..52c8f7cd6dab3 100644 --- a/src/Compilers/VisualBasic/Portable/Emit/NoPia/EmbeddedMethod.vb +++ b/src/Compilers/VisualBasic/Portable/Emit/NoPia/EmbeddedMethod.vb @@ -27,7 +27,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Emit.NoPia End Property Protected Overrides Function GetCustomAttributesToEmit(moduleBuilder As PEModuleBuilder) As IEnumerable(Of VisualBasicAttributeData) - Return UnderlyingMethod.AdaptedMethodSymbol.GetCustomAttributesToEmit(moduleBuilder.CompilationState) + Return UnderlyingMethod.AdaptedMethodSymbol.GetCustomAttributesToEmit(moduleBuilder) End Function Protected Overrides Function GetParameters() As ImmutableArray(Of EmbeddedParameter) diff --git a/src/Compilers/VisualBasic/Portable/Emit/NoPia/EmbeddedParameter.vb b/src/Compilers/VisualBasic/Portable/Emit/NoPia/EmbeddedParameter.vb index 0f5c7ba45956a..ef0dc5e17cba1 100644 --- a/src/Compilers/VisualBasic/Portable/Emit/NoPia/EmbeddedParameter.vb +++ b/src/Compilers/VisualBasic/Portable/Emit/NoPia/EmbeddedParameter.vb @@ -22,7 +22,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Emit.NoPia End Sub Protected Overrides Function GetCustomAttributesToEmit(moduleBuilder As PEModuleBuilder) As IEnumerable(Of VisualBasicAttributeData) - Return UnderlyingParameter.AdaptedParameterSymbol.GetCustomAttributesToEmit(moduleBuilder.CompilationState) + Return UnderlyingParameter.AdaptedParameterSymbol.GetCustomAttributesToEmit(moduleBuilder) End Function Protected Overrides ReadOnly Property HasDefaultValue As Boolean diff --git a/src/Compilers/VisualBasic/Portable/Emit/NoPia/EmbeddedProperty.vb b/src/Compilers/VisualBasic/Portable/Emit/NoPia/EmbeddedProperty.vb index 5e8b113067a8e..3abd3b202aeaf 100644 --- a/src/Compilers/VisualBasic/Portable/Emit/NoPia/EmbeddedProperty.vb +++ b/src/Compilers/VisualBasic/Portable/Emit/NoPia/EmbeddedProperty.vb @@ -21,7 +21,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Emit.NoPia End Sub Protected Overrides Function GetCustomAttributesToEmit(moduleBuilder As PEModuleBuilder) As IEnumerable(Of VisualBasicAttributeData) - Return UnderlyingProperty.AdaptedPropertySymbol.GetCustomAttributesToEmit(moduleBuilder.CompilationState) + Return UnderlyingProperty.AdaptedPropertySymbol.GetCustomAttributesToEmit(moduleBuilder) End Function Protected Overrides Function GetParameters() As ImmutableArray(Of EmbeddedParameter) diff --git a/src/Compilers/VisualBasic/Portable/Emit/NoPia/EmbeddedType.vb b/src/Compilers/VisualBasic/Portable/Emit/NoPia/EmbeddedType.vb index a4cb610621fc7..3652cc24922a5 100644 --- a/src/Compilers/VisualBasic/Portable/Emit/NoPia/EmbeddedType.vb +++ b/src/Compilers/VisualBasic/Portable/Emit/NoPia/EmbeddedType.vb @@ -187,7 +187,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Emit.NoPia End Property Protected Overrides Function GetCustomAttributesToEmit(moduleBuilder As PEModuleBuilder) As IEnumerable(Of VisualBasicAttributeData) - Return UnderlyingNamedType.AdaptedNamedTypeSymbol.GetCustomAttributesToEmit(moduleBuilder.CompilationState) + Return UnderlyingNamedType.AdaptedNamedTypeSymbol.GetCustomAttributesToEmit(moduleBuilder) End Function Protected Overrides Function CreateTypeIdentifierAttribute(hasGuid As Boolean, syntaxNodeOpt As SyntaxNode, diagnostics As DiagnosticBag) As VisualBasicAttributeData diff --git a/src/Compilers/VisualBasic/Portable/Emit/PEModuleBuilder.vb b/src/Compilers/VisualBasic/Portable/Emit/PEModuleBuilder.vb index 449082250f976..1003bacbef3d0 100644 --- a/src/Compilers/VisualBasic/Portable/Emit/PEModuleBuilder.vb +++ b/src/Compilers/VisualBasic/Portable/Emit/PEModuleBuilder.vb @@ -180,7 +180,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Emit End Function Public NotOverridable Overrides Function GetSourceAssemblyAttributes(isRefAssembly As Boolean) As IEnumerable(Of Cci.ICustomAttribute) - Return SourceModule.ContainingSourceAssembly.GetAssemblyCustomAttributesToEmit(Me.CompilationState, + Return SourceModule.ContainingSourceAssembly.GetAssemblyCustomAttributesToEmit(Me, isRefAssembly, emittingAssemblyAttributesInNetModule:=OutputKind.IsNetModule()) End Function @@ -190,7 +190,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Emit End Function Public NotOverridable Overrides Function GetSourceModuleAttributes() As IEnumerable(Of Cci.ICustomAttribute) - Return SourceModule.GetCustomAttributesToEmit(Me.CompilationState) + Return SourceModule.GetCustomAttributesToEmit(Me) End Function Public NotOverridable Overrides Function GetSymbolToLocationMap() As MultiDictionary(Of Cci.DebugSourceDocument, Cci.DefinitionWithLocation) @@ -443,7 +443,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Emit ' exported types are not emitted in EnC deltas (hence generation 0): Dim fullEmittedName As String = MetadataHelpers.BuildQualifiedName( DirectCast(typeReference, Cci.INamespaceTypeReference).NamespaceName, - Cci.MetadataWriter.GetMangledName(DirectCast(typeReference, Cci.INamedTypeReference), generation:=0)) + Cci.MetadataWriter.GetMetadataName(DirectCast(typeReference, Cci.INamedTypeReference), generation:=0)) ' First check against types declared in the primary module If ContainsTopLevelType(fullEmittedName) Then diff --git a/src/Compilers/VisualBasic/Portable/Emit/SourceAssemblySymbolAdapter.vb b/src/Compilers/VisualBasic/Portable/Emit/SourceAssemblySymbolAdapter.vb index 180067d82cba2..3eda631743f52 100644 --- a/src/Compilers/VisualBasic/Portable/Emit/SourceAssemblySymbolAdapter.vb +++ b/src/Compilers/VisualBasic/Portable/Emit/SourceAssemblySymbolAdapter.vb @@ -3,15 +3,17 @@ ' See the LICENSE file in the project root for more information. Imports Microsoft.CodeAnalysis.PooledObjects +Imports Microsoft.CodeAnalysis.VisualBasic.Emit + Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols Partial Friend Class SourceAssemblySymbol - Friend Function GetAssemblyCustomAttributesToEmit(compilationState As ModuleCompilationState, + Friend Function GetAssemblyCustomAttributesToEmit(moduleBuilder As PEModuleBuilder, emittingRefAssembly As Boolean, emittingAssemblyAttributesInNetModule As Boolean) As IEnumerable(Of VisualBasicAttributeData) Dim synthesized As ArrayBuilder(Of SynthesizedAttributeData) = Nothing - AddSynthesizedAttributes(compilationState, synthesized) + AddSynthesizedAttributes(moduleBuilder, synthesized) If emittingRefAssembly AndAlso Not HasReferenceAssemblyAttribute Then Dim referenceAssemblyAttribute = Me.DeclaringCompilation. diff --git a/src/Compilers/VisualBasic/Portable/Emit/SymbolAdapter.vb b/src/Compilers/VisualBasic/Portable/Emit/SymbolAdapter.vb index 5483bb6836d37..aa07f6ef3a194 100644 --- a/src/Compilers/VisualBasic/Portable/Emit/SymbolAdapter.vb +++ b/src/Compilers/VisualBasic/Portable/Emit/SymbolAdapter.vb @@ -34,7 +34,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic End Sub Private Function IReferenceGetAttributes(context As EmitContext) As IEnumerable(Of Cci.ICustomAttribute) Implements Cci.IReference.GetAttributes - Return AdaptedSymbol.GetCustomAttributesToEmit(DirectCast(context.Module, PEModuleBuilder).CompilationState) + Return AdaptedSymbol.GetCustomAttributesToEmit(DirectCast(context.Module, PEModuleBuilder)) End Function End Class @@ -72,15 +72,15 @@ Namespace Microsoft.CodeAnalysis.VisualBasic Return Me.IsDefinition OrElse Not Me.Equals(Me.OriginalDefinition) End Function - Friend Overridable Function GetCustomAttributesToEmit(compilationState As ModuleCompilationState) As IEnumerable(Of VisualBasicAttributeData) - Return GetCustomAttributesToEmit(compilationState, emittingAssemblyAttributesInNetModule:=False) + Friend Overridable Function GetCustomAttributesToEmit(moduleBuilder As PEModuleBuilder) As IEnumerable(Of VisualBasicAttributeData) + Return GetCustomAttributesToEmit(moduleBuilder, emittingAssemblyAttributesInNetModule:=False) End Function - Friend Function GetCustomAttributesToEmit(compilationState As ModuleCompilationState, emittingAssemblyAttributesInNetModule As Boolean) As IEnumerable(Of VisualBasicAttributeData) + Friend Function GetCustomAttributesToEmit(moduleBuilder As PEModuleBuilder, emittingAssemblyAttributesInNetModule As Boolean) As IEnumerable(Of VisualBasicAttributeData) Debug.Assert(Me.Kind <> SymbolKind.Assembly) Dim synthesized As ArrayBuilder(Of SynthesizedAttributeData) = Nothing - AddSynthesizedAttributes(compilationState, synthesized) + AddSynthesizedAttributes(moduleBuilder, synthesized) Return GetCustomAttributesToEmit(Me.GetAttributes(), synthesized, isReturnType:=False, emittingAssemblyAttributesInNetModule:=emittingAssemblyAttributesInNetModule) End Function diff --git a/src/Compilers/VisualBasic/Portable/Errors/ErrorFacts.vb b/src/Compilers/VisualBasic/Portable/Errors/ErrorFacts.vb new file mode 100644 index 0000000000000..2b43089ba88fa --- /dev/null +++ b/src/Compilers/VisualBasic/Portable/Errors/ErrorFacts.vb @@ -0,0 +1,1538 @@ +' Licensed to the .NET Foundation under one or more 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.VisualBasic + Partial Friend Module ErrorFacts + ''' + ''' Returns true if this is a build-only diagnostic that is never reported from + ''' API. + ''' Diagnostics generated during compilation phases such as lowering, emit, etc. + ''' are example of build-only diagnostics. + ''' + Public Function IsBuildOnlyDiagnostic(code As ERRID) As Boolean + If code >= ERRID.WRN_NextAvailable Then + Return False + End If + + Select Case code + Case ERRID.ERR_TypeRefResolutionError3, + ERRID.ERR_MissingRuntimeHelper, + ERRID.ERR_CannotGotoNonScopeBlocksWithClosure + Return True + Case ERRID.Void, + ERRID.Unknown, + ERRID.ERR_None, + ERRID.ERR_FileNotFound, + ERRID.ERR_ArgumentRequired, + ERRID.WRN_BadSwitch, + ERRID.ERR_NoSources, + ERRID.ERR_SwitchNeedsBool, + ERRID.ERR_NoResponseFile, + ERRID.ERR_CantOpenFileWrite, + ERRID.ERR_InvalidSwitchValue, + ERRID.ERR_BinaryFile, + ERRID.ERR_BadCodepage, + ERRID.ERR_LibNotFound, + ERRID.ERR_IconFileAndWin32ResFile, + ERRID.WRN_NoConfigInResponseFile, + ERRID.ERR_NoSourcesOut, + ERRID.ERR_NeedModule, + ERRID.ERR_InvalidAssemblyName, + ERRID.FTL_InvalidInputFileName, + ERRID.ERR_ConflictingManifestSwitches, + ERRID.WRN_IgnoreModuleManifest, + ERRID.WRN_BadUILang, + ERRID.ERR_VBCoreNetModuleConflict, + ERRID.ERR_InvalidFormatForGuidForOption, + ERRID.ERR_MissingGuidForOption, + ERRID.ERR_BadChecksumAlgorithm, + ERRID.ERR_MutuallyExclusiveOptions, + ERRID.ERR_BadSwitchValue, + ERRID.ERR_InvalidInNamespace, + ERRID.ERR_UndefinedType1, + ERRID.ERR_MissingNext, + ERRID.ERR_IllegalCharConstant, + ERRID.ERR_UnreferencedAssemblyEvent3, + ERRID.ERR_UnreferencedModuleEvent3, + ERRID.ERR_LbExpectedEndIf, + ERRID.ERR_LbNoMatchingIf, + ERRID.ERR_LbBadElseif, + ERRID.ERR_InheritsFromRestrictedType1, + ERRID.ERR_InvOutsideProc, + ERRID.ERR_DelegateCantImplement, + ERRID.ERR_DelegateCantHandleEvents, + ERRID.ERR_IsOperatorRequiresReferenceTypes1, + ERRID.ERR_TypeOfRequiresReferenceType1, + ERRID.ERR_ReadOnlyHasSet, + ERRID.ERR_WriteOnlyHasGet, + ERRID.ERR_InvInsideProc, + ERRID.ERR_EndProp, + ERRID.ERR_EndSubExpected, + ERRID.ERR_EndFunctionExpected, + ERRID.ERR_LbElseNoMatchingIf, + ERRID.ERR_CantRaiseBaseEvent, + ERRID.ERR_TryWithoutCatchOrFinally, + ERRID.ERR_EventsCantBeFunctions, + ERRID.ERR_MissingEndBrack, + ERRID.ERR_Syntax, + ERRID.ERR_Overflow, + ERRID.ERR_IllegalChar, + ERRID.ERR_StrictDisallowsObjectOperand1, + ERRID.ERR_LoopControlMustNotBeProperty, + ERRID.ERR_MethodBodyNotAtLineStart, + ERRID.ERR_MaximumNumberOfErrors, + ERRID.ERR_UseOfKeywordNotInInstanceMethod1, + ERRID.ERR_UseOfKeywordFromStructure1, + ERRID.ERR_BadAttributeConstructor1, + ERRID.ERR_ParamArrayWithOptArgs, + ERRID.ERR_ExpectedArray1, + ERRID.ERR_ParamArrayNotArray, + ERRID.ERR_ParamArrayRank, + ERRID.ERR_ArrayRankLimit, + ERRID.ERR_AsNewArray, + ERRID.ERR_TooManyArgs1, + ERRID.ERR_ExpectedCase, + ERRID.ERR_RequiredConstExpr, + ERRID.ERR_RequiredConstConversion2, + ERRID.ERR_InvalidMe, + ERRID.ERR_ReadOnlyAssignment, + ERRID.ERR_ExitSubOfFunc, + ERRID.ERR_ExitPropNot, + ERRID.ERR_ExitFuncOfSub, + ERRID.ERR_LValueRequired, + ERRID.ERR_ForIndexInUse1, + ERRID.ERR_NextForMismatch1, + ERRID.ERR_CaseElseNoSelect, + ERRID.ERR_CaseNoSelect, + ERRID.ERR_CantAssignToConst, + ERRID.ERR_NamedSubscript, + ERRID.ERR_ExpectedEndIf, + ERRID.ERR_ExpectedEndWhile, + ERRID.ERR_ExpectedLoop, + ERRID.ERR_ExpectedNext, + ERRID.ERR_ExpectedEndWith, + ERRID.ERR_ElseNoMatchingIf, + ERRID.ERR_EndIfNoMatchingIf, + ERRID.ERR_EndSelectNoSelect, + ERRID.ERR_ExitDoNotWithinDo, + ERRID.ERR_EndWhileNoWhile, + ERRID.ERR_LoopNoMatchingDo, + ERRID.ERR_NextNoMatchingFor, + ERRID.ERR_EndWithWithoutWith, + ERRID.ERR_MultiplyDefined1, + ERRID.ERR_ExpectedEndSelect, + ERRID.ERR_ExitForNotWithinFor, + ERRID.ERR_ExitWhileNotWithinWhile, + ERRID.ERR_ReadOnlyProperty1, + ERRID.ERR_ExitSelectNotWithinSelect, + ERRID.ERR_BranchOutOfFinally, + ERRID.ERR_QualNotObjectRecord1, + ERRID.ERR_TooFewIndices, + ERRID.ERR_TooManyIndices, + ERRID.ERR_EnumNotExpression1, + ERRID.ERR_TypeNotExpression1, + ERRID.ERR_ClassNotExpression1, + ERRID.ERR_StructureNotExpression1, + ERRID.ERR_InterfaceNotExpression1, + ERRID.ERR_NamespaceNotExpression1, + ERRID.ERR_BadNamespaceName1, + ERRID.ERR_XmlPrefixNotExpression, + ERRID.ERR_MultipleExtends, + ERRID.ERR_PropMustHaveGetSet, + ERRID.ERR_WriteOnlyHasNoWrite, + ERRID.ERR_ReadOnlyHasNoGet, + ERRID.ERR_BadAttribute1, + ERRID.ERR_LabelNotDefined1, + ERRID.ERR_ErrorCreatingWin32ResourceFile, + ERRID.ERR_UnableToCreateTempFile, + ERRID.ERR_RequiredNewCall2, + ERRID.ERR_UnimplementedMember3, + ERRID.ERR_BadWithRef, + ERRID.ERR_DuplicateAccessCategoryUsed, + ERRID.ERR_DuplicateModifierCategoryUsed, + ERRID.ERR_DuplicateSpecifier, + ERRID.ERR_TypeConflict6, + ERRID.ERR_UnrecognizedTypeKeyword, + ERRID.ERR_ExtraSpecifiers, + ERRID.ERR_UnrecognizedType, + ERRID.ERR_InvalidUseOfKeyword, + ERRID.ERR_InvalidEndEnum, + ERRID.ERR_MissingEndEnum, + ERRID.ERR_ExpectedDeclaration, + ERRID.ERR_ParamArrayMustBeLast, + ERRID.ERR_SpecifiersInvalidOnInheritsImplOpt, + ERRID.ERR_ExpectedSpecifier, + ERRID.ERR_ExpectedComma, + ERRID.ERR_ExpectedAs, + ERRID.ERR_ExpectedRparen, + ERRID.ERR_ExpectedLparen, + ERRID.ERR_InvalidNewInType, + ERRID.ERR_ExpectedExpression, + ERRID.ERR_ExpectedOptional, + ERRID.ERR_ExpectedIdentifier, + ERRID.ERR_ExpectedIntLiteral, + ERRID.ERR_ExpectedEOS, + ERRID.ERR_ExpectedForOptionStmt, + ERRID.ERR_InvalidOptionCompare, + ERRID.ERR_ExpectedOptionCompare, + ERRID.ERR_StrictDisallowImplicitObject, + ERRID.ERR_StrictDisallowsImplicitProc, + ERRID.ERR_StrictDisallowsImplicitArgs, + ERRID.ERR_InvalidParameterSyntax, + ERRID.ERR_ExpectedSubFunction, + ERRID.ERR_ExpectedStringLiteral, + ERRID.ERR_MissingLibInDeclare, + ERRID.ERR_DelegateNoInvoke1, + ERRID.ERR_MissingIsInTypeOf, + ERRID.ERR_DuplicateOption1, + ERRID.ERR_ModuleCantInherit, + ERRID.ERR_ModuleCantImplement, + ERRID.ERR_BadImplementsType, + ERRID.ERR_BadConstFlags1, + ERRID.ERR_BadWithEventsFlags1, + ERRID.ERR_BadDimFlags1, + ERRID.ERR_DuplicateParamName1, + ERRID.ERR_LoopDoubleCondition, + ERRID.ERR_ExpectedRelational, + ERRID.ERR_ExpectedExitKind, + ERRID.ERR_ExpectedNamedArgument, + ERRID.ERR_BadMethodFlags1, + ERRID.ERR_BadEventFlags1, + ERRID.ERR_BadDeclareFlags1, + ERRID.ERR_BadLocalConstFlags1, + ERRID.ERR_BadLocalDimFlags1, + ERRID.ERR_ExpectedConditionalDirective, + ERRID.ERR_ExpectedEQ, + ERRID.ERR_ConstructorNotFound1, + ERRID.ERR_InvalidEndInterface, + ERRID.ERR_MissingEndInterface, + ERRID.ERR_InheritsFrom2, + ERRID.ERR_InheritanceCycle1, + ERRID.ERR_InheritsFromNonClass, + ERRID.ERR_MultiplyDefinedType3, + ERRID.ERR_BadOverrideAccess2, + ERRID.ERR_CantOverrideNotOverridable2, + ERRID.ERR_DuplicateProcDef1, + ERRID.ERR_BadInterfaceMethodFlags1, + ERRID.ERR_NamedParamNotFound2, + ERRID.ERR_BadInterfacePropertyFlags1, + ERRID.ERR_NamedArgUsedTwice2, + ERRID.ERR_InterfaceCantUseEventSpecifier1, + ERRID.ERR_TypecharNoMatch2, + ERRID.ERR_ExpectedSubOrFunction, + ERRID.ERR_BadEmptyEnum1, + ERRID.ERR_InvalidConstructorCall, + ERRID.ERR_CantOverrideConstructor, + ERRID.ERR_OverrideNotNeeded3, + ERRID.ERR_ExpectedDot, + ERRID.ERR_DuplicateLocals1, + ERRID.ERR_InvInsideEndsProc, + ERRID.ERR_LocalSameAsFunc, + ERRID.ERR_RecordEmbeds2, + ERRID.ERR_RecordCycle2, + ERRID.ERR_InterfaceCycle1, + ERRID.ERR_SubNewCycle2, + ERRID.ERR_SubNewCycle1, + ERRID.ERR_InheritsFromCantInherit3, + ERRID.ERR_OverloadWithOptional2, + ERRID.ERR_OverloadWithReturnType2, + ERRID.ERR_TypeCharWithType1, + ERRID.ERR_TypeCharOnSub, + ERRID.ERR_OverloadWithDefault2, + ERRID.ERR_MissingSubscript, + ERRID.ERR_OverrideWithDefault2, + ERRID.ERR_OverrideWithOptional2, + ERRID.ERR_FieldOfValueFieldOfMarshalByRef3, + ERRID.ERR_TypeMismatch2, + ERRID.ERR_CaseAfterCaseElse, + ERRID.ERR_ConvertArrayMismatch4, + ERRID.ERR_ConvertObjectArrayMismatch3, + ERRID.ERR_ForLoopType1, + ERRID.ERR_OverloadWithByref2, + ERRID.ERR_InheritsFromNonInterface, + ERRID.ERR_BadInterfaceOrderOnInherits, + ERRID.ERR_DuplicateDefaultProps1, + ERRID.ERR_DefaultMissingFromProperty2, + ERRID.ERR_OverridingPropertyKind2, + ERRID.ERR_NewInInterface, + ERRID.ERR_BadFlagsOnNew1, + ERRID.ERR_OverloadingPropertyKind2, + ERRID.ERR_NoDefaultNotExtend1, + ERRID.ERR_OverloadWithArrayVsParamArray2, + ERRID.ERR_BadInstanceMemberAccess, + ERRID.ERR_ExpectedRbrace, + ERRID.ERR_ModuleAsType1, + ERRID.ERR_NewIfNullOnNonClass, + ERRID.ERR_CatchAfterFinally, + ERRID.ERR_CatchNoMatchingTry, + ERRID.ERR_FinallyAfterFinally, + ERRID.ERR_FinallyNoMatchingTry, + ERRID.ERR_EndTryNoTry, + ERRID.ERR_ExpectedEndTry, + ERRID.ERR_BadDelegateFlags1, + ERRID.ERR_NoConstructorOnBase2, + ERRID.ERR_InaccessibleSymbol2, + ERRID.ERR_InaccessibleMember3, + ERRID.ERR_CatchNotException1, + ERRID.ERR_ExitTryNotWithinTry, + ERRID.ERR_BadRecordFlags1, + ERRID.ERR_BadEnumFlags1, + ERRID.ERR_BadInterfaceFlags1, + ERRID.ERR_OverrideWithByref2, + ERRID.ERR_MyBaseAbstractCall1, + ERRID.ERR_IdentNotMemberOfInterface4, + ERRID.ERR_ImplementingInterfaceWithDifferentTupleNames5, + ERRID.ERR_WithEventsRequiresClass, + ERRID.ERR_WithEventsAsStruct, + ERRID.ERR_ConvertArrayRankMismatch2, + ERRID.ERR_RedimRankMismatch, + ERRID.ERR_StartupCodeNotFound1, + ERRID.ERR_ConstAsNonConstant, + ERRID.ERR_InvalidEndSub, + ERRID.ERR_InvalidEndFunction, + ERRID.ERR_InvalidEndProperty, + ERRID.ERR_ModuleCantUseMethodSpecifier1, + ERRID.ERR_ModuleCantUseEventSpecifier1, + ERRID.ERR_StructCantUseVarSpecifier1, + ERRID.ERR_InvalidOverrideDueToReturn2, + ERRID.ERR_ConstantWithNoValue, + ERRID.ERR_ExpressionOverflow1, + ERRID.ERR_DuplicatePropertyGet, + ERRID.ERR_DuplicatePropertySet, + ERRID.ERR_NameNotDeclared1, + ERRID.ERR_BinaryOperands3, + ERRID.ERR_ExpectedProcedure, + ERRID.ERR_OmittedArgument2, + ERRID.ERR_NameNotMember2, + ERRID.ERR_EndClassNoClass, + ERRID.ERR_BadClassFlags1, + ERRID.ERR_ImportsMustBeFirst, + ERRID.ERR_NonNamespaceOrClassOnImport2, + ERRID.ERR_TypecharNotallowed, + ERRID.ERR_ObjectReferenceNotSupplied, + ERRID.ERR_MyClassNotInClass, + ERRID.ERR_IndexedNotArrayOrProc, + ERRID.ERR_EventSourceIsArray, + ERRID.ERR_SharedConstructorWithParams, + ERRID.ERR_SharedConstructorIllegalSpec1, + ERRID.ERR_ExpectedEndClass, + ERRID.ERR_UnaryOperand2, + ERRID.ERR_BadFlagsWithDefault1, + ERRID.ERR_VoidValue, + ERRID.ERR_ConstructorFunction, + ERRID.ERR_InvalidLiteralExponent, + ERRID.ERR_NewCannotHandleEvents, + ERRID.ERR_CircularEvaluation1, + ERRID.ERR_BadFlagsOnSharedMeth1, + ERRID.ERR_BadFlagsOnSharedProperty1, + ERRID.ERR_BadFlagsOnStdModuleProperty1, + ERRID.ERR_SharedOnProcThatImpl, + ERRID.ERR_NoWithEventsVarOnHandlesList, + ERRID.ERR_AccessMismatch6, + ERRID.ERR_InheritanceAccessMismatch5, + ERRID.ERR_NarrowingConversionDisallowed2, + ERRID.ERR_NoArgumentCountOverloadCandidates1, + ERRID.ERR_NoViableOverloadCandidates1, + ERRID.ERR_NoCallableOverloadCandidates2, + ERRID.ERR_NoNonNarrowingOverloadCandidates2, + ERRID.ERR_ArgumentNarrowing3, + ERRID.ERR_NoMostSpecificOverload2, + ERRID.ERR_NotMostSpecificOverload, + ERRID.ERR_OverloadCandidate2, + ERRID.ERR_NoGetProperty1, + ERRID.ERR_NoSetProperty1, + ERRID.ERR_ParamTypingInconsistency, + ERRID.ERR_ParamNameFunctionNameCollision, + ERRID.ERR_DateToDoubleConversion, + ERRID.ERR_DoubleToDateConversion, + ERRID.ERR_ZeroDivide, + ERRID.ERR_TryAndOnErrorDoNotMix, + ERRID.ERR_PropertyAccessIgnored, + ERRID.ERR_InterfaceNoDefault1, + ERRID.ERR_InvalidAssemblyAttribute1, + ERRID.ERR_InvalidModuleAttribute1, + ERRID.ERR_AmbiguousInUnnamedNamespace1, + ERRID.ERR_DefaultMemberNotProperty1, + ERRID.ERR_AmbiguousInNamespace2, + ERRID.ERR_AmbiguousInImports2, + ERRID.ERR_AmbiguousInModules2, + ERRID.ERR_ArrayInitializerTooFewDimensions, + ERRID.ERR_ArrayInitializerTooManyDimensions, + ERRID.ERR_InitializerTooFewElements1, + ERRID.ERR_InitializerTooManyElements1, + ERRID.ERR_NewOnAbstractClass, + ERRID.ERR_DuplicateNamedImportAlias1, + ERRID.ERR_DuplicatePrefix, + ERRID.ERR_StrictDisallowsLateBinding, + ERRID.ERR_AddressOfOperandNotMethod, + ERRID.ERR_EndExternalSource, + ERRID.ERR_ExpectedEndExternalSource, + ERRID.ERR_NestedExternalSource, + ERRID.ERR_AddressOfNotDelegate1, + ERRID.ERR_SyncLockRequiresReferenceType1, + ERRID.ERR_MethodAlreadyImplemented2, + ERRID.ERR_DuplicateInInherits1, + ERRID.ERR_NamedParamArrayArgument, + ERRID.ERR_OmittedParamArrayArgument, + ERRID.ERR_ParamArrayArgumentMismatch, + ERRID.ERR_EventNotFound1, + ERRID.ERR_ModuleCantUseVariableSpecifier1, + ERRID.ERR_SharedEventNeedsSharedHandler, + ERRID.ERR_ExpectedMinus, + ERRID.ERR_InterfaceMemberSyntax, + ERRID.ERR_InvInsideInterface, + ERRID.ERR_InvInsideEndsInterface, + ERRID.ERR_BadFlagsInNotInheritableClass1, + ERRID.ERR_UnimplementedMustOverride, + ERRID.ERR_BaseOnlyClassesMustBeExplicit2, + ERRID.ERR_NegativeArraySize, + ERRID.ERR_MyClassAbstractCall1, + ERRID.ERR_EndDisallowedInDllProjects, + ERRID.ERR_BlockLocalShadowing1, + ERRID.ERR_ModuleNotAtNamespace, + ERRID.ERR_NamespaceNotAtNamespace, + ERRID.ERR_InvInsideEndsEnum, + ERRID.ERR_InvalidOptionStrict, + ERRID.ERR_EndStructureNoStructure, + ERRID.ERR_EndModuleNoModule, + ERRID.ERR_EndNamespaceNoNamespace, + ERRID.ERR_ExpectedEndStructure, + ERRID.ERR_ExpectedEndModule, + ERRID.ERR_ExpectedEndNamespace, + ERRID.ERR_OptionStmtWrongOrder, + ERRID.ERR_StructCantInherit, + ERRID.ERR_NewInStruct, + ERRID.ERR_InvalidEndGet, + ERRID.ERR_MissingEndGet, + ERRID.ERR_InvalidEndSet, + ERRID.ERR_MissingEndSet, + ERRID.ERR_InvInsideEndsProperty, + ERRID.ERR_DuplicateWriteabilityCategoryUsed, + ERRID.ERR_ExpectedGreater, + ERRID.ERR_AttributeStmtWrongOrder, + ERRID.ERR_NoExplicitArraySizes, + ERRID.ERR_BadPropertyFlags1, + ERRID.ERR_InvalidOptionExplicit, + ERRID.ERR_MultipleParameterSpecifiers, + ERRID.ERR_MultipleOptionalParameterSpecifiers, + ERRID.ERR_UnsupportedProperty1, + ERRID.ERR_InvalidOptionalParameterUsage1, + ERRID.ERR_ReturnFromNonFunction, + ERRID.ERR_UnterminatedStringLiteral, + ERRID.ERR_UnsupportedType1, + ERRID.ERR_InvalidEnumBase, + ERRID.ERR_ByRefIllegal1, + ERRID.ERR_UnreferencedAssembly3, + ERRID.ERR_UnreferencedModule3, + ERRID.ERR_ReturnWithoutValue, + ERRID.ERR_UnsupportedField1, + ERRID.ERR_UnsupportedMethod1, + ERRID.ERR_NoNonIndexProperty1, + ERRID.ERR_BadAttributePropertyType1, + ERRID.ERR_LocalsCannotHaveAttributes, + ERRID.ERR_PropertyOrFieldNotDefined1, + ERRID.ERR_InvalidAttributeUsage2, + ERRID.ERR_InvalidMultipleAttributeUsage1, + ERRID.ERR_CantThrowNonException, + ERRID.ERR_MustBeInCatchToRethrow, + ERRID.ERR_ParamArrayMustBeByVal, + ERRID.ERR_UseOfObsoleteSymbol2, + ERRID.ERR_RedimNoSizes, + ERRID.ERR_InitWithMultipleDeclarators, + ERRID.ERR_InitWithExplicitArraySizes, + ERRID.ERR_EndSyncLockNoSyncLock, + ERRID.ERR_ExpectedEndSyncLock, + ERRID.ERR_NameNotEvent2, + ERRID.ERR_AddOrRemoveHandlerEvent, + ERRID.ERR_UnrecognizedEnd, + ERRID.ERR_ArrayInitForNonArray2, + ERRID.ERR_EndRegionNoRegion, + ERRID.ERR_ExpectedEndRegion, + ERRID.ERR_InheritsStmtWrongOrder, + ERRID.ERR_AmbiguousAcrossInterfaces3, + ERRID.ERR_DefaultPropertyAmbiguousAcrossInterfaces4, + ERRID.ERR_InterfaceEventCantUse1, + ERRID.ERR_ExecutableAsDeclaration, + ERRID.ERR_StructureNoDefault1, + ERRID.ERR_MustShadow2, + ERRID.ERR_OverrideWithOptionalTypes2, + ERRID.ERR_ExpectedEndOfExpression, + ERRID.ERR_StructsCannotHandleEvents, + ERRID.ERR_OverridesImpliesOverridable, + ERRID.ERR_LocalNamedSameAsParam1, + ERRID.ERR_ModuleCantUseTypeSpecifier1, + ERRID.ERR_InValidSubMainsFound1, + ERRID.ERR_MoreThanOneValidMainWasFound2, + ERRID.ERR_CannotConvertValue2, + ERRID.ERR_OnErrorInSyncLock, + ERRID.ERR_NarrowingConversionCollection2, + ERRID.ERR_GotoIntoTryHandler, + ERRID.ERR_GotoIntoSyncLock, + ERRID.ERR_GotoIntoWith, + ERRID.ERR_GotoIntoFor, + ERRID.ERR_BadAttributeNonPublicConstructor, + ERRID.ERR_DefaultEventNotFound1, + ERRID.ERR_InvalidNonSerializedUsage, + ERRID.ERR_ExpectedContinueKind, + ERRID.ERR_ContinueDoNotWithinDo, + ERRID.ERR_ContinueForNotWithinFor, + ERRID.ERR_ContinueWhileNotWithinWhile, + ERRID.ERR_DuplicateParameterSpecifier, + ERRID.ERR_ModuleCantUseDLLDeclareSpecifier1, + ERRID.ERR_StructCantUseDLLDeclareSpecifier1, + ERRID.ERR_TryCastOfValueType1, + ERRID.ERR_TryCastOfUnconstrainedTypeParam1, + ERRID.ERR_AmbiguousDelegateBinding2, + ERRID.ERR_SharedStructMemberCannotSpecifyNew, + ERRID.ERR_GenericSubMainsFound1, + ERRID.ERR_GeneralProjectImportsError3, + ERRID.ERR_InvalidTypeForAliasesImport2, + ERRID.ERR_UnsupportedConstant2, + ERRID.ERR_ObsoleteArgumentsNeedParens, + ERRID.ERR_ObsoleteLineNumbersAreLabels, + ERRID.ERR_ObsoleteStructureNotType, + ERRID.ERR_ObsoleteObjectNotVariant, + ERRID.ERR_ObsoleteLetSetNotNeeded, + ERRID.ERR_ObsoletePropertyGetLetSet, + ERRID.ERR_ObsoleteWhileWend, + ERRID.ERR_ObsoleteRedimAs, + ERRID.ERR_ObsoleteOptionalWithoutValue, + ERRID.ERR_ObsoleteGosub, + ERRID.ERR_ObsoleteOnGotoGosub, + ERRID.ERR_ObsoleteEndIf, + ERRID.ERR_ObsoleteExponent, + ERRID.ERR_ObsoleteAsAny, + ERRID.ERR_ObsoleteGetStatement, + ERRID.ERR_OverrideWithArrayVsParamArray2, + ERRID.ERR_CircularBaseDependencies4, + ERRID.ERR_NestedBase2, + ERRID.ERR_AccessMismatchOutsideAssembly4, + ERRID.ERR_InheritanceAccessMismatchOutside3, + ERRID.ERR_UseOfObsoletePropertyAccessor3, + ERRID.ERR_UseOfObsoletePropertyAccessor2, + ERRID.ERR_AccessMismatchImplementedEvent6, + ERRID.ERR_AccessMismatchImplementedEvent4, + ERRID.ERR_InheritanceCycleInImportedType1, + ERRID.ERR_NoNonObsoleteConstructorOnBase3, + ERRID.ERR_NoNonObsoleteConstructorOnBase4, + ERRID.ERR_RequiredNonObsoleteNewCall3, + ERRID.ERR_RequiredNonObsoleteNewCall4, + ERRID.ERR_InheritsTypeArgAccessMismatch7, + ERRID.ERR_InheritsTypeArgAccessMismatchOutside5, + ERRID.ERR_PartialTypeAccessMismatch3, + ERRID.ERR_PartialTypeBadMustInherit1, + ERRID.ERR_MustOverOnNotInheritPartClsMem1, + ERRID.ERR_BaseMismatchForPartialClass3, + ERRID.ERR_PartialTypeTypeParamNameMismatch3, + ERRID.ERR_PartialTypeConstraintMismatch1, + ERRID.ERR_LateBoundOverloadInterfaceCall1, + ERRID.ERR_RequiredAttributeConstConversion2, + ERRID.ERR_AmbiguousOverrides3, + ERRID.ERR_OverriddenCandidate1, + ERRID.ERR_AmbiguousImplements3, + ERRID.ERR_AddressOfNotCreatableDelegate1, + ERRID.ERR_ComClassGenericMethod, + ERRID.ERR_SyntaxInCastOp, + ERRID.ERR_ArrayInitializerForNonConstDim, + ERRID.ERR_DelegateBindingFailure3, + ERRID.ERR_StructLayoutAttributeNotAllowed, + ERRID.ERR_IterationVariableShadowLocal1, + ERRID.ERR_InvalidOptionInfer, + ERRID.ERR_CircularInference1, + ERRID.ERR_InAccessibleOverridingMethod5, + ERRID.ERR_NoSuitableWidestType1, + ERRID.ERR_AmbiguousWidestType3, + ERRID.ERR_ExpectedAssignmentOperatorInInit, + ERRID.ERR_ExpectedQualifiedNameInInit, + ERRID.ERR_ExpectedLbrace, + ERRID.ERR_UnrecognizedTypeOrWith, + ERRID.ERR_DuplicateAggrMemberInit1, + ERRID.ERR_NonFieldPropertyAggrMemberInit1, + ERRID.ERR_SharedMemberAggrMemberInit1, + ERRID.ERR_ParameterizedPropertyInAggrInit1, + ERRID.ERR_NoZeroCountArgumentInitCandidates1, + ERRID.ERR_AggrInitInvalidForObject, + ERRID.ERR_InitializerExpected, + ERRID.ERR_LineContWithCommentOrNoPrecSpace, + ERRID.ERR_InvInsideEnum, + ERRID.ERR_InvInsideBlock, + ERRID.ERR_UnexpectedExpressionStatement, + ERRID.ERR_WinRTEventWithoutDelegate, + ERRID.ERR_SecurityCriticalAsyncInClassOrStruct, + ERRID.ERR_SecurityCriticalAsync, + ERRID.ERR_BadModuleFile1, + ERRID.ERR_BadRefLib1, + ERRID.ERR_EventHandlerSignatureIncompatible2, + ERRID.ERR_ConditionalCompilationConstantNotValid, + ERRID.ERR_InterfaceImplementedTwice1, + ERRID.ERR_InterfaceNotImplemented1, + ERRID.ERR_AmbiguousImplementsMember3, + ERRID.ERR_ImplementsOnNew, + ERRID.ERR_ArrayInitInStruct, + ERRID.ERR_EventTypeNotDelegate, + ERRID.ERR_ProtectedTypeOutsideClass, + ERRID.ERR_DefaultPropertyWithNoParams, + ERRID.ERR_InitializerInStruct, + ERRID.ERR_DuplicateImport1, + ERRID.ERR_BadModuleFlags1, + ERRID.ERR_ImplementsStmtWrongOrder, + ERRID.ERR_MemberConflictWithSynth4, + ERRID.ERR_SynthMemberClashesWithSynth7, + ERRID.ERR_SynthMemberClashesWithMember5, + ERRID.ERR_MemberClashesWithSynth6, + ERRID.ERR_SetHasOnlyOneParam, + ERRID.ERR_SetValueNotPropertyType, + ERRID.ERR_SetHasToBeByVal1, + ERRID.ERR_StructureCantUseProtected, + ERRID.ERR_BadInterfaceDelegateSpecifier1, + ERRID.ERR_BadInterfaceEnumSpecifier1, + ERRID.ERR_BadInterfaceClassSpecifier1, + ERRID.ERR_BadInterfaceStructSpecifier1, + ERRID.ERR_UseOfObsoleteSymbolNoMessage1, + ERRID.ERR_MetaDataIsNotAssembly, + ERRID.ERR_MetaDataIsNotModule, + ERRID.ERR_ReferenceComparison3, + ERRID.ERR_CatchVariableNotLocal1, + ERRID.ERR_ModuleMemberCantImplement, + ERRID.ERR_EventDelegatesCantBeFunctions, + ERRID.ERR_InvalidDate, + ERRID.ERR_CantOverride4, + ERRID.ERR_CantSpecifyArraysOnBoth, + ERRID.ERR_NotOverridableRequiresOverrides, + ERRID.ERR_PrivateTypeOutsideType, + ERRID.ERR_ParamArrayWrongType, + ERRID.ERR_CoClassMissing2, + ERRID.ERR_InvalidMeReference, + ERRID.ERR_InvalidImplicitMeReference, + ERRID.ERR_RuntimeMemberNotFound2, + ERRID.ERR_BadPropertyAccessorFlags, + ERRID.ERR_BadPropertyAccessorFlagsRestrict, + ERRID.ERR_OnlyOneAccessorForGetSet, + ERRID.ERR_NoAccessibleSet, + ERRID.ERR_NoAccessibleGet, + ERRID.ERR_WriteOnlyNoAccessorFlag, + ERRID.ERR_ReadOnlyNoAccessorFlag, + ERRID.ERR_BadPropertyAccessorFlags1, + ERRID.ERR_BadPropertyAccessorFlags2, + ERRID.ERR_BadPropertyAccessorFlags3, + ERRID.ERR_InAccessibleCoClass3, + ERRID.ERR_MissingValuesForArraysInApplAttrs, + ERRID.ERR_ExitEventMemberNotInvalid, + ERRID.ERR_InvInsideEndsEvent, + ERRID.ERR_MissingEndEvent, + ERRID.ERR_MissingEndAddHandler, + ERRID.ERR_MissingEndRemoveHandler, + ERRID.ERR_MissingEndRaiseEvent, + ERRID.ERR_CustomEventInvInInterface, + ERRID.ERR_CustomEventRequiresAs, + ERRID.ERR_InvalidEndEvent, + ERRID.ERR_InvalidEndAddHandler, + ERRID.ERR_InvalidEndRemoveHandler, + ERRID.ERR_InvalidEndRaiseEvent, + ERRID.ERR_DuplicateAddHandlerDef, + ERRID.ERR_DuplicateRemoveHandlerDef, + ERRID.ERR_DuplicateRaiseEventDef, + ERRID.ERR_MissingAddHandlerDef1, + ERRID.ERR_MissingRemoveHandlerDef1, + ERRID.ERR_MissingRaiseEventDef1, + ERRID.ERR_EventAddRemoveHasOnlyOneParam, + ERRID.ERR_EventAddRemoveByrefParamIllegal, + ERRID.ERR_SpecifiersInvOnEventMethod, + ERRID.ERR_AddRemoveParamNotEventType, + ERRID.ERR_RaiseEventShapeMismatch1, + ERRID.ERR_EventMethodOptionalParamIllegal1, + ERRID.ERR_CantReferToMyGroupInsideGroupType1, + ERRID.ERR_InvalidUseOfCustomModifier, + ERRID.ERR_InvalidOptionStrictCustom, + ERRID.ERR_ObsoleteInvalidOnEventMember, + ERRID.ERR_DelegateBindingIncompatible2, + ERRID.ERR_ExpectedXmlName, + ERRID.ERR_UndefinedXmlPrefix, + ERRID.ERR_DuplicateXmlAttribute, + ERRID.ERR_MismatchedXmlEndTag, + ERRID.ERR_MissingXmlEndTag, + ERRID.ERR_ReservedXmlPrefix, + ERRID.ERR_MissingVersionInXmlDecl, + ERRID.ERR_IllegalAttributeInXmlDecl, + ERRID.ERR_QuotedEmbeddedExpression, + ERRID.ERR_VersionMustBeFirstInXmlDecl, + ERRID.ERR_AttributeOrder, + ERRID.ERR_ExpectedXmlEndEmbedded, + ERRID.ERR_ExpectedXmlEndPI, + ERRID.ERR_ExpectedXmlEndComment, + ERRID.ERR_ExpectedXmlEndCData, + ERRID.ERR_ExpectedSQuote, + ERRID.ERR_ExpectedQuote, + ERRID.ERR_ExpectedLT, + ERRID.ERR_StartAttributeValue, + ERRID.ERR_ExpectedDiv, + ERRID.ERR_NoXmlAxesLateBinding, + ERRID.ERR_IllegalXmlStartNameChar, + ERRID.ERR_IllegalXmlNameChar, + ERRID.ERR_IllegalXmlCommentChar, + ERRID.ERR_EmbeddedExpression, + ERRID.ERR_ExpectedXmlWhiteSpace, + ERRID.ERR_IllegalProcessingInstructionName, + ERRID.ERR_DTDNotSupported, + ERRID.ERR_IllegalXmlWhiteSpace, + ERRID.ERR_ExpectedSColon, + ERRID.ERR_ExpectedXmlBeginEmbedded, + ERRID.ERR_XmlEntityReference, + ERRID.ERR_InvalidAttributeValue1, + ERRID.ERR_InvalidAttributeValue2, + ERRID.ERR_ReservedXmlNamespace, + ERRID.ERR_IllegalDefaultNamespace, + ERRID.ERR_QualifiedNameNotAllowed, + ERRID.ERR_ExpectedXmlns, + ERRID.ERR_IllegalXmlnsPrefix, + ERRID.ERR_XmlFeaturesNotAvailable, + ERRID.ERR_UnableToReadUacManifest2, + ERRID.ERR_TypeMismatchForXml3, + ERRID.ERR_BinaryOperandsForXml4, + ERRID.ERR_FullWidthAsXmlDelimiter, + ERRID.ERR_XmlEndCDataNotAllowedInContent, + ERRID.ERR_EventImplRemoveHandlerParamWrong, + ERRID.ERR_MixingWinRTAndNETEvents, + ERRID.ERR_AddParamWrongForWinRT, + ERRID.ERR_RemoveParamWrongForWinRT, + ERRID.ERR_ReImplementingWinRTInterface5, + ERRID.ERR_ReImplementingWinRTInterface4, + ERRID.ERR_XmlEndElementNoMatchingStart, + ERRID.ERR_UndefinedTypeOrNamespace1, + ERRID.ERR_BadInterfaceInterfaceSpecifier1, + ERRID.ERR_TypeClashesWithVbCoreType4, + ERRID.ERR_SecurityAttributeMissingAction, + ERRID.ERR_SecurityAttributeInvalidAction, + ERRID.ERR_SecurityAttributeInvalidActionAssembly, + ERRID.ERR_SecurityAttributeInvalidActionTypeOrMethod, + ERRID.ERR_PrincipalPermissionInvalidAction, + ERRID.ERR_PermissionSetAttributeInvalidFile, + ERRID.ERR_PermissionSetAttributeFileReadError, + ERRID.ERR_ExpectedWarningKeyword, + ERRID.ERR_InvalidHashAlgorithmName, + ERRID.ERR_InvalidSubsystemVersion, + ERRID.ERR_LibAnycpu32bitPreferredConflict, + ERRID.ERR_RestrictedAccess, + ERRID.ERR_RestrictedConversion1, + ERRID.ERR_NoTypecharInLabel, + ERRID.ERR_RestrictedType1, + ERRID.ERR_NoTypecharInAlias, + ERRID.ERR_NoAccessibleConstructorOnBase, + ERRID.ERR_BadStaticLocalInStruct, + ERRID.ERR_DuplicateLocalStatic1, + ERRID.ERR_ImportAliasConflictsWithType2, + ERRID.ERR_CantShadowAMustOverride1, + ERRID.ERR_MultipleEventImplMismatch3, + ERRID.ERR_BadSpecifierCombo2, + ERRID.ERR_MustBeOverloads2, + ERRID.ERR_MustOverridesInClass1, + ERRID.ERR_HandlesSyntaxInClass, + ERRID.ERR_SynthMemberShadowsMustOverride5, + ERRID.ERR_CannotOverrideInAccessibleMember, + ERRID.ERR_HandlesSyntaxInModule, + ERRID.ERR_IsNotOpRequiresReferenceTypes1, + ERRID.ERR_ClashWithReservedEnumMember1, + ERRID.ERR_MultiplyDefinedEnumMember2, + ERRID.ERR_BadUseOfVoid, + ERRID.ERR_EventImplMismatch5, + ERRID.ERR_ForwardedTypeUnavailable3, + ERRID.ERR_TypeFwdCycle2, + ERRID.ERR_BadTypeInCCExpression, + ERRID.ERR_BadCCExpression, + ERRID.ERR_VoidArrayDisallowed, + ERRID.ERR_MetadataMembersAmbiguous3, + ERRID.ERR_TypeOfExprAlwaysFalse2, + ERRID.ERR_OnlyPrivatePartialMethods1, + ERRID.ERR_PartialMethodsMustBePrivate, + ERRID.ERR_OnlyOnePartialMethodAllowed2, + ERRID.ERR_OnlyOneImplementingMethodAllowed3, + ERRID.ERR_PartialMethodMustBeEmpty, + ERRID.ERR_PartialMethodsMustBeSub1, + ERRID.ERR_PartialMethodGenericConstraints2, + ERRID.ERR_PartialDeclarationImplements1, + ERRID.ERR_NoPartialMethodInAddressOf1, + ERRID.ERR_ImplementationMustBePrivate2, + ERRID.ERR_PartialMethodParamNamesMustMatch3, + ERRID.ERR_PartialMethodTypeParamNameMismatch3, + ERRID.ERR_PropertyDoesntImplementAllAccessors, + ERRID.ERR_InvalidAttributeUsageOnAccessor, + ERRID.ERR_NestedTypeInInheritsClause2, + ERRID.ERR_TypeInItsInheritsClause1, + ERRID.ERR_BaseTypeReferences2, + ERRID.ERR_IllegalBaseTypeReferences3, + ERRID.ERR_InvalidCoClass1, + ERRID.ERR_InvalidOutputName, + ERRID.ERR_InvalidFileAlignment, + ERRID.ERR_InvalidDebugInformationFormat, + ERRID.ERR_ConstantStringTooLong, + ERRID.ERR_MustInheritEventNotOverridden, + ERRID.ERR_BadAttributeSharedProperty1, + ERRID.ERR_BadAttributeReadOnlyProperty1, + ERRID.ERR_DuplicateResourceName1, + ERRID.ERR_AttributeMustBeClassNotStruct1, + ERRID.ERR_AttributeMustInheritSysAttr, + ERRID.ERR_AttributeCannotBeAbstract, + ERRID.ERR_UnableToOpenResourceFile1, + ERRID.ERR_BadAttributeNonPublicProperty1, + ERRID.ERR_STAThreadAndMTAThread0, + ERRID.ERR_IndirectUnreferencedAssembly4, + ERRID.ERR_BadAttributeNonPublicType1, + ERRID.ERR_BadAttributeNonPublicContType2, + ERRID.ERR_BadMetaDataReference1, + ERRID.ERR_DllImportOnNonEmptySubOrFunction, + ERRID.ERR_DllImportNotLegalOnDeclare, + ERRID.ERR_DllImportNotLegalOnGetOrSet, + ERRID.ERR_DllImportOnGenericSubOrFunction, + ERRID.ERR_ComClassOnGeneric, + ERRID.ERR_DllImportOnInstanceMethod, + ERRID.ERR_DllImportOnInterfaceMethod, + ERRID.ERR_DllImportNotLegalOnEventMethod, + ERRID.ERR_FriendAssemblyBadArguments, + ERRID.ERR_FriendAssemblyStrongNameRequired, + ERRID.ERR_FriendAssemblyNameInvalid, + ERRID.ERR_FriendAssemblyBadAccessOverride2, + ERRID.ERR_AbsentReferenceToPIA1, + ERRID.ERR_CannotLinkClassWithNoPIA1, + ERRID.ERR_InvalidStructMemberNoPIA1, + ERRID.ERR_NoPIAAttributeMissing2, + ERRID.ERR_NestedGlobalNamespace, + ERRID.ERR_PIAHasNoAssemblyGuid1, + ERRID.ERR_DuplicateLocalTypes3, + ERRID.ERR_PIAHasNoTypeLibAttribute1, + ERRID.ERR_SourceInterfaceMustBeInterface, + ERRID.ERR_EventNoPIANoBackingMember, + ERRID.ERR_NestedInteropType, + ERRID.ERR_IsNestedIn2, + ERRID.ERR_LocalTypeNameClash2, + ERRID.ERR_InteropMethodWithBody1, + ERRID.ERR_UseOfLocalBeforeDeclaration1, + ERRID.ERR_UseOfKeywordFromModule1, + ERRID.ERR_BogusWithinLineIf, + ERRID.ERR_CharToIntegralTypeMismatch1, + ERRID.ERR_IntegralToCharTypeMismatch1, + ERRID.ERR_NoDirectDelegateConstruction1, + ERRID.ERR_MethodMustBeFirstStatementOnLine, + ERRID.ERR_AttrAssignmentNotFieldOrProp1, + ERRID.ERR_StrictDisallowsObjectComparison1, + ERRID.ERR_NoConstituentArraySizes, + ERRID.ERR_FileAttributeNotAssemblyOrModule, + ERRID.ERR_FunctionResultCannotBeIndexed1, + ERRID.ERR_ArgumentSyntax, + ERRID.ERR_ExpectedResumeOrGoto, + ERRID.ERR_ExpectedAssignmentOperator, + ERRID.ERR_NamedArgAlsoOmitted2, + ERRID.ERR_CannotCallEvent1, + ERRID.ERR_ForEachCollectionDesignPattern1, + ERRID.ERR_DefaultValueForNonOptionalParam, + ERRID.ERR_ExpectedDotAfterMyBase, + ERRID.ERR_ExpectedDotAfterMyClass, + ERRID.ERR_StrictArgumentCopyBackNarrowing3, + ERRID.ERR_LbElseifAfterElse, + ERRID.ERR_StandaloneAttribute, + ERRID.ERR_NoUniqueConstructorOnBase2, + ERRID.ERR_ExtraNextVariable, + ERRID.ERR_RequiredNewCallTooMany2, + ERRID.ERR_ForCtlVarArraySizesSpecified, + ERRID.ERR_BadFlagsOnNewOverloads, + ERRID.ERR_TypeCharOnGenericParam, + ERRID.ERR_TooFewGenericArguments1, + ERRID.ERR_TooManyGenericArguments1, + ERRID.ERR_GenericConstraintNotSatisfied2, + ERRID.ERR_TypeOrMemberNotGeneric1, + ERRID.ERR_NewIfNullOnGenericParam, + ERRID.ERR_MultipleClassConstraints1, + ERRID.ERR_ConstNotClassInterfaceOrTypeParam1, + ERRID.ERR_DuplicateTypeParamName1, + ERRID.ERR_UnboundTypeParam2, + ERRID.ERR_IsOperatorGenericParam1, + ERRID.ERR_ArgumentCopyBackNarrowing3, + ERRID.ERR_ShadowingGenericParamWithMember1, + ERRID.ERR_GenericParamBase2, + ERRID.ERR_ImplementsGenericParam, + ERRID.ERR_OnlyNullLowerBound, + ERRID.ERR_ClassConstraintNotInheritable1, + ERRID.ERR_ConstraintIsRestrictedType1, + ERRID.ERR_GenericParamsOnInvalidMember, + ERRID.ERR_GenericArgsOnAttributeSpecifier, + ERRID.ERR_AttrCannotBeGenerics, + ERRID.ERR_BadStaticLocalInGenericMethod, + ERRID.ERR_SyntMemberShadowsGenericParam3, + ERRID.ERR_ConstraintAlreadyExists1, + ERRID.ERR_InterfacePossiblyImplTwice2, + ERRID.ERR_ModulesCannotBeGeneric, + ERRID.ERR_GenericClassCannotInheritAttr, + ERRID.ERR_DeclaresCantBeInGeneric, + ERRID.ERR_OverrideWithConstraintMismatch2, + ERRID.ERR_ImplementsWithConstraintMismatch3, + ERRID.ERR_OpenTypeDisallowed, + ERRID.ERR_HandlesInvalidOnGenericMethod, + ERRID.ERR_MultipleNewConstraints, + ERRID.ERR_MustInheritForNewConstraint2, + ERRID.ERR_NoSuitableNewForNewConstraint2, + ERRID.ERR_BadGenericParamForNewConstraint2, + ERRID.ERR_NewArgsDisallowedForTypeParam, + ERRID.ERR_DuplicateRawGenericTypeImport1, + ERRID.ERR_NoTypeArgumentCountOverloadCand1, + ERRID.ERR_TypeArgsUnexpected, + ERRID.ERR_NameSameAsMethodTypeParam1, + ERRID.ERR_TypeParamNameFunctionNameCollision, + ERRID.ERR_BadConstraintSyntax, + ERRID.ERR_OfExpected, + ERRID.ERR_ArrayOfRawGenericInvalid, + ERRID.ERR_ForEachAmbiguousIEnumerable1, + ERRID.ERR_IsNotOperatorGenericParam1, + ERRID.ERR_TypeParamQualifierDisallowed, + ERRID.ERR_TypeParamMissingCommaOrRParen, + ERRID.ERR_TypeParamMissingAsCommaOrRParen, + ERRID.ERR_MultipleReferenceConstraints, + ERRID.ERR_MultipleValueConstraints, + ERRID.ERR_NewAndValueConstraintsCombined, + ERRID.ERR_RefAndValueConstraintsCombined, + ERRID.ERR_BadTypeArgForStructConstraint2, + ERRID.ERR_BadTypeArgForRefConstraint2, + ERRID.ERR_RefAndClassTypeConstrCombined, + ERRID.ERR_ValueAndClassTypeConstrCombined, + ERRID.ERR_ConstraintClashIndirectIndirect4, + ERRID.ERR_ConstraintClashDirectIndirect3, + ERRID.ERR_ConstraintClashIndirectDirect3, + ERRID.ERR_ConstraintCycleLink2, + ERRID.ERR_ConstraintCycle2, + ERRID.ERR_TypeParamWithStructConstAsConst, + ERRID.ERR_NullableDisallowedForStructConstr1, + ERRID.ERR_ConflictingDirectConstraints3, + ERRID.ERR_InterfaceUnifiesWithInterface2, + ERRID.ERR_BaseUnifiesWithInterfaces3, + ERRID.ERR_InterfaceBaseUnifiesWithBase4, + ERRID.ERR_InterfaceUnifiesWithBase3, + ERRID.ERR_OptionalsCantBeStructGenericParams, + ERRID.ERR_AddressOfNullableMethod, + ERRID.ERR_IsOperatorNullable1, + ERRID.ERR_IsNotOperatorNullable1, + ERRID.ERR_ClassInheritsBaseUnifiesWithInterfaces3, + ERRID.ERR_ClassInheritsInterfaceBaseUnifiesWithBase4, + ERRID.ERR_ClassInheritsInterfaceUnifiesWithBase3, + ERRID.ERR_ShadowingTypeOutsideClass1, + ERRID.ERR_PropertySetParamCollisionWithValue, + ERRID.ERR_SxSIndirectRefHigherThanDirectRef3, + ERRID.ERR_DuplicateReference2, + ERRID.ERR_DuplicateReferenceStrong, + ERRID.ERR_IllegalCallOrIndex, + ERRID.ERR_ConflictDefaultPropertyAttribute, + ERRID.ERR_BadAttributeUuid2, + ERRID.ERR_ComClassAndReservedAttribute1, + ERRID.ERR_ComClassRequiresPublicClass2, + ERRID.ERR_ComClassReservedDispIdZero1, + ERRID.ERR_ComClassReservedDispId1, + ERRID.ERR_ComClassDuplicateGuids1, + ERRID.ERR_ComClassCantBeAbstract0, + ERRID.ERR_ComClassRequiresPublicClass1, + ERRID.ERR_UnknownOperator, + ERRID.ERR_DuplicateConversionCategoryUsed, + ERRID.ERR_OperatorNotOverloadable, + ERRID.ERR_InvalidHandles, + ERRID.ERR_InvalidImplements, + ERRID.ERR_EndOperatorExpected, + ERRID.ERR_EndOperatorNotAtLineStart, + ERRID.ERR_InvalidEndOperator, + ERRID.ERR_ExitOperatorNotValid, + ERRID.ERR_ParamArrayIllegal1, + ERRID.ERR_OptionalIllegal1, + ERRID.ERR_OperatorMustBePublic, + ERRID.ERR_OperatorMustBeShared, + ERRID.ERR_BadOperatorFlags1, + ERRID.ERR_OneParameterRequired1, + ERRID.ERR_TwoParametersRequired1, + ERRID.ERR_OneOrTwoParametersRequired1, + ERRID.ERR_ConvMustBeWideningOrNarrowing, + ERRID.ERR_OperatorDeclaredInModule, + ERRID.ERR_InvalidSpecifierOnNonConversion1, + ERRID.ERR_UnaryParamMustBeContainingType1, + ERRID.ERR_BinaryParamMustBeContainingType1, + ERRID.ERR_ConvParamMustBeContainingType1, + ERRID.ERR_OperatorRequiresBoolReturnType1, + ERRID.ERR_ConversionToSameType, + ERRID.ERR_ConversionToInterfaceType, + ERRID.ERR_ConversionToBaseType, + ERRID.ERR_ConversionToDerivedType, + ERRID.ERR_ConversionToObject, + ERRID.ERR_ConversionFromInterfaceType, + ERRID.ERR_ConversionFromBaseType, + ERRID.ERR_ConversionFromDerivedType, + ERRID.ERR_ConversionFromObject, + ERRID.ERR_MatchingOperatorExpected2, + ERRID.ERR_UnacceptableLogicalOperator3, + ERRID.ERR_ConditionOperatorRequired3, + ERRID.ERR_CopyBackTypeMismatch3, + ERRID.ERR_ForLoopOperatorRequired2, + ERRID.ERR_UnacceptableForLoopOperator2, + ERRID.ERR_UnacceptableForLoopRelOperator2, + ERRID.ERR_OperatorRequiresIntegerParameter1, + ERRID.ERR_CantSpecifyNullableOnBoth, + ERRID.ERR_BadTypeArgForStructConstraintNull, + ERRID.ERR_CantSpecifyArrayAndNullableOnBoth, + ERRID.ERR_CantSpecifyTypeCharacterOnIIF, + ERRID.ERR_IllegalOperandInIIFCount, + ERRID.ERR_IllegalOperandInIIFName, + ERRID.ERR_IllegalOperandInIIFConversion, + ERRID.ERR_IllegalCondTypeInIIF, + ERRID.ERR_CantCallIIF, + ERRID.ERR_CantSpecifyAsNewAndNullable, + ERRID.ERR_IllegalOperandInIIFConversion2, + ERRID.ERR_BadNullTypeInCCExpression, + ERRID.ERR_NullableImplicit, + ERRID.ERR_DuplicateResourceFileName1, + ERRID.ERR_ExpectedDotAfterGlobalNameSpace, + ERRID.ERR_NoGlobalExpectedIdentifier, + ERRID.ERR_NoGlobalInHandles, + ERRID.ERR_ElseIfNoMatchingIf, + ERRID.ERR_BadAttributeConstructor2, + ERRID.ERR_EndUsingWithoutUsing, + ERRID.ERR_ExpectedEndUsing, + ERRID.ERR_GotoIntoUsing, + ERRID.ERR_UsingRequiresDisposePattern, + ERRID.ERR_UsingResourceVarNeedsInitializer, + ERRID.ERR_UsingResourceVarCantBeArray, + ERRID.ERR_OnErrorInUsing, + ERRID.ERR_PropertyNameConflictInMyCollection, + ERRID.ERR_InvalidImplicitVar, + ERRID.ERR_ObjectInitializerRequiresFieldName, + ERRID.ERR_ExpectedFrom, + ERRID.ERR_LambdaBindingMismatch1, + ERRID.ERR_CannotLiftByRefParamQuery1, + ERRID.ERR_ExpressionTreeNotSupported, + ERRID.ERR_CannotLiftStructureMeQuery, + ERRID.ERR_InferringNonArrayType1, + ERRID.ERR_ByRefParamInExpressionTree, + ERRID.ERR_DuplicateAnonTypeMemberName1, + ERRID.ERR_BadAnonymousTypeForExprTree, + ERRID.ERR_CannotLiftAnonymousType1, + ERRID.ERR_ExtensionOnlyAllowedOnModuleSubOrFunction, + ERRID.ERR_ExtensionMethodNotInModule, + ERRID.ERR_ExtensionMethodNoParams, + ERRID.ERR_ExtensionMethodOptionalFirstArg, + ERRID.ERR_ExtensionMethodParamArrayFirstArg, + ERRID.ERR_AnonymousTypeFieldNameInference, + ERRID.ERR_NameNotMemberOfAnonymousType2, + ERRID.ERR_ExtensionAttributeInvalid, + ERRID.ERR_AnonymousTypePropertyOutOfOrder1, + ERRID.ERR_AnonymousTypeDisallowsTypeChar, + ERRID.ERR_ExtensionMethodUncallable1, + ERRID.ERR_ExtensionMethodOverloadCandidate3, + ERRID.ERR_DelegateBindingMismatch, + ERRID.ERR_DelegateBindingTypeInferenceFails, + ERRID.ERR_TooManyArgs, + ERRID.ERR_NamedArgAlsoOmitted1, + ERRID.ERR_NamedArgUsedTwice1, + ERRID.ERR_NamedParamNotFound1, + ERRID.ERR_OmittedArgument1, + ERRID.ERR_UnboundTypeParam1, + ERRID.ERR_ExtensionMethodOverloadCandidate2, + ERRID.ERR_AnonymousTypeNeedField, + ERRID.ERR_AnonymousTypeNameWithoutPeriod, + ERRID.ERR_AnonymousTypeExpectedIdentifier, + ERRID.ERR_TooManyArgs2, + ERRID.ERR_NamedArgAlsoOmitted3, + ERRID.ERR_NamedArgUsedTwice3, + ERRID.ERR_NamedParamNotFound3, + ERRID.ERR_OmittedArgument3, + ERRID.ERR_UnboundTypeParam3, + ERRID.ERR_TooFewGenericArguments2, + ERRID.ERR_TooManyGenericArguments2, + ERRID.ERR_ExpectedInOrEq, + ERRID.ERR_ExpectedQueryableSource, + ERRID.ERR_QueryOperatorNotFound, + ERRID.ERR_CannotUseOnErrorGotoWithClosure, + ERRID.ERR_CannotLiftRestrictedTypeQuery, + ERRID.ERR_QueryAnonymousTypeFieldNameInference, + ERRID.ERR_QueryDuplicateAnonTypeMemberName1, + ERRID.ERR_QueryAnonymousTypeDisallowsTypeChar, + ERRID.ERR_ReadOnlyInClosure, + ERRID.ERR_ExprTreeNoMultiDimArrayCreation, + ERRID.ERR_ExprTreeNoLateBind, + ERRID.ERR_ExpectedBy, + ERRID.ERR_QueryInvalidControlVariableName1, + ERRID.ERR_ExpectedIn, + ERRID.ERR_QueryNameNotDeclared, + ERRID.ERR_SharedEventNeedsHandlerInTheSameType, + ERRID.ERR_NestedFunctionArgumentNarrowing3, + ERRID.ERR_AnonTypeFieldXMLNameInference, + ERRID.ERR_QueryAnonTypeFieldXMLNameInference, + ERRID.ERR_ExpectedInto, + ERRID.ERR_TypeCharOnAggregation, + ERRID.ERR_ExpectedOn, + ERRID.ERR_ExpectedEquals, + ERRID.ERR_ExpectedAnd, + ERRID.ERR_EqualsTypeMismatch, + ERRID.ERR_EqualsOperandIsBad, + ERRID.ERR_LambdaNotDelegate1, + ERRID.ERR_LambdaNotCreatableDelegate1, + ERRID.ERR_CannotInferNullableForVariable1, + ERRID.ERR_NullableTypeInferenceNotSupported, + ERRID.ERR_ExpectedJoin, + ERRID.ERR_NullableParameterMustSpecifyType, + ERRID.ERR_IterationVariableShadowLocal2, + ERRID.ERR_LambdasCannotHaveAttributes, + ERRID.ERR_LambdaInSelectCaseExpr, + ERRID.ERR_AddressOfInSelectCaseExpr, + ERRID.ERR_NullableCharNotSupported, + ERRID.ERR_CannotLiftStructureMeLambda, + ERRID.ERR_CannotLiftByRefParamLambda1, + ERRID.ERR_CannotLiftRestrictedTypeLambda, + ERRID.ERR_LambdaParamShadowLocal1, + ERRID.ERR_StrictDisallowImplicitObjectLambda, + ERRID.ERR_CantSpecifyParamsOnLambdaParamNoType, + ERRID.ERR_TypeInferenceFailure1, + ERRID.ERR_TypeInferenceFailure2, + ERRID.ERR_TypeInferenceFailure3, + ERRID.ERR_TypeInferenceFailureNoExplicit1, + ERRID.ERR_TypeInferenceFailureNoExplicit2, + ERRID.ERR_TypeInferenceFailureNoExplicit3, + ERRID.ERR_TypeInferenceFailureAmbiguous1, + ERRID.ERR_TypeInferenceFailureAmbiguous2, + ERRID.ERR_TypeInferenceFailureAmbiguous3, + ERRID.ERR_TypeInferenceFailureNoExplicitAmbiguous1, + ERRID.ERR_TypeInferenceFailureNoExplicitAmbiguous2, + ERRID.ERR_TypeInferenceFailureNoExplicitAmbiguous3, + ERRID.ERR_TypeInferenceFailureNoBest1, + ERRID.ERR_TypeInferenceFailureNoBest2, + ERRID.ERR_TypeInferenceFailureNoBest3, + ERRID.ERR_TypeInferenceFailureNoExplicitNoBest1, + ERRID.ERR_TypeInferenceFailureNoExplicitNoBest2, + ERRID.ERR_TypeInferenceFailureNoExplicitNoBest3, + ERRID.ERR_DelegateBindingMismatchStrictOff2, + ERRID.ERR_InaccessibleReturnTypeOfMember2, + ERRID.ERR_LocalNamedSameAsParamInLambda1, + ERRID.ERR_MultilineLambdasCannotContainOnError, + ERRID.ERR_LambdaBindingMismatch2, + ERRID.ERR_StaticInLambda, + ERRID.ERR_MultilineLambdaMissingSub, + ERRID.ERR_MultilineLambdaMissingFunction, + ERRID.ERR_StatementLambdaInExpressionTree, + ERRID.ERR_AttributeOnLambdaReturnType, + ERRID.ERR_ExpectedIdentifierOrGroup, + ERRID.ERR_UnexpectedGroup, + ERRID.ERR_DelegateBindingMismatchStrictOff3, + ERRID.ERR_DelegateBindingIncompatible3, + ERRID.ERR_ArgumentNarrowing2, + ERRID.ERR_OverloadCandidate1, + ERRID.ERR_AutoPropertyInitializedInStructure, + ERRID.ERR_InitializedExpandedProperty, + ERRID.ERR_LanguageVersion, + ERRID.ERR_ArrayInitNoType, + ERRID.ERR_NotACollection1, + ERRID.ERR_NoAddMethod1, + ERRID.ERR_CantCombineInitializers, + ERRID.ERR_EmptyAggregateInitializer, + ERRID.ERR_VarianceDisallowedHere, + ERRID.ERR_VarianceInterfaceNesting, + ERRID.ERR_VarianceOutParamDisallowed1, + ERRID.ERR_VarianceInParamDisallowed1, + ERRID.ERR_VarianceOutParamDisallowedForGeneric3, + ERRID.ERR_VarianceInParamDisallowedForGeneric3, + ERRID.ERR_VarianceOutParamDisallowedHere2, + ERRID.ERR_VarianceInParamDisallowedHere2, + ERRID.ERR_VarianceOutParamDisallowedHereForGeneric4, + ERRID.ERR_VarianceInParamDisallowedHereForGeneric4, + ERRID.ERR_VarianceTypeDisallowed2, + ERRID.ERR_VarianceTypeDisallowedForGeneric4, + ERRID.ERR_LambdaTooManyTypesObjectDisallowed, + ERRID.ERR_VarianceTypeDisallowedHere3, + ERRID.ERR_VarianceTypeDisallowedHereForGeneric5, + ERRID.ERR_AmbiguousCastConversion2, + ERRID.ERR_VariancePreventsSynthesizedEvents2, + ERRID.ERR_NestingViolatesCLS1, + ERRID.ERR_VarianceOutNullableDisallowed2, + ERRID.ERR_VarianceInNullableDisallowed2, + ERRID.ERR_VarianceOutByValDisallowed1, + ERRID.ERR_VarianceInReturnDisallowed1, + ERRID.ERR_VarianceOutConstraintDisallowed1, + ERRID.ERR_VarianceInReadOnlyPropertyDisallowed1, + ERRID.ERR_VarianceOutWriteOnlyPropertyDisallowed1, + ERRID.ERR_VarianceOutPropertyDisallowed1, + ERRID.ERR_VarianceInPropertyDisallowed1, + ERRID.ERR_VarianceOutByRefDisallowed1, + ERRID.ERR_VarianceInByRefDisallowed1, + ERRID.ERR_LambdaNoType, + ERRID.ERR_VarianceConversionFailedOut6, + ERRID.ERR_VarianceConversionFailedIn6, + ERRID.ERR_VarianceIEnumerableSuggestion3, + ERRID.ERR_VarianceConversionFailedTryOut4, + ERRID.ERR_VarianceConversionFailedTryIn4, + ERRID.ERR_AutoPropertyCantHaveParams, + ERRID.ERR_IdentityDirectCastForFloat, + ERRID.ERR_TypeDisallowsElements, + ERRID.ERR_TypeDisallowsAttributes, + ERRID.ERR_TypeDisallowsDescendants, + ERRID.ERR_TypeOrMemberNotGeneric2, + ERRID.ERR_ExtensionMethodCannotBeLateBound, + ERRID.ERR_TypeInferenceArrayRankMismatch1, + ERRID.ERR_QueryStrictDisallowImplicitObject, + ERRID.ERR_IfNoType, + ERRID.ERR_IfNoTypeObjectDisallowed, + ERRID.ERR_IfTooManyTypesObjectDisallowed, + ERRID.ERR_ArrayInitNoTypeObjectDisallowed, + ERRID.ERR_ArrayInitTooManyTypesObjectDisallowed, + ERRID.ERR_LambdaNoTypeObjectDisallowed, + ERRID.ERR_OverloadsModifierInModule, + ERRID.ERR_SubRequiresSingleStatement, + ERRID.ERR_SubDisallowsStatement, + ERRID.ERR_SubRequiresParenthesesLParen, + ERRID.ERR_SubRequiresParenthesesDot, + ERRID.ERR_SubRequiresParenthesesBang, + ERRID.ERR_CannotEmbedInterfaceWithGeneric, + ERRID.ERR_CannotUseGenericTypeAcrossAssemblyBoundaries, + ERRID.ERR_CannotUseGenericBaseTypeAcrossAssemblyBoundaries, + ERRID.ERR_BadAsyncByRefParam, + ERRID.ERR_BadIteratorByRefParam, + ERRID.ERR_BadAsyncInQuery, + ERRID.ERR_BadGetAwaiterMethod1, + ERRID.ERR_RestrictedResumableType1, + ERRID.ERR_BadAwaitNothing, + ERRID.ERR_AsyncSubMain, + ERRID.ERR_PartialMethodsMustNotBeAsync1, + ERRID.ERR_InvalidAsyncIteratorModifiers, + ERRID.ERR_BadAwaitNotInAsyncMethodOrLambda, + ERRID.ERR_BadIteratorReturn, + ERRID.ERR_BadYieldInTryHandler, + ERRID.ERR_BadYieldInNonIteratorMethod, + ERRID.ERR_BadReturnValueInIterator, + ERRID.ERR_BadAwaitInTryHandler, + ERRID.ERR_BadAsyncReturn, + ERRID.ERR_BadResumableAccessReturnVariable, + ERRID.ERR_BadIteratorExpressionLambda, + ERRID.ERR_ConstructorAsync, + ERRID.ERR_InvalidLambdaModifier, + ERRID.ERR_ReturnFromNonGenericTaskAsync, + ERRID.ERR_BadOverloadCandidates2, + ERRID.ERR_BadStaticInitializerInResumable, + ERRID.ERR_ResumablesCannotContainOnError, + ERRID.ERR_FriendRefNotEqualToThis, + ERRID.ERR_FriendRefSigningMismatch, + ERRID.ERR_FailureSigningAssembly, + ERRID.ERR_SignButNoPrivateKey, + ERRID.ERR_InvalidVersionFormat, + ERRID.ERR_ExpectedSingleScript, + ERRID.ERR_ReferenceDirectiveOnlyAllowedInScripts, + ERRID.ERR_NamespaceNotAllowedInScript, + ERRID.ERR_KeywordNotAllowedInScript, + ERRID.ERR_ReservedAssemblyName, + ERRID.ERR_ConstructorCannotBeDeclaredPartial, + ERRID.ERR_ModuleEmitFailure, + ERRID.ERR_ParameterNotValidForType, + ERRID.ERR_MarshalUnmanagedTypeNotValidForFields, + ERRID.ERR_MarshalUnmanagedTypeOnlyValidForFields, + ERRID.ERR_AttributeParameterRequired1, + ERRID.ERR_AttributeParameterRequired2, + ERRID.ERR_InvalidVersionFormat2, + ERRID.ERR_InvalidAssemblyCultureForExe, + ERRID.ERR_InvalidMultipleAttributeUsageInNetModule2, + ERRID.ERR_SecurityAttributeInvalidTarget, + ERRID.ERR_PublicKeyFileFailure, + ERRID.ERR_PublicKeyContainerFailure, + ERRID.ERR_InvalidAssemblyCulture, + ERRID.ERR_EncUpdateFailedMissingAttribute, + ERRID.ERR_CantAwaitAsyncSub1, + ERRID.ERR_ResumableLambdaInExpressionTree, + ERRID.ERR_DllImportOnResumableMethod, + ERRID.ERR_CannotLiftRestrictedTypeResumable1, + ERRID.ERR_BadIsCompletedOnCompletedGetResult2, + ERRID.ERR_SynchronizedAsyncMethod, + ERRID.ERR_BadAsyncReturnOperand1, + ERRID.ERR_DoesntImplementAwaitInterface2, + ERRID.ERR_BadAwaitInNonAsyncMethod, + ERRID.ERR_BadAwaitInNonAsyncVoidMethod, + ERRID.ERR_BadAwaitInNonAsyncLambda, + ERRID.ERR_LoopControlMustNotAwait, + ERRID.ERR_MyGroupCollectionAttributeCycle, + ERRID.ERR_LiteralExpected, + ERRID.ERR_PartialMethodDefaultParameterValueMismatch2, + ERRID.ERR_PartialMethodParamArrayMismatch2, + ERRID.ERR_NetModuleNameMismatch, + ERRID.ERR_BadModuleName, + ERRID.ERR_CmdOptionConflictsSource, + ERRID.ERR_TypeForwardedToMultipleAssemblies, + ERRID.ERR_InvalidSignaturePublicKey, + ERRID.ERR_CollisionWithPublicTypeInModule, + ERRID.ERR_ExportedTypeConflictsWithDeclaration, + ERRID.ERR_ExportedTypesConflict, + ERRID.ERR_AgnosticToMachineModule, + ERRID.ERR_ConflictingMachineModule, + ERRID.ERR_CryptoHashFailed, + ERRID.ERR_CantHaveWin32ResAndManifest, + ERRID.ERR_ForwardedTypeConflictsWithDeclaration, + ERRID.ERR_ForwardedTypeConflictsWithExportedType, + ERRID.ERR_ForwardedTypesConflict, + ERRID.ERR_TooLongMetadataName, + ERRID.ERR_MissingNetModuleReference, + ERRID.ERR_UnsupportedModule1, + ERRID.ERR_UnsupportedEvent1, + ERRID.ERR_NetModuleNameMustBeUnique, + ERRID.ERR_PDBWritingFailed, + ERRID.ERR_ParamDefaultValueDiffersFromAttribute, + ERRID.ERR_ResourceInModule, + ERRID.ERR_FieldHasMultipleDistinctConstantValues, + ERRID.ERR_AmbiguousInNamespaces2, + ERRID.ERR_EncNoPIAReference, + ERRID.ERR_LinkedNetmoduleMetadataMustProvideFullPEImage, + ERRID.ERR_CantReadRulesetFile, + ERRID.ERR_MetadataReferencesNotSupported, + ERRID.ERR_PlatformDoesntSupport, + ERRID.ERR_CantUseRequiredAttribute, + ERRID.ERR_EncodinglessSyntaxTree, + ERRID.ERR_InvalidFormatSpecifier, + ERRID.ERR_CannotBeMadeNullable1, + ERRID.ERR_BadConditionalWithRef, + ERRID.ERR_NullPropagatingOpInExpressionTree, + ERRID.ERR_TooLongOrComplexExpression, + ERRID.ERR_BadPdbData, + ERRID.ERR_AutoPropertyCantBeWriteOnly, + ERRID.ERR_ExpressionDoesntHaveName, + ERRID.ERR_InvalidNameOfSubExpression, + ERRID.ERR_MethodTypeArgsUnexpected, + ERRID.ERR_InReferencedAssembly, + ERRID.ERR_EncReferenceToAddedMember, + ERRID.ERR_InterpolationFormatWhitespace, + ERRID.ERR_InterpolationAlignmentOutOfRange, + ERRID.ERR_InterpolatedStringFactoryError, + ERRID.ERR_DebugEntryPointNotSourceMethodDefinition, + ERRID.ERR_InvalidPathMap, + ERRID.ERR_PublicSignNoKey, + ERRID.ERR_TooManyUserStrings, + ERRID.ERR_PeWritingFailure, + ERRID.ERR_OptionMustBeAbsolutePath, + ERRID.ERR_DocFileGen, + ERRID.ERR_TupleTooFewElements, + ERRID.ERR_TupleReservedElementNameAnyPosition, + ERRID.ERR_TupleReservedElementName, + ERRID.ERR_TupleDuplicateElementName, + ERRID.ERR_RefReturningCallInExpressionTree, + ERRID.ERR_SourceLinkRequiresPdb, + ERRID.ERR_CannotEmbedWithoutPdb, + ERRID.ERR_InvalidInstrumentationKind, + ERRID.ERR_ValueTupleTypeRefResolutionError1, + ERRID.ERR_TupleElementNamesAttributeMissing, + ERRID.ERR_ExplicitTupleElementNamesAttribute, + ERRID.ERR_TupleLiteralDisallowsTypeChar, + ERRID.ERR_DuplicateProcDefWithDifferentTupleNames2, + ERRID.ERR_InterfaceImplementedTwiceWithDifferentTupleNames2, + ERRID.ERR_InterfaceImplementedTwiceWithDifferentTupleNames3, + ERRID.ERR_InterfaceImplementedTwiceWithDifferentTupleNamesReverse3, + ERRID.ERR_InterfaceImplementedTwiceWithDifferentTupleNames4, + ERRID.ERR_InterfaceInheritedTwiceWithDifferentTupleNames2, + ERRID.ERR_InterfaceInheritedTwiceWithDifferentTupleNames3, + ERRID.ERR_InterfaceInheritedTwiceWithDifferentTupleNamesReverse3, + ERRID.ERR_InterfaceInheritedTwiceWithDifferentTupleNames4, + ERRID.ERR_NewWithTupleTypeSyntax, + ERRID.ERR_PredefinedValueTupleTypeMustBeStruct, + ERRID.ERR_PublicSignNetModule, + ERRID.ERR_BadAssemblyName, + ERRID.ERR_Merge_conflict_marker_encountered, + ERRID.ERR_BadSourceCodeKind, + ERRID.ERR_BadDocumentationMode, + ERRID.ERR_BadLanguageVersion, + ERRID.ERR_InvalidPreprocessorConstantType, + ERRID.ERR_TupleInferredNamesNotAvailable, + ERRID.ERR_InvalidDebugInfo, + ERRID.ERR_NoRefOutWhenRefOnly, + ERRID.ERR_NoNetModuleOutputWhenRefOutOrRefOnly, + ERRID.ERR_BadNonTrailingNamedArgument, + ERRID.ERR_ExpectedNamedArgumentInAttributeList, + ERRID.ERR_NamedArgumentSpecificationBeforeFixedArgumentInLateboundInvocation, + ERRID.ERR_ValueTupleResolutionAmbiguous3, + ERRID.ERR_CommentsAfterLineContinuationNotAvailable1, + ERRID.ERR_DefaultInterfaceImplementationInNoPIAType, + ERRID.ERR_ReAbstractionInNoPIAType, + ERRID.ERR_RuntimeDoesNotSupportDefaultInterfaceImplementation, + ERRID.ERR_RuntimeDoesNotSupportProtectedAccessForInterfaceMember, + ERRID.ERR_AssignmentInitOnly, + ERRID.ERR_OverridingInitOnlyProperty, + ERRID.ERR_PropertyDoesntImplementInitOnly, + ERRID.ERR_BadAbstractStaticMemberAccess, + ERRID.ERR_UnimplementedSharedMember, + ERRID.ERR_UnmanagedCallersOnlyNotSupported, + ERRID.ERR_MultipleAnalyzerConfigsInSameDir, + ERRID.ERR_StdInOptionProvidedButConsoleInputIsNotRedirected, + ERRID.ERR_UnsupportedCompilerFeature, + ERRID.ERR_DoNotUseCompilerFeatureRequired, + ERRID.ERR_NextAvailable, + ERRID.WRN_UseOfObsoleteSymbol2, + ERRID.WRN_InvalidOverrideDueToTupleNames2, + ERRID.WRN_MustOverloadBase4, + ERRID.WRN_OverrideType5, + ERRID.WRN_MustOverride2, + ERRID.WRN_DefaultnessShadowed4, + ERRID.WRN_UseOfObsoleteSymbolNoMessage1, + ERRID.WRN_AssemblyGeneration0, + ERRID.WRN_AssemblyGeneration1, + ERRID.WRN_ComClassNoMembers1, + ERRID.WRN_SynthMemberShadowsMember5, + ERRID.WRN_MemberShadowsSynthMember6, + ERRID.WRN_SynthMemberShadowsSynthMember7, + ERRID.WRN_UseOfObsoletePropertyAccessor3, + ERRID.WRN_UseOfObsoletePropertyAccessor2, + ERRID.WRN_FieldNotCLSCompliant1, + ERRID.WRN_BaseClassNotCLSCompliant2, + ERRID.WRN_ProcTypeNotCLSCompliant1, + ERRID.WRN_ParamNotCLSCompliant1, + ERRID.WRN_InheritedInterfaceNotCLSCompliant2, + ERRID.WRN_CLSMemberInNonCLSType3, + ERRID.WRN_NameNotCLSCompliant1, + ERRID.WRN_EnumUnderlyingTypeNotCLS1, + ERRID.WRN_NonCLSMemberInCLSInterface1, + ERRID.WRN_NonCLSMustOverrideInCLSType1, + ERRID.WRN_ArrayOverloadsNonCLS2, + ERRID.WRN_RootNamespaceNotCLSCompliant1, + ERRID.WRN_RootNamespaceNotCLSCompliant2, + ERRID.WRN_GenericConstraintNotCLSCompliant1, + ERRID.WRN_TypeNotCLSCompliant1, + ERRID.WRN_OptionalValueNotCLSCompliant1, + ERRID.WRN_CLSAttrInvalidOnGetSet, + ERRID.WRN_TypeConflictButMerged6, + ERRID.WRN_ShadowingGenericParamWithParam1, + ERRID.WRN_CannotFindStandardLibrary1, + ERRID.WRN_EventDelegateTypeNotCLSCompliant2, + ERRID.WRN_DebuggerHiddenIgnoredOnProperties, + ERRID.WRN_SelectCaseInvalidRange, + ERRID.WRN_CLSEventMethodInNonCLSType3, + ERRID.WRN_ExpectedInitComponentCall2, + ERRID.WRN_NamespaceCaseMismatch3, + ERRID.WRN_UndefinedOrEmptyNamespaceOrClass1, + ERRID.WRN_UndefinedOrEmptyProjectNamespaceOrClass1, + ERRID.WRN_IndirectRefToLinkedAssembly2, + ERRID.WRN_DelaySignButNoKey, + ERRID.WRN_UnimplementedCommandLineSwitch, + ERRID.WRN_NoNonObsoleteConstructorOnBase3, + ERRID.WRN_NoNonObsoleteConstructorOnBase4, + ERRID.WRN_RequiredNonObsoleteNewCall3, + ERRID.WRN_RequiredNonObsoleteNewCall4, + ERRID.WRN_MissingAsClauseinOperator, + ERRID.WRN_ConstraintsFailedForInferredArgs2, + ERRID.WRN_ConditionalNotValidOnFunction, + ERRID.WRN_UseSwitchInsteadOfAttribute, + ERRID.WRN_TupleLiteralNameMismatch, + ERRID.WRN_ReferencedAssemblyDoesNotHaveStrongName, + ERRID.WRN_RecursiveAddHandlerCall, + ERRID.WRN_ImplicitConversionCopyBack, + ERRID.WRN_MustShadowOnMultipleInheritance2, + ERRID.WRN_RecursiveOperatorCall, + ERRID.WRN_ImplicitConversionSubst1, + ERRID.WRN_LateBindingResolution, + ERRID.WRN_ObjectMath1, + ERRID.WRN_ObjectMath2, + ERRID.WRN_ObjectAssumedVar1, + ERRID.WRN_ObjectAssumed1, + ERRID.WRN_ObjectAssumedProperty1, + ERRID.WRN_UnusedLocal, + ERRID.WRN_SharedMemberThroughInstance, + ERRID.WRN_RecursivePropertyCall, + ERRID.WRN_OverlappingCatch, + ERRID.WRN_DefAsgUseNullRefByRef, + ERRID.WRN_DuplicateCatch, + ERRID.WRN_ObjectMath1Not, + ERRID.WRN_BadChecksumValExtChecksum, + ERRID.WRN_MultipleDeclFileExtChecksum, + ERRID.WRN_BadGUIDFormatExtChecksum, + ERRID.WRN_ObjectMathSelectCase, + ERRID.WRN_EqualToLiteralNothing, + ERRID.WRN_NotEqualToLiteralNothing, + ERRID.WRN_UnusedLocalConst, + ERRID.WRN_ComClassInterfaceShadows5, + ERRID.WRN_ComClassPropertySetObject1, + ERRID.WRN_DefAsgUseNullRef, + ERRID.WRN_DefAsgNoRetValFuncRef1, + ERRID.WRN_DefAsgNoRetValOpRef1, + ERRID.WRN_DefAsgNoRetValPropRef1, + ERRID.WRN_DefAsgUseNullRefByRefStr, + ERRID.WRN_DefAsgUseNullRefStr, + ERRID.WRN_StaticLocalNoInference, + ERRID.WRN_InvalidAssemblyName, + ERRID.WRN_XMLDocBadXMLLine, + ERRID.WRN_XMLDocMoreThanOneCommentBlock, + ERRID.WRN_XMLDocNotFirstOnLine, + ERRID.WRN_XMLDocInsideMethod, + ERRID.WRN_XMLDocParseError1, + ERRID.WRN_XMLDocDuplicateXMLNode1, + ERRID.WRN_XMLDocIllegalTagOnElement2, + ERRID.WRN_XMLDocBadParamTag2, + ERRID.WRN_XMLDocParamTagWithoutName, + ERRID.WRN_XMLDocCrefAttributeNotFound1, + ERRID.WRN_XMLMissingFileOrPathAttribute1, + ERRID.WRN_XMLCannotWriteToXMLDocFile2, + ERRID.WRN_XMLDocWithoutLanguageElement, + ERRID.WRN_XMLDocReturnsOnWriteOnlyProperty, + ERRID.WRN_XMLDocOnAPartialType, + ERRID.WRN_XMLDocReturnsOnADeclareSub, + ERRID.WRN_XMLDocStartTagWithNoEndTag, + ERRID.WRN_XMLDocBadGenericParamTag2, + ERRID.WRN_XMLDocGenericParamTagWithoutName, + ERRID.WRN_XMLDocExceptionTagWithoutCRef, + ERRID.WRN_XMLDocInvalidXMLFragment, + ERRID.WRN_XMLDocBadFormedXML, + ERRID.WRN_InterfaceConversion2, + ERRID.WRN_LiftControlVariableLambda, + ERRID.WRN_LambdaPassedToRemoveHandler, + ERRID.WRN_LiftControlVariableQuery, + ERRID.WRN_RelDelegatePassedToRemoveHandler, + ERRID.WRN_AmbiguousCastConversion2, + ERRID.WRN_VarianceDeclarationAmbiguous3, + ERRID.WRN_ArrayInitNoTypeObjectAssumed, + ERRID.WRN_TypeInferenceAssumed3, + ERRID.WRN_VarianceConversionFailedOut6, + ERRID.WRN_VarianceConversionFailedIn6, + ERRID.WRN_VarianceIEnumerableSuggestion3, + ERRID.WRN_VarianceConversionFailedTryOut4, + ERRID.WRN_VarianceConversionFailedTryIn4, + ERRID.WRN_IfNoTypeObjectAssumed, + ERRID.WRN_IfTooManyTypesObjectAssumed, + ERRID.WRN_ArrayInitTooManyTypesObjectAssumed, + ERRID.WRN_LambdaNoTypeObjectAssumed, + ERRID.WRN_LambdaTooManyTypesObjectAssumed, + ERRID.WRN_MissingAsClauseinVarDecl, + ERRID.WRN_MissingAsClauseinFunction, + ERRID.WRN_MissingAsClauseinProperty, + ERRID.WRN_ObsoleteIdentityDirectCastForValueType, + ERRID.WRN_ImplicitConversion2, + ERRID.WRN_MutableStructureInUsing, + ERRID.WRN_MutableGenericStructureInUsing, + ERRID.WRN_DefAsgNoRetValFuncVal1, + ERRID.WRN_DefAsgNoRetValOpVal1, + ERRID.WRN_DefAsgNoRetValPropVal1, + ERRID.WRN_AsyncLacksAwaits, + ERRID.WRN_AsyncSubCouldBeFunction, + ERRID.WRN_UnobservedAwaitableExpression, + ERRID.WRN_UnobservedAwaitableDelegate, + ERRID.WRN_PrefixAndXmlnsLocalName, + ERRID.WRN_UseValueForXmlExpression3, + ERRID.WRN_ReturnTypeAttributeOnWriteOnlyProperty, + ERRID.WRN_InvalidVersionFormat, + ERRID.WRN_MainIgnored, + ERRID.WRN_EmptyPrefixAndXmlnsLocalName, + ERRID.WRN_DefAsgNoRetValWinRtEventVal1, + ERRID.WRN_AssemblyAttributeFromModuleIsOverridden, + ERRID.WRN_RefCultureMismatch, + ERRID.WRN_ConflictingMachineAssembly, + ERRID.WRN_PdbLocalNameTooLong, + ERRID.WRN_PdbUsingNameTooLong, + ERRID.WRN_XMLDocCrefToTypeParameter, + ERRID.WRN_AnalyzerCannotBeCreated, + ERRID.WRN_NoAnalyzerInAssembly, + ERRID.WRN_UnableToLoadAnalyzer, + ERRID.WRN_AttributeIgnoredWhenPublicSigning, + ERRID.WRN_Experimental, + ERRID.WRN_AttributeNotSupportedInVB, + ERRID.WRN_GeneratorFailedDuringInitialization, + ERRID.WRN_GeneratorFailedDuringGeneration, + ERRID.WRN_AnalyzerReferencesFramework, + ERRID.WRN_CallerArgumentExpressionAttributeSelfReferential, + ERRID.WRN_CallerArgumentExpressionAttributeHasInvalidParameterName, + ERRID.WRN_AnalyzerReferencesNewerCompiler + Return False + Case Else + ' NOTE: All error codes must be explicitly handled in the below select case statement + ' to ensure that we correctly classify all error codes as build-only or not. + Throw New NotImplementedException($"ERRID.{code}") + End Select + End Function + End Module +End Namespace diff --git a/src/Compilers/VisualBasic/Portable/Errors/Errors.vb b/src/Compilers/VisualBasic/Portable/Errors/Errors.vb index 3f5ac0d42f3e4..fdf78f60a2cce 100644 --- a/src/Compilers/VisualBasic/Portable/Errors/Errors.vb +++ b/src/Compilers/VisualBasic/Portable/Errors/Errors.vb @@ -2002,6 +2002,8 @@ Namespace Microsoft.CodeAnalysis.VisualBasic ' // AVAILABLE 42600 - 49998 WRN_NextAvailable = 42600 + ' NOTE: On adding a new ERRID, you will need to update ErrorFacts.IsBuildOnlyDiagnostic to handle it. + '// HIDDENS AND INFOS BEGIN HERE HDN_UnusedImportClause = 50000 HDN_UnusedImportStatement = 50001 diff --git a/src/Compilers/VisualBasic/Portable/Generated/Syntax.xml.Internal.Generated.vb b/src/Compilers/VisualBasic/Portable/Generated/Syntax.xml.Internal.Generated.vb index 39dba26d74cc7..1696ce95a0760 100644 --- a/src/Compilers/VisualBasic/Portable/Generated/Syntax.xml.Internal.Generated.vb +++ b/src/Compilers/VisualBasic/Portable/Generated/Syntax.xml.Internal.Generated.vb @@ -42980,7 +42980,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Syntax.InternalSyntax ''' Represents an "End XXX" statement, where XXX is a single keyword. ''' ''' - ''' A representing the specific kind of + ''' A representing the specific kind of ''' EndBlockStatementSyntax. One of EndIfStatement, EndUsingStatement, ''' EndWithStatement, EndSelectStatement, EndStructureStatement, EndEnumStatement, ''' EndInterfaceStatement, EndClassStatement, EndModuleStatement, @@ -43783,7 +43783,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Syntax.InternalSyntax ''' one of: NewConstraint, ReferenceConstraint or ValueConstraint. ''' ''' - ''' A representing the specific kind of + ''' A representing the specific kind of ''' SpecialConstraintSyntax. One of NewConstraint, ClassConstraint, ''' StructureConstraint. ''' @@ -43927,7 +43927,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Syntax.InternalSyntax ''' beginning declaration, a body of executable statements and an end statement. ''' ''' - ''' A representing the specific kind of MethodBlockSyntax. + ''' A representing the specific kind of MethodBlockSyntax. ''' One of SubBlock, FunctionBlock. ''' ''' @@ -44204,9 +44204,9 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Syntax.InternalSyntax ''' Examples include property accessors and custom event accessors. ''' ''' - ''' A representing the specific kind of AccessorBlockSyntax. - ''' One of GetAccessorBlock, SetAccessorBlock, AddHandlerAccessorBlock, - ''' RemoveHandlerAccessorBlock, RaiseEventAccessorBlock. + ''' A representing the specific kind of + ''' AccessorBlockSyntax. One of GetAccessorBlock, SetAccessorBlock, + ''' AddHandlerAccessorBlock, RemoveHandlerAccessorBlock, RaiseEventAccessorBlock. ''' ''' ''' The "Get", "Set", "AddHandler", "RemoveHandler", or "RaiseEvent" statement that @@ -44441,7 +44441,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Syntax.InternalSyntax ''' that BlockStatement. ''' ''' - ''' A representing the specific kind of + ''' A representing the specific kind of ''' MethodStatementSyntax. One of SubStatement, FunctionStatement. ''' ''' @@ -44635,7 +44635,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Syntax.InternalSyntax ''' A Declare statement that declares an external DLL method. ''' ''' - ''' A representing the specific kind of + ''' A representing the specific kind of ''' DeclareStatementSyntax. One of DeclareSubStatement, DeclareFunctionStatement. ''' ''' @@ -44780,7 +44780,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Syntax.InternalSyntax ''' A statement that declares a delegate type. ''' ''' - ''' A representing the specific kind of + ''' A representing the specific kind of ''' DelegateStatementSyntax. One of DelegateSubStatement, ''' DelegateFunctionStatement. ''' @@ -45106,7 +45106,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Syntax.InternalSyntax ''' Begin of a BlockNode, and the body of the accessor is the Body of that node. ''' ''' - ''' A representing the specific kind of + ''' A representing the specific kind of ''' AccessorStatementSyntax. One of GetAccessorStatement, SetAccessorStatement, ''' AddHandlerAccessorStatement, RemoveHandlerAccessorStatement, ''' RaiseEventAccessorStatement. @@ -46167,8 +46167,8 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Syntax.InternalSyntax ''' or next keyword. ''' ''' - ''' A representing the specific kind of LabelSyntax. One of - ''' IdentifierLabel, NumericLabel, NextLabel. + ''' A representing the specific kind of LabelSyntax. One + ''' of IdentifierLabel, NumericLabel, NextLabel. ''' ''' ''' The label name (identifier), line number (integer literal), or next keyword @@ -46248,7 +46248,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Syntax.InternalSyntax ''' kind of statement this is. ''' ''' - ''' A representing the specific kind of + ''' A representing the specific kind of ''' StopOrEndStatementSyntax. One of StopStatement, EndStatement. ''' ''' @@ -46539,10 +46539,11 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Syntax.InternalSyntax ''' Kind. ''' ''' - ''' A representing the specific kind of ExitStatementSyntax. - ''' One of ExitDoStatement, ExitForStatement, ExitSubStatement, - ''' ExitFunctionStatement, ExitOperatorStatement, ExitPropertyStatement, - ''' ExitTryStatement, ExitSelectStatement, ExitWhileStatement. + ''' A representing the specific kind of + ''' ExitStatementSyntax. One of ExitDoStatement, ExitForStatement, + ''' ExitSubStatement, ExitFunctionStatement, ExitOperatorStatement, + ''' ExitPropertyStatement, ExitTryStatement, ExitSelectStatement, + ''' ExitWhileStatement. ''' ''' ''' The "Exit" keyword. @@ -46665,7 +46666,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Syntax.InternalSyntax ''' determined by examining the Kind. ''' ''' - ''' A representing the specific kind of + ''' A representing the specific kind of ''' ContinueStatementSyntax. One of ContinueWhileStatement, ContinueDoStatement, ''' ContinueForStatement. ''' @@ -47243,7 +47244,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Syntax.InternalSyntax ''' Represents an OnError Goto statement. ''' ''' - ''' A representing the specific kind of + ''' A representing the specific kind of ''' OnErrorGoToStatementSyntax. One of OnErrorGoToZeroStatement, ''' OnErrorGoToMinusOneStatement, OnErrorGoToLabelStatement. ''' @@ -47841,7 +47842,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Syntax.InternalSyntax ''' Represents a relation clause in a Case statement, such as "Is > expression". ''' ''' - ''' A representing the specific kind of + ''' A representing the specific kind of ''' RelationalCaseClauseSyntax. One of CaseEqualsClause, CaseNotEqualsClause, ''' CaseLessThanClause, CaseLessThanOrEqualClause, CaseGreaterThanOrEqualClause, ''' CaseGreaterThanClause. @@ -48070,7 +48071,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Syntax.InternalSyntax ''' is a Do While, Do Until, Do Loop While, Do Loop Until, or infinite Do Loop. ''' ''' - ''' A representing the specific kind of DoLoopBlockSyntax. + ''' A representing the specific kind of DoLoopBlockSyntax. ''' One of SimpleDoLoopBlock, DoWhileLoopBlock, DoUntilLoopBlock, DoLoopWhileBlock, ''' DoLoopUntilBlock. ''' @@ -48191,7 +48192,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Syntax.InternalSyntax ''' The Do statement that begins a Do-Loop block. ''' ''' - ''' A representing the specific kind of DoStatementSyntax. + ''' A representing the specific kind of DoStatementSyntax. ''' One of SimpleDoStatement, DoWhileStatement, DoUntilStatement. ''' ''' @@ -48308,8 +48309,9 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Syntax.InternalSyntax ''' The Loop statement that begins a Do-Loop block. ''' ''' - ''' A representing the specific kind of LoopStatementSyntax. - ''' One of SimpleLoopStatement, LoopWhileStatement, LoopUntilStatement. + ''' A representing the specific kind of + ''' LoopStatementSyntax. One of SimpleLoopStatement, LoopWhileStatement, + ''' LoopUntilStatement. ''' ''' ''' The "Loop" keyword. @@ -48403,7 +48405,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Syntax.InternalSyntax ''' indicate which kind of clause. ''' ''' - ''' A representing the specific kind of + ''' A representing the specific kind of ''' WhileOrUntilClauseSyntax. One of WhileClause, UntilClause. ''' ''' @@ -49107,7 +49109,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Syntax.InternalSyntax ''' determined by checking the Kind. ''' ''' - ''' A representing the specific kind of + ''' A representing the specific kind of ''' AssignmentStatementSyntax. One of SimpleAssignmentStatement, ''' MidAssignmentStatement, AddAssignmentStatement, SubtractAssignmentStatement, ''' MultiplyAssignmentStatement, DivideAssignmentStatement, @@ -49258,7 +49260,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Syntax.InternalSyntax ''' determines which one. ''' ''' - ''' A representing the specific kind of + ''' A representing the specific kind of ''' AddRemoveHandlerStatementSyntax. One of AddHandlerStatement, ''' RemoveHandlerStatement. ''' @@ -49722,7 +49724,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Syntax.InternalSyntax ''' value from the token. ''' ''' - ''' A representing the specific kind of + ''' A representing the specific kind of ''' LiteralExpressionSyntax. One of CharacterLiteralExpression, ''' TrueLiteralExpression, FalseLiteralExpression, NumericLiteralExpression, ''' DateLiteralExpression, StringLiteralExpression, NothingLiteralExpression. @@ -50051,7 +50053,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Syntax.InternalSyntax ''' Represents a TypeOf...Is or IsNot expression. ''' ''' - ''' A representing the specific kind of + ''' A representing the specific kind of ''' TypeOfExpressionSyntax. One of TypeOfIsExpression, TypeOfIsNotExpression. ''' ''' @@ -50168,7 +50170,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Syntax.InternalSyntax ''' property determines which kind of access. ''' ''' - ''' A representing the specific kind of + ''' A representing the specific kind of ''' MemberAccessExpressionSyntax. One of SimpleMemberAccessExpression, ''' DictionaryAccessExpression. ''' @@ -50288,7 +50290,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Syntax.InternalSyntax ''' Kind property determines which kind of access. ''' ''' - ''' A representing the specific kind of + ''' A representing the specific kind of ''' XmlMemberAccessExpressionSyntax. One of XmlElementAccessExpression, ''' XmlDescendantAccessExpression, XmlAttributeAccessExpression. ''' @@ -51328,7 +51330,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Syntax.InternalSyntax ''' exact operation being performed is determined by the Operator property. ''' ''' - ''' A representing the specific kind of + ''' A representing the specific kind of ''' BinaryExpressionSyntax. One of AddExpression, SubtractExpression, ''' MultiplyExpression, DivideExpression, IntegerDivideExpression, ''' ExponentiateExpression, LeftShiftExpression, RightShiftExpression, @@ -51481,7 +51483,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Syntax.InternalSyntax ''' Describes a unary operator: Plus, Negate, Not or AddressOf. ''' ''' - ''' A representing the specific kind of + ''' A representing the specific kind of ''' UnaryExpressionSyntax. One of UnaryPlusExpression, UnaryMinusExpression, ''' NotExpression, AddressOfExpression. ''' @@ -51649,7 +51651,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Syntax.InternalSyntax ''' Represents a single line lambda expression. ''' ''' - ''' A representing the specific kind of + ''' A representing the specific kind of ''' SingleLineLambdaExpressionSyntax. One of SingleLineFunctionLambdaExpression, ''' SingleLineSubLambdaExpression. ''' @@ -51755,7 +51757,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Syntax.InternalSyntax ''' Represents a multi-line lambda expression. ''' ''' - ''' A representing the specific kind of + ''' A representing the specific kind of ''' MultiLineLambdaExpressionSyntax. One of MultiLineFunctionLambdaExpression, ''' MultiLineSubLambdaExpression. ''' @@ -51856,8 +51858,8 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Syntax.InternalSyntax ''' Represents the header part of a lambda expression ''' ''' - ''' A representing the specific kind of LambdaHeaderSyntax. - ''' One of SubLambdaHeader, FunctionLambdaHeader. + ''' A representing the specific kind of + ''' LambdaHeaderSyntax. One of SubLambdaHeader, FunctionLambdaHeader. ''' ''' ''' A list of all attribute lists on this declaration. If no attributes were @@ -52427,7 +52429,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Syntax.InternalSyntax ''' tells which. ''' ''' - ''' A representing the specific kind of + ''' A representing the specific kind of ''' PartitionWhileClauseSyntax. One of SkipWhileClause, TakeWhileClause. ''' ''' @@ -52520,7 +52522,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Syntax.InternalSyntax ''' Represents a "Skip" or "Take" query operator. The Kind property tells which. ''' ''' - ''' A representing the specific kind of + ''' A representing the specific kind of ''' PartitionClauseSyntax. One of SkipClause, TakeClause. ''' ''' @@ -52765,8 +52767,8 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Syntax.InternalSyntax ''' whether to order in ascending or descending order. ''' ''' - ''' A representing the specific kind of OrderingSyntax. One - ''' of AscendingOrdering, DescendingOrdering. + ''' A representing the specific kind of OrderingSyntax. + ''' One of AscendingOrdering, DescendingOrdering. ''' ''' ''' The expression to sort by. @@ -53610,8 +53612,8 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Syntax.InternalSyntax ''' normalization such as comment, pi and cdata text. ''' ''' - ''' A representing the specific kind of XmlTextTokenSyntax. - ''' One of XmlTextLiteralToken, XmlEntityLiteralToken, + ''' A representing the specific kind of + ''' XmlTextTokenSyntax. One of XmlTextLiteralToken, XmlEntityLiteralToken, ''' DocumentationCommentLineBreakToken. ''' ''' @@ -54050,8 +54052,8 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Syntax.InternalSyntax ''' directives, and disabled code. ''' ''' - ''' A representing the specific kind of SyntaxTrivia. One of - ''' WhitespaceTrivia, EndOfLineTrivia, ColonTrivia, CommentTrivia, + ''' A representing the specific kind of SyntaxTrivia. One + ''' of WhitespaceTrivia, EndOfLineTrivia, ColonTrivia, CommentTrivia, ''' ConflictMarkerTrivia, LineContinuationTrivia, ''' DocumentationCommentExteriorTrivia, DisabledTextTrivia. ''' @@ -55056,7 +55058,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Syntax.InternalSyntax ''' Represents an "End XXX" statement, where XXX is a single keyword. ''' ''' - ''' A representing the specific kind of + ''' A representing the specific kind of ''' EndBlockStatementSyntax. One of EndIfStatement, EndUsingStatement, ''' EndWithStatement, EndSelectStatement, EndStructureStatement, EndEnumStatement, ''' EndInterfaceStatement, EndClassStatement, EndModuleStatement, @@ -55859,7 +55861,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Syntax.InternalSyntax ''' one of: NewConstraint, ReferenceConstraint or ValueConstraint. ''' ''' - ''' A representing the specific kind of + ''' A representing the specific kind of ''' SpecialConstraintSyntax. One of NewConstraint, ClassConstraint, ''' StructureConstraint. ''' @@ -56003,7 +56005,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Syntax.InternalSyntax ''' beginning declaration, a body of executable statements and an end statement. ''' ''' - ''' A representing the specific kind of MethodBlockSyntax. + ''' A representing the specific kind of MethodBlockSyntax. ''' One of SubBlock, FunctionBlock. ''' ''' @@ -56280,9 +56282,9 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Syntax.InternalSyntax ''' Examples include property accessors and custom event accessors. ''' ''' - ''' A representing the specific kind of AccessorBlockSyntax. - ''' One of GetAccessorBlock, SetAccessorBlock, AddHandlerAccessorBlock, - ''' RemoveHandlerAccessorBlock, RaiseEventAccessorBlock. + ''' A representing the specific kind of + ''' AccessorBlockSyntax. One of GetAccessorBlock, SetAccessorBlock, + ''' AddHandlerAccessorBlock, RemoveHandlerAccessorBlock, RaiseEventAccessorBlock. ''' ''' ''' The "Get", "Set", "AddHandler", "RemoveHandler", or "RaiseEvent" statement that @@ -56517,7 +56519,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Syntax.InternalSyntax ''' that BlockStatement. ''' ''' - ''' A representing the specific kind of + ''' A representing the specific kind of ''' MethodStatementSyntax. One of SubStatement, FunctionStatement. ''' ''' @@ -56711,7 +56713,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Syntax.InternalSyntax ''' A Declare statement that declares an external DLL method. ''' ''' - ''' A representing the specific kind of + ''' A representing the specific kind of ''' DeclareStatementSyntax. One of DeclareSubStatement, DeclareFunctionStatement. ''' ''' @@ -56856,7 +56858,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Syntax.InternalSyntax ''' A statement that declares a delegate type. ''' ''' - ''' A representing the specific kind of + ''' A representing the specific kind of ''' DelegateStatementSyntax. One of DelegateSubStatement, ''' DelegateFunctionStatement. ''' @@ -57182,7 +57184,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Syntax.InternalSyntax ''' Begin of a BlockNode, and the body of the accessor is the Body of that node. ''' ''' - ''' A representing the specific kind of + ''' A representing the specific kind of ''' AccessorStatementSyntax. One of GetAccessorStatement, SetAccessorStatement, ''' AddHandlerAccessorStatement, RemoveHandlerAccessorStatement, ''' RaiseEventAccessorStatement. @@ -58243,8 +58245,8 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Syntax.InternalSyntax ''' or next keyword. ''' ''' - ''' A representing the specific kind of LabelSyntax. One of - ''' IdentifierLabel, NumericLabel, NextLabel. + ''' A representing the specific kind of LabelSyntax. One + ''' of IdentifierLabel, NumericLabel, NextLabel. ''' ''' ''' The label name (identifier), line number (integer literal), or next keyword @@ -58324,7 +58326,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Syntax.InternalSyntax ''' kind of statement this is. ''' ''' - ''' A representing the specific kind of + ''' A representing the specific kind of ''' StopOrEndStatementSyntax. One of StopStatement, EndStatement. ''' ''' @@ -58615,10 +58617,11 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Syntax.InternalSyntax ''' Kind. ''' ''' - ''' A representing the specific kind of ExitStatementSyntax. - ''' One of ExitDoStatement, ExitForStatement, ExitSubStatement, - ''' ExitFunctionStatement, ExitOperatorStatement, ExitPropertyStatement, - ''' ExitTryStatement, ExitSelectStatement, ExitWhileStatement. + ''' A representing the specific kind of + ''' ExitStatementSyntax. One of ExitDoStatement, ExitForStatement, + ''' ExitSubStatement, ExitFunctionStatement, ExitOperatorStatement, + ''' ExitPropertyStatement, ExitTryStatement, ExitSelectStatement, + ''' ExitWhileStatement. ''' ''' ''' The "Exit" keyword. @@ -58741,7 +58744,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Syntax.InternalSyntax ''' determined by examining the Kind. ''' ''' - ''' A representing the specific kind of + ''' A representing the specific kind of ''' ContinueStatementSyntax. One of ContinueWhileStatement, ContinueDoStatement, ''' ContinueForStatement. ''' @@ -59319,7 +59322,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Syntax.InternalSyntax ''' Represents an OnError Goto statement. ''' ''' - ''' A representing the specific kind of + ''' A representing the specific kind of ''' OnErrorGoToStatementSyntax. One of OnErrorGoToZeroStatement, ''' OnErrorGoToMinusOneStatement, OnErrorGoToLabelStatement. ''' @@ -59917,7 +59920,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Syntax.InternalSyntax ''' Represents a relation clause in a Case statement, such as "Is > expression". ''' ''' - ''' A representing the specific kind of + ''' A representing the specific kind of ''' RelationalCaseClauseSyntax. One of CaseEqualsClause, CaseNotEqualsClause, ''' CaseLessThanClause, CaseLessThanOrEqualClause, CaseGreaterThanOrEqualClause, ''' CaseGreaterThanClause. @@ -60146,7 +60149,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Syntax.InternalSyntax ''' is a Do While, Do Until, Do Loop While, Do Loop Until, or infinite Do Loop. ''' ''' - ''' A representing the specific kind of DoLoopBlockSyntax. + ''' A representing the specific kind of DoLoopBlockSyntax. ''' One of SimpleDoLoopBlock, DoWhileLoopBlock, DoUntilLoopBlock, DoLoopWhileBlock, ''' DoLoopUntilBlock. ''' @@ -60267,7 +60270,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Syntax.InternalSyntax ''' The Do statement that begins a Do-Loop block. ''' ''' - ''' A representing the specific kind of DoStatementSyntax. + ''' A representing the specific kind of DoStatementSyntax. ''' One of SimpleDoStatement, DoWhileStatement, DoUntilStatement. ''' ''' @@ -60384,8 +60387,9 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Syntax.InternalSyntax ''' The Loop statement that begins a Do-Loop block. ''' ''' - ''' A representing the specific kind of LoopStatementSyntax. - ''' One of SimpleLoopStatement, LoopWhileStatement, LoopUntilStatement. + ''' A representing the specific kind of + ''' LoopStatementSyntax. One of SimpleLoopStatement, LoopWhileStatement, + ''' LoopUntilStatement. ''' ''' ''' The "Loop" keyword. @@ -60479,7 +60483,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Syntax.InternalSyntax ''' indicate which kind of clause. ''' ''' - ''' A representing the specific kind of + ''' A representing the specific kind of ''' WhileOrUntilClauseSyntax. One of WhileClause, UntilClause. ''' ''' @@ -61183,7 +61187,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Syntax.InternalSyntax ''' determined by checking the Kind. ''' ''' - ''' A representing the specific kind of + ''' A representing the specific kind of ''' AssignmentStatementSyntax. One of SimpleAssignmentStatement, ''' MidAssignmentStatement, AddAssignmentStatement, SubtractAssignmentStatement, ''' MultiplyAssignmentStatement, DivideAssignmentStatement, @@ -61334,7 +61338,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Syntax.InternalSyntax ''' determines which one. ''' ''' - ''' A representing the specific kind of + ''' A representing the specific kind of ''' AddRemoveHandlerStatementSyntax. One of AddHandlerStatement, ''' RemoveHandlerStatement. ''' @@ -61798,7 +61802,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Syntax.InternalSyntax ''' value from the token. ''' ''' - ''' A representing the specific kind of + ''' A representing the specific kind of ''' LiteralExpressionSyntax. One of CharacterLiteralExpression, ''' TrueLiteralExpression, FalseLiteralExpression, NumericLiteralExpression, ''' DateLiteralExpression, StringLiteralExpression, NothingLiteralExpression. @@ -62127,7 +62131,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Syntax.InternalSyntax ''' Represents a TypeOf...Is or IsNot expression. ''' ''' - ''' A representing the specific kind of + ''' A representing the specific kind of ''' TypeOfExpressionSyntax. One of TypeOfIsExpression, TypeOfIsNotExpression. ''' ''' @@ -62244,7 +62248,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Syntax.InternalSyntax ''' property determines which kind of access. ''' ''' - ''' A representing the specific kind of + ''' A representing the specific kind of ''' MemberAccessExpressionSyntax. One of SimpleMemberAccessExpression, ''' DictionaryAccessExpression. ''' @@ -62364,7 +62368,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Syntax.InternalSyntax ''' Kind property determines which kind of access. ''' ''' - ''' A representing the specific kind of + ''' A representing the specific kind of ''' XmlMemberAccessExpressionSyntax. One of XmlElementAccessExpression, ''' XmlDescendantAccessExpression, XmlAttributeAccessExpression. ''' @@ -63404,7 +63408,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Syntax.InternalSyntax ''' exact operation being performed is determined by the Operator property. ''' ''' - ''' A representing the specific kind of + ''' A representing the specific kind of ''' BinaryExpressionSyntax. One of AddExpression, SubtractExpression, ''' MultiplyExpression, DivideExpression, IntegerDivideExpression, ''' ExponentiateExpression, LeftShiftExpression, RightShiftExpression, @@ -63557,7 +63561,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Syntax.InternalSyntax ''' Describes a unary operator: Plus, Negate, Not or AddressOf. ''' ''' - ''' A representing the specific kind of + ''' A representing the specific kind of ''' UnaryExpressionSyntax. One of UnaryPlusExpression, UnaryMinusExpression, ''' NotExpression, AddressOfExpression. ''' @@ -63725,7 +63729,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Syntax.InternalSyntax ''' Represents a single line lambda expression. ''' ''' - ''' A representing the specific kind of + ''' A representing the specific kind of ''' SingleLineLambdaExpressionSyntax. One of SingleLineFunctionLambdaExpression, ''' SingleLineSubLambdaExpression. ''' @@ -63831,7 +63835,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Syntax.InternalSyntax ''' Represents a multi-line lambda expression. ''' ''' - ''' A representing the specific kind of + ''' A representing the specific kind of ''' MultiLineLambdaExpressionSyntax. One of MultiLineFunctionLambdaExpression, ''' MultiLineSubLambdaExpression. ''' @@ -63932,8 +63936,8 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Syntax.InternalSyntax ''' Represents the header part of a lambda expression ''' ''' - ''' A representing the specific kind of LambdaHeaderSyntax. - ''' One of SubLambdaHeader, FunctionLambdaHeader. + ''' A representing the specific kind of + ''' LambdaHeaderSyntax. One of SubLambdaHeader, FunctionLambdaHeader. ''' ''' ''' A list of all attribute lists on this declaration. If no attributes were @@ -64503,7 +64507,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Syntax.InternalSyntax ''' tells which. ''' ''' - ''' A representing the specific kind of + ''' A representing the specific kind of ''' PartitionWhileClauseSyntax. One of SkipWhileClause, TakeWhileClause. ''' ''' @@ -64596,7 +64600,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Syntax.InternalSyntax ''' Represents a "Skip" or "Take" query operator. The Kind property tells which. ''' ''' - ''' A representing the specific kind of + ''' A representing the specific kind of ''' PartitionClauseSyntax. One of SkipClause, TakeClause. ''' ''' @@ -64841,8 +64845,8 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Syntax.InternalSyntax ''' whether to order in ascending or descending order. ''' ''' - ''' A representing the specific kind of OrderingSyntax. One - ''' of AscendingOrdering, DescendingOrdering. + ''' A representing the specific kind of OrderingSyntax. + ''' One of AscendingOrdering, DescendingOrdering. ''' ''' ''' The expression to sort by. @@ -65686,8 +65690,8 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Syntax.InternalSyntax ''' normalization such as comment, pi and cdata text. ''' ''' - ''' A representing the specific kind of XmlTextTokenSyntax. - ''' One of XmlTextLiteralToken, XmlEntityLiteralToken, + ''' A representing the specific kind of + ''' XmlTextTokenSyntax. One of XmlTextLiteralToken, XmlEntityLiteralToken, ''' DocumentationCommentLineBreakToken. ''' ''' @@ -66126,8 +66130,8 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Syntax.InternalSyntax ''' directives, and disabled code. ''' ''' - ''' A representing the specific kind of SyntaxTrivia. One of - ''' WhitespaceTrivia, EndOfLineTrivia, ColonTrivia, CommentTrivia, + ''' A representing the specific kind of SyntaxTrivia. One + ''' of WhitespaceTrivia, EndOfLineTrivia, ColonTrivia, CommentTrivia, ''' ConflictMarkerTrivia, LineContinuationTrivia, ''' DocumentationCommentExteriorTrivia, DisabledTextTrivia. ''' diff --git a/src/Compilers/VisualBasic/Portable/Generated/Syntax.xml.Main.Generated.vb b/src/Compilers/VisualBasic/Portable/Generated/Syntax.xml.Main.Generated.vb index 4287cc2552882..ec83b983e2522 100644 --- a/src/Compilers/VisualBasic/Portable/Generated/Syntax.xml.Main.Generated.vb +++ b/src/Compilers/VisualBasic/Portable/Generated/Syntax.xml.Main.Generated.vb @@ -6539,7 +6539,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic ''' Represents an "End XXX" statement, where XXX is a single keyword. ''' ''' - ''' A representing the specific kind of + ''' A representing the specific kind of ''' EndBlockStatementSyntax. One of EndIfStatement, EndUsingStatement, ''' EndWithStatement, EndSelectStatement, EndStructureStatement, EndEnumStatement, ''' EndInterfaceStatement, EndClassStatement, EndModuleStatement, @@ -6629,7 +6629,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic ''' Represents an "End XXX" statement, where XXX is a single keyword. ''' ''' - ''' A representing the specific kind of + ''' A representing the specific kind of ''' EndBlockStatementSyntax. One of EndIfStatement, EndUsingStatement, ''' EndWithStatement, EndSelectStatement, EndStructureStatement, EndEnumStatement, ''' EndInterfaceStatement, EndClassStatement, EndModuleStatement, @@ -8185,7 +8185,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic ''' one of: NewConstraint, ReferenceConstraint or ValueConstraint. ''' ''' - ''' A representing the specific kind of + ''' A representing the specific kind of ''' SpecialConstraintSyntax. One of NewConstraint, ClassConstraint, ''' StructureConstraint. ''' @@ -8397,7 +8397,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic ''' beginning declaration, a body of executable statements and an end statement. ''' ''' - ''' A representing the specific kind of MethodBlockSyntax. + ''' A representing the specific kind of MethodBlockSyntax. ''' One of SubBlock, FunctionBlock. ''' ''' @@ -8454,7 +8454,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic ''' beginning declaration, a body of executable statements and an end statement. ''' ''' - ''' A representing the specific kind of MethodBlockSyntax. + ''' A representing the specific kind of MethodBlockSyntax. ''' One of SubBlock, FunctionBlock. ''' ''' @@ -8944,9 +8944,9 @@ Namespace Microsoft.CodeAnalysis.VisualBasic ''' Examples include property accessors and custom event accessors. ''' ''' - ''' A representing the specific kind of AccessorBlockSyntax. - ''' One of GetAccessorBlock, SetAccessorBlock, AddHandlerAccessorBlock, - ''' RemoveHandlerAccessorBlock, RaiseEventAccessorBlock. + ''' A representing the specific kind of + ''' AccessorBlockSyntax. One of GetAccessorBlock, SetAccessorBlock, + ''' AddHandlerAccessorBlock, RemoveHandlerAccessorBlock, RaiseEventAccessorBlock. ''' ''' ''' The "Get", "Set", "AddHandler", "RemoveHandler", or "RaiseEvent" statement that @@ -9017,9 +9017,9 @@ Namespace Microsoft.CodeAnalysis.VisualBasic ''' Examples include property accessors and custom event accessors. ''' ''' - ''' A representing the specific kind of AccessorBlockSyntax. - ''' One of GetAccessorBlock, SetAccessorBlock, AddHandlerAccessorBlock, - ''' RemoveHandlerAccessorBlock, RaiseEventAccessorBlock. + ''' A representing the specific kind of + ''' AccessorBlockSyntax. One of GetAccessorBlock, SetAccessorBlock, + ''' AddHandlerAccessorBlock, RemoveHandlerAccessorBlock, RaiseEventAccessorBlock. ''' ''' ''' The "Get", "Set", "AddHandler", "RemoveHandler", or "RaiseEvent" statement that @@ -9446,7 +9446,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic ''' that BlockStatement. ''' ''' - ''' A representing the specific kind of + ''' A representing the specific kind of ''' MethodStatementSyntax. One of SubStatement, FunctionStatement. ''' ''' @@ -9517,7 +9517,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic ''' that BlockStatement. ''' ''' - ''' A representing the specific kind of + ''' A representing the specific kind of ''' MethodStatementSyntax. One of SubStatement, FunctionStatement. ''' ''' @@ -9538,7 +9538,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic ''' that BlockStatement. ''' ''' - ''' A representing the specific kind of + ''' A representing the specific kind of ''' MethodStatementSyntax. One of SubStatement, FunctionStatement. ''' ''' @@ -9935,7 +9935,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic ''' A Declare statement that declares an external DLL method. ''' ''' - ''' A representing the specific kind of + ''' A representing the specific kind of ''' DeclareStatementSyntax. One of DeclareSubStatement, DeclareFunctionStatement. ''' ''' @@ -10035,7 +10035,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic ''' A Declare statement that declares an external DLL method. ''' ''' - ''' A representing the specific kind of + ''' A representing the specific kind of ''' DeclareStatementSyntax. One of DeclareSubStatement, DeclareFunctionStatement. ''' ''' @@ -10081,7 +10081,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic ''' A Declare statement that declares an external DLL method. ''' ''' - ''' A representing the specific kind of + ''' A representing the specific kind of ''' DeclareStatementSyntax. One of DeclareSubStatement, DeclareFunctionStatement. ''' ''' @@ -10102,7 +10102,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic ''' A Declare statement that declares an external DLL method. ''' ''' - ''' A representing the specific kind of + ''' A representing the specific kind of ''' DeclareStatementSyntax. One of DeclareSubStatement, DeclareFunctionStatement. ''' ''' @@ -10342,7 +10342,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic ''' A statement that declares a delegate type. ''' ''' - ''' A representing the specific kind of + ''' A representing the specific kind of ''' DelegateStatementSyntax. One of DelegateSubStatement, ''' DelegateFunctionStatement. ''' @@ -10412,7 +10412,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic ''' A statement that declares a delegate type. ''' ''' - ''' A representing the specific kind of + ''' A representing the specific kind of ''' DelegateStatementSyntax. One of DelegateSubStatement, ''' DelegateFunctionStatement. ''' @@ -10453,7 +10453,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic ''' A statement that declares a delegate type. ''' ''' - ''' A representing the specific kind of + ''' A representing the specific kind of ''' DelegateStatementSyntax. One of DelegateSubStatement, ''' DelegateFunctionStatement. ''' @@ -10472,7 +10472,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic ''' A statement that declares a delegate type. ''' ''' - ''' A representing the specific kind of + ''' A representing the specific kind of ''' DelegateStatementSyntax. One of DelegateSubStatement, ''' DelegateFunctionStatement. ''' @@ -11195,7 +11195,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic ''' Begin of a BlockNode, and the body of the accessor is the Body of that node. ''' ''' - ''' A representing the specific kind of + ''' A representing the specific kind of ''' AccessorStatementSyntax. One of GetAccessorStatement, SetAccessorStatement, ''' AddHandlerAccessorStatement, RemoveHandlerAccessorStatement, ''' RaiseEventAccessorStatement. @@ -11252,7 +11252,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic ''' Begin of a BlockNode, and the body of the accessor is the Body of that node. ''' ''' - ''' A representing the specific kind of + ''' A representing the specific kind of ''' AccessorStatementSyntax. One of GetAccessorStatement, SetAccessorStatement, ''' AddHandlerAccessorStatement, RemoveHandlerAccessorStatement, ''' RaiseEventAccessorStatement. @@ -13227,8 +13227,8 @@ Namespace Microsoft.CodeAnalysis.VisualBasic ''' or next keyword. ''' ''' - ''' A representing the specific kind of LabelSyntax. One of - ''' IdentifierLabel, NumericLabel, NextLabel. + ''' A representing the specific kind of LabelSyntax. One + ''' of IdentifierLabel, NumericLabel, NextLabel. ''' ''' ''' The label name (identifier), line number (integer literal), or next keyword @@ -13262,8 +13262,8 @@ Namespace Microsoft.CodeAnalysis.VisualBasic ''' or next keyword. ''' ''' - ''' A representing the specific kind of LabelSyntax. One of - ''' IdentifierLabel, NumericLabel, NextLabel. + ''' A representing the specific kind of LabelSyntax. One + ''' of IdentifierLabel, NumericLabel, NextLabel. ''' ''' ''' The label name (identifier), line number (integer literal), or next keyword @@ -13315,7 +13315,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic ''' kind of statement this is. ''' ''' - ''' A representing the specific kind of + ''' A representing the specific kind of ''' StopOrEndStatementSyntax. One of StopStatement, EndStatement. ''' ''' @@ -13654,10 +13654,11 @@ Namespace Microsoft.CodeAnalysis.VisualBasic ''' Kind. ''' ''' - ''' A representing the specific kind of ExitStatementSyntax. - ''' One of ExitDoStatement, ExitForStatement, ExitSubStatement, - ''' ExitFunctionStatement, ExitOperatorStatement, ExitPropertyStatement, - ''' ExitTryStatement, ExitSelectStatement, ExitWhileStatement. + ''' A representing the specific kind of + ''' ExitStatementSyntax. One of ExitDoStatement, ExitForStatement, + ''' ExitSubStatement, ExitFunctionStatement, ExitOperatorStatement, + ''' ExitPropertyStatement, ExitTryStatement, ExitSelectStatement, + ''' ExitWhileStatement. ''' ''' ''' The "Exit" keyword. @@ -13710,10 +13711,11 @@ Namespace Microsoft.CodeAnalysis.VisualBasic ''' Kind. ''' ''' - ''' A representing the specific kind of ExitStatementSyntax. - ''' One of ExitDoStatement, ExitForStatement, ExitSubStatement, - ''' ExitFunctionStatement, ExitOperatorStatement, ExitPropertyStatement, - ''' ExitTryStatement, ExitSelectStatement, ExitWhileStatement. + ''' A representing the specific kind of + ''' ExitStatementSyntax. One of ExitDoStatement, ExitForStatement, + ''' ExitSubStatement, ExitFunctionStatement, ExitOperatorStatement, + ''' ExitPropertyStatement, ExitTryStatement, ExitSelectStatement, + ''' ExitWhileStatement. ''' ''' ''' The keyword describing the block to exit. @@ -13835,7 +13837,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic ''' determined by examining the Kind. ''' ''' - ''' A representing the specific kind of + ''' A representing the specific kind of ''' ContinueStatementSyntax. One of ContinueWhileStatement, ContinueDoStatement, ''' ContinueForStatement. ''' @@ -13879,7 +13881,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic ''' determined by examining the Kind. ''' ''' - ''' A representing the specific kind of + ''' A representing the specific kind of ''' ContinueStatementSyntax. One of ContinueWhileStatement, ContinueDoStatement, ''' ContinueForStatement. ''' @@ -15325,7 +15327,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic ''' Represents an OnError Goto statement. ''' ''' - ''' A representing the specific kind of + ''' A representing the specific kind of ''' OnErrorGoToStatementSyntax. One of OnErrorGoToZeroStatement, ''' OnErrorGoToMinusOneStatement, OnErrorGoToLabelStatement. ''' @@ -15382,7 +15384,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic ''' Represents an OnError Goto statement. ''' ''' - ''' A representing the specific kind of + ''' A representing the specific kind of ''' OnErrorGoToStatementSyntax. One of OnErrorGoToZeroStatement, ''' OnErrorGoToMinusOneStatement, OnErrorGoToLabelStatement. ''' @@ -15583,7 +15585,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic ''' this is a "Resume", "Resume Next" or "Resume label" statement. ''' ''' - ''' A representing the specific kind of + ''' A representing the specific kind of ''' ResumeStatementSyntax. One of ResumeStatement, ResumeLabelStatement, ''' ResumeNextStatement. ''' @@ -15613,7 +15615,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic ''' this is a "Resume", "Resume Next" or "Resume label" statement. ''' ''' - ''' A representing the specific kind of + ''' A representing the specific kind of ''' ResumeStatementSyntax. One of ResumeStatement, ResumeLabelStatement, ''' ResumeNextStatement. ''' @@ -15632,7 +15634,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic ''' this is a "Resume", "Resume Next" or "Resume label" statement. ''' ''' - ''' A representing the specific kind of + ''' A representing the specific kind of ''' ResumeStatementSyntax. One of ResumeStatement, ResumeLabelStatement, ''' ResumeNextStatement. ''' @@ -15921,8 +15923,8 @@ Namespace Microsoft.CodeAnalysis.VisualBasic ''' Represents a case statement and its subsequent block. ''' ''' - ''' A representing the specific kind of CaseBlockSyntax. One - ''' of CaseBlock, CaseElseBlock. + ''' A representing the specific kind of CaseBlockSyntax. + ''' One of CaseBlock, CaseElseBlock. ''' ''' ''' The statement that begins the case block. @@ -15951,8 +15953,8 @@ Namespace Microsoft.CodeAnalysis.VisualBasic ''' Represents a case statement and its subsequent block. ''' ''' - ''' A representing the specific kind of CaseBlockSyntax. One - ''' of CaseBlock, CaseElseBlock. + ''' A representing the specific kind of CaseBlockSyntax. + ''' One of CaseBlock, CaseElseBlock. ''' ''' ''' The statement that begins the case block. @@ -16068,8 +16070,8 @@ Namespace Microsoft.CodeAnalysis.VisualBasic ''' Kind=Case. ''' ''' - ''' A representing the specific kind of CaseStatementSyntax. - ''' One of CaseStatement, CaseElseStatement. + ''' A representing the specific kind of + ''' CaseStatementSyntax. One of CaseStatement, CaseElseStatement. ''' ''' ''' The "Case" keyword @@ -16097,8 +16099,8 @@ Namespace Microsoft.CodeAnalysis.VisualBasic ''' Kind=Case. ''' ''' - ''' A representing the specific kind of CaseStatementSyntax. - ''' One of CaseStatement, CaseElseStatement. + ''' A representing the specific kind of + ''' CaseStatementSyntax. One of CaseStatement, CaseElseStatement. ''' ''' ''' A list of clauses associated with this Case. If Kind=CaseElse, then this list @@ -16115,8 +16117,8 @@ Namespace Microsoft.CodeAnalysis.VisualBasic ''' Kind=Case. ''' ''' - ''' A representing the specific kind of CaseStatementSyntax. - ''' One of CaseStatement, CaseElseStatement. + ''' A representing the specific kind of + ''' CaseStatementSyntax. One of CaseStatement, CaseElseStatement. ''' ''' ''' A list of clauses associated with this Case. If Kind=CaseElse, then this list @@ -17419,7 +17421,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic ''' Represents a relation clause in a Case statement, such as "Is > expression". ''' ''' - ''' A representing the specific kind of + ''' A representing the specific kind of ''' RelationalCaseClauseSyntax. One of CaseEqualsClause, CaseNotEqualsClause, ''' CaseLessThanClause, CaseLessThanOrEqualClause, CaseGreaterThanOrEqualClause, ''' CaseGreaterThanClause. @@ -17579,7 +17581,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic ''' Represents a relation clause in a Case statement, such as "Is > expression". ''' ''' - ''' A representing the specific kind of + ''' A representing the specific kind of ''' RelationalCaseClauseSyntax. One of CaseEqualsClause, CaseNotEqualsClause, ''' CaseLessThanClause, CaseLessThanOrEqualClause, CaseGreaterThanOrEqualClause, ''' CaseGreaterThanClause. @@ -17994,7 +17996,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic ''' is a Do While, Do Until, Do Loop While, Do Loop Until, or infinite Do Loop. ''' ''' - ''' A representing the specific kind of DoLoopBlockSyntax. + ''' A representing the specific kind of DoLoopBlockSyntax. ''' One of SimpleDoLoopBlock, DoWhileLoopBlock, DoUntilLoopBlock, DoLoopWhileBlock, ''' DoLoopUntilBlock. ''' @@ -18064,7 +18066,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic ''' is a Do While, Do Until, Do Loop While, Do Loop Until, or infinite Do Loop. ''' ''' - ''' A representing the specific kind of DoLoopBlockSyntax. + ''' A representing the specific kind of DoLoopBlockSyntax. ''' One of SimpleDoLoopBlock, DoWhileLoopBlock, DoUntilLoopBlock, DoLoopWhileBlock, ''' DoLoopUntilBlock. ''' @@ -18203,7 +18205,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic ''' The Do statement that begins a Do-Loop block. ''' ''' - ''' A representing the specific kind of DoStatementSyntax. + ''' A representing the specific kind of DoStatementSyntax. ''' One of SimpleDoStatement, DoWhileStatement, DoUntilStatement. ''' ''' @@ -18240,7 +18242,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic ''' The Do statement that begins a Do-Loop block. ''' ''' - ''' A representing the specific kind of DoStatementSyntax. + ''' A representing the specific kind of DoStatementSyntax. ''' One of SimpleDoStatement, DoWhileStatement, DoUntilStatement. ''' ''' @@ -18256,7 +18258,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic ''' The Do statement that begins a Do-Loop block. ''' ''' - ''' A representing the specific kind of DoStatementSyntax. + ''' A representing the specific kind of DoStatementSyntax. ''' One of SimpleDoStatement, DoWhileStatement, DoUntilStatement. ''' Public Shared Function DoStatement(ByVal kind As SyntaxKind) As DoStatementSyntax @@ -18388,8 +18390,9 @@ Namespace Microsoft.CodeAnalysis.VisualBasic ''' The Loop statement that begins a Do-Loop block. ''' ''' - ''' A representing the specific kind of LoopStatementSyntax. - ''' One of SimpleLoopStatement, LoopWhileStatement, LoopUntilStatement. + ''' A representing the specific kind of + ''' LoopStatementSyntax. One of SimpleLoopStatement, LoopWhileStatement, + ''' LoopUntilStatement. ''' ''' ''' The "Loop" keyword. @@ -18425,8 +18428,9 @@ Namespace Microsoft.CodeAnalysis.VisualBasic ''' The Loop statement that begins a Do-Loop block. ''' ''' - ''' A representing the specific kind of LoopStatementSyntax. - ''' One of SimpleLoopStatement, LoopWhileStatement, LoopUntilStatement. + ''' A representing the specific kind of + ''' LoopStatementSyntax. One of SimpleLoopStatement, LoopWhileStatement, + ''' LoopUntilStatement. ''' ''' ''' The "While expression" or "Until expression" clause of the Loop statement, if @@ -18441,8 +18445,9 @@ Namespace Microsoft.CodeAnalysis.VisualBasic ''' The Loop statement that begins a Do-Loop block. ''' ''' - ''' A representing the specific kind of LoopStatementSyntax. - ''' One of SimpleLoopStatement, LoopWhileStatement, LoopUntilStatement. + ''' A representing the specific kind of + ''' LoopStatementSyntax. One of SimpleLoopStatement, LoopWhileStatement, + ''' LoopUntilStatement. ''' Public Shared Function LoopStatement(ByVal kind As SyntaxKind) As LoopStatementSyntax Return SyntaxFactory.LoopStatement(kind, SyntaxFactory.Token(SyntaxKind.LoopKeyword), Nothing) @@ -18747,7 +18752,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic ''' indicate which kind of clause. ''' ''' - ''' A representing the specific kind of + ''' A representing the specific kind of ''' WhileOrUntilClauseSyntax. One of WhileClause, UntilClause. ''' ''' @@ -23042,7 +23047,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic ''' determined by checking the Kind. ''' ''' - ''' A representing the specific kind of + ''' A representing the specific kind of ''' AssignmentStatementSyntax. One of SimpleAssignmentStatement, ''' MidAssignmentStatement, AddAssignmentStatement, SubtractAssignmentStatement, ''' MultiplyAssignmentStatement, DivideAssignmentStatement, @@ -23951,7 +23956,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic ''' determines which one. ''' ''' - ''' A representing the specific kind of + ''' A representing the specific kind of ''' AddRemoveHandlerStatementSyntax. One of AddHandlerStatement, ''' RemoveHandlerStatement. ''' @@ -24222,7 +24227,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic ''' determines which one. ''' ''' - ''' A representing the specific kind of + ''' A representing the specific kind of ''' AddRemoveHandlerStatementSyntax. One of AddHandlerStatement, ''' RemoveHandlerStatement. ''' @@ -24535,7 +24540,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic ''' Represents a ReDim statement. ''' ''' - ''' A representing the specific kind of + ''' A representing the specific kind of ''' ReDimStatementSyntax. One of ReDimStatement, ReDimPreserveStatement. ''' ''' @@ -24565,7 +24570,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic ''' Represents a ReDim statement. ''' ''' - ''' A representing the specific kind of + ''' A representing the specific kind of ''' ReDimStatementSyntax. One of ReDimStatement, ReDimPreserveStatement. ''' ''' @@ -24580,7 +24585,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic ''' Represents a ReDim statement. ''' ''' - ''' A representing the specific kind of + ''' A representing the specific kind of ''' ReDimStatementSyntax. One of ReDimStatement, ReDimPreserveStatement. ''' ''' @@ -25026,7 +25031,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic ''' value from the token. ''' ''' - ''' A representing the specific kind of + ''' A representing the specific kind of ''' LiteralExpressionSyntax. One of CharacterLiteralExpression, ''' TrueLiteralExpression, FalseLiteralExpression, NumericLiteralExpression, ''' DateLiteralExpression, StringLiteralExpression, NothingLiteralExpression. @@ -25871,7 +25876,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic ''' Represents a TypeOf...Is or IsNot expression. ''' ''' - ''' A representing the specific kind of + ''' A representing the specific kind of ''' TypeOfExpressionSyntax. One of TypeOfIsExpression, TypeOfIsNotExpression. ''' ''' @@ -26045,7 +26050,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic ''' Represents a TypeOf...Is or IsNot expression. ''' ''' - ''' A representing the specific kind of + ''' A representing the specific kind of ''' TypeOfExpressionSyntax. One of TypeOfIsExpression, TypeOfIsNotExpression. ''' ''' @@ -26229,7 +26234,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic ''' property determines which kind of access. ''' ''' - ''' A representing the specific kind of + ''' A representing the specific kind of ''' MemberAccessExpressionSyntax. One of SimpleMemberAccessExpression, ''' DictionaryAccessExpression. ''' @@ -26277,7 +26282,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic ''' property determines which kind of access. ''' ''' - ''' A representing the specific kind of + ''' A representing the specific kind of ''' MemberAccessExpressionSyntax. One of SimpleMemberAccessExpression, ''' DictionaryAccessExpression. ''' @@ -26511,7 +26516,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic ''' Kind property determines which kind of access. ''' ''' - ''' A representing the specific kind of + ''' A representing the specific kind of ''' XmlMemberAccessExpressionSyntax. One of XmlElementAccessExpression, ''' XmlDescendantAccessExpression, XmlAttributeAccessExpression. ''' @@ -26558,7 +26563,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic ''' Kind property determines which kind of access. ''' ''' - ''' A representing the specific kind of + ''' A representing the specific kind of ''' XmlMemberAccessExpressionSyntax. One of XmlElementAccessExpression, ''' XmlDescendantAccessExpression, XmlAttributeAccessExpression. ''' @@ -26582,7 +26587,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic ''' Kind property determines which kind of access. ''' ''' - ''' A representing the specific kind of + ''' A representing the specific kind of ''' XmlMemberAccessExpressionSyntax. One of XmlElementAccessExpression, ''' XmlDescendantAccessExpression, XmlAttributeAccessExpression. ''' @@ -33922,7 +33927,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic ''' exact operation being performed is determined by the Operator property. ''' ''' - ''' A representing the specific kind of + ''' A representing the specific kind of ''' BinaryExpressionSyntax. One of AddExpression, SubtractExpression, ''' MultiplyExpression, DivideExpression, IntegerDivideExpression, ''' ExponentiateExpression, LeftShiftExpression, RightShiftExpression, @@ -34802,7 +34807,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic ''' Describes a unary operator: Plus, Negate, Not or AddressOf. ''' ''' - ''' A representing the specific kind of + ''' A representing the specific kind of ''' UnaryExpressionSyntax. One of UnaryPlusExpression, UnaryMinusExpression, ''' NotExpression, AddressOfExpression. ''' @@ -36239,7 +36244,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic ''' Represents a single line lambda expression. ''' ''' - ''' A representing the specific kind of + ''' A representing the specific kind of ''' SingleLineLambdaExpressionSyntax. One of SingleLineFunctionLambdaExpression, ''' SingleLineSubLambdaExpression. ''' @@ -36651,7 +36656,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic ''' Represents a multi-line lambda expression. ''' ''' - ''' A representing the specific kind of + ''' A representing the specific kind of ''' MultiLineLambdaExpressionSyntax. One of MultiLineFunctionLambdaExpression, ''' MultiLineSubLambdaExpression. ''' @@ -36698,7 +36703,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic ''' Represents a multi-line lambda expression. ''' ''' - ''' A representing the specific kind of + ''' A representing the specific kind of ''' MultiLineLambdaExpressionSyntax. One of MultiLineFunctionLambdaExpression, ''' MultiLineSubLambdaExpression. ''' @@ -36856,8 +36861,8 @@ Namespace Microsoft.CodeAnalysis.VisualBasic ''' Represents the header part of a lambda expression ''' ''' - ''' A representing the specific kind of LambdaHeaderSyntax. - ''' One of SubLambdaHeader, FunctionLambdaHeader. + ''' A representing the specific kind of + ''' LambdaHeaderSyntax. One of SubLambdaHeader, FunctionLambdaHeader. ''' ''' ''' A list of all attribute lists on this declaration. If no attributes were @@ -36905,8 +36910,8 @@ Namespace Microsoft.CodeAnalysis.VisualBasic ''' Represents the header part of a lambda expression ''' ''' - ''' A representing the specific kind of LambdaHeaderSyntax. - ''' One of SubLambdaHeader, FunctionLambdaHeader. + ''' A representing the specific kind of + ''' LambdaHeaderSyntax. One of SubLambdaHeader, FunctionLambdaHeader. ''' ''' ''' The "Sub" or "Function" keyword that introduces this lambda expression. @@ -38594,7 +38599,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic ''' tells which. ''' ''' - ''' A representing the specific kind of + ''' A representing the specific kind of ''' PartitionWhileClauseSyntax. One of SkipWhileClause, TakeWhileClause. ''' ''' @@ -38749,7 +38754,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic ''' tells which. ''' ''' - ''' A representing the specific kind of + ''' A representing the specific kind of ''' PartitionWhileClauseSyntax. One of SkipWhileClause, TakeWhileClause. ''' ''' @@ -39052,7 +39057,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic ''' Represents a "Skip" or "Take" query operator. The Kind property tells which. ''' ''' - ''' A representing the specific kind of + ''' A representing the specific kind of ''' PartitionClauseSyntax. One of SkipClause, TakeClause. ''' ''' @@ -40018,8 +40023,8 @@ Namespace Microsoft.CodeAnalysis.VisualBasic ''' whether to order in ascending or descending order. ''' ''' - ''' A representing the specific kind of OrderingSyntax. One - ''' of AscendingOrdering, DescendingOrdering. + ''' A representing the specific kind of OrderingSyntax. + ''' One of AscendingOrdering, DescendingOrdering. ''' ''' ''' The expression to sort by. @@ -40163,8 +40168,8 @@ Namespace Microsoft.CodeAnalysis.VisualBasic ''' whether to order in ascending or descending order. ''' ''' - ''' A representing the specific kind of OrderingSyntax. One - ''' of AscendingOrdering, DescendingOrdering. + ''' A representing the specific kind of OrderingSyntax. + ''' One of AscendingOrdering, DescendingOrdering. ''' ''' ''' The expression to sort by. @@ -41813,8 +41818,8 @@ Namespace Microsoft.CodeAnalysis.VisualBasic ''' normalization such as comment, pi and cdata text. ''' ''' - ''' A representing the specific kind of XmlTextTokenSyntax. - ''' One of XmlTextLiteralToken, XmlEntityLiteralToken, + ''' A representing the specific kind of + ''' XmlTextTokenSyntax. One of XmlTextLiteralToken, XmlEntityLiteralToken, ''' DocumentationCommentLineBreakToken. ''' ''' @@ -41837,8 +41842,8 @@ Namespace Microsoft.CodeAnalysis.VisualBasic ''' normalization such as comment, pi and cdata text. ''' ''' - ''' A representing the specific kind of XmlTextTokenSyntax. - ''' One of XmlTextLiteralToken, XmlEntityLiteralToken, + ''' A representing the specific kind of + ''' XmlTextTokenSyntax. One of XmlTextLiteralToken, XmlEntityLiteralToken, ''' DocumentationCommentLineBreakToken. ''' ''' @@ -42902,8 +42907,8 @@ Namespace Microsoft.CodeAnalysis.VisualBasic ''' directives, and disabled code. ''' ''' - ''' A representing the specific kind of SyntaxTrivia. One of - ''' WhitespaceTrivia, EndOfLineTrivia, ColonTrivia, CommentTrivia, + ''' A representing the specific kind of SyntaxTrivia. One + ''' of WhitespaceTrivia, EndOfLineTrivia, ColonTrivia, CommentTrivia, ''' ConflictMarkerTrivia, LineContinuationTrivia, ''' DocumentationCommentExteriorTrivia, DisabledTextTrivia. ''' @@ -43400,7 +43405,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic ''' source. ''' ''' - ''' A representing the specific kind of + ''' A representing the specific kind of ''' IfDirectiveTriviaSyntax. One of IfDirectiveTrivia, ElseIfDirectiveTrivia. ''' ''' @@ -43542,7 +43547,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic ''' source. ''' ''' - ''' A representing the specific kind of + ''' A representing the specific kind of ''' IfDirectiveTriviaSyntax. One of IfDirectiveTrivia, ElseIfDirectiveTrivia. ''' Public Shared Function IfDirectiveTrivia(ByVal kind As SyntaxKind, ifOrElseIfKeyword As SyntaxToken, condition As ExpressionSyntax) As IfDirectiveTriviaSyntax diff --git a/src/Compilers/VisualBasic/Portable/Lowering/AsyncRewriter/AsyncRewriter.AsyncMethodToClassRewriter.Await.vb b/src/Compilers/VisualBasic/Portable/Lowering/AsyncRewriter/AsyncRewriter.AsyncMethodToClassRewriter.Await.vb index f17a07d87530c..4589bb498960e 100644 --- a/src/Compilers/VisualBasic/Portable/Lowering/AsyncRewriter/AsyncRewriter.AsyncMethodToClassRewriter.Await.vb +++ b/src/Compilers/VisualBasic/Portable/Lowering/AsyncRewriter/AsyncRewriter.AsyncMethodToClassRewriter.Await.vb @@ -110,9 +110,9 @@ Namespace Microsoft.CodeAnalysis.VisualBasic End Function Private Function GenerateAwaitForIncompleteTask(awaiterTemp As LocalSymbol) As BoundBlock - Dim stateNumber As Integer = 0 + Dim state As StateMachineState = 0 Dim resumeLabel As GeneratedLabelSymbol = Nothing - AddResumableState(awaiterTemp.GetDeclaratorSyntax(), stateNumber, resumeLabel) + AddResumableState(awaiterTemp.GetDeclaratorSyntax(), state, resumeLabel) Dim awaiterType As TypeSymbol = awaiterTemp.Type Dim awaiterFieldType As TypeSymbol = awaiterType @@ -127,7 +127,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic blockBuilder.Add( Me.F.Assignment( Me.F.Field(Me.F.Me(), Me.StateField, True), - Me.F.AssignmentExpression(Me.F.Local(Me.CachedState, True), Me.F.Literal(stateNumber)))) + Me.F.AssignmentExpression(Me.F.Local(Me.CachedState, True), Me.F.Literal(state)))) ' Emit Await yield point to be injected into PDB blockBuilder.Add(Me.F.NoOp(NoOpStatementFlavor.AwaitYieldPoint)) @@ -253,7 +253,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic blockBuilder.Add( Me.F.Assignment( Me.F.Field(Me.F.Me(), Me.StateField, True), - Me.F.AssignmentExpression(Me.F.Local(Me.CachedState, True), Me.F.Literal(StateMachineStates.NotStartedStateMachine)))) + Me.F.AssignmentExpression(Me.F.Local(Me.CachedState, True), Me.F.Literal(StateMachineState.NotStartedOrRunningState)))) ' STMT: $awaiterTemp = Me.$awaiter ' or diff --git a/src/Compilers/VisualBasic/Portable/Lowering/AsyncRewriter/AsyncRewriter.AsyncMethodToClassRewriter.vb b/src/Compilers/VisualBasic/Portable/Lowering/AsyncRewriter/AsyncRewriter.AsyncMethodToClassRewriter.vb index 3675beb28001b..5be9c3691e995 100644 --- a/src/Compilers/VisualBasic/Portable/Lowering/AsyncRewriter/AsyncRewriter.AsyncMethodToClassRewriter.vb +++ b/src/Compilers/VisualBasic/Portable/Lowering/AsyncRewriter/AsyncRewriter.AsyncMethodToClassRewriter.vb @@ -88,9 +88,9 @@ Namespace Microsoft.CodeAnalysis.VisualBasic Me._nextAwaiterId = If(slotAllocatorOpt IsNot Nothing, slotAllocatorOpt.PreviousAwaiterSlotCount, 0) End Sub - Protected Overrides ReadOnly Property FirstIncreasingResumableState As Integer + Protected Overrides ReadOnly Property FirstIncreasingResumableState As StateMachineState Get - Return StateMachineStates.FirstResumableAsyncState + Return StateMachineState.FirstResumableAsyncState End Get End Property @@ -177,7 +177,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic exceptionLocal, Me.F.Block( SyntheticBoundNodeFactory.HiddenSequencePoint(), - Me.F.Assignment(Me.F.Field(Me.F.Me(), Me.StateField, True), Me.F.Literal(StateMachineStates.FinishedStateMachine)), + Me.F.Assignment(Me.F.Field(Me.F.Me(), Me.StateField, True), Me.F.Literal(StateMachineState.FinishedState)), Me.F.ExpressionStatement( Me._owner.GenerateMethodCall( Me.F.Field(Me.F.Me(), Me._builder, False), @@ -193,7 +193,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic ' STMT: state = cachedState = finishedState Dim stateDone = Me.F.Assignment( Me.F.Field(Me.F.Me(), Me.StateField, True), - Me.F.AssignmentExpression(Me.F.Local(Me.CachedState, True), Me.F.Literal(StateMachineStates.FinishedStateMachine))) + Me.F.AssignmentExpression(Me.F.Local(Me.CachedState, True), Me.F.Literal(StateMachineState.FinishedState))) Dim block As MethodBlockSyntax = TryCast(body.Syntax, MethodBlockSyntax) If (block Is Nothing) Then bodyBuilder.Add(stateDone) diff --git a/src/Compilers/VisualBasic/Portable/Lowering/AsyncRewriter/AsyncRewriter.vb b/src/Compilers/VisualBasic/Portable/Lowering/AsyncRewriter/AsyncRewriter.vb index d1032d750de75..930068a8a9131 100644 --- a/src/Compilers/VisualBasic/Portable/Lowering/AsyncRewriter/AsyncRewriter.vb +++ b/src/Compilers/VisualBasic/Portable/Lowering/AsyncRewriter/AsyncRewriter.vb @@ -216,7 +216,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic bodyBuilder.Add( Me.F.Assignment( stateFieldAsLValue, - Me.F.Literal(StateMachineStates.NotStartedStateMachine))) + Me.F.Literal(StateMachineState.NotStartedOrRunningState))) ' STAT: localStateMachine.$builder = System.Runtime.CompilerServices.AsyncTaskMethodBuilder(Of typeArgs).Create() Dim constructedBuilderField As FieldSymbol = Me._builderField.AsMember(frameType) diff --git a/src/Compilers/VisualBasic/Portable/Lowering/IteratorRewriter/IteratorRewriter.IteratorMethodToClassRewriter.vb b/src/Compilers/VisualBasic/Portable/Lowering/IteratorRewriter/IteratorRewriter.IteratorMethodToClassRewriter.vb index 91f657ed0a1e0..eb4598d3edb9f 100644 --- a/src/Compilers/VisualBasic/Portable/Lowering/IteratorRewriter/IteratorRewriter.IteratorMethodToClassRewriter.vb +++ b/src/Compilers/VisualBasic/Portable/Lowering/IteratorRewriter/IteratorRewriter.IteratorMethodToClassRewriter.vb @@ -38,9 +38,9 @@ Namespace Microsoft.CodeAnalysis.VisualBasic _current = current End Sub - Protected Overrides ReadOnly Property FirstIncreasingResumableState As Integer + Protected Overrides ReadOnly Property FirstIncreasingResumableState As StateMachineState Get - Return StateMachineStates.FirstResumableIteratorState + Return StateMachineState.FirstResumableIteratorState End Get End Property @@ -58,7 +58,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic F.CurrentMethod = moveNextMethod Dim initialLabel As GeneratedLabelSymbol = Nothing - AddState(StateMachineStates.InitialIteratorState, initialLabel) + AddState(StateMachineState.InitialIteratorState, initialLabel) Me._methodValue = Me.F.SynthesizedLocal(F.CurrentMethod.ReturnType, SynthesizedLocalKind.StateMachineReturnValue, F.Syntax) @@ -83,7 +83,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic Dispatch(isOutermost:=True), GenerateReturn(finished:=True), F.Label(initialLabel), - F.Assignment(F.Field(F.Me, Me.StateField, True), Me.F.AssignmentExpression(Me.F.Local(Me.CachedState, True), Me.F.Literal(StateMachineStates.NotStartedStateMachine))), + F.Assignment(F.Field(F.Me, Me.StateField, True), Me.F.AssignmentExpression(Me.F.Local(Me.CachedState, True), Me.F.Literal(StateMachineState.NotStartedOrRunningState))), newBody, HandleReturn() )) @@ -107,7 +107,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic F.Select( F.Field(F.Me, Me.StateField, False), sections), - F.Assignment(F.Field(F.Me, Me.StateField, True), F.Literal(StateMachineStates.NotStartedStateMachine)), + F.Assignment(F.Field(F.Me, Me.StateField, True), F.Literal(StateMachineState.NotStartedOrRunningState)), F.Label(breakLabel), F.ExpressionStatement(F.Call(F.Me, moveNextMethod)), F.Return() @@ -190,7 +190,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic ' : ' Me.state = -1 - Dim stateNumber As Integer = 0 + Dim stateNumber As StateMachineState = 0 Dim resumeLabel As GeneratedLabelSymbol = Nothing AddResumableState(node.Syntax, stateNumber, resumeLabel) @@ -201,7 +201,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic F.Assignment(F.Field(F.Me, Me.StateField, True), F.AssignmentExpression(F.Local(Me.CachedState, True), F.Literal(stateNumber))), GenerateReturn(finished:=False), F.Label(resumeLabel), - F.Assignment(F.Field(F.Me, Me.StateField, True), F.AssignmentExpression(F.Local(Me.CachedState, True), F.Literal(StateMachineStates.NotStartedStateMachine))) + F.Assignment(F.Field(F.Me, Me.StateField, True), F.AssignmentExpression(F.Local(Me.CachedState, True), F.Literal(StateMachineState.NotStartedOrRunningState))) ) ) diff --git a/src/Compilers/VisualBasic/Portable/Lowering/IteratorRewriter/IteratorRewriter.vb b/src/Compilers/VisualBasic/Portable/Lowering/IteratorRewriter/IteratorRewriter.vb index 125c80376913d..83aa334ed42b0 100644 --- a/src/Compilers/VisualBasic/Portable/Lowering/IteratorRewriter/IteratorRewriter.vb +++ b/src/Compilers/VisualBasic/Portable/Lowering/IteratorRewriter/IteratorRewriter.vb @@ -215,11 +215,11 @@ Namespace Microsoft.CodeAnalysis.VisualBasic F.If( condition:= F.LogicalAndAlso( - F.IntEqual(F.Field(F.Me, StateField, False), F.Literal(StateMachineStates.FinishedStateMachine)), + F.IntEqual(F.Field(F.Me, StateField, False), F.Literal(StateMachineState.FinishedState)), F.IntEqual(F.Field(F.Me, _initialThreadIdField, False), managedThreadId)), thenClause:= F.Block( - F.Assignment(F.Field(F.Me, StateField, True), F.Literal(StateMachineStates.FirstUnusedState)), + F.Assignment(F.Field(F.Me, StateField, True), F.Literal(StateMachineState.FirstUnusedState)), F.Assignment(F.Local(resultVariable, True), F.Me), If(Method.IsShared OrElse Method.MeParameter.Type.IsReferenceType, F.Goto(thisInitialized), @@ -323,7 +323,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic Protected Overrides Sub InitializeStateMachine(bodyBuilder As ArrayBuilder(Of BoundStatement), frameType As NamedTypeSymbol, stateMachineLocal As LocalSymbol) ' Dim stateMachineLocal As new IteratorImplementationClass(N) ' where N is either 0 (if we're producing an enumerator) or -2 (if we're producing an enumerable) - Dim initialState = If(_isEnumerable, StateMachineStates.FinishedStateMachine, StateMachineStates.FirstUnusedState) + Dim initialState = If(_isEnumerable, StateMachineState.FinishedState, StateMachineState.FirstUnusedState) bodyBuilder.Add( F.Assignment( F.Local(stateMachineLocal, True), diff --git a/src/Compilers/VisualBasic/Portable/Lowering/LambdaRewriter/LambdaFrameConstructor.vb b/src/Compilers/VisualBasic/Portable/Lowering/LambdaRewriter/LambdaFrameConstructor.vb index 090a2843311a3..cf680d2d5bc01 100644 --- a/src/Compilers/VisualBasic/Portable/Lowering/LambdaRewriter/LambdaFrameConstructor.vb +++ b/src/Compilers/VisualBasic/Portable/Lowering/LambdaRewriter/LambdaFrameConstructor.vb @@ -4,6 +4,7 @@ Imports Microsoft.CodeAnalysis.PooledObjects Imports Microsoft.CodeAnalysis.Symbols +Imports Microsoft.CodeAnalysis.VisualBasic.Emit Imports Microsoft.CodeAnalysis.VisualBasic.Symbols Namespace Microsoft.CodeAnalysis.VisualBasic @@ -45,8 +46,8 @@ Namespace Microsoft.CodeAnalysis.VisualBasic Return False End Function - Friend Overrides Sub AddSynthesizedAttributes(compilationState As ModuleCompilationState, ByRef attributes As ArrayBuilder(Of SynthesizedAttributeData)) - MyBase.AddSynthesizedAttributes(compilationState, attributes) + Friend Overrides Sub AddSynthesizedAttributes(moduleBuilder As PEModuleBuilder, ByRef attributes As ArrayBuilder(Of SynthesizedAttributeData)) + MyBase.AddSynthesizedAttributes(moduleBuilder, attributes) ' Dev11 adds DebuggerNonUserCode; there is no reason to do so since: ' - we emit no debug info for the body diff --git a/src/Compilers/VisualBasic/Portable/Lowering/LambdaRewriter/SynthesizedLambdaMethod.vb b/src/Compilers/VisualBasic/Portable/Lowering/LambdaRewriter/SynthesizedLambdaMethod.vb index 06abd854cd0a5..919fa2fddbabb 100644 --- a/src/Compilers/VisualBasic/Portable/Lowering/LambdaRewriter/SynthesizedLambdaMethod.vb +++ b/src/Compilers/VisualBasic/Portable/Lowering/LambdaRewriter/SynthesizedLambdaMethod.vb @@ -7,6 +7,7 @@ Imports System.Collections.Immutable Imports Microsoft.CodeAnalysis.CodeGen Imports Microsoft.CodeAnalysis.PooledObjects Imports Microsoft.CodeAnalysis.Symbols +Imports Microsoft.CodeAnalysis.VisualBasic.Emit Imports Microsoft.CodeAnalysis.VisualBasic.Symbols Imports Microsoft.CodeAnalysis.VisualBasic.Syntax @@ -195,8 +196,8 @@ Namespace Microsoft.CodeAnalysis.VisualBasic Return DirectCast(substituted.GetMemberForDefinition(Me), MethodSymbol) End Function - Friend Overrides Sub AddSynthesizedAttributes(compilationState As ModuleCompilationState, ByRef attributes As ArrayBuilder(Of SynthesizedAttributeData)) - MyBase.AddSynthesizedAttributes(compilationState, attributes) + Friend Overrides Sub AddSynthesizedAttributes(moduleBuilder As PEModuleBuilder, ByRef attributes As ArrayBuilder(Of SynthesizedAttributeData)) + MyBase.AddSynthesizedAttributes(moduleBuilder, attributes) ' Lambda that doesn't contain user code may still call to a user code (e.g. delegate relaxation stubs). We want the stack frame to be hidden. ' Dev11 marks such lambda with DebuggerStepThrough attribute but that seems to be useless. Rather we hide the frame completely. @@ -205,7 +206,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic End If If Me.IsAsync OrElse Me.IsIterator Then - AddSynthesizedAttribute(attributes, Me.DeclaringCompilation.SynthesizeStateMachineAttribute(Me, compilationState)) + AddSynthesizedAttribute(attributes, Me.DeclaringCompilation.SynthesizeStateMachineAttribute(Me, moduleBuilder.CompilationState)) If Me.IsAsync Then ' Async kick-off method calls MoveNext, which contains user code. diff --git a/src/Compilers/VisualBasic/Portable/Lowering/MethodToClassRewriter/MethodToClassRewriter.MyBaseMyClassWrapper.vb b/src/Compilers/VisualBasic/Portable/Lowering/MethodToClassRewriter/MethodToClassRewriter.MyBaseMyClassWrapper.vb index aa72f94662fb1..5044a0ad61a66 100644 --- a/src/Compilers/VisualBasic/Portable/Lowering/MethodToClassRewriter/MethodToClassRewriter.MyBaseMyClassWrapper.vb +++ b/src/Compilers/VisualBasic/Portable/Lowering/MethodToClassRewriter/MethodToClassRewriter.MyBaseMyClassWrapper.vb @@ -212,8 +212,8 @@ Namespace Microsoft.CodeAnalysis.VisualBasic End Get End Property - Friend Overrides Sub AddSynthesizedAttributes(compilationState as ModuleCompilationState, ByRef attributes As ArrayBuilder(Of SynthesizedAttributeData)) - MyBase.AddSynthesizedAttributes(compilationState, attributes) + Friend Overrides Sub AddSynthesizedAttributes(moduleBuilder As PEModuleBuilder, ByRef attributes As ArrayBuilder(Of SynthesizedAttributeData)) + MyBase.AddSynthesizedAttributes(moduleBuilder, attributes) Dim compilation = Me.DeclaringCompilation diff --git a/src/Compilers/VisualBasic/Portable/Lowering/StateMachineRewriter/StateMachineRewriter.StateMachineMethodToClassRewriter.vb b/src/Compilers/VisualBasic/Portable/Lowering/StateMachineRewriter/StateMachineRewriter.StateMachineMethodToClassRewriter.vb index 92fd33e37bf90..a55cb0d640606 100644 --- a/src/Compilers/VisualBasic/Portable/Lowering/StateMachineRewriter/StateMachineRewriter.StateMachineMethodToClassRewriter.vb +++ b/src/Compilers/VisualBasic/Portable/Lowering/StateMachineRewriter/StateMachineRewriter.StateMachineMethodToClassRewriter.vb @@ -19,7 +19,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic Protected Friend ReadOnly F As SyntheticBoundNodeFactory Private ReadOnly _resumableStateAllocator As ResumableStateMachineStateAllocator - Private _nextFinalizerState As Integer + Private _nextFinalizerState As StateMachineState ''' ''' The "state" of the state machine that is the translation of the iterator method. @@ -61,7 +61,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic ''' this is the state for finalization from anywhere in this try block. ''' Initially set to -1, representing the no-op finalization required at the top level. ''' - Private _currentFinalizerState As Integer = -1 + Private _currentFinalizerState As StateMachineState = StateMachineState.NotStartedOrRunningState ''' ''' The set of local variables and parameters that were hoisted and need a proxy. @@ -99,14 +99,14 @@ Namespace Microsoft.CodeAnalysis.VisualBasic _resumableStateAllocator = New ResumableStateMachineStateAllocator( slotAllocatorOpt, firstState:=FirstIncreasingResumableState, increasing:=True) - _nextFinalizerState = If(slotAllocatorOpt?.GetFirstUnusedStateMachineState(increasing:=False), StateMachineStates.FirstIteratorFinalizeState) + _nextFinalizerState = If(slotAllocatorOpt?.GetFirstUnusedStateMachineState(increasing:=False), StateMachineState.FirstIteratorFinalizeState) For Each p In initialProxies Proxies.Add(p.Key, p.Value) Next End Sub - Protected MustOverride ReadOnly Property FirstIncreasingResumableState As Integer + Protected MustOverride ReadOnly Property FirstIncreasingResumableState As StateMachineState Protected MustOverride ReadOnly Property EncMissingStateMessage As String ''' @@ -156,30 +156,30 @@ Namespace Microsoft.CodeAnalysis.VisualBasic End Sub End Structure - Protected Sub AddResumableState(awaitOrYieldReturnSyntax As SyntaxNode, ByRef stateNumber As Integer, ByRef resumeLabel As GeneratedLabelSymbol) - stateNumber = _resumableStateAllocator.AllocateState(awaitOrYieldReturnSyntax) + Protected Sub AddResumableState(awaitOrYieldReturnSyntax As SyntaxNode, ByRef state As StateMachineState, ByRef resumeLabel As GeneratedLabelSymbol) + state = _resumableStateAllocator.AllocateState(awaitOrYieldReturnSyntax) If _tryBlockSyntaxForNextFinalizerState IsNot Nothing Then If SlotAllocatorOpt Is Nothing OrElse Not SlotAllocatorOpt.TryGetPreviousStateMachineState(_tryBlockSyntaxForNextFinalizerState, _currentFinalizerState) Then _currentFinalizerState = _nextFinalizerState - _nextFinalizerState -= 1 + _nextFinalizerState = CType(_nextFinalizerState - 1, StateMachineState) End If AddStateDebugInfo(_tryBlockSyntaxForNextFinalizerState, _currentFinalizerState) _tryBlockSyntaxForNextFinalizerState = Nothing End If - AddStateDebugInfo(awaitOrYieldReturnSyntax, stateNumber) - AddState(stateNumber, resumeLabel) + AddStateDebugInfo(awaitOrYieldReturnSyntax, state) + AddState(state, resumeLabel) End Sub - Protected Sub AddStateDebugInfo(node As SyntaxNode, stateNumber As Integer) + Protected Sub AddStateDebugInfo(node As SyntaxNode, state As StateMachineState) Debug.Assert(SyntaxBindingUtilities.BindsToResumableStateMachineState(node) OrElse SyntaxBindingUtilities.BindsToTryStatement(node), $"Unexpected syntax: {node.Kind()}") Dim syntaxOffset = CurrentMethod.CalculateLocalSyntaxOffset(node.SpanStart, node.SyntaxTree) - _stateDebugInfoBuilder.Add(New StateMachineStateDebugInfo(syntaxOffset, stateNumber)) + _stateDebugInfoBuilder.Add(New StateMachineStateDebugInfo(syntaxOffset, state)) End Sub Protected Sub AddState(stateNumber As Integer, ByRef resumeLabel As GeneratedLabelSymbol) @@ -333,11 +333,11 @@ Namespace Microsoft.CodeAnalysis.VisualBasic ''' Public Overrides Function VisitTryStatement(node As BoundTryStatement) As BoundNode Dim oldDispatches As Dictionary(Of LabelSymbol, List(Of Integer)) = Me.Dispatches - Dim oldFinalizerState As Integer = Me._currentFinalizerState + Dim oldFinalizerState As StateMachineState = Me._currentFinalizerState Dim oldTryBlockSyntax As SyntaxNode = Me._tryBlockSyntaxForNextFinalizerState Me.Dispatches = Nothing - Me._currentFinalizerState = -1 + Me._currentFinalizerState = StateMachineState.NotStartedOrRunningState Me._tryBlockSyntaxForNextFinalizerState = node.Syntax Dim tryBlock As BoundBlock = Me.F.Block(DirectCast(Me.Visit(node.TryBlock), BoundStatement)) @@ -360,7 +360,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic Me.F.Label(finalizer), Me.F.Assignment( F.Field(F.Me(), Me.StateField, True), - F.AssignmentExpression(F.Local(Me.CachedState, True), F.Literal(StateMachineStates.NotStartedStateMachine))), + F.AssignmentExpression(F.Local(Me.CachedState, True), F.Literal(StateMachineState.NotStartedOrRunningState))), Me.GenerateReturn(False), Me.F.Label(skipFinalizer), tryBlock) @@ -388,7 +388,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic Me.F.If( condition:=Me.F.IntLessThan( Me.F.Local(Me.CachedState, False), - Me.F.Literal(StateMachineStates.FirstUnusedState)), + Me.F.Literal(StateMachineState.FirstUnusedState)), thenClause:=DirectCast(Me.Visit(node.FinallyBlockOpt), BoundBlock)), SyntheticBoundNodeFactory.HiddenSequencePoint())) diff --git a/src/Compilers/VisualBasic/Portable/Lowering/StateMachineRewriter/StateMachineRewriter.vb b/src/Compilers/VisualBasic/Portable/Lowering/StateMachineRewriter/StateMachineRewriter.vb index 008be8c2623d7..3da03f41713ed 100644 --- a/src/Compilers/VisualBasic/Portable/Lowering/StateMachineRewriter/StateMachineRewriter.vb +++ b/src/Compilers/VisualBasic/Portable/Lowering/StateMachineRewriter/StateMachineRewriter.vb @@ -342,9 +342,9 @@ Namespace Microsoft.CodeAnalysis.VisualBasic Select Case local.SynthesizedKind Case SynthesizedLocalKind.LambdaDisplayClass - proxyName = GeneratedNameConstants.StateMachineHoistedUserVariablePrefix & GeneratedNameConstants.ClosureVariablePrefix & "$" & slotIndex + proxyName = GeneratedNameConstants.StateMachineHoistedUserVariableOrDisplayClassPrefix & GeneratedNameConstants.ClosureVariablePrefix & "$" & slotIndex Case SynthesizedLocalKind.UserDefined - proxyName = GeneratedNameConstants.StateMachineHoistedUserVariablePrefix & local.Name & "$" & slotIndex + proxyName = GeneratedNameConstants.StateMachineHoistedUserVariableOrDisplayClassPrefix & local.Name & "$" & slotIndex Case SynthesizedLocalKind.With proxyName = GeneratedNameConstants.HoistedWithLocalPrefix & slotIndex Case Else diff --git a/src/Compilers/VisualBasic/Portable/Lowering/StateMachineRewriter/StateMachineStates.vb b/src/Compilers/VisualBasic/Portable/Lowering/StateMachineRewriter/StateMachineStates.vb deleted file mode 100644 index 1e23ee0be7571..0000000000000 --- a/src/Compilers/VisualBasic/Portable/Lowering/StateMachineRewriter/StateMachineStates.vb +++ /dev/null @@ -1,22 +0,0 @@ -' Licensed to the .NET Foundation under one or more agreements. -' The .NET Foundation licenses this file to you under the MIT license. -' See the LICENSE file in the project root for more information. - -Imports Microsoft.Cci -Imports Microsoft.CodeAnalysis.Text -Imports Microsoft.CodeAnalysis.VisualBasic.Symbols -Imports Microsoft.CodeAnalysis.VisualBasic.Syntax - -Namespace Microsoft.CodeAnalysis.VisualBasic - - Friend NotInheritable Class StateMachineStates - Public Const FirstIteratorFinalizeState As Integer = -3 - Public Const InitialIteratorState As Integer = 0 - Public Const FinishedStateMachine As Integer = -2 - Public Const NotStartedStateMachine As Integer = -1 - Public Const FirstUnusedState As Integer = 0 - Public Const FirstResumableIteratorState As Integer = InitialIteratorState + 1 - Public Const FirstResumableAsyncState As Integer = 0 - End Class - -End Namespace diff --git a/src/Compilers/VisualBasic/Portable/Lowering/StateMachineRewriter/SynthesizedContainer.vb b/src/Compilers/VisualBasic/Portable/Lowering/StateMachineRewriter/SynthesizedContainer.vb index 99149d59e367d..33c4331f7713c 100644 --- a/src/Compilers/VisualBasic/Portable/Lowering/StateMachineRewriter/SynthesizedContainer.vb +++ b/src/Compilers/VisualBasic/Portable/Lowering/StateMachineRewriter/SynthesizedContainer.vb @@ -10,6 +10,7 @@ Imports Microsoft.CodeAnalysis Imports Microsoft.CodeAnalysis.Collections Imports Microsoft.CodeAnalysis.PooledObjects Imports Microsoft.CodeAnalysis.Text +Imports Microsoft.CodeAnalysis.VisualBasic.Emit Imports Microsoft.CodeAnalysis.VisualBasic.Symbols Imports Microsoft.CodeAnalysis.VisualBasic.Syntax @@ -304,8 +305,8 @@ Namespace Microsoft.CodeAnalysis.VisualBasic End Get End Property - Friend Overrides Sub AddSynthesizedAttributes(compilationState As ModuleCompilationState, ByRef attributes As ArrayBuilder(Of SynthesizedAttributeData)) - MyBase.AddSynthesizedAttributes(compilationState, attributes) + Friend Overrides Sub AddSynthesizedAttributes(moduleBuilder As PEModuleBuilder, ByRef attributes As ArrayBuilder(Of SynthesizedAttributeData)) + MyBase.AddSynthesizedAttributes(moduleBuilder, attributes) Dim compilation = Me.DeclaringCompilation diff --git a/src/Compilers/VisualBasic/Portable/Lowering/StateMachineRewriter/SynthesizedStateMachineMethod.vb b/src/Compilers/VisualBasic/Portable/Lowering/StateMachineRewriter/SynthesizedStateMachineMethod.vb index 1bb04d9296dcd..3ce1935a5db6a 100644 --- a/src/Compilers/VisualBasic/Portable/Lowering/StateMachineRewriter/SynthesizedStateMachineMethod.vb +++ b/src/Compilers/VisualBasic/Portable/Lowering/StateMachineRewriter/SynthesizedStateMachineMethod.vb @@ -5,6 +5,7 @@ Imports System.Collections.Immutable Imports Microsoft.CodeAnalysis.PooledObjects Imports Microsoft.CodeAnalysis.Symbols +Imports Microsoft.CodeAnalysis.VisualBasic.Emit Imports Microsoft.CodeAnalysis.VisualBasic.Symbols Namespace Microsoft.CodeAnalysis.VisualBasic @@ -190,8 +191,8 @@ Namespace Microsoft.CodeAnalysis.VisualBasic MyBase.New(stateMachineType, WellKnownMemberNames.MoveNextMethodName, interfaceMethod, syntax, declaredAccessibility, generateDebugInfo:=True, hasMethodBodyDependency:=True) End Sub - Friend Overrides Sub AddSynthesizedAttributes(compilationState As ModuleCompilationState, ByRef attributes As ArrayBuilder(Of SynthesizedAttributeData)) - MyBase.AddSynthesizedAttributes(compilationState, attributes) + Friend Overrides Sub AddSynthesizedAttributes(moduleBuilder As PEModuleBuilder, ByRef attributes As ArrayBuilder(Of SynthesizedAttributeData)) + MyBase.AddSynthesizedAttributes(moduleBuilder, attributes) Debug.Assert(WellKnownMembers.IsSynthesizedAttributeOptional(WellKnownMember.System_Runtime_CompilerServices_CompilerGeneratedAttribute__ctor)) Dim compilation = Me.DeclaringCompilation @@ -246,8 +247,8 @@ Namespace Microsoft.CodeAnalysis.VisualBasic hasMethodBodyDependency:=hasMethodBodyDependency, associatedProperty:=associatedProperty) End Sub - Friend Overrides Sub AddSynthesizedAttributes(compilationState As ModuleCompilationState, ByRef attributes As ArrayBuilder(Of SynthesizedAttributeData)) - MyBase.AddSynthesizedAttributes(compilationState, attributes) + Friend Overrides Sub AddSynthesizedAttributes(moduleBuilder As PEModuleBuilder, ByRef attributes As ArrayBuilder(Of SynthesizedAttributeData)) + MyBase.AddSynthesizedAttributes(moduleBuilder, attributes) Debug.Assert(WellKnownMembers.IsSynthesizedAttributeOptional(WellKnownMember.System_Diagnostics_DebuggerNonUserCodeAttribute__ctor)) Dim compilation = Me.DeclaringCompilation diff --git a/src/Compilers/VisualBasic/Portable/Lowering/SyntheticBoundNodeFactory.vb b/src/Compilers/VisualBasic/Portable/Lowering/SyntheticBoundNodeFactory.vb index 2d2ac8d4731be..21a9bf79b7314 100644 --- a/src/Compilers/VisualBasic/Portable/Lowering/SyntheticBoundNodeFactory.vb +++ b/src/Compilers/VisualBasic/Portable/Lowering/SyntheticBoundNodeFactory.vb @@ -448,6 +448,10 @@ Namespace Microsoft.CodeAnalysis.VisualBasic Return boundNode End Function + Public Function Literal(value As StateMachineState) As BoundLiteral + Return Literal(CType(value, Integer)) + End Function + Public Function BadExpression(ParamArray subExpressions As BoundExpression()) As BoundExpression Dim boundNode = New BoundBadExpression(_syntax, LookupResultKind.Empty, ImmutableArray(Of Symbol).Empty, ImmutableArray.Create(subExpressions), ErrorTypeSymbol.UnknownResultType, hasErrors:=True) boundNode.SetWasCompilerGenerated() diff --git a/src/Compilers/VisualBasic/Portable/PublicAPI.Unshipped.txt b/src/Compilers/VisualBasic/Portable/PublicAPI.Unshipped.txt index 8b137891791fe..9a31aa7a58e6f 100644 --- a/src/Compilers/VisualBasic/Portable/PublicAPI.Unshipped.txt +++ b/src/Compilers/VisualBasic/Portable/PublicAPI.Unshipped.txt @@ -1 +1 @@ - +*REMOVED*Overrides Microsoft.CodeAnalysis.VisualBasic.VisualBasicCompilationOptions.GetHashCode() -> Integer diff --git a/src/Compilers/VisualBasic/Portable/Scanner/Scanner.vb b/src/Compilers/VisualBasic/Portable/Scanner/Scanner.vb index 7890a82cbd0bb..514782dbea993 100644 --- a/src/Compilers/VisualBasic/Portable/Scanner/Scanner.vb +++ b/src/Compilers/VisualBasic/Portable/Scanner/Scanner.vb @@ -637,6 +637,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Syntax.InternalSyntax ch <> "R"c AndAlso ch <> "r"c AndAlso ch <> "<"c AndAlso + ch <> "|"c AndAlso ch <> "="c AndAlso ch <> ">"c Then Return Nothing @@ -708,15 +709,15 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Syntax.InternalSyntax Return False End Function - ' All conflict markers consist of the same character repeated seven times. If it Is - ' a <<<<<<< Or >>>>>>> marker then it Is also followed by a space. + ' All conflict markers consist of the same character repeated seven times. If it is + ' a <<<<<<< or >>>>>>> marker then it is also followed by a space. Private Shared ReadOnly s_conflictMarkerLength As Integer = "<<<<<<<".Length Private Function IsConflictMarkerTrivia() As Boolean If CanGet() Then Dim ch = Peek() - If ch = "<"c OrElse ch = ">"c OrElse ch = "="c Then + If ch = "<"c OrElse ch = ">"c OrElse ch = "|"c OrElse ch = "="c Then Dim position = _lineBufferOffset Dim text = _buffer @@ -730,7 +731,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Syntax.InternalSyntax End If Next - If firstCh = "="c Then + If firstCh = "|"c OrElse firstCh = "="c Then Return True End If @@ -754,18 +755,22 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Syntax.InternalSyntax ' Now add the newlines as the next trivia. ScanConflictMarkerEndOfLine(tList) - If startCh = "="c Then + If startCh = "|"c OrElse startCh = "="c Then ' Consume everything from the start of the mid-conflict marker to the start of the next ' end-conflict marker. - ScanConflictMarkerDisabledText(tList) + ScanConflictMarkerDisabledText(startCh = "="c, tList) End If End Sub - Private Sub ScanConflictMarkerDisabledText(tList As SyntaxListBuilder) + Private Sub ScanConflictMarkerDisabledText(atSecondMiddleMarker As Boolean, tList As SyntaxListBuilder) Dim start = _lineBufferOffset While CanGet() Dim ch = Peek() + If Not atSecondMiddleMarker AndAlso ch = "="c AndAlso IsConflictMarkerTrivia() Then + Exit While + End If + If ch = ">"c AndAlso IsConflictMarkerTrivia() Then Exit While End If diff --git a/src/Compilers/VisualBasic/Portable/Semantics/Conversions.vb b/src/Compilers/VisualBasic/Portable/Semantics/Conversions.vb index fbffca62ee1a1..54ccdf4317f11 100644 --- a/src/Compilers/VisualBasic/Portable/Semantics/Conversions.vb +++ b/src/Compilers/VisualBasic/Portable/Semantics/Conversions.vb @@ -231,7 +231,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic End Operator ''' - ''' Creates a from this Visual Basic conversion. + ''' Creates a from this Visual Basic conversion. ''' ''' The that represents this conversion. ''' diff --git a/src/Compilers/VisualBasic/Portable/Semantics/Operators.vb b/src/Compilers/VisualBasic/Portable/Semantics/Operators.vb index a9d943013e408..9b23ee6e1792a 100644 --- a/src/Compilers/VisualBasic/Portable/Semantics/Operators.vb +++ b/src/Compilers/VisualBasic/Portable/Semantics/Operators.vb @@ -214,11 +214,11 @@ Namespace Microsoft.CodeAnalysis.VisualBasic End Select End Function - Friend Shared Function TryGetOperatorName(op As BinaryOperatorKind) As String + Friend Shared Function TryGetOperatorName(op As BinaryOperatorKind, isChecked As Boolean) As String Select Case (op And BinaryOperatorKind.OpMask) Case BinaryOperatorKind.Add - Return WellKnownMemberNames.AdditionOperatorName + Return If(isChecked, WellKnownMemberNames.CheckedAdditionOperatorName, WellKnownMemberNames.AdditionOperatorName) Case BinaryOperatorKind.Concatenate Return WellKnownMemberNames.ConcatenateOperatorName Case BinaryOperatorKind.Like @@ -236,9 +236,9 @@ Namespace Microsoft.CodeAnalysis.VisualBasic Case BinaryOperatorKind.GreaterThan Return WellKnownMemberNames.GreaterThanOperatorName Case BinaryOperatorKind.Subtract - Return WellKnownMemberNames.SubtractionOperatorName + Return If(isChecked, WellKnownMemberNames.CheckedSubtractionOperatorName, WellKnownMemberNames.SubtractionOperatorName) Case BinaryOperatorKind.Multiply - Return WellKnownMemberNames.MultiplyOperatorName + Return If(isChecked, WellKnownMemberNames.CheckedMultiplyOperatorName, WellKnownMemberNames.MultiplyOperatorName) Case BinaryOperatorKind.Power Return WellKnownMemberNames.ExponentOperatorName Case BinaryOperatorKind.Divide @@ -246,7 +246,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic Case BinaryOperatorKind.Modulo Return WellKnownMemberNames.ModulusOperatorName Case BinaryOperatorKind.IntegerDivide - Return WellKnownMemberNames.IntegerDivisionOperatorName + Return If(isChecked, WellKnownMemberNames.CheckedDivisionOperatorName, WellKnownMemberNames.IntegerDivisionOperatorName) Case BinaryOperatorKind.LeftShift Return WellKnownMemberNames.LeftShiftOperatorName Case BinaryOperatorKind.RightShift @@ -267,13 +267,13 @@ Namespace Microsoft.CodeAnalysis.VisualBasic End Select End Function - Friend Shared Function TryGetOperatorName(op As UnaryOperatorKind) As String + Friend Shared Function TryGetOperatorName(op As UnaryOperatorKind, isChecked As Boolean) As String Select Case (op And UnaryOperatorKind.OpMask) Case UnaryOperatorKind.Plus Return WellKnownMemberNames.UnaryPlusOperatorName Case UnaryOperatorKind.Minus - Return WellKnownMemberNames.UnaryNegationOperatorName + Return If(isChecked, WellKnownMemberNames.CheckedUnaryNegationOperatorName, WellKnownMemberNames.UnaryNegationOperatorName) Case UnaryOperatorKind.Not Return WellKnownMemberNames.OnesComplementOperatorName Case UnaryOperatorKind.Implicit diff --git a/src/Compilers/VisualBasic/Portable/SourceGeneration/VisualBasicSyntaxHelper.vb b/src/Compilers/VisualBasic/Portable/SourceGeneration/VisualBasicSyntaxHelper.vb index 8aa7563127965..6d3572dbb55f0 100644 --- a/src/Compilers/VisualBasic/Portable/SourceGeneration/VisualBasicSyntaxHelper.vb +++ b/src/Compilers/VisualBasic/Portable/SourceGeneration/VisualBasicSyntaxHelper.vb @@ -4,6 +4,7 @@ Imports System.Runtime.CompilerServices Imports System.Runtime.InteropServices +Imports System.Threading Imports Microsoft.CodeAnalysis.PooledObjects Imports Microsoft.CodeAnalysis.SourceGeneration Imports Microsoft.CodeAnalysis.VisualBasic.Syntax @@ -19,6 +20,8 @@ Namespace Microsoft.CodeAnalysis.VisualBasic Public Overrides ReadOnly Property IsCaseSensitive As Boolean = False + Protected Overrides ReadOnly Property AttributeListKind As Integer = SyntaxKind.AttributeList + Public Overrides Function IsValidIdentifier(name As String) As Boolean Return SyntaxFacts.IsValidIdentifier(name) End Function @@ -67,36 +70,38 @@ Namespace Microsoft.CodeAnalysis.VisualBasic Return TypeOf node Is LambdaExpressionSyntax End Function - Public Overrides Function GetUnqualifiedIdentifierOfName(node As SyntaxNode) As SyntaxToken - Dim name = DirectCast(node, NameSyntax) + Public Overrides Function GetUnqualifiedIdentifierOfName(node As SyntaxNode) As String + Return GetUnqualifiedIdentifierOfName(DirectCast(node.Green, InternalSyntax.NameSyntax)) + End Function - Dim qualifiedName = TryCast(name, QualifiedNameSyntax) + Private Overloads Shared Function GetUnqualifiedIdentifierOfName(name As InternalSyntax.NameSyntax) As String + Dim qualifiedName = TryCast(name, InternalSyntax.QualifiedNameSyntax) If qualifiedName IsNot Nothing Then - Return qualifiedName.Right.Identifier + Return qualifiedName.Right.Identifier.ValueText End If - Dim simpleName = TryCast(node, SimpleNameSyntax) + Dim simpleName = TryCast(name, InternalSyntax.SimpleNameSyntax) If simpleName IsNot Nothing Then - Return simpleName.Identifier + Return simpleName.Identifier.ValueText End If - Throw ExceptionUtilities.UnexpectedValue(node.Kind()) + Throw ExceptionUtilities.UnexpectedValue(name.KindText) End Function - Public Overrides Sub AddAliases(node As SyntaxNode, aliases As ArrayBuilder(Of (aliasName As String, symbolName As String)), [global] As Boolean) + Public Overrides Sub AddAliases(node As GreenNode, aliases As ArrayBuilder(Of (aliasName As String, symbolName As String)), [global] As Boolean) ' VB does not have global aliases at the syntax level. If [global] Then Return End If - Dim compilationUnit = TryCast(node, CompilationUnitSyntax) + Dim compilationUnit = TryCast(node, InternalSyntax.CompilationUnitSyntax) If compilationUnit Is Nothing Then Return End If For Each importsStatement In compilationUnit.Imports - For Each importsClause In importsStatement.ImportsClauses - ProcessImportsClause(aliases, importsClause) + For i = 0 To importsStatement.ImportsClauses.Count - 1 + ProcessImportsClause(aliases, importsStatement.ImportsClauses(i)) Next Next End Sub @@ -106,15 +111,20 @@ Namespace Microsoft.CodeAnalysis.VisualBasic For Each globalImport In vbOptions.GlobalImports Dim clause = globalImport.Clause - ProcessImportsClause(aliases, clause) + ProcessImportsClause(aliases, DirectCast(clause.Green, InternalSyntax.ImportsClauseSyntax)) Next End Sub - Private Sub ProcessImportsClause(aliases As ArrayBuilder(Of (aliasName As String, symbolName As String)), clause As ImportsClauseSyntax) - Dim importsClause = TryCast(clause, SimpleImportsClauseSyntax) + Private Shared Sub ProcessImportsClause(aliases As ArrayBuilder(Of (aliasName As String, symbolName As String)), clause As InternalSyntax.ImportsClauseSyntax) + Dim importsClause = TryCast(clause, InternalSyntax.SimpleImportsClauseSyntax) If importsClause?.Alias IsNot Nothing Then - aliases.Add((importsClause.Alias.Identifier.ValueText, GetUnqualifiedIdentifierOfName(importsClause.Name).ValueText)) + aliases.Add((importsClause.Alias.Identifier.ValueText, GetUnqualifiedIdentifierOfName(importsClause.Name))) End If End Sub + + Public Overrides Function ContainsGlobalAliases(root As SyntaxNode) As Boolean + ' VB does not have global aliases + Return False + End Function End Class End Namespace diff --git a/src/Compilers/VisualBasic/Portable/Symbols/AnonymousTypes/SynthesizedSymbols/AnonymousDelegate_TemplateSymbol.vb b/src/Compilers/VisualBasic/Portable/Symbols/AnonymousTypes/SynthesizedSymbols/AnonymousDelegate_TemplateSymbol.vb index 9fee14955477a..ea3003ae95ce7 100644 --- a/src/Compilers/VisualBasic/Portable/Symbols/AnonymousTypes/SynthesizedSymbols/AnonymousDelegate_TemplateSymbol.vb +++ b/src/Compilers/VisualBasic/Portable/Symbols/AnonymousTypes/SynthesizedSymbols/AnonymousDelegate_TemplateSymbol.vb @@ -7,6 +7,7 @@ Imports System.Collections.Immutable Imports Microsoft.CodeAnalysis Imports Microsoft.CodeAnalysis.Emit Imports Microsoft.CodeAnalysis.PooledObjects +Imports Microsoft.CodeAnalysis.VisualBasic.Emit Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols Partial Friend NotInheritable Class AnonymousTypeManager @@ -168,8 +169,8 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols End Get End Property - Friend Overrides Sub AddSynthesizedAttributes(compilationState As ModuleCompilationState, ByRef attributes As ArrayBuilder(Of SynthesizedAttributeData)) - MyBase.AddSynthesizedAttributes(compilationState, attributes) + Friend Overrides Sub AddSynthesizedAttributes(moduleBuilder As PEModuleBuilder, ByRef attributes As ArrayBuilder(Of SynthesizedAttributeData)) + MyBase.AddSynthesizedAttributes(moduleBuilder, attributes) ' Attribute: System.Runtime.CompilerServices.CompilerGeneratedAttribute() AddSynthesizedAttribute(attributes, Manager.Compilation.TrySynthesizeAttribute( diff --git a/src/Compilers/VisualBasic/Portable/Symbols/AnonymousTypes/SynthesizedSymbols/AnonymousType_ConstructorSymbol.vb b/src/Compilers/VisualBasic/Portable/Symbols/AnonymousTypes/SynthesizedSymbols/AnonymousType_ConstructorSymbol.vb index d4c250185795e..b4c623cc8ee70 100644 --- a/src/Compilers/VisualBasic/Portable/Symbols/AnonymousTypes/SynthesizedSymbols/AnonymousType_ConstructorSymbol.vb +++ b/src/Compilers/VisualBasic/Portable/Symbols/AnonymousTypes/SynthesizedSymbols/AnonymousType_ConstructorSymbol.vb @@ -4,6 +4,7 @@ Imports System.Collections.Immutable Imports Microsoft.CodeAnalysis.PooledObjects +Imports Microsoft.CodeAnalysis.VisualBasic.Emit Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols @@ -39,8 +40,8 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols End Get End Property - Friend Overrides Sub AddSynthesizedAttributes(compilationState As ModuleCompilationState, ByRef attributes As ArrayBuilder(Of SynthesizedAttributeData)) - MyBase.AddSynthesizedAttributes(compilationState, attributes) + Friend Overrides Sub AddSynthesizedAttributes(moduleBuilder As PEModuleBuilder, ByRef attributes As ArrayBuilder(Of SynthesizedAttributeData)) + MyBase.AddSynthesizedAttributes(moduleBuilder, attributes) Dim compilation = DirectCast(Me.ContainingType, AnonymousTypeTemplateSymbol).Manager.Compilation AddSynthesizedAttribute(attributes, compilation.SynthesizeDebuggerHiddenAttribute()) diff --git a/src/Compilers/VisualBasic/Portable/Symbols/AnonymousTypes/SynthesizedSymbols/AnonymousType_EqualsMethodSymbol.vb b/src/Compilers/VisualBasic/Portable/Symbols/AnonymousTypes/SynthesizedSymbols/AnonymousType_EqualsMethodSymbol.vb index 178a597d39eec..8d99035cf5b03 100644 --- a/src/Compilers/VisualBasic/Portable/Symbols/AnonymousTypes/SynthesizedSymbols/AnonymousType_EqualsMethodSymbol.vb +++ b/src/Compilers/VisualBasic/Portable/Symbols/AnonymousTypes/SynthesizedSymbols/AnonymousType_EqualsMethodSymbol.vb @@ -4,6 +4,7 @@ Imports System.Collections.Immutable Imports Microsoft.CodeAnalysis.PooledObjects +Imports Microsoft.CodeAnalysis.VisualBasic.Emit Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols @@ -82,8 +83,8 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols End Get End Property - Friend Overrides Sub AddSynthesizedAttributes(compilationState As ModuleCompilationState, ByRef attributes As ArrayBuilder(Of SynthesizedAttributeData)) - MyBase.AddSynthesizedAttributes(compilationState, attributes) + Friend Overrides Sub AddSynthesizedAttributes(moduleBuilder As PEModuleBuilder, ByRef attributes As ArrayBuilder(Of SynthesizedAttributeData)) + MyBase.AddSynthesizedAttributes(moduleBuilder, attributes) Dim compilation = DirectCast(Me.ContainingType, AnonymousTypeTemplateSymbol).Manager.Compilation AddSynthesizedAttribute(attributes, compilation.SynthesizeDebuggerHiddenAttribute()) diff --git a/src/Compilers/VisualBasic/Portable/Symbols/AnonymousTypes/SynthesizedSymbols/AnonymousType_GetHashCodeMethodSymbol.vb b/src/Compilers/VisualBasic/Portable/Symbols/AnonymousTypes/SynthesizedSymbols/AnonymousType_GetHashCodeMethodSymbol.vb index 25f0a815ddf64..17edaba998aa9 100644 --- a/src/Compilers/VisualBasic/Portable/Symbols/AnonymousTypes/SynthesizedSymbols/AnonymousType_GetHashCodeMethodSymbol.vb +++ b/src/Compilers/VisualBasic/Portable/Symbols/AnonymousTypes/SynthesizedSymbols/AnonymousType_GetHashCodeMethodSymbol.vb @@ -3,6 +3,7 @@ ' See the LICENSE file in the project root for more information. Imports Microsoft.CodeAnalysis.PooledObjects +Imports Microsoft.CodeAnalysis.VisualBasic.Emit Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols @@ -51,8 +52,8 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols End Get End Property - Friend Overrides Sub AddSynthesizedAttributes(compilationState As ModuleCompilationState, ByRef attributes As ArrayBuilder(Of SynthesizedAttributeData)) - MyBase.AddSynthesizedAttributes(compilationState, attributes) + Friend Overrides Sub AddSynthesizedAttributes(moduleBuilder As PEModuleBuilder, ByRef attributes As ArrayBuilder(Of SynthesizedAttributeData)) + MyBase.AddSynthesizedAttributes(moduleBuilder, attributes) Dim compilation = DirectCast(Me.ContainingType, AnonymousTypeTemplateSymbol).Manager.Compilation AddSynthesizedAttribute(attributes, compilation.SynthesizeDebuggerHiddenAttribute()) diff --git a/src/Compilers/VisualBasic/Portable/Symbols/AnonymousTypes/SynthesizedSymbols/AnonymousType_IEquatable_EqualsMethodSymbol.vb b/src/Compilers/VisualBasic/Portable/Symbols/AnonymousTypes/SynthesizedSymbols/AnonymousType_IEquatable_EqualsMethodSymbol.vb index 9ee1be26218e4..9bbba28d771d9 100644 --- a/src/Compilers/VisualBasic/Portable/Symbols/AnonymousTypes/SynthesizedSymbols/AnonymousType_IEquatable_EqualsMethodSymbol.vb +++ b/src/Compilers/VisualBasic/Portable/Symbols/AnonymousTypes/SynthesizedSymbols/AnonymousType_IEquatable_EqualsMethodSymbol.vb @@ -4,6 +4,7 @@ Imports System.Collections.Immutable Imports Microsoft.CodeAnalysis.PooledObjects +Imports Microsoft.CodeAnalysis.VisualBasic.Emit Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols @@ -88,8 +89,8 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols End Get End Property - Friend Overrides Sub AddSynthesizedAttributes(compilationState As ModuleCompilationState, ByRef attributes As ArrayBuilder(Of SynthesizedAttributeData)) - MyBase.AddSynthesizedAttributes(compilationState, attributes) + Friend Overrides Sub AddSynthesizedAttributes(moduleBuilder As PEModuleBuilder, ByRef attributes As ArrayBuilder(Of SynthesizedAttributeData)) + MyBase.AddSynthesizedAttributes(moduleBuilder, attributes) Dim compilation = DirectCast(Me.ContainingType, AnonymousTypeTemplateSymbol).Manager.Compilation AddSynthesizedAttribute(attributes, compilation.SynthesizeDebuggerHiddenAttribute()) diff --git a/src/Compilers/VisualBasic/Portable/Symbols/AnonymousTypes/SynthesizedSymbols/AnonymousType_PropertyAccessors.vb b/src/Compilers/VisualBasic/Portable/Symbols/AnonymousTypes/SynthesizedSymbols/AnonymousType_PropertyAccessors.vb index 27d1b72867ea0..8c162192daf50 100644 --- a/src/Compilers/VisualBasic/Portable/Symbols/AnonymousTypes/SynthesizedSymbols/AnonymousType_PropertyAccessors.vb +++ b/src/Compilers/VisualBasic/Portable/Symbols/AnonymousTypes/SynthesizedSymbols/AnonymousType_PropertyAccessors.vb @@ -5,6 +5,7 @@ Imports System.Collections.Immutable Imports Microsoft.CodeAnalysis.PooledObjects Imports Microsoft.CodeAnalysis.Text +Imports Microsoft.CodeAnalysis.VisualBasic.Emit Imports Microsoft.CodeAnalysis.VisualBasic.Symbols Imports Microsoft.CodeAnalysis.VisualBasic.Syntax Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols @@ -37,8 +38,8 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols End Get End Property - Friend Overrides Sub AddSynthesizedAttributes(compilationState As ModuleCompilationState, ByRef attributes As ArrayBuilder(Of SynthesizedAttributeData)) - MyBase.AddSynthesizedAttributes(compilationState, attributes) + Friend Overrides Sub AddSynthesizedAttributes(moduleBuilder As PEModuleBuilder, ByRef attributes As ArrayBuilder(Of SynthesizedAttributeData)) + MyBase.AddSynthesizedAttributes(moduleBuilder, attributes) ' Dev11 adds DebuggerNonUserCode; there is no reason to do so since: ' - we emit no debug info for the body diff --git a/src/Compilers/VisualBasic/Portable/Symbols/AnonymousTypes/SynthesizedSymbols/AnonymousType_TemplateSymbol.vb b/src/Compilers/VisualBasic/Portable/Symbols/AnonymousTypes/SynthesizedSymbols/AnonymousType_TemplateSymbol.vb index c3073a4669646..39a1f21f7f527 100644 --- a/src/Compilers/VisualBasic/Portable/Symbols/AnonymousTypes/SynthesizedSymbols/AnonymousType_TemplateSymbol.vb +++ b/src/Compilers/VisualBasic/Portable/Symbols/AnonymousTypes/SynthesizedSymbols/AnonymousType_TemplateSymbol.vb @@ -8,6 +8,7 @@ Imports Microsoft.CodeAnalysis Imports Microsoft.CodeAnalysis.Collections Imports Microsoft.CodeAnalysis.Emit Imports Microsoft.CodeAnalysis.PooledObjects +Imports Microsoft.CodeAnalysis.VisualBasic.Emit Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols @@ -142,8 +143,8 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols End Get End Property - Friend Overrides Sub AddSynthesizedAttributes(compilationState As ModuleCompilationState, ByRef attributes As ArrayBuilder(Of SynthesizedAttributeData)) - MyBase.AddSynthesizedAttributes(compilationState, attributes) + Friend Overrides Sub AddSynthesizedAttributes(moduleBuilder As PEModuleBuilder, ByRef attributes As ArrayBuilder(Of SynthesizedAttributeData)) + MyBase.AddSynthesizedAttributes(moduleBuilder, attributes) ' Attribute: System.Runtime.CompilerServices.CompilerGeneratedAttribute() AddSynthesizedAttribute(attributes, Manager.Compilation.TrySynthesizeAttribute( diff --git a/src/Compilers/VisualBasic/Portable/Symbols/AnonymousTypes/SynthesizedSymbols/AnonymousType_ToStringMethodSymbol.vb b/src/Compilers/VisualBasic/Portable/Symbols/AnonymousTypes/SynthesizedSymbols/AnonymousType_ToStringMethodSymbol.vb index 34d1dfe78ab4f..d09e5a0359145 100644 --- a/src/Compilers/VisualBasic/Portable/Symbols/AnonymousTypes/SynthesizedSymbols/AnonymousType_ToStringMethodSymbol.vb +++ b/src/Compilers/VisualBasic/Portable/Symbols/AnonymousTypes/SynthesizedSymbols/AnonymousType_ToStringMethodSymbol.vb @@ -5,6 +5,7 @@ Imports Microsoft.CodeAnalysis.Collections Imports Microsoft.CodeAnalysis.PooledObjects Imports Microsoft.CodeAnalysis.Text +Imports Microsoft.CodeAnalysis.VisualBasic.Emit Imports Microsoft.CodeAnalysis.VisualBasic.Symbols Imports Microsoft.CodeAnalysis.VisualBasic.Syntax @@ -55,8 +56,8 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols End Get End Property - Friend Overrides Sub AddSynthesizedAttributes(compilationState As ModuleCompilationState, ByRef attributes As ArrayBuilder(Of SynthesizedAttributeData)) - MyBase.AddSynthesizedAttributes(compilationState, attributes) + Friend Overrides Sub AddSynthesizedAttributes(moduleBuilder As PEModuleBuilder, ByRef attributes As ArrayBuilder(Of SynthesizedAttributeData)) + MyBase.AddSynthesizedAttributes(moduleBuilder, attributes) ' May call user-defined method. Dim compilation = DirectCast(Me.ContainingType, AnonymousTypeTemplateSymbol).Manager.Compilation diff --git a/src/Compilers/VisualBasic/Portable/Symbols/Metadata/PE/MemberRefMetadataDecoder.vb b/src/Compilers/VisualBasic/Portable/Symbols/Metadata/PE/MemberRefMetadataDecoder.vb index a1aaf1c031212..e60cde33cb68f 100644 --- a/src/Compilers/VisualBasic/Portable/Symbols/Metadata/PE/MemberRefMetadataDecoder.vb +++ b/src/Compilers/VisualBasic/Portable/Symbols/Metadata/PE/MemberRefMetadataDecoder.vb @@ -92,13 +92,29 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols.Metadata.PE ''' ''' Search through the members of the type symbol to find the method that matches a particular signature. ''' - ''' A MemberRef handle that can be used to obtain the name and signature of the method + ''' A MemberRef or a MethodDef handle that can be used to obtain the name and signature of the method ''' True to only return a method. ''' The matching method symbol, or null if the inputs do not correspond to a valid method. - Friend Function FindMember(memberRef As MemberReferenceHandle, methodsOnly As Boolean) As Symbol + Friend Function FindMember(memberRefOrMethodDef As EntityHandle, methodsOnly As Boolean) As Symbol Try - Dim memberName As String = [Module].GetMemberRefNameOrThrow(memberRef) - Dim signatureHandle = [Module].GetSignatureOrThrow(memberRef) + Dim memberName As String + Dim signatureHandle As BlobHandle + + Select Case memberRefOrMethodDef.Kind + Case HandleKind.MemberReference + Dim memberRef = CType(memberRefOrMethodDef, MemberReferenceHandle) + memberName = [Module].GetMemberRefNameOrThrow(memberRef) + signatureHandle = [Module].GetSignatureOrThrow(memberRef) + + Case HandleKind.MethodDefinition + Dim methodDef = CType(memberRefOrMethodDef, MethodDefinitionHandle) + memberName = [Module].GetMethodDefNameOrThrow(methodDef) + signatureHandle = [Module].GetMethodSignatureOrThrow(methodDef) + + Case Else + Throw ExceptionUtilities.UnexpectedValue(memberRefOrMethodDef.Kind) + End Select + Dim signatureHeader As SignatureHeader Dim signaturePointer As BlobReader = Me.DecodeSignatureHeaderOrThrow(signatureHandle, signatureHeader) diff --git a/src/Compilers/VisualBasic/Portable/Symbols/Metadata/PE/MetadataDecoder.vb b/src/Compilers/VisualBasic/Portable/Symbols/Metadata/PE/MetadataDecoder.vb index 179fb887b6af2..ff31389f95d4f 100644 --- a/src/Compilers/VisualBasic/Portable/Symbols/Metadata/PE/MetadataDecoder.vb +++ b/src/Compilers/VisualBasic/Portable/Symbols/Metadata/PE/MetadataDecoder.vb @@ -415,14 +415,26 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols.Metadata.PE End Function Protected Overrides Function FindMethodSymbolInType(typeSymbol As TypeSymbol, targetMethodDef As MethodDefinitionHandle) As MethodSymbol - Debug.Assert(TypeOf typeSymbol Is PENamedTypeSymbol OrElse TypeOf typeSymbol Is ErrorTypeSymbol) + Debug.Assert(typeSymbol.IsDefinition) - For Each member In typeSymbol.GetMembersUnordered() - Dim method As PEMethodSymbol = TryCast(member, PEMethodSymbol) - If method IsNot Nothing AndAlso method.Handle = targetMethodDef Then - Return method - End If - Next + Dim peTypeSymbol As PENamedTypeSymbol = TryCast(typeSymbol, PENamedTypeSymbol) + If peTypeSymbol IsNot Nothing AndAlso peTypeSymbol.ContainingPEModule Is ModuleSymbol Then + + For Each member In typeSymbol.GetMembersUnordered() + Dim method As PEMethodSymbol = TryCast(member, PEMethodSymbol) + If method IsNot Nothing AndAlso method.Handle = targetMethodDef Then + Return method + End If + Next + + ElseIf Not TypeOf typeSymbol Is ErrorTypeSymbol Then + + ' We're going to use a special decoder that can generate usable symbols for type parameters without full context. + ' (We're not just using a different type - we're also changing the type context.) + Dim memberRefDecoder = New MemberRefMetadataDecoder(ModuleSymbol, typeSymbol) + + Return DirectCast(memberRefDecoder.FindMember(targetMethodDef, methodsOnly:=True), MethodSymbol) + End If Return Nothing End Function diff --git a/src/Compilers/VisualBasic/Portable/Symbols/Metadata/PE/PEEventSymbol.vb b/src/Compilers/VisualBasic/Portable/Symbols/Metadata/PE/PEEventSymbol.vb index d72f126a5fbcb..3cf9c9de8f1a3 100644 --- a/src/Compilers/VisualBasic/Portable/Symbols/Metadata/PE/PEEventSymbol.vb +++ b/src/Compilers/VisualBasic/Portable/Symbols/Metadata/PE/PEEventSymbol.vb @@ -14,6 +14,7 @@ Imports Microsoft.CodeAnalysis.VisualBasic.Symbols Imports Microsoft.CodeAnalysis.VisualBasic.Syntax Imports Roslyn.Utilities Imports System.Reflection.Metadata.Ecma335 +Imports Microsoft.CodeAnalysis.VisualBasic.Emit Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols.Metadata.PE @@ -264,7 +265,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols.Metadata.PE Return _lazyCustomAttributes End Function - Friend Overrides Function GetCustomAttributesToEmit(compilationState As ModuleCompilationState) As IEnumerable(Of VisualBasicAttributeData) + Friend Overrides Function GetCustomAttributesToEmit(moduleBuilder As PEModuleBuilder) As IEnumerable(Of VisualBasicAttributeData) Return GetAttributes() End Function diff --git a/src/Compilers/VisualBasic/Portable/Symbols/Metadata/PE/PEFieldSymbol.vb b/src/Compilers/VisualBasic/Portable/Symbols/Metadata/PE/PEFieldSymbol.vb index 235cf07de7c88..ae303d9888ca5 100644 --- a/src/Compilers/VisualBasic/Portable/Symbols/Metadata/PE/PEFieldSymbol.vb +++ b/src/Compilers/VisualBasic/Portable/Symbols/Metadata/PE/PEFieldSymbol.vb @@ -15,6 +15,7 @@ Imports Microsoft.CodeAnalysis.VisualBasic.Symbols Imports Microsoft.CodeAnalysis.VisualBasic.Syntax Imports TypeKind = Microsoft.CodeAnalysis.TypeKind Imports System.Reflection.Metadata.Ecma335 +Imports Microsoft.CodeAnalysis.VisualBasic.Emit Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols.Metadata.PE @@ -167,7 +168,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols.Metadata.PE Return Nothing End Function - Friend Overrides Iterator Function GetCustomAttributesToEmit(compilationState As ModuleCompilationState) As IEnumerable(Of VisualBasicAttributeData) + Friend Overrides Iterator Function GetCustomAttributesToEmit(moduleBuilder As PEModuleBuilder) As IEnumerable(Of VisualBasicAttributeData) For Each attribute In GetAttributes() Yield attribute Next diff --git a/src/Compilers/VisualBasic/Portable/Symbols/Metadata/PE/PEMethodSymbol.vb b/src/Compilers/VisualBasic/Portable/Symbols/Metadata/PE/PEMethodSymbol.vb index 406a96f7fcbfc..d379cf6a85615 100644 --- a/src/Compilers/VisualBasic/Portable/Symbols/Metadata/PE/PEMethodSymbol.vb +++ b/src/Compilers/VisualBasic/Portable/Symbols/Metadata/PE/PEMethodSymbol.vb @@ -15,6 +15,7 @@ Imports Microsoft.CodeAnalysis.VisualBasic.Symbols Imports Microsoft.CodeAnalysis.VisualBasic.Syntax Imports System.Runtime.InteropServices Imports System.Reflection.Metadata.Ecma335 +Imports Microsoft.CodeAnalysis.VisualBasic.Emit Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols.Metadata.PE @@ -632,7 +633,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols.Metadata.PE End If End Function - Friend Overrides Function GetCustomAttributesToEmit(compilationState As ModuleCompilationState) As IEnumerable(Of VisualBasicAttributeData) + Friend Overrides Function GetCustomAttributesToEmit(moduleBuilder As PEModuleBuilder) As IEnumerable(Of VisualBasicAttributeData) Return GetAttributes() End Function diff --git a/src/Compilers/VisualBasic/Portable/Symbols/Metadata/PE/PENamedTypeSymbol.vb b/src/Compilers/VisualBasic/Portable/Symbols/Metadata/PE/PENamedTypeSymbol.vb index 66e1b5ce8715b..f92c64777235f 100644 --- a/src/Compilers/VisualBasic/Portable/Symbols/Metadata/PE/PENamedTypeSymbol.vb +++ b/src/Compilers/VisualBasic/Portable/Symbols/Metadata/PE/PENamedTypeSymbol.vb @@ -20,6 +20,7 @@ Imports TypeKind = Microsoft.CodeAnalysis.TypeKind Imports TypeAttributes = System.Reflection.TypeAttributes Imports FieldAttributes = System.Reflection.FieldAttributes Imports System.Reflection.Metadata.Ecma335 +Imports Microsoft.CodeAnalysis.VisualBasic.Emit Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols.Metadata.PE @@ -432,7 +433,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols.Metadata.PE Return _lazyCustomAttributes End Function - Friend Overrides Iterator Function GetCustomAttributesToEmit(compilationState As ModuleCompilationState) As IEnumerable(Of VisualBasicAttributeData) + Friend Overrides Iterator Function GetCustomAttributesToEmit(moduleBuilder As PEModuleBuilder) As IEnumerable(Of VisualBasicAttributeData) For Each attribute In GetAttributes() Yield attribute Next diff --git a/src/Compilers/VisualBasic/Portable/Symbols/Metadata/PE/PEParameterSymbol.vb b/src/Compilers/VisualBasic/Portable/Symbols/Metadata/PE/PEParameterSymbol.vb index 8865007dbdcb9..78a883dd86bdf 100644 --- a/src/Compilers/VisualBasic/Portable/Symbols/Metadata/PE/PEParameterSymbol.vb +++ b/src/Compilers/VisualBasic/Portable/Symbols/Metadata/PE/PEParameterSymbol.vb @@ -10,6 +10,7 @@ Imports System.Reflection.Metadata Imports Microsoft.CodeAnalysis.PooledObjects Imports Microsoft.CodeAnalysis.VisualBasic.Symbols Imports System.Reflection.Metadata.Ecma335 +Imports Microsoft.CodeAnalysis.VisualBasic.Emit Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols.Metadata.PE @@ -417,7 +418,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols.Metadata.PE Return _lazyCustomAttributes End Function - Friend Overrides Iterator Function GetCustomAttributesToEmit(compilationState As ModuleCompilationState) As IEnumerable(Of VisualBasicAttributeData) + Friend Overrides Iterator Function GetCustomAttributesToEmit(moduleBuilder As PEModuleBuilder) As IEnumerable(Of VisualBasicAttributeData) For Each attribute In GetAttributes() Yield attribute Next diff --git a/src/Compilers/VisualBasic/Portable/Symbols/Metadata/PE/PEPropertySymbol.vb b/src/Compilers/VisualBasic/Portable/Symbols/Metadata/PE/PEPropertySymbol.vb index 6a12ecc276166..69c8626504d6f 100644 --- a/src/Compilers/VisualBasic/Portable/Symbols/Metadata/PE/PEPropertySymbol.vb +++ b/src/Compilers/VisualBasic/Portable/Symbols/Metadata/PE/PEPropertySymbol.vb @@ -10,6 +10,7 @@ Imports System.Reflection.Metadata Imports Microsoft.Cci Imports Microsoft.CodeAnalysis.PooledObjects Imports System.Reflection.Metadata.Ecma335 +Imports Microsoft.CodeAnalysis.VisualBasic.Emit Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols.Metadata.PE @@ -336,7 +337,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols.Metadata.PE Return _lazyCustomAttributes End Function - Friend Overrides Function GetCustomAttributesToEmit(compilationState As ModuleCompilationState) As IEnumerable(Of VisualBasicAttributeData) + Friend Overrides Function GetCustomAttributesToEmit(moduleBuilder As PEModuleBuilder) As IEnumerable(Of VisualBasicAttributeData) Return GetAttributes() End Function diff --git a/src/Compilers/VisualBasic/Portable/Symbols/NamedTypeSymbol.vb b/src/Compilers/VisualBasic/Portable/Symbols/NamedTypeSymbol.vb index 77b23983ca0b2..f53888191d8c1 100644 --- a/src/Compilers/VisualBasic/Portable/Symbols/NamedTypeSymbol.vb +++ b/src/Compilers/VisualBasic/Portable/Symbols/NamedTypeSymbol.vb @@ -159,7 +159,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols ' Therefore it is a good practice to avoid type names with dots. Debug.Assert(Me.IsErrorType OrElse Not (TypeOf Me Is SourceNamedTypeSymbol) OrElse Not Name.Contains("."), "type name contains dots: " + Name) - Return If(MangleName, MetadataHelpers.ComposeAritySuffixedMetadataName(Name, Arity), Name) + Return If(MangleName, MetadataHelpers.ComposeAritySuffixedMetadataName(Name, Arity, associatedFileIdentifier:=Nothing), Name) End Get End Property @@ -1216,6 +1216,12 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols End Get End Property + Private ReadOnly Property INamedTypeSymbol_IsFileLocal As Boolean Implements INamedTypeSymbol.IsFileLocal + Get + Return False + End Get + End Property + Private ReadOnly Property INamedTypeSymbol_NativeIntegerUnderlyingType As INamedTypeSymbol Implements INamedTypeSymbol.NativeIntegerUnderlyingType Get Return Nothing diff --git a/src/Compilers/VisualBasic/Portable/Symbols/Retargeting/RetargetingEventSymbol.vb b/src/Compilers/VisualBasic/Portable/Symbols/Retargeting/RetargetingEventSymbol.vb index ffc31033eac10..79d13814153a1 100644 --- a/src/Compilers/VisualBasic/Portable/Symbols/Retargeting/RetargetingEventSymbol.vb +++ b/src/Compilers/VisualBasic/Portable/Symbols/Retargeting/RetargetingEventSymbol.vb @@ -7,6 +7,7 @@ Imports System.Globalization Imports System.Threading Imports Microsoft.CodeAnalysis.PooledObjects Imports Microsoft.CodeAnalysis.Text +Imports Microsoft.CodeAnalysis.VisualBasic.Emit Imports Microsoft.CodeAnalysis.VisualBasic.Symbols Imports Microsoft.CodeAnalysis.VisualBasic.Syntax Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols.Retargeting @@ -79,8 +80,8 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols.Retargeting Return RetargetingTranslator.GetRetargetedAttributes(_underlyingEvent, _lazyCustomAttributes) End Function - Friend Overrides Function GetCustomAttributesToEmit(compilationState As ModuleCompilationState) As IEnumerable(Of VisualBasicAttributeData) - Return RetargetingTranslator.RetargetAttributes(_underlyingEvent.GetCustomAttributesToEmit(compilationState)) + Friend Overrides Function GetCustomAttributesToEmit(moduleBuilder As PEModuleBuilder) As IEnumerable(Of VisualBasicAttributeData) + Return RetargetingTranslator.RetargetAttributes(_underlyingEvent.GetCustomAttributesToEmit(moduleBuilder)) End Function Public Overrides ReadOnly Property AddMethod As MethodSymbol diff --git a/src/Compilers/VisualBasic/Portable/Symbols/Retargeting/RetargetingFieldSymbol.vb b/src/Compilers/VisualBasic/Portable/Symbols/Retargeting/RetargetingFieldSymbol.vb index 35e8eb2d5829b..6724641e11f4f 100644 --- a/src/Compilers/VisualBasic/Portable/Symbols/Retargeting/RetargetingFieldSymbol.vb +++ b/src/Compilers/VisualBasic/Portable/Symbols/Retargeting/RetargetingFieldSymbol.vb @@ -8,6 +8,7 @@ Imports System.Collections.Immutable Imports System.Globalization Imports System.Threading Imports Microsoft.CodeAnalysis.Text +Imports Microsoft.CodeAnalysis.VisualBasic.Emit Imports Microsoft.CodeAnalysis.VisualBasic.Symbols Imports Microsoft.CodeAnalysis.VisualBasic.Syntax @@ -106,8 +107,8 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols.Retargeting Return RetargetingTranslator.GetRetargetedAttributes(_underlyingField, _lazyCustomAttributes) End Function - Friend Overrides Function GetCustomAttributesToEmit(compilationState As ModuleCompilationState) As IEnumerable(Of VisualBasicAttributeData) - Return RetargetingTranslator.RetargetAttributes(_underlyingField.GetCustomAttributesToEmit(compilationState)) + Friend Overrides Function GetCustomAttributesToEmit(moduleBuilder As PEModuleBuilder) As IEnumerable(Of VisualBasicAttributeData) + Return RetargetingTranslator.RetargetAttributes(_underlyingField.GetCustomAttributesToEmit(moduleBuilder)) End Function Public Overrides ReadOnly Property ContainingAssembly As AssemblySymbol diff --git a/src/Compilers/VisualBasic/Portable/Symbols/Retargeting/RetargetingMethodSymbol.vb b/src/Compilers/VisualBasic/Portable/Symbols/Retargeting/RetargetingMethodSymbol.vb index 83708b7deb791..ff84b2ff4355f 100644 --- a/src/Compilers/VisualBasic/Portable/Symbols/Retargeting/RetargetingMethodSymbol.vb +++ b/src/Compilers/VisualBasic/Portable/Symbols/Retargeting/RetargetingMethodSymbol.vb @@ -10,6 +10,7 @@ Imports System.Threading Imports Microsoft.CodeAnalysis.Collections Imports Microsoft.CodeAnalysis.PooledObjects Imports Microsoft.CodeAnalysis.Text +Imports Microsoft.CodeAnalysis.VisualBasic.Emit Imports Microsoft.CodeAnalysis.VisualBasic.Symbols Imports Microsoft.CodeAnalysis.VisualBasic.Syntax @@ -380,8 +381,8 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols.Retargeting Return RetargetingTranslator.GetRetargetedAttributes(_underlyingMethod, _lazyReturnTypeCustomAttributes, True) End Function - Friend Overrides Function GetCustomAttributesToEmit(compilationState As ModuleCompilationState) As IEnumerable(Of VisualBasicAttributeData) - Return RetargetingTranslator.RetargetAttributes(_underlyingMethod.GetCustomAttributesToEmit(compilationState)) + Friend Overrides Function GetCustomAttributesToEmit(moduleBuilder As PEModuleBuilder) As IEnumerable(Of VisualBasicAttributeData) + Return RetargetingTranslator.RetargetAttributes(_underlyingMethod.GetCustomAttributesToEmit(moduleBuilder)) End Function Public Overrides ReadOnly Property ContainingAssembly As AssemblySymbol diff --git a/src/Compilers/VisualBasic/Portable/Symbols/Retargeting/RetargetingNamedTypeSymbol.vb b/src/Compilers/VisualBasic/Portable/Symbols/Retargeting/RetargetingNamedTypeSymbol.vb index 30e5fd66d96bf..462ab4d8955a2 100644 --- a/src/Compilers/VisualBasic/Portable/Symbols/Retargeting/RetargetingNamedTypeSymbol.vb +++ b/src/Compilers/VisualBasic/Portable/Symbols/Retargeting/RetargetingNamedTypeSymbol.vb @@ -11,6 +11,7 @@ Imports System.Threading Imports Microsoft.CodeAnalysis.Collections Imports Microsoft.CodeAnalysis.PooledObjects Imports Microsoft.CodeAnalysis.Text +Imports Microsoft.CodeAnalysis.VisualBasic.Emit Imports Microsoft.CodeAnalysis.VisualBasic.Symbols Imports Microsoft.CodeAnalysis.VisualBasic.Syntax Imports TypeKind = Microsoft.CodeAnalysis.TypeKind @@ -473,8 +474,8 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols.Retargeting Return RetargetingTranslator.GetRetargetedAttributes(_underlyingType, _lazyCustomAttributes) End Function - Friend Overrides Function GetCustomAttributesToEmit(compilationState As ModuleCompilationState) As IEnumerable(Of VisualBasicAttributeData) - Return RetargetingTranslator.RetargetAttributes(_underlyingType.GetCustomAttributesToEmit(compilationState)) + Friend Overrides Function GetCustomAttributesToEmit(moduleBuilder As PEModuleBuilder) As IEnumerable(Of VisualBasicAttributeData) + Return RetargetingTranslator.RetargetAttributes(_underlyingType.GetCustomAttributesToEmit(moduleBuilder)) End Function Public Overrides ReadOnly Property ContainingAssembly As AssemblySymbol diff --git a/src/Compilers/VisualBasic/Portable/Symbols/Retargeting/RetargetingParameterSymbol.vb b/src/Compilers/VisualBasic/Portable/Symbols/Retargeting/RetargetingParameterSymbol.vb index d3ff256fc8c4a..31e5a475310d3 100644 --- a/src/Compilers/VisualBasic/Portable/Symbols/Retargeting/RetargetingParameterSymbol.vb +++ b/src/Compilers/VisualBasic/Portable/Symbols/Retargeting/RetargetingParameterSymbol.vb @@ -5,6 +5,7 @@ Imports System.Collections.Immutable Imports System.Globalization Imports System.Threading +Imports Microsoft.CodeAnalysis.VisualBasic.Emit Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols.Retargeting @@ -216,8 +217,8 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols.Retargeting Return RetargetingTranslator.GetRetargetedAttributes(_underlyingParameter, _lazyCustomAttributes) End Function - Friend Overrides Function GetCustomAttributesToEmit(compilationState As ModuleCompilationState) As IEnumerable(Of VisualBasicAttributeData) - Return RetargetingTranslator.RetargetAttributes(_underlyingParameter.GetCustomAttributesToEmit(compilationState)) + Friend Overrides Function GetCustomAttributesToEmit(moduleBuilder As PEModuleBuilder) As IEnumerable(Of VisualBasicAttributeData) + Return RetargetingTranslator.RetargetAttributes(_underlyingParameter.GetCustomAttributesToEmit(moduleBuilder)) End Function Public Overrides ReadOnly Property ContainingAssembly As AssemblySymbol diff --git a/src/Compilers/VisualBasic/Portable/Symbols/Retargeting/RetargetingPropertySymbol.vb b/src/Compilers/VisualBasic/Portable/Symbols/Retargeting/RetargetingPropertySymbol.vb index d479b415b252a..efac9a254ed24 100644 --- a/src/Compilers/VisualBasic/Portable/Symbols/Retargeting/RetargetingPropertySymbol.vb +++ b/src/Compilers/VisualBasic/Portable/Symbols/Retargeting/RetargetingPropertySymbol.vb @@ -7,6 +7,7 @@ Imports System.Globalization Imports System.Threading Imports Microsoft.CodeAnalysis.PooledObjects Imports Microsoft.CodeAnalysis.Text +Imports Microsoft.CodeAnalysis.VisualBasic.Emit Imports Microsoft.CodeAnalysis.VisualBasic.Symbols Imports Microsoft.CodeAnalysis.VisualBasic.Syntax Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols.Retargeting @@ -95,8 +96,8 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols.Retargeting Return RetargetingTranslator.GetRetargetedAttributes(_underlyingProperty, _lazyCustomAttributes) End Function - Friend Overrides Function GetCustomAttributesToEmit(compilationState As ModuleCompilationState) As IEnumerable(Of VisualBasicAttributeData) - Return RetargetingTranslator.RetargetAttributes(_underlyingProperty.GetCustomAttributesToEmit(compilationState)) + Friend Overrides Function GetCustomAttributesToEmit(moduleBuilder As PEModuleBuilder) As IEnumerable(Of VisualBasicAttributeData) + Return RetargetingTranslator.RetargetAttributes(_underlyingProperty.GetCustomAttributesToEmit(moduleBuilder)) End Function Public Overrides ReadOnly Property GetMethod As MethodSymbol diff --git a/src/Compilers/VisualBasic/Portable/Symbols/Source/SourceAssemblySymbol.vb b/src/Compilers/VisualBasic/Portable/Symbols/Source/SourceAssemblySymbol.vb index 13733e7c3a794..6705be55e6fa7 100644 --- a/src/Compilers/VisualBasic/Portable/Symbols/Source/SourceAssemblySymbol.vb +++ b/src/Compilers/VisualBasic/Portable/Symbols/Source/SourceAssemblySymbol.vb @@ -12,6 +12,7 @@ Imports System.Security.Cryptography Imports System.Threading Imports Microsoft.CodeAnalysis.PooledObjects Imports Microsoft.CodeAnalysis.Symbols +Imports Microsoft.CodeAnalysis.VisualBasic.Emit Imports Microsoft.CodeAnalysis.VisualBasic.Symbols Imports Microsoft.CodeAnalysis.VisualBasic.Symbols.Metadata.PE Imports Microsoft.CodeAnalysis.VisualBasic.Syntax @@ -1461,8 +1462,8 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols End Get End Property - Friend Overrides Sub AddSynthesizedAttributes(compilationState As ModuleCompilationState, ByRef attributes As ArrayBuilder(Of SynthesizedAttributeData)) - MyBase.AddSynthesizedAttributes(compilationState, attributes) + Friend Overrides Sub AddSynthesizedAttributes(moduleBuilder As PEModuleBuilder, ByRef attributes As ArrayBuilder(Of SynthesizedAttributeData)) + MyBase.AddSynthesizedAttributes(moduleBuilder, attributes) Debug.Assert(_lazyEmitExtensionAttribute <> ThreeState.Unknown) Debug.Assert(_lazySourceAttributesBag.IsSealed) diff --git a/src/Compilers/VisualBasic/Portable/Symbols/Source/SourceEventSymbol.vb b/src/Compilers/VisualBasic/Portable/Symbols/Source/SourceEventSymbol.vb index 6f07654e05a5c..8a2d779409972 100644 --- a/src/Compilers/VisualBasic/Portable/Symbols/Source/SourceEventSymbol.vb +++ b/src/Compilers/VisualBasic/Portable/Symbols/Source/SourceEventSymbol.vb @@ -8,6 +8,7 @@ Imports System.Runtime.InteropServices Imports System.Threading Imports Microsoft.CodeAnalysis.PooledObjects Imports Microsoft.CodeAnalysis.Text +Imports Microsoft.CodeAnalysis.VisualBasic.Emit Imports Microsoft.CodeAnalysis.VisualBasic.Symbols Imports Microsoft.CodeAnalysis.VisualBasic.Syntax @@ -763,8 +764,8 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols End Get End Property - Friend Overrides Sub AddSynthesizedAttributes(compilationState As ModuleCompilationState, ByRef attributes As ArrayBuilder(Of SynthesizedAttributeData)) - MyBase.AddSynthesizedAttributes(compilationState, attributes) + Friend Overrides Sub AddSynthesizedAttributes(moduleBuilder As PEModuleBuilder, ByRef attributes As ArrayBuilder(Of SynthesizedAttributeData)) + MyBase.AddSynthesizedAttributes(moduleBuilder, attributes) If Me.Type.ContainsTupleNames() Then AddSynthesizedAttribute(attributes, DeclaringCompilation.SynthesizeTupleNamesAttribute(Type)) diff --git a/src/Compilers/VisualBasic/Portable/Symbols/Source/SourceFieldSymbol.vb b/src/Compilers/VisualBasic/Portable/Symbols/Source/SourceFieldSymbol.vb index e6827cfdcef82..4c1cea291fbba 100644 --- a/src/Compilers/VisualBasic/Portable/Symbols/Source/SourceFieldSymbol.vb +++ b/src/Compilers/VisualBasic/Portable/Symbols/Source/SourceFieldSymbol.vb @@ -9,6 +9,7 @@ Imports System.Runtime.InteropServices Imports System.Threading Imports Microsoft.CodeAnalysis.PooledObjects Imports Microsoft.CodeAnalysis.Text +Imports Microsoft.CodeAnalysis.VisualBasic.Emit Imports Microsoft.CodeAnalysis.VisualBasic.Symbols Imports Microsoft.CodeAnalysis.VisualBasic.Syntax Imports TypeKind = Microsoft.CodeAnalysis.TypeKind @@ -652,8 +653,8 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols _lazyCustomAttributesBag = attributeData End Sub - Friend Overrides Sub AddSynthesizedAttributes(compilationState as ModuleCompilationState, ByRef attributes As ArrayBuilder(Of SynthesizedAttributeData)) - MyBase.AddSynthesizedAttributes(compilationState, attributes) + Friend Overrides Sub AddSynthesizedAttributes(moduleBuilder As PEModuleBuilder, ByRef attributes As ArrayBuilder(Of SynthesizedAttributeData)) + MyBase.AddSynthesizedAttributes(moduleBuilder, attributes) If Me.IsConst Then If Me.GetConstantValue(ConstantFieldsInProgress.Empty) IsNot Nothing Then diff --git a/src/Compilers/VisualBasic/Portable/Symbols/Source/SourceMemberContainerTypeSymbol.vb b/src/Compilers/VisualBasic/Portable/Symbols/Source/SourceMemberContainerTypeSymbol.vb index c608f11ad7fc5..2210045f4b0a6 100644 --- a/src/Compilers/VisualBasic/Portable/Symbols/Source/SourceMemberContainerTypeSymbol.vb +++ b/src/Compilers/VisualBasic/Portable/Symbols/Source/SourceMemberContainerTypeSymbol.vb @@ -6,6 +6,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 Imports Microsoft.CodeAnalysis.VisualBasic.Syntax Imports Roslyn.Utilities @@ -31,13 +32,13 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols [Public] = CUShort(Accessibility.Public) AccessibilityMask = &H7 - [Class] = CUShort(TYPEKIND.Class) << TypeKindShift - [Structure] = CUShort(TYPEKIND.Structure) << TypeKindShift - [Interface] = CUShort(TYPEKIND.Interface) << TypeKindShift - [Enum] = CUShort(TYPEKIND.Enum) << TypeKindShift - [Delegate] = CUShort(TYPEKIND.Delegate) << TypeKindShift - [Module] = CUShort(TYPEKIND.Module) << TypeKindShift - Submission = CUShort(TYPEKIND.Submission) << TypeKindShift + [Class] = CUShort(TypeKind.Class) << TypeKindShift + [Structure] = CUShort(TypeKind.Structure) << TypeKindShift + [Interface] = CUShort(TypeKind.Interface) << TypeKindShift + [Enum] = CUShort(TypeKind.Enum) << TypeKindShift + [Delegate] = CUShort(TypeKind.Delegate) << TypeKindShift + [Module] = CUShort(TypeKind.Module) << TypeKindShift + Submission = CUShort(TypeKind.Submission) << TypeKindShift TypeKindMask = &HF0 TypeKindShift = 4 @@ -239,7 +240,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols ' In case Vb Core Runtime is being embedded, we should mark attribute ' 'Microsoft.VisualBasic.CompilerServices.StandardModuleAttribute' ' as being referenced if the named type just created is a module - If type.TypeKind = TYPEKIND.Module Then + If type.TypeKind = TypeKind.Module Then type.DeclaringCompilation.EmbeddedSymbolManager.RegisterModuleDeclaration() End If @@ -1264,9 +1265,9 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols End Get End Property - Public Overrides ReadOnly Property TypeKind As TYPEKIND + Public Overrides ReadOnly Property TypeKind As TypeKind Get - Return CType((_flags And SourceTypeFlags.TypeKindMask) >> CUInt(SourceTypeFlags.TypeKindShift), TYPEKIND) + Return CType((_flags And SourceTypeFlags.TypeKindMask) >> CUInt(SourceTypeFlags.TypeKindShift), TypeKind) End Get End Property @@ -2662,7 +2663,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols If propertySymbol.IsAutoProperty AndAlso propertySymbol.ContainingType.TypeKind = TypeKind.Structure Then - binder.ReportDiagnostic(diagBag, syntax.Identifier, ERRID.ERR_AutoPropertyInitializedInStructure) + Binder.ReportDiagnostic(diagBag, syntax.Identifier, ERRID.ERR_AutoPropertyInitializedInStructure) End If AddInitializer(instanceInitializers, initializer, members.InstanceSyntaxLength) @@ -3488,7 +3489,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols Debug.Assert(Me.IsDefinition) ' Don't do this on constructed types ' Enums and Delegates have nothing to do. - Dim myTypeKind As TYPEKIND = Me.TypeKind + Dim myTypeKind As TypeKind = Me.TypeKind Dim operatorsKnownToHavePair As HashSet(Of MethodSymbol) = Nothing If myTypeKind = TypeKind.Class OrElse myTypeKind = TypeKind.Interface OrElse myTypeKind = TypeKind.Structure OrElse myTypeKind = TypeKind.Module Then @@ -4026,8 +4027,8 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols End Get End Property - Friend Overrides Sub AddSynthesizedAttributes(compilationState As ModuleCompilationState, ByRef attributes As ArrayBuilder(Of SynthesizedAttributeData)) - MyBase.AddSynthesizedAttributes(compilationState, attributes) + Friend Overrides Sub AddSynthesizedAttributes(moduleBuilder As PEModuleBuilder, ByRef attributes As ArrayBuilder(Of SynthesizedAttributeData)) + MyBase.AddSynthesizedAttributes(moduleBuilder, attributes) If EmitExtensionAttribute Then AddSynthesizedAttribute(attributes, Me.DeclaringCompilation.SynthesizeExtensionAttribute()) diff --git a/src/Compilers/VisualBasic/Portable/Symbols/Source/SourceMemberMethodSymbol.vb b/src/Compilers/VisualBasic/Portable/Symbols/Source/SourceMemberMethodSymbol.vb index 7e9ffd6fd433c..5c1b0591fee8c 100644 --- a/src/Compilers/VisualBasic/Portable/Symbols/Source/SourceMemberMethodSymbol.vb +++ b/src/Compilers/VisualBasic/Portable/Symbols/Source/SourceMemberMethodSymbol.vb @@ -7,6 +7,7 @@ Imports System.Runtime.InteropServices Imports System.Threading Imports Microsoft.CodeAnalysis.PooledObjects Imports Microsoft.CodeAnalysis.Text +Imports Microsoft.CodeAnalysis.VisualBasic.Emit Imports Microsoft.CodeAnalysis.VisualBasic.Symbols Imports Microsoft.CodeAnalysis.VisualBasic.Syntax @@ -174,11 +175,11 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols End Get End Property - Friend Overrides Sub AddSynthesizedAttributes(compilationState As ModuleCompilationState, ByRef attributes As ArrayBuilder(Of SynthesizedAttributeData)) - MyBase.AddSynthesizedAttributes(compilationState, attributes) + Friend Overrides Sub AddSynthesizedAttributes(moduleBuilder As PEModuleBuilder, ByRef attributes As ArrayBuilder(Of SynthesizedAttributeData)) + MyBase.AddSynthesizedAttributes(moduleBuilder, attributes) If Me.IsAsync OrElse Me.IsIterator Then - AddSynthesizedAttribute(attributes, Me.DeclaringCompilation.SynthesizeStateMachineAttribute(Me, compilationState)) + AddSynthesizedAttribute(attributes, Me.DeclaringCompilation.SynthesizeStateMachineAttribute(Me, moduleBuilder.CompilationState)) If Me.IsAsync Then ' Async kick-off method calls MoveNext, which contains user code. diff --git a/src/Compilers/VisualBasic/Portable/Symbols/Source/SourceMethodSymbol.vb b/src/Compilers/VisualBasic/Portable/Symbols/Source/SourceMethodSymbol.vb index 63f4f03001473..0f7833b23c834 100644 --- a/src/Compilers/VisualBasic/Portable/Symbols/Source/SourceMethodSymbol.vb +++ b/src/Compilers/VisualBasic/Portable/Symbols/Source/SourceMethodSymbol.vb @@ -10,6 +10,7 @@ Imports System.Threading Imports Microsoft.Cci Imports Microsoft.CodeAnalysis.PooledObjects Imports Microsoft.CodeAnalysis.Text +Imports Microsoft.CodeAnalysis.VisualBasic.Emit Imports Microsoft.CodeAnalysis.VisualBasic.Symbols Imports Microsoft.CodeAnalysis.VisualBasic.Syntax Imports CallingConvention = Microsoft.Cci.CallingConvention ' to resolve ambiguity with System.Runtime.InteropServices.CallingConvention @@ -1438,8 +1439,8 @@ lReportErrorOnTwoTokens: Return Me.GetAttributesBag().Attributes End Function - Friend Overrides Sub AddSynthesizedAttributes(compilationState As ModuleCompilationState, ByRef attributes As ArrayBuilder(Of SynthesizedAttributeData)) - MyBase.AddSynthesizedAttributes(compilationState, attributes) + Friend Overrides Sub AddSynthesizedAttributes(moduleBuilder As PEModuleBuilder, ByRef attributes As ArrayBuilder(Of SynthesizedAttributeData)) + MyBase.AddSynthesizedAttributes(moduleBuilder, attributes) ' Emit synthesized STAThreadAttribute for this method if both the following requirements are met: ' (a) This is the entry point method. diff --git a/src/Compilers/VisualBasic/Portable/Symbols/Source/SourceNamedTypeSymbol.vb b/src/Compilers/VisualBasic/Portable/Symbols/Source/SourceNamedTypeSymbol.vb index aba3b806ad3cb..7b36f3b707726 100644 --- a/src/Compilers/VisualBasic/Portable/Symbols/Source/SourceNamedTypeSymbol.vb +++ b/src/Compilers/VisualBasic/Portable/Symbols/Source/SourceNamedTypeSymbol.vb @@ -9,7 +9,9 @@ Imports System.Globalization Imports System.Runtime.InteropServices Imports System.Threading Imports Microsoft.CodeAnalysis.PooledObjects +Imports Microsoft.CodeAnalysis.Symbols Imports Microsoft.CodeAnalysis.Text +Imports Microsoft.CodeAnalysis.VisualBasic.Emit Imports Microsoft.CodeAnalysis.VisualBasic.Symbols Imports Microsoft.CodeAnalysis.VisualBasic.Syntax Imports TypeKind = Microsoft.CodeAnalysis.TypeKind @@ -2466,8 +2468,8 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols End Get End Property - Friend Overrides Sub AddSynthesizedAttributes(compilationState As ModuleCompilationState, ByRef attributes As ArrayBuilder(Of SynthesizedAttributeData)) - MyBase.AddSynthesizedAttributes(compilationState, attributes) + Friend Overrides Sub AddSynthesizedAttributes(moduleBuilder As PEModuleBuilder, ByRef attributes As ArrayBuilder(Of SynthesizedAttributeData)) + MyBase.AddSynthesizedAttributes(moduleBuilder, attributes) Dim compilation = Me.DeclaringCompilation @@ -2531,6 +2533,25 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols AddSynthesizedAttribute(attributes, compilation.SynthesizeTupleNamesAttribute(baseType)) End If End If + + ' Add MetadataUpdateOriginalTypeAttribute when a reloadable type is emitted to EnC delta + If moduleBuilder.EncSymbolChanges?.IsReplaced(CType(Me, ISymbolInternal).GetISymbol()) = True Then + ' Note that we use this source named type symbol in the attribute argument (of System.Type). + ' We do not have access to the original symbol from this compilation. However, System.Type + ' is encoded in the attribute as a string containing a fully qualified type name. + ' The name of the current type symbol as provided by ISymbol.Name is the same as the name of + ' the original type symbol that is being replaced by this type symbol. + ' The "#{generation}" suffix is appended to the TypeDef name in the metadata writer, + ' but not to the attribute value. + Dim originalType = Me + + AddSynthesizedAttribute( + attributes, + compilation.TrySynthesizeAttribute( + WellKnownMember.System_Runtime_CompilerServices_MetadataUpdateOriginalTypeAttribute__ctor, + ImmutableArray.Create(New TypedConstant(compilation.GetWellKnownType(WellKnownType.System_Type), TypedConstantKind.Type, originalType)), + isOptionalUse:=True)) + End If End Sub Private Function HasDefaultMemberAttribute() As Boolean diff --git a/src/Compilers/VisualBasic/Portable/Symbols/Source/SourceNamedTypeSymbol_ComClass.vb b/src/Compilers/VisualBasic/Portable/Symbols/Source/SourceNamedTypeSymbol_ComClass.vb index 2841a81e8c809..39fd3ada671f6 100644 --- a/src/Compilers/VisualBasic/Portable/Symbols/Source/SourceNamedTypeSymbol_ComClass.vb +++ b/src/Compilers/VisualBasic/Portable/Symbols/Source/SourceNamedTypeSymbol_ComClass.vb @@ -5,6 +5,7 @@ Imports System.Collections.Immutable Imports System.Runtime.InteropServices Imports Microsoft.CodeAnalysis.PooledObjects +Imports Microsoft.CodeAnalysis.VisualBasic.Emit Imports Microsoft.CodeAnalysis.VisualBasic.Symbols Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols @@ -981,8 +982,8 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols Return ImmutableArray(Of VisualBasicAttributeData).Empty End Function - Friend Overrides Sub AddSynthesizedAttributes(compilationState As ModuleCompilationState, ByRef attributes As ArrayBuilder(Of SynthesizedAttributeData)) - MyBase.AddSynthesizedAttributes(compilationState, attributes) + Friend Overrides Sub AddSynthesizedAttributes(moduleBuilder As PEModuleBuilder, ByRef attributes As ArrayBuilder(Of SynthesizedAttributeData)) + MyBase.AddSynthesizedAttributes(moduleBuilder, attributes) Dim compilation As VisualBasicCompilation = _comClass.DeclaringCompilation Dim id As String = If(_isEventInterface, _comClass._comClassData.EventId, _comClass._comClassData.InterfaceId) @@ -1336,8 +1337,8 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols Return attributes.ToImmutableAndFree() End Function - Friend Overrides Sub AddSynthesizedAttributes(compilationState As ModuleCompilationState, ByRef attributes As ArrayBuilder(Of SynthesizedAttributeData)) - MyBase.AddSynthesizedAttributes(compilationState, attributes) + Friend Overrides Sub AddSynthesizedAttributes(moduleBuilder As PEModuleBuilder, ByRef attributes As ArrayBuilder(Of SynthesizedAttributeData)) + MyBase.AddSynthesizedAttributes(moduleBuilder, attributes) If _synthesizedDispId = ReservedDispId.None Then Return @@ -1612,15 +1613,15 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols Return _clonedFrom.GetAttributes() End Function - Friend Overrides Sub AddSynthesizedAttributes(compilationState As ModuleCompilationState, ByRef attributes As ArrayBuilder(Of SynthesizedAttributeData)) - MyBase.AddSynthesizedAttributes(compilationState, attributes) + Friend Overrides Sub AddSynthesizedAttributes(moduleBuilder As PEModuleBuilder, ByRef attributes As ArrayBuilder(Of SynthesizedAttributeData)) + MyBase.AddSynthesizedAttributes(moduleBuilder, attributes) If IsComEventParameter Then Return End If Dim toClone As ArrayBuilder(Of SynthesizedAttributeData) = Nothing - _clonedFrom.AddSynthesizedAttributes(compilationState, toClone) + _clonedFrom.AddSynthesizedAttributes(moduleBuilder, toClone) Dim compilation = Me.DeclaringCompilation Dim paramArrayAttribute As NamedTypeSymbol = compilation.GetWellKnownType(WellKnownType.System_ParamArrayAttribute) @@ -1832,8 +1833,8 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols Return _clonedFrom.GetAttributes() End Function - Friend Overrides Sub AddSynthesizedAttributes(compilationState As ModuleCompilationState, ByRef attributes As ArrayBuilder(Of SynthesizedAttributeData)) - MyBase.AddSynthesizedAttributes(compilationState, attributes) + Friend Overrides Sub AddSynthesizedAttributes(moduleBuilder As PEModuleBuilder, ByRef attributes As ArrayBuilder(Of SynthesizedAttributeData)) + MyBase.AddSynthesizedAttributes(moduleBuilder, attributes) If _synthesizedDispId = ReservedDispId.None Then Return diff --git a/src/Compilers/VisualBasic/Portable/Symbols/Source/SourceParameterSymbol.vb b/src/Compilers/VisualBasic/Portable/Symbols/Source/SourceParameterSymbol.vb index 313c892c02ba3..faf2cdba15f3c 100644 --- a/src/Compilers/VisualBasic/Portable/Symbols/Source/SourceParameterSymbol.vb +++ b/src/Compilers/VisualBasic/Portable/Symbols/Source/SourceParameterSymbol.vb @@ -4,6 +4,7 @@ Imports System.Collections.Immutable Imports System.Runtime.InteropServices +Imports Microsoft.CodeAnalysis.VisualBasic.Emit Imports Microsoft.CodeAnalysis.VisualBasic.Symbols Imports Microsoft.CodeAnalysis.VisualBasic.Syntax @@ -264,8 +265,8 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols Return MyBase.EarlyDecodeWellKnownAttribute(arguments) End Function - Friend Overrides Iterator Function GetCustomAttributesToEmit(compilationState As ModuleCompilationState) As IEnumerable(Of VisualBasicAttributeData) - Dim attributes = MyBase.GetCustomAttributesToEmit(compilationState) + Friend Overrides Iterator Function GetCustomAttributesToEmit(moduleBuilder As PEModuleBuilder) As IEnumerable(Of VisualBasicAttributeData) + Dim attributes = MyBase.GetCustomAttributesToEmit(moduleBuilder) For Each attribute In attributes If AttributeData.IsTargetEarlyAttribute(attributeType:=attribute.AttributeClass, attributeArgCount:=attribute.CommonConstructorArguments.Length, description:=AttributeDescription.CallerArgumentExpressionAttribute) Then diff --git a/src/Compilers/VisualBasic/Portable/Symbols/Source/SourceParameterSymbolBase.vb b/src/Compilers/VisualBasic/Portable/Symbols/Source/SourceParameterSymbolBase.vb index c27ad4524ba58..a6b934d87984d 100644 --- a/src/Compilers/VisualBasic/Portable/Symbols/Source/SourceParameterSymbolBase.vb +++ b/src/Compilers/VisualBasic/Portable/Symbols/Source/SourceParameterSymbolBase.vb @@ -4,6 +4,7 @@ Imports System.Collections.Immutable Imports Microsoft.CodeAnalysis.PooledObjects +Imports Microsoft.CodeAnalysis.VisualBasic.Emit Imports Microsoft.CodeAnalysis.VisualBasic.Symbols Imports Microsoft.CodeAnalysis.VisualBasic.Syntax @@ -38,8 +39,8 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols Friend MustOverride ReadOnly Property HasDefaultValueAttribute As Boolean - Friend NotOverridable Overrides Sub AddSynthesizedAttributes(compilationState as ModuleCompilationState, ByRef attributes As ArrayBuilder(Of SynthesizedAttributeData)) - MyBase.AddSynthesizedAttributes(compilationState, attributes) + Friend NotOverridable Overrides Sub AddSynthesizedAttributes(moduleBuilder As PEModuleBuilder, ByRef attributes As ArrayBuilder(Of SynthesizedAttributeData)) + MyBase.AddSynthesizedAttributes(moduleBuilder, attributes) ' Create the ParamArrayAttribute If IsParamArray AndAlso Not HasParamArrayAttribute Then diff --git a/src/Compilers/VisualBasic/Portable/Symbols/Source/SourcePropertyAccessorSymbol.vb b/src/Compilers/VisualBasic/Portable/Symbols/Source/SourcePropertyAccessorSymbol.vb index d9cb2f4c5ee2d..b5dcf3f99022f 100644 --- a/src/Compilers/VisualBasic/Portable/Symbols/Source/SourcePropertyAccessorSymbol.vb +++ b/src/Compilers/VisualBasic/Portable/Symbols/Source/SourcePropertyAccessorSymbol.vb @@ -5,6 +5,7 @@ Imports System.Collections.Immutable Imports System.Threading Imports Microsoft.CodeAnalysis.PooledObjects +Imports Microsoft.CodeAnalysis.VisualBasic.Emit Imports Microsoft.CodeAnalysis.VisualBasic.Symbols Imports Microsoft.CodeAnalysis.VisualBasic.Syntax @@ -492,8 +493,8 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols End Get End Property - Friend Overrides Sub AddSynthesizedAttributes(compilationState as ModuleCompilationState, ByRef attributes As ArrayBuilder(Of SynthesizedAttributeData)) - MyBase.AddSynthesizedAttributes(compilationState, attributes) + Friend Overrides Sub AddSynthesizedAttributes(moduleBuilder As PEModuleBuilder, ByRef attributes As ArrayBuilder(Of SynthesizedAttributeData)) + MyBase.AddSynthesizedAttributes(moduleBuilder, attributes) If m_property.IsAutoProperty Then Dim compilation = DeclaringCompilation diff --git a/src/Compilers/VisualBasic/Portable/Symbols/Source/SourcePropertySymbol.vb b/src/Compilers/VisualBasic/Portable/Symbols/Source/SourcePropertySymbol.vb index 23019fe70facf..eb38d02a40e6a 100644 --- a/src/Compilers/VisualBasic/Portable/Symbols/Source/SourcePropertySymbol.vb +++ b/src/Compilers/VisualBasic/Portable/Symbols/Source/SourcePropertySymbol.vb @@ -11,6 +11,7 @@ Imports System.Runtime.InteropServices Imports System.Threading Imports Microsoft.CodeAnalysis.PooledObjects Imports Microsoft.CodeAnalysis.Text +Imports Microsoft.CodeAnalysis.VisualBasic.Emit Imports Microsoft.CodeAnalysis.VisualBasic.Symbols Imports Microsoft.CodeAnalysis.VisualBasic.Syntax Imports TypeKind = Microsoft.CodeAnalysis.TypeKind @@ -1205,8 +1206,8 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols End Get End Property - Friend Overrides Sub AddSynthesizedAttributes(compilationState As ModuleCompilationState, ByRef attributes As ArrayBuilder(Of SynthesizedAttributeData)) - MyBase.AddSynthesizedAttributes(compilationState, attributes) + Friend Overrides Sub AddSynthesizedAttributes(moduleBuilder As PEModuleBuilder, ByRef attributes As ArrayBuilder(Of SynthesizedAttributeData)) + MyBase.AddSynthesizedAttributes(moduleBuilder, attributes) If Me.Type.ContainsTupleNames() Then AddSynthesizedAttribute(attributes, DeclaringCompilation.SynthesizeTupleNamesAttribute(Type)) diff --git a/src/Compilers/VisualBasic/Portable/Symbols/Source/SourceWithEventsBackingFieldSymbol.vb b/src/Compilers/VisualBasic/Portable/Symbols/Source/SourceWithEventsBackingFieldSymbol.vb index 2554a86cc0f26..d6515c0da4534 100644 --- a/src/Compilers/VisualBasic/Portable/Symbols/Source/SourceWithEventsBackingFieldSymbol.vb +++ b/src/Compilers/VisualBasic/Portable/Symbols/Source/SourceWithEventsBackingFieldSymbol.vb @@ -6,6 +6,7 @@ Imports System.Collections.Immutable Imports System.Runtime.InteropServices Imports Microsoft.CodeAnalysis.PooledObjects Imports Microsoft.CodeAnalysis.Text +Imports Microsoft.CodeAnalysis.VisualBasic.Emit Imports Microsoft.CodeAnalysis.VisualBasic.Symbols Imports Microsoft.CodeAnalysis.VisualBasic.Syntax Imports TypeKind = Microsoft.CodeAnalysis.TypeKind @@ -57,8 +58,8 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols End Get End Property - Friend Overrides Sub AddSynthesizedAttributes(compilationState as ModuleCompilationState, ByRef attributes As ArrayBuilder(Of SynthesizedAttributeData)) - MyBase.AddSynthesizedAttributes(compilationState, attributes) + Friend Overrides Sub AddSynthesizedAttributes(moduleBuilder As PEModuleBuilder, ByRef attributes As ArrayBuilder(Of SynthesizedAttributeData)) + MyBase.AddSynthesizedAttributes(moduleBuilder, attributes) Dim compilation = _property.DeclaringCompilation diff --git a/src/Compilers/VisualBasic/Portable/Symbols/Source/SynthesizedConstructorSymbol.vb b/src/Compilers/VisualBasic/Portable/Symbols/Source/SynthesizedConstructorSymbol.vb index 817cfbf5964f1..6c7ae1ef2531a 100644 --- a/src/Compilers/VisualBasic/Portable/Symbols/Source/SynthesizedConstructorSymbol.vb +++ b/src/Compilers/VisualBasic/Portable/Symbols/Source/SynthesizedConstructorSymbol.vb @@ -4,6 +4,7 @@ Imports System.Collections.Immutable Imports Microsoft.CodeAnalysis.PooledObjects +Imports Microsoft.CodeAnalysis.VisualBasic.Emit Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols @@ -36,8 +37,8 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols Me._debuggable = isDebuggable End Sub - Friend Overrides Sub AddSynthesizedAttributes(compilationState as ModuleCompilationState, ByRef attributes As ArrayBuilder(Of SynthesizedAttributeData)) - MyBase.AddSynthesizedAttributes(compilationState, attributes) + Friend Overrides Sub AddSynthesizedAttributes(moduleBuilder As PEModuleBuilder, ByRef attributes As ArrayBuilder(Of SynthesizedAttributeData)) + MyBase.AddSynthesizedAttributes(moduleBuilder, attributes) ' Dev11 emits DebuggerNonUserCodeAttribute. This attribute is not needed since we don't emit any debug info for the constructor. End Sub diff --git a/src/Compilers/VisualBasic/Portable/Symbols/Source/SynthesizedEventAccessorSymbol.vb b/src/Compilers/VisualBasic/Portable/Symbols/Source/SynthesizedEventAccessorSymbol.vb index 391aac38de489..bdb51f893cf6e 100644 --- a/src/Compilers/VisualBasic/Portable/Symbols/Source/SynthesizedEventAccessorSymbol.vb +++ b/src/Compilers/VisualBasic/Portable/Symbols/Source/SynthesizedEventAccessorSymbol.vb @@ -8,6 +8,7 @@ Imports System.Threading Imports Microsoft.CodeAnalysis.PooledObjects Imports Microsoft.CodeAnalysis.RuntimeMembers Imports Microsoft.CodeAnalysis.Text +Imports Microsoft.CodeAnalysis.VisualBasic.Emit Imports Microsoft.CodeAnalysis.VisualBasic.Symbols Imports Microsoft.CodeAnalysis.VisualBasic.Syntax @@ -489,8 +490,8 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols Dim unusedReturnType = Me.ReturnType End Sub - Friend Overrides Sub AddSynthesizedAttributes(compilationState As ModuleCompilationState, ByRef attributes As ArrayBuilder(Of SynthesizedAttributeData)) - MyBase.AddSynthesizedAttributes(compilationState, attributes) + Friend Overrides Sub AddSynthesizedAttributes(moduleBuilder As PEModuleBuilder, ByRef attributes As ArrayBuilder(Of SynthesizedAttributeData)) + MyBase.AddSynthesizedAttributes(moduleBuilder, attributes) Debug.Assert(Not ContainingType.IsImplicitlyDeclared) Dim compilation = Me.DeclaringCompilation diff --git a/src/Compilers/VisualBasic/Portable/Symbols/Source/SynthesizedFieldSymbol.vb b/src/Compilers/VisualBasic/Portable/Symbols/Source/SynthesizedFieldSymbol.vb index 2c91a6cd059fe..6411c6aed8c5c 100644 --- a/src/Compilers/VisualBasic/Portable/Symbols/Source/SynthesizedFieldSymbol.vb +++ b/src/Compilers/VisualBasic/Portable/Symbols/Source/SynthesizedFieldSymbol.vb @@ -7,6 +7,7 @@ Imports System.Collections.Immutable Imports System.Diagnostics Imports Microsoft.CodeAnalysis.PooledObjects Imports Microsoft.CodeAnalysis.Text +Imports Microsoft.CodeAnalysis.VisualBasic.Emit Imports Microsoft.CodeAnalysis.VisualBasic.Symbols Imports Microsoft.CodeAnalysis.VisualBasic.Syntax @@ -54,8 +55,8 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols End Get End Property - Friend Overrides Sub AddSynthesizedAttributes(compilationState As ModuleCompilationState, ByRef attributes As ArrayBuilder(Of SynthesizedAttributeData)) - MyBase.AddSynthesizedAttributes(compilationState, attributes) + Friend Overrides Sub AddSynthesizedAttributes(moduleBuilder As PEModuleBuilder, ByRef attributes As ArrayBuilder(Of SynthesizedAttributeData)) + MyBase.AddSynthesizedAttributes(moduleBuilder, attributes) ' enum fields do not need to be marked as generated If (_isSpecialNameAndRuntimeSpecial) Then diff --git a/src/Compilers/VisualBasic/Portable/Symbols/Source/SynthesizedMainTypeEntryPoint.vb b/src/Compilers/VisualBasic/Portable/Symbols/Source/SynthesizedMainTypeEntryPoint.vb index 4fe54c9f36c06..f417c51ba7b1e 100644 --- a/src/Compilers/VisualBasic/Portable/Symbols/Source/SynthesizedMainTypeEntryPoint.vb +++ b/src/Compilers/VisualBasic/Portable/Symbols/Source/SynthesizedMainTypeEntryPoint.vb @@ -8,6 +8,7 @@ Imports System.Diagnostics Imports System.Runtime.InteropServices Imports Microsoft.CodeAnalysis.PooledObjects Imports Microsoft.CodeAnalysis.Text +Imports Microsoft.CodeAnalysis.VisualBasic.Emit Imports Microsoft.CodeAnalysis.VisualBasic.Symbols Imports Microsoft.CodeAnalysis.VisualBasic.Syntax Imports TypeKind = Microsoft.CodeAnalysis.TypeKind @@ -81,8 +82,8 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols Return New BoundBlock(syntaxNode, Nothing, ImmutableArray(Of LocalSymbol).Empty, ImmutableArray.Create(statement, New BoundReturnStatement(syntaxNode, Nothing, Nothing, Nothing))) End Function - Friend Overrides Sub AddSynthesizedAttributes(compilationState As ModuleCompilationState, ByRef attributes As ArrayBuilder(Of SynthesizedAttributeData)) - MyBase.AddSynthesizedAttributes(compilationState, attributes) + Friend Overrides Sub AddSynthesizedAttributes(moduleBuilder As PEModuleBuilder, ByRef attributes As ArrayBuilder(Of SynthesizedAttributeData)) + MyBase.AddSynthesizedAttributes(moduleBuilder, attributes) AddSynthesizedAttribute(attributes, DeclaringCompilation.TrySynthesizeAttribute(WellKnownMember.System_STAThreadAttribute__ctor)) diff --git a/src/Compilers/VisualBasic/Portable/Symbols/Source/SynthesizedMyGroupCollectionPropertyAccessorSymbol.vb b/src/Compilers/VisualBasic/Portable/Symbols/Source/SynthesizedMyGroupCollectionPropertyAccessorSymbol.vb index 806cef8a94cb8..c6f0dd3fa1384 100644 --- a/src/Compilers/VisualBasic/Portable/Symbols/Source/SynthesizedMyGroupCollectionPropertyAccessorSymbol.vb +++ b/src/Compilers/VisualBasic/Portable/Symbols/Source/SynthesizedMyGroupCollectionPropertyAccessorSymbol.vb @@ -8,6 +8,7 @@ Imports System.Diagnostics Imports System.Runtime.InteropServices Imports Microsoft.CodeAnalysis.PooledObjects Imports Microsoft.CodeAnalysis.Text +Imports Microsoft.CodeAnalysis.VisualBasic.Emit Imports Microsoft.CodeAnalysis.VisualBasic.Symbols Imports Microsoft.CodeAnalysis.VisualBasic.Syntax Imports TypeKind = Microsoft.CodeAnalysis.TypeKind @@ -34,8 +35,8 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols End Get End Property - Friend Overrides Sub AddSynthesizedAttributes(compilationState as ModuleCompilationState, ByRef attributes As ArrayBuilder(Of SynthesizedAttributeData)) - MyBase.AddSynthesizedAttributes(compilationState, attributes) + Friend Overrides Sub AddSynthesizedAttributes(moduleBuilder As PEModuleBuilder, ByRef attributes As ArrayBuilder(Of SynthesizedAttributeData)) + MyBase.AddSynthesizedAttributes(moduleBuilder, attributes) ' Note, Dev11 emits DebuggerNonUserCodeAttribute, but we are using DebuggerHiddenAttribute instead. AddSynthesizedAttribute(attributes, Me.DeclaringCompilation.SynthesizeDebuggerHiddenAttribute()) diff --git a/src/Compilers/VisualBasic/Portable/Symbols/Source/SynthesizedMyGroupCollectionPropertyBackingFieldSymbol.vb b/src/Compilers/VisualBasic/Portable/Symbols/Source/SynthesizedMyGroupCollectionPropertyBackingFieldSymbol.vb index f4055eab5999b..492b19c9295ee 100644 --- a/src/Compilers/VisualBasic/Portable/Symbols/Source/SynthesizedMyGroupCollectionPropertyBackingFieldSymbol.vb +++ b/src/Compilers/VisualBasic/Portable/Symbols/Source/SynthesizedMyGroupCollectionPropertyBackingFieldSymbol.vb @@ -6,6 +6,7 @@ Imports System.Collections.Generic Imports System.Diagnostics Imports Microsoft.CodeAnalysis.PooledObjects Imports Microsoft.CodeAnalysis.Text +Imports Microsoft.CodeAnalysis.VisualBasic.Emit Imports Microsoft.CodeAnalysis.VisualBasic.Symbols Imports Microsoft.CodeAnalysis.VisualBasic.Syntax @@ -32,7 +33,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols Return LexicalSortKey.NotInSource End Function - Friend Overrides Sub AddSynthesizedAttributes(compilationState as ModuleCompilationState, ByRef attributes As ArrayBuilder(Of SynthesizedAttributeData)) + Friend Overrides Sub AddSynthesizedAttributes(moduleBuilder As PEModuleBuilder, ByRef attributes As ArrayBuilder(Of SynthesizedAttributeData)) AddSynthesizedAttribute(attributes, Me.DeclaringCompilation.SynthesizeEditorBrowsableNeverAttribute()) End Sub diff --git a/src/Compilers/VisualBasic/Portable/Symbols/Source/SynthesizedStaticLocalBackingField.vb b/src/Compilers/VisualBasic/Portable/Symbols/Source/SynthesizedStaticLocalBackingField.vb index 1035949649c2c..f03d520929a21 100644 --- a/src/Compilers/VisualBasic/Portable/Symbols/Source/SynthesizedStaticLocalBackingField.vb +++ b/src/Compilers/VisualBasic/Portable/Symbols/Source/SynthesizedStaticLocalBackingField.vb @@ -6,6 +6,7 @@ Imports System.Collections.Generic Imports System.Diagnostics Imports Microsoft.CodeAnalysis.PooledObjects Imports Microsoft.CodeAnalysis.Text +Imports Microsoft.CodeAnalysis.VisualBasic.Emit Imports Microsoft.CodeAnalysis.VisualBasic.Symbols Imports Microsoft.CodeAnalysis.VisualBasic.Syntax @@ -54,7 +55,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols End Get End Property - Friend Overrides Sub AddSynthesizedAttributes(compilationState as ModuleCompilationState, ByRef attributes As ArrayBuilder(Of SynthesizedAttributeData)) + Friend Overrides Sub AddSynthesizedAttributes(moduleBuilder As PEModuleBuilder, ByRef attributes As ArrayBuilder(Of SynthesizedAttributeData)) ' no attributes on static backing fields - Dev12 behavior End Sub End Class diff --git a/src/Compilers/VisualBasic/Portable/Symbols/Source/SynthesizedWithEventsAccessorSymbol.vb b/src/Compilers/VisualBasic/Portable/Symbols/Source/SynthesizedWithEventsAccessorSymbol.vb index 37c3f7d6f4a51..a0f8b38f79825 100644 --- a/src/Compilers/VisualBasic/Portable/Symbols/Source/SynthesizedWithEventsAccessorSymbol.vb +++ b/src/Compilers/VisualBasic/Portable/Symbols/Source/SynthesizedWithEventsAccessorSymbol.vb @@ -4,6 +4,7 @@ Imports System.Collections.Immutable Imports Microsoft.CodeAnalysis.PooledObjects +Imports Microsoft.CodeAnalysis.VisualBasic.Emit Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols ''' @@ -86,8 +87,8 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols Protected MustOverride Function GetParameters() As ImmutableArray(Of ParameterSymbol) - Friend Overrides Sub AddSynthesizedAttributes(compilationState As ModuleCompilationState, ByRef attributes As ArrayBuilder(Of SynthesizedAttributeData)) - MyBase.AddSynthesizedAttributes(compilationState, attributes) + Friend Overrides Sub AddSynthesizedAttributes(moduleBuilder As PEModuleBuilder, ByRef attributes As ArrayBuilder(Of SynthesizedAttributeData)) + MyBase.AddSynthesizedAttributes(moduleBuilder, attributes) Debug.Assert(Not ContainingType.IsImplicitlyDeclared) Dim compilation = Me.DeclaringCompilation diff --git a/src/Compilers/VisualBasic/Portable/Symbols/Symbol_Attributes.vb b/src/Compilers/VisualBasic/Portable/Symbols/Symbol_Attributes.vb index 20d452ce3ee47..c5a457bb9b0c8 100644 --- a/src/Compilers/VisualBasic/Portable/Symbols/Symbol_Attributes.vb +++ b/src/Compilers/VisualBasic/Portable/Symbols/Symbol_Attributes.vb @@ -6,6 +6,7 @@ Imports System.Collections.Generic Imports System.Collections.Immutable Imports System.Runtime.InteropServices Imports System.Threading +Imports Microsoft.CodeAnalysis.VisualBasic.Emit Imports Microsoft.CodeAnalysis.PooledObjects Imports Microsoft.CodeAnalysis.VisualBasic.Symbols Imports Microsoft.CodeAnalysis.VisualBasic.Syntax @@ -32,7 +33,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic ''' ''' Build and add synthesized attributes for this symbol. ''' - Friend Overridable Sub AddSynthesizedAttributes(compilationState As ModuleCompilationState, ByRef attributes As ArrayBuilder(Of SynthesizedAttributeData)) + Friend Overridable Sub AddSynthesizedAttributes(moduleBuilder As PEModuleBuilder, ByRef attributes As ArrayBuilder(Of SynthesizedAttributeData)) End Sub ''' diff --git a/src/Compilers/VisualBasic/Portable/Symbols/SynthesizedSymbols/GeneratedNameConstants.vb b/src/Compilers/VisualBasic/Portable/Symbols/SynthesizedSymbols/GeneratedNameConstants.vb index 8159cb3052cf3..2c15a74fa72a3 100644 --- a/src/Compilers/VisualBasic/Portable/Symbols/SynthesizedSymbols/GeneratedNameConstants.vb +++ b/src/Compilers/VisualBasic/Portable/Symbols/SynthesizedSymbols/GeneratedNameConstants.vb @@ -22,7 +22,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols Friend Const HoistedUserVariablePrefix As String = "$VB$Local_" Friend Const HoistedSpecialVariablePrefix As String = "$VB$NonLocal_" ' prefixes Me and Closure variables when hoisted Friend Const HoistedWithLocalPrefix As String = "$W" - Friend Const StateMachineHoistedUserVariablePrefix As String = "$VB$ResumableLocal_" + Friend Const StateMachineHoistedUserVariableOrDisplayClassPrefix As String = "$VB$ResumableLocal_" Friend Const ClosureVariablePrefix As String = "$VB$Closure_" Friend Const DisplayClassPrefix As String = "_Closure$__" Friend Const StateMachineTypeNamePrefix As String = "VB$StateMachine_" diff --git a/src/Compilers/VisualBasic/Portable/Symbols/SynthesizedSymbols/GeneratedNameKind.vb b/src/Compilers/VisualBasic/Portable/Symbols/SynthesizedSymbols/GeneratedNameKind.vb index 6d5bf8fd2d5a3..2898015ea50c4 100644 --- a/src/Compilers/VisualBasic/Portable/Symbols/SynthesizedSymbols/GeneratedNameKind.vb +++ b/src/Compilers/VisualBasic/Portable/Symbols/SynthesizedSymbols/GeneratedNameKind.vb @@ -17,7 +17,8 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols IteratorParameterProxyField StateMachineAwaiterField StateMachineStateField - StateMachineHoistedUserVariableField + StateMachineHoistedUserVariableOrDisplayClassField + HoistedWithLocalPrefix StaticLocalField TransparentIdentifier AnonymousTransparentIdentifier diff --git a/src/Compilers/VisualBasic/Portable/Symbols/SynthesizedSymbols/GeneratedNameParser.vb b/src/Compilers/VisualBasic/Portable/Symbols/SynthesizedSymbols/GeneratedNameParser.vb index 99e3e070d47b1..2ed02fbccf203 100644 --- a/src/Compilers/VisualBasic/Portable/Symbols/SynthesizedSymbols/GeneratedNameParser.vb +++ b/src/Compilers/VisualBasic/Portable/Symbols/SynthesizedSymbols/GeneratedNameParser.vb @@ -26,8 +26,10 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols Return GeneratedNameKind.IteratorParameterProxyField ElseIf name.StartsWith(GeneratedNameConstants.StateMachineAwaiterFieldPrefix, StringComparison.Ordinal) Then Return GeneratedNameKind.StateMachineAwaiterField - ElseIf name.StartsWith(GeneratedNameConstants.StateMachineHoistedUserVariablePrefix, StringComparison.Ordinal) Then - Return GeneratedNameKind.StateMachineHoistedUserVariableField + ElseIf name.StartsWith(GeneratedNameConstants.HoistedWithLocalPrefix, StringComparison.Ordinal) Then + Return GeneratedNameKind.HoistedWithLocalPrefix + ElseIf name.StartsWith(GeneratedNameConstants.StateMachineHoistedUserVariableOrDisplayClassPrefix, StringComparison.Ordinal) Then + Return GeneratedNameKind.StateMachineHoistedUserVariableOrDisplayClassField ElseIf name.StartsWith(GeneratedNameConstants.AnonymousTypeTemplateNamePrefix, StringComparison.Ordinal) Then Return GeneratedNameKind.AnonymousType ElseIf name.StartsWith(GeneratedNameConstants.DisplayClassPrefix, StringComparison.Ordinal) Then @@ -83,16 +85,16 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols ''' ''' Try to parse the local name and return and if successful. ''' - Public Shared Function TryParseStateMachineHoistedUserVariableName(proxyName As String, ByRef variableName As String, ByRef index As Integer) As Boolean + Public Shared Function TryParseStateMachineHoistedUserVariableOrDisplayClassName(proxyName As String, ByRef variableName As String, ByRef index As Integer) As Boolean variableName = Nothing index = 0 ' All names should start with "$VB$ResumableLocal_" - If Not proxyName.StartsWith(GeneratedNameConstants.StateMachineHoistedUserVariablePrefix, StringComparison.Ordinal) Then + If Not proxyName.StartsWith(GeneratedNameConstants.StateMachineHoistedUserVariableOrDisplayClassPrefix, StringComparison.Ordinal) Then Return False End If - Dim prefixLen As Integer = GeneratedNameConstants.StateMachineHoistedUserVariablePrefix.Length + Dim prefixLen As Integer = GeneratedNameConstants.StateMachineHoistedUserVariableOrDisplayClassPrefix.Length Dim separator As Integer = proxyName.LastIndexOf("$"c) If separator <= prefixLen Then Return False diff --git a/src/Compilers/VisualBasic/Portable/Symbols/SynthesizedSymbols/SynthesizedBackingFieldBase.vb b/src/Compilers/VisualBasic/Portable/Symbols/SynthesizedSymbols/SynthesizedBackingFieldBase.vb index 59010152ac4c5..af78f26b65aca 100644 --- a/src/Compilers/VisualBasic/Portable/Symbols/SynthesizedSymbols/SynthesizedBackingFieldBase.vb +++ b/src/Compilers/VisualBasic/Portable/Symbols/SynthesizedSymbols/SynthesizedBackingFieldBase.vb @@ -5,6 +5,7 @@ Imports System.Collections.Immutable Imports Microsoft.CodeAnalysis.PooledObjects Imports Microsoft.CodeAnalysis.Text +Imports Microsoft.CodeAnalysis.VisualBasic.Emit Imports Microsoft.CodeAnalysis.VisualBasic.Symbols Imports Microsoft.CodeAnalysis.VisualBasic.Syntax @@ -121,8 +122,8 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols End Get End Property - Friend Overrides Sub AddSynthesizedAttributes(compilationState as ModuleCompilationState, ByRef attributes As ArrayBuilder(Of SynthesizedAttributeData)) - MyBase.AddSynthesizedAttributes(compilationState, attributes) + Friend Overrides Sub AddSynthesizedAttributes(moduleBuilder As PEModuleBuilder, ByRef attributes As ArrayBuilder(Of SynthesizedAttributeData)) + MyBase.AddSynthesizedAttributes(moduleBuilder, attributes) Dim compilation = Me.DeclaringCompilation diff --git a/src/Compilers/VisualBasic/Portable/Symbols/SynthesizedSymbols/SynthesizedDelegateMethodSymbol.vb b/src/Compilers/VisualBasic/Portable/Symbols/SynthesizedSymbols/SynthesizedDelegateMethodSymbol.vb index 3d337f2c80c06..ef4ab1cec98e4 100644 --- a/src/Compilers/VisualBasic/Portable/Symbols/SynthesizedSymbols/SynthesizedDelegateMethodSymbol.vb +++ b/src/Compilers/VisualBasic/Portable/Symbols/SynthesizedSymbols/SynthesizedDelegateMethodSymbol.vb @@ -6,6 +6,7 @@ Imports System.Collections.Immutable Imports System.Threading Imports Microsoft.CodeAnalysis.PooledObjects Imports Microsoft.CodeAnalysis.Text +Imports Microsoft.CodeAnalysis.VisualBasic.Emit Imports Microsoft.CodeAnalysis.VisualBasic.Symbols Imports Microsoft.CodeAnalysis.VisualBasic.Syntax @@ -431,8 +432,8 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols End Get End Property - Friend Overrides Sub AddSynthesizedAttributes(compilationState As ModuleCompilationState, ByRef attributes As ArrayBuilder(Of SynthesizedAttributeData)) - MyBase.AddSynthesizedAttributes(compilationState, attributes) + Friend Overrides Sub AddSynthesizedAttributes(moduleBuilder As PEModuleBuilder, ByRef attributes As ArrayBuilder(Of SynthesizedAttributeData)) + MyBase.AddSynthesizedAttributes(moduleBuilder, attributes) ' Dev11 emits DebuggerNonUserCodeAttribute on methods of anon delegates but not of user defined delegates. ' In both cases the debugger hides these methods so no attribute is necessary. diff --git a/src/Compilers/VisualBasic/Portable/Symbols/SynthesizedSymbols/SynthesizedInterfaceImplementationStubSymbol.vb b/src/Compilers/VisualBasic/Portable/Symbols/SynthesizedSymbols/SynthesizedInterfaceImplementationStubSymbol.vb index 24a62a61eabb5..75c743524cc64 100644 --- a/src/Compilers/VisualBasic/Portable/Symbols/SynthesizedSymbols/SynthesizedInterfaceImplementationStubSymbol.vb +++ b/src/Compilers/VisualBasic/Portable/Symbols/SynthesizedSymbols/SynthesizedInterfaceImplementationStubSymbol.vb @@ -4,6 +4,7 @@ Imports System.Collections.Immutable Imports Microsoft.CodeAnalysis.PooledObjects +Imports Microsoft.CodeAnalysis.VisualBasic.Emit Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols @@ -180,8 +181,8 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols End Get End Property - Friend Overrides Sub AddSynthesizedAttributes(compilationState As ModuleCompilationState, ByRef attributes As ArrayBuilder(Of SynthesizedAttributeData)) - MyBase.AddSynthesizedAttributes(compilationState, attributes) + Friend Overrides Sub AddSynthesizedAttributes(moduleBuilder As PEModuleBuilder, ByRef attributes As ArrayBuilder(Of SynthesizedAttributeData)) + MyBase.AddSynthesizedAttributes(moduleBuilder, attributes) Dim compilation = Me.DeclaringCompilation diff --git a/src/Compilers/VisualBasic/Portable/Symbols/SynthesizedSymbols/SynthesizedIntrinsicOperatorSymbol.vb b/src/Compilers/VisualBasic/Portable/Symbols/SynthesizedSymbols/SynthesizedIntrinsicOperatorSymbol.vb index f84a7e47e813c..9411b52ca4b4e 100644 --- a/src/Compilers/VisualBasic/Portable/Symbols/SynthesizedSymbols/SynthesizedIntrinsicOperatorSymbol.vb +++ b/src/Compilers/VisualBasic/Portable/Symbols/SynthesizedSymbols/SynthesizedIntrinsicOperatorSymbol.vb @@ -11,27 +11,40 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols Private ReadOnly _name As String Private ReadOnly _parameters As ImmutableArray(Of ParameterSymbol) Private ReadOnly _returnType As TypeSymbol - Private ReadOnly _isCheckedBuiltin As Boolean - Public Sub New(container As NamedTypeSymbol, name As String, rightType As TypeSymbol, returnType As TypeSymbol, isCheckedBuiltin As Boolean) + Public Sub New(container As NamedTypeSymbol, name As String, rightType As TypeSymbol, returnType As TypeSymbol) MyBase.New(container) _name = name _returnType = returnType _parameters = (New ParameterSymbol() {New SynthesizedOperatorParameterSymbol(Me, container, 0, "left"), New SynthesizedOperatorParameterSymbol(Me, rightType, 1, "right")}).AsImmutableOrNull() - _isCheckedBuiltin = isCheckedBuiltin End Sub - Public Sub New(container As NamedTypeSymbol, name As String, returnType As TypeSymbol, isCheckedBuiltin As Boolean) + Public Sub New(container As NamedTypeSymbol, name As String, returnType As TypeSymbol) MyBase.New(container) _name = name _returnType = returnType _parameters = (New ParameterSymbol() {New SynthesizedOperatorParameterSymbol(Me, container, 0, "value")}).AsImmutableOrNull() - _isCheckedBuiltin = isCheckedBuiltin End Sub + Public Overrides ReadOnly Property IsCheckedBuiltin As Boolean + Get + Select Case Me.Name + Case WellKnownMemberNames.CheckedUnaryNegationOperatorName, + WellKnownMemberNames.CheckedAdditionOperatorName, + WellKnownMemberNames.CheckedDivisionOperatorName, + WellKnownMemberNames.CheckedMultiplyOperatorName, + WellKnownMemberNames.CheckedSubtractionOperatorName + Return True + + Case Else + Return False + End Select + End Get + End Property + Public Overrides ReadOnly Property Name As String Get Return _name @@ -61,8 +74,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols Return False End If - If _isCheckedBuiltin = other._isCheckedBuiltin AndAlso - _parameters.Length = other._parameters.Length AndAlso + If _parameters.Length = other._parameters.Length AndAlso String.Equals(_name, other._name, StringComparison.Ordinal) AndAlso TypeSymbol.Equals(m_containingType, other.m_containingType, TypeCompareKind.ConsiderEverything) AndAlso TypeSymbol.Equals(_returnType, other._returnType, TypeCompareKind.ConsiderEverything) Then @@ -149,12 +161,6 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols End Get End Property - Public Overrides ReadOnly Property IsCheckedBuiltin As Boolean - Get - Return _isCheckedBuiltin - End Get - End Property - Public Overrides Function GetDocumentationCommentId() As String Return Nothing End Function diff --git a/src/Compilers/VisualBasic/Portable/Symbols/SynthesizedSymbols/SynthesizedMethod.vb b/src/Compilers/VisualBasic/Portable/Symbols/SynthesizedSymbols/SynthesizedMethod.vb index 5ae8811f96dd5..ba5ca41da756e 100644 --- a/src/Compilers/VisualBasic/Portable/Symbols/SynthesizedSymbols/SynthesizedMethod.vb +++ b/src/Compilers/VisualBasic/Portable/Symbols/SynthesizedSymbols/SynthesizedMethod.vb @@ -6,6 +6,7 @@ Imports System.Collections.Immutable Imports System.Threading Imports Microsoft.CodeAnalysis.PooledObjects Imports Microsoft.CodeAnalysis.Text +Imports Microsoft.CodeAnalysis.VisualBasic.Emit Imports Microsoft.CodeAnalysis.VisualBasic.Symbols Imports Microsoft.CodeAnalysis.VisualBasic.Syntax @@ -100,8 +101,8 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols End Get End Property - Friend Overrides Sub AddSynthesizedAttributes(compilationState As ModuleCompilationState, ByRef attributes As ArrayBuilder(Of SynthesizedAttributeData)) - MyBase.AddSynthesizedAttributes(compilationState, attributes) + Friend Overrides Sub AddSynthesizedAttributes(moduleBuilder As PEModuleBuilder, ByRef attributes As ArrayBuilder(Of SynthesizedAttributeData)) + MyBase.AddSynthesizedAttributes(moduleBuilder, attributes) Dim sourceType = TryCast(ContainingSymbol, SourceMemberContainerTypeSymbol) diff --git a/src/Compilers/VisualBasic/Portable/Symbols/SynthesizedSymbols/SynthesizedParameterSymbol.vb b/src/Compilers/VisualBasic/Portable/Symbols/SynthesizedSymbols/SynthesizedParameterSymbol.vb index 21ab1995a5b1a..d21b88cf07993 100644 --- a/src/Compilers/VisualBasic/Portable/Symbols/SynthesizedSymbols/SynthesizedParameterSymbol.vb +++ b/src/Compilers/VisualBasic/Portable/Symbols/SynthesizedSymbols/SynthesizedParameterSymbol.vb @@ -5,6 +5,7 @@ Imports System.Collections.Immutable Imports Microsoft.CodeAnalysis.PooledObjects Imports Microsoft.CodeAnalysis.Text +Imports Microsoft.CodeAnalysis.VisualBasic.Emit Imports Microsoft.CodeAnalysis.VisualBasic.Symbols Imports Microsoft.CodeAnalysis.VisualBasic.Syntax @@ -243,7 +244,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols End Get End Property - Friend NotOverridable Overrides Sub AddSynthesizedAttributes(compilationState As ModuleCompilationState, ByRef attributes As ArrayBuilder(Of SynthesizedAttributeData)) + Friend NotOverridable Overrides Sub AddSynthesizedAttributes(moduleBuilder As PEModuleBuilder, ByRef attributes As ArrayBuilder(Of SynthesizedAttributeData)) Dim compilation = Me.DeclaringCompilation If Type.ContainsTupleNames() AndAlso compilation.HasTupleNamesAttributes Then diff --git a/src/Compilers/VisualBasic/Portable/Symbols/Tuples/TupleTypeSymbol.vb b/src/Compilers/VisualBasic/Portable/Symbols/Tuples/TupleTypeSymbol.vb index e77f913ae329e..6ff4def5218b9 100644 --- a/src/Compilers/VisualBasic/Portable/Symbols/Tuples/TupleTypeSymbol.vb +++ b/src/Compilers/VisualBasic/Portable/Symbols/Tuples/TupleTypeSymbol.vb @@ -9,6 +9,7 @@ Imports System.Threading Imports Microsoft.CodeAnalysis.Collections Imports Microsoft.CodeAnalysis.PooledObjects Imports Microsoft.CodeAnalysis.RuntimeMembers +Imports Microsoft.CodeAnalysis.VisualBasic.Emit Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols Friend NotInheritable Class TupleTypeSymbol @@ -1048,7 +1049,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols Throw ExceptionUtilities.Unreachable End Function - Friend Overrides Function GetCustomAttributesToEmit(compilationState As ModuleCompilationState) As IEnumerable(Of VisualBasicAttributeData) + Friend Overrides Function GetCustomAttributesToEmit(moduleBuilder As PEModuleBuilder) As IEnumerable(Of VisualBasicAttributeData) Throw ExceptionUtilities.Unreachable End Function diff --git a/src/Compilers/VisualBasic/Portable/Symbols/Wrapped/WrappedParameterSymbol.vb b/src/Compilers/VisualBasic/Portable/Symbols/Wrapped/WrappedParameterSymbol.vb index 173c53d3f71df..56dd496553479 100644 --- a/src/Compilers/VisualBasic/Portable/Symbols/Wrapped/WrappedParameterSymbol.vb +++ b/src/Compilers/VisualBasic/Portable/Symbols/Wrapped/WrappedParameterSymbol.vb @@ -7,6 +7,7 @@ Imports System.Globalization Imports System.Runtime.InteropServices Imports System.Threading Imports Microsoft.CodeAnalysis.PooledObjects +Imports Microsoft.CodeAnalysis.VisualBasic.Emit Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols ''' @@ -174,8 +175,8 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols Return Me._underlyingParameter.GetAttributes() End Function - Friend Overrides Sub AddSynthesizedAttributes(compilationState As ModuleCompilationState, ByRef attributes As ArrayBuilder(Of SynthesizedAttributeData)) - Me._underlyingParameter.AddSynthesizedAttributes(compilationState, attributes) + Friend Overrides Sub AddSynthesizedAttributes(moduleBuilder As PEModuleBuilder, ByRef attributes As ArrayBuilder(Of SynthesizedAttributeData)) + Me._underlyingParameter.AddSynthesizedAttributes(moduleBuilder, attributes) End Sub Public Overrides Function GetDocumentationCommentXml(Optional preferredCulture As CultureInfo = Nothing, Optional expandIncludes As Boolean = False, Optional cancellationToken As CancellationToken = Nothing) As String diff --git a/src/Compilers/VisualBasic/Portable/VisualBasicCompilationOptions.vb b/src/Compilers/VisualBasic/Portable/VisualBasicCompilationOptions.vb index ff4d41831ce7b..bda5f0c523db3 100644 --- a/src/Compilers/VisualBasic/Portable/VisualBasicCompilationOptions.vb +++ b/src/Compilers/VisualBasic/Portable/VisualBasicCompilationOptions.vb @@ -660,9 +660,9 @@ Namespace Microsoft.CodeAnalysis.VisualBasic ''' ''' Creates a new VisualBasicCompilationOptions instance with a different deterministic mode specified. + ''' ''' The deterministic mode. ''' A new instance of VisualBasicCompilationOptions, if the deterministic mode is different; otherwise the current instance. - ''' Public Shadows Function WithDeterministic(deterministic As Boolean) As VisualBasicCompilationOptions If deterministic = Me.Deterministic Then Return Me @@ -1117,8 +1117,8 @@ Namespace Microsoft.CodeAnalysis.VisualBasic ''' Creates a hashcode for this instance. ''' ''' A hashcode representing this instance. - Public Overrides Function GetHashCode() As Integer - Return Hash.Combine(MyBase.GetHashCodeHelper(), + Protected Overrides Function ComputeHashCode() As Integer + Return Hash.Combine(GetHashCodeHelper(), Hash.Combine(Hash.CombineValues(Me.GlobalImports), Hash.Combine(If(Me.RootNamespace IsNot Nothing, StringComparer.Ordinal.GetHashCode(Me.RootNamespace), 0), Hash.Combine(Me.OptionStrict, diff --git a/src/Compilers/VisualBasic/Test/CommandLine/CommandLineTests.vb b/src/Compilers/VisualBasic/Test/CommandLine/CommandLineTests.vb index c5b50b6ef4fc1..6b21bf94250fc 100644 --- a/src/Compilers/VisualBasic/Test/CommandLine/CommandLineTests.vb +++ b/src/Compilers/VisualBasic/Test/CommandLine/CommandLineTests.vb @@ -27,6 +27,7 @@ Imports Roslyn.Test.PdbUtilities Imports Roslyn.Test.Utilities Imports Roslyn.Test.Utilities.SharedResourceHelpers Imports Roslyn.Utilities +Imports TestResources.Analyzers Imports Xunit Namespace Microsoft.CodeAnalysis.VisualBasic.CommandLine.UnitTests @@ -7822,7 +7823,7 @@ BC2006: option 'analyzerconfig' requires ':']]> Optional expectedWarningCount As Integer = 0, Optional expectedErrorCount As Integer = 0, Optional errorlog As Boolean = False, - Optional analyzers As ImmutableArray(Of DiagnosticAnalyzer) = Nothing) As String + Optional analyzers As DiagnosticAnalyzer() = Nothing) As String Dim args = { "/nologo", "/preferreduilang:en", "/t:library", sourceFile.Path @@ -8844,13 +8845,20 @@ Class C End Class .Value).Path - Dim vbc = New MockVisualBasicCompiler(Nothing, _baseDirectory, {"/reportanalyzer", "/t:library", "/a:" + Assembly.GetExecutingAssembly().Location, source}) + Dim vbc = New MockVisualBasicCompiler( + Nothing, + _baseDirectory, + {"/reportanalyzer", "/t:library", source}, + analyzers:={New WarningDiagnosticAnalyzer()}, + generators:={New DoNothingGenerator().AsSourceGenerator()}) Dim outWriter = New StringWriter() Dim exitCode = vbc.Run(outWriter, Nothing) Assert.Equal(0, exitCode) Dim output = outWriter.ToString() Assert.Contains(New WarningDiagnosticAnalyzer().ToString(), output, StringComparison.Ordinal) Assert.Contains(CodeAnalysisResources.AnalyzerExecutionTimeColumnHeader, output, StringComparison.Ordinal) + Assert.Contains(CodeAnalysisResources.GeneratorNameColumnHeader, output, StringComparison.Ordinal) + Assert.Contains(GetType(DoNothingGenerator).FullName, output, StringComparison.Ordinal) CleanupAllGeneratedFiles(source) End Sub @@ -9680,10 +9688,9 @@ End Class" suppressor.SuppressionDescriptor.Id, suppressor.SuppressionDescriptor.Justification) - Dim suppressors = ImmutableArray.Create(Of DiagnosticAnalyzer)(suppressor) output = VerifyOutput(dir, file, expectedInfoCount:=1, expectedWarningCount:=0, includeCurrentAssemblyAsAnalyzerReference:=False, - analyzers:=suppressors) + analyzers:={suppressor}) Assert.DoesNotContain("warning BC40008", output, StringComparison.Ordinal) Assert.Contains("info SP0001", output, StringComparison.Ordinal) Assert.Contains(suppressionMessage, output, StringComparison.Ordinal) @@ -9723,7 +9730,7 @@ End Class" ' and info diagnostic is logged with programmatic suppression information. Dim suppressor = New DiagnosticSuppressorForId("BC40008") - Dim suppressors = ImmutableArray.Create(Of DiagnosticAnalyzer)(suppressor) + Dim suppressors = {suppressor} output = VerifyOutput(dir, file, expectedInfoCount:=1, expectedWarningCount:=0, expectedErrorCount:=0, additionalFlags:={"/warnaserror+"}, includeCurrentAssemblyAsAnalyzerReference:=False, @@ -9760,7 +9767,7 @@ End Class" Assert.Contains("error BC30203", output, StringComparison.Ordinal) ' Verify that compiler error BC30203 cannot be suppressed with diagnostic suppressor. - Dim analyzers = ImmutableArray.Create(Of DiagnosticAnalyzer)(New DiagnosticSuppressorForId("BC30203")) + Dim analyzers = {New DiagnosticSuppressorForId("BC30203")} output = VerifyOutput(dir, file, expectedErrorCount:=1, includeCurrentAssemblyAsAnalyzerReference:=False, analyzers:=analyzers) @@ -9781,7 +9788,7 @@ End Class" ' Verify that analyzer warning is reported. Dim analyzer = New CompilationAnalyzerWithSeverity(DiagnosticSeverity.Warning, configurable:=True) - Dim analyzers = ImmutableArray.Create(Of DiagnosticAnalyzer)(analyzer) + Dim analyzers = {analyzer} Dim output = VerifyOutput(dir, file, expectedWarningCount:=1, includeCurrentAssemblyAsAnalyzerReference:=False, analyzers:=analyzers) @@ -9798,7 +9805,7 @@ End Class" suppressor.SuppressionDescriptor.Id, suppressor.SuppressionDescriptor.Justification) - Dim analyzerAndSuppressor = ImmutableArray.Create(Of DiagnosticAnalyzer)(analyzer, suppressor) + Dim analyzerAndSuppressor As DiagnosticAnalyzer() = {analyzer, suppressor} output = VerifyOutput(dir, file, expectedInfoCount:=1, expectedWarningCount:=0, includeCurrentAssemblyAsAnalyzerReference:=False, analyzers:=analyzerAndSuppressor) @@ -9826,7 +9833,7 @@ End Class" ' Verify that "NotConfigurable" analyzer warning cannot be suppressed with diagnostic suppressor even with /warnaserror. analyzer = New CompilationAnalyzerWithSeverity(DiagnosticSeverity.Warning, configurable:=False) suppressor = New DiagnosticSuppressorForId(analyzer.Descriptor.Id) - analyzerAndSuppressor = ImmutableArray.Create(Of DiagnosticAnalyzer)(analyzer, suppressor) + analyzerAndSuppressor = {analyzer, suppressor} output = VerifyOutput(dir, file, expectedWarningCount:=1, includeCurrentAssemblyAsAnalyzerReference:=False, analyzers:=analyzerAndSuppressor) @@ -9847,15 +9854,14 @@ End Class" ' Verify that analyzer error is reported. Dim analyzer = New CompilationAnalyzerWithSeverity(DiagnosticSeverity.Error, configurable:=True) - Dim analyzers = ImmutableArray.Create(Of DiagnosticAnalyzer)(analyzer) Dim output = VerifyOutput(dir, file, expectedErrorCount:=1, includeCurrentAssemblyAsAnalyzerReference:=False, - analyzers:=analyzers) + analyzers:={analyzer}) Assert.Contains($"error {analyzer.Descriptor.Id}", output, StringComparison.Ordinal) ' Verify that analyzer error cannot be suppressed with diagnostic suppressor. Dim suppressor = New DiagnosticSuppressorForId(analyzer.Descriptor.Id) - Dim analyzerAndSuppressor = ImmutableArray.Create(Of DiagnosticAnalyzer)(analyzer, suppressor) + Dim analyzerAndSuppressor As DiagnosticAnalyzer() = {analyzer, suppressor} output = VerifyOutput(dir, file, expectedErrorCount:=1, includeCurrentAssemblyAsAnalyzerReference:=False, analyzers:=analyzerAndSuppressor) @@ -10041,7 +10047,7 @@ End Class" additionalFlags, expectedErrorCount:=expectedErrorCount, expectedWarningCount:=expectedWarningCount, - analyzers:=ImmutableArray.Create(analyzer)) + analyzers:={analyzer}) Dim expectedODiagnosticSeverity = If(warnAsError, "error", "warning") Assert.Contains($"{expectedODiagnosticSeverity} {WarningDiagnosticAnalyzer.Warning01.Id}", output) @@ -10173,7 +10179,7 @@ dotnet_diagnostic.{diagnosticId}.severity = {severityString}") expectedWarningCount:=expectedWarningCount, expectedErrorCount:=expectedErrorCount, additionalFlags:=additionalFlags, - analyzers:=ImmutableArray.Create(Of DiagnosticAnalyzer)(analyzer)) + analyzers:={analyzer}) End Sub @@ -10281,7 +10287,7 @@ End Class" Dim output = VerifyOutput(srcDirectory, srcFile, expectedWarningCount:=1, includeCurrentAssemblyAsAnalyzerReference:=False, additionalFlags:={"/additionalfile:" & additionalFile.Path}, - analyzers:=ImmutableArray.Create(analyzer)) + analyzers:={analyzer}) Assert.Contains("b.txt(1) : warning ID0001", output, StringComparison.Ordinal) CleanupAllGeneratedFiles(srcDirectory.Path) End Sub @@ -10365,7 +10371,7 @@ dotnet_diagnostic.{diagnosticId}.severity = {analyzerConfigSeverity}") Dim output = VerifyOutput(dir, src, includeCurrentAssemblyAsAnalyzerReference:=False, additionalArgs, expectedErrorCount:=If(expectError, 1, 0), expectedWarningCount:=If(expectWarning, 1, 0), - analyzers:=analyzers.ToImmutableArrayOrEmpty()) + analyzers:=analyzers) If expectError Then Assert.Contains($"error {diagnosticId}", output) diff --git a/src/Compilers/VisualBasic/Test/Emit/Attributes/AssemblyAttributes.vb b/src/Compilers/VisualBasic/Test/Emit/Attributes/AssemblyAttributes.vb index 77914f0881528..e5038848267da 100644 --- a/src/Compilers/VisualBasic/Test/Emit/Attributes/AssemblyAttributes.vb +++ b/src/Compilers/VisualBasic/Test/Emit/Attributes/AssemblyAttributes.vb @@ -5,13 +5,17 @@ Imports System.Collections.Immutable Imports System.IO Imports System.Reflection +Imports System.Reflection.Emit Imports System.Reflection.Metadata Imports System.Reflection.Metadata.Ecma335 Imports System.Runtime.InteropServices +Imports System.Threading Imports Microsoft.CodeAnalysis +Imports Microsoft.CodeAnalysis.Emit Imports Microsoft.CodeAnalysis.PooledObjects Imports Microsoft.CodeAnalysis.Test.Utilities Imports Microsoft.CodeAnalysis.VisualBasic +Imports Microsoft.CodeAnalysis.VisualBasic.Emit Imports Microsoft.CodeAnalysis.VisualBasic.Symbols Imports Microsoft.CodeAnalysis.VisualBasic.Symbols.Metadata.PE Imports Microsoft.CodeAnalysis.VisualBasic.UnitTests @@ -1231,8 +1235,10 @@ End Class ' We should get only unique netmodule/assembly attributes here, duplicate ones should not be emitted. Dim expectedEmittedAttrsCount As Integer = expectedSrcAttrCount - expectedDuplicateAttrCount + Dim moduleBuilder = CreateTestModuleBuilder(compilation) + Dim allEmittedAttrs = DirectCast(assembly, SourceAssemblySymbol). - GetAssemblyCustomAttributesToEmit(New ModuleCompilationState, emittingRefAssembly:=False, emittingAssemblyAttributesInNetModule:=False). + GetAssemblyCustomAttributesToEmit(moduleBuilder, emittingRefAssembly:=False, emittingAssemblyAttributesInNetModule:=False). Cast(Of VisualBasicAttributeData)() Dim emittedAttrs = allEmittedAttrs.Where(Function(a) a.AttributeClass.Name.Equals(attrTypeName)).AsImmutable() @@ -1243,6 +1249,18 @@ End Class Assert.True(uniqueAttributes.Add(attr)) Next End Sub + + Private Shared Function CreateTestModuleBuilder(compilation As Compilation) As PEModuleBuilder + Return DirectCast(compilation.CheckOptionsAndCreateModuleBuilder( + New DiagnosticBag(), + manifestResources:=Nothing, + EmitOptions.Default, + debugEntryPoint:=Nothing, + sourceLinkStream:=Nothing, + embeddedTexts:=Nothing, + testData:=Nothing, + CancellationToken.None), PEModuleBuilder) + End Function #End Region @@ -1516,8 +1534,9 @@ End Class expectedDuplicateAttrCount:=1, attrTypeName:="AssemblyTitleAttribute") + Dim moduleBuilder = CreateTestModuleBuilder(consoleappCompilation) Dim attrs = DirectCast(consoleappCompilation.Assembly, SourceAssemblySymbol). - GetAssemblyCustomAttributesToEmit(New ModuleCompilationState, emittingRefAssembly:=False, emittingAssemblyAttributesInNetModule:=False). + GetAssemblyCustomAttributesToEmit(moduleBuilder, emittingRefAssembly:=False, emittingAssemblyAttributesInNetModule:=False). Cast(Of VisualBasicAttributeData)() For Each a In attrs diff --git a/src/Compilers/VisualBasic/Test/Emit/Emit/EditAndContinue/EditAndContinueStateMachineTests.vb b/src/Compilers/VisualBasic/Test/Emit/Emit/EditAndContinue/EditAndContinueStateMachineTests.vb index 63ccaf7249d88..3f81fd670e558 100644 --- a/src/Compilers/VisualBasic/Test/Emit/Emit/EditAndContinue/EditAndContinueStateMachineTests.vb +++ b/src/Compilers/VisualBasic/Test/Emit/Emit/EditAndContinue/EditAndContinueStateMachineTests.vb @@ -8217,6 +8217,227 @@ End Class") End Sub + + Public Sub LiftedClosure() + Dim source0 = MarkedSource(" +Imports System +Imports System.Threading.Tasks +Class C + Shared Async Function M() As Task + Dim num As Integer = 1 + + Await Task.Delay(1) + + G(Function() num) + End Function + + Shared Sub G(f As Func(Of Integer)) + End Sub +End Class") + + Dim source1 = MarkedSource(" +Imports System +Imports System.Threading.Tasks +Class C + Shared Async Function M() As Task + Dim num As Integer = 1 + + Await Task.Delay(2) + + G(Function() num) + End Function + + Shared Sub G(f As Func(Of Integer)) + End Sub +End Class") + Dim compilation0 = CreateCompilationWithMscorlib45AndVBRuntime({source0.Tree}, options:=ComSafeDebugDll) + Dim compilation1 = compilation0.WithSource(source1.Tree) + + Dim m0 = compilation0.GetMember(Of MethodSymbol)("C.M") + Dim m1 = compilation1.GetMember(Of MethodSymbol)("C.M") + + Dim v0 = CompileAndVerify(compilation0) + Using md0 = ModuleMetadata.CreateFromImage(v0.EmittedAssemblyData) + + Dim reader0 = md0.MetadataReader + Dim generation0 = EmitBaseline.CreateInitialBaseline(md0, AddressOf v0.CreateSymReader().GetEncMethodDebugInfo) + + ' Notice encLocalSlotMap CDI on both M and MoveNext methods. + ' The former is used to calculate mapping for variables lifted to fields of the state machine, + ' the latter is used to map local variable slots in the MoveNext method. + ' Here, the variable lifted to the state machine field is the closure pointer storage. + v0.VerifyPdb(" + + + + + + + + + + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +", options:=PdbValidationOptions.ExcludeDocuments Or PdbValidationOptions.ExcludeSequencePoints Or PdbValidationOptions.ExcludeNamespaces Or PdbValidationOptions.ExcludeScopes, + format:=DebugInformationFormat.PortablePdb) + + CheckNames(reader0, reader0.GetTypeDefNames(), "", "C", "VB$StateMachine_1_M", "_Closure$__1-0") + + Dim diff1 = compilation1.EmitDifference( + generation0, + ImmutableArray.Create( + SemanticEdit.Create(SemanticEditKind.Update, m0, m1, GetSyntaxMapFromMarkers(source0, source1), preserveLocalVariables:=True))) + + ' Notice that we reused field "$VB$ResumableLocal_$VB$Closure_$0" (there is no "$VB$ResumableLocal_$VB$Closure_$1"), which stores the closure pointer. + diff1.VerifySynthesizedMembers( + "C: {VB$StateMachine_1_M, _Closure$__1-0}", + "C.VB$StateMachine_1_M: {$State, $Builder, $VB$ResumableLocal_$VB$Closure_$0, $A0, MoveNext, System.Runtime.CompilerServices.IAsyncStateMachine.SetStateMachine}", + "C._Closure$__1-0: {_Lambda$__0}") + End Using + End Sub + + + Public Sub LiftedWithStatementVariable() + Dim source0 = MarkedSource(" +Imports System +Imports System.Threading.Tasks +Class C + Private X As Integer = 1 + Private Y As Integer = 2 + + Shared Async Function M() As Task + With New C() + Await G() + Console.Write(.X) + End With + End Function + + Shared Function G() As Task(Of Integer) + Return Task.FromResult(1) + End Function +End Class") + + Dim source1 = MarkedSource(" +Imports System +Imports System.Threading.Tasks +Class C + Private X As Integer = 1 + Private Y As Integer = 2 + + Shared Async Function M() As Task + With New C() + Await G() + Console.Write(.Y) + End With + End Function + + Shared Function G() As Task(Of Integer) + Return Task.FromResult(1) + End Function +End Class") + Dim compilation0 = CreateCompilationWithMscorlib45AndVBRuntime({source0.Tree}, options:=ComSafeDebugDll) + Dim compilation1 = compilation0.WithSource(source1.Tree) + + Dim m0 = compilation0.GetMember(Of MethodSymbol)("C.M") + Dim m1 = compilation1.GetMember(Of MethodSymbol)("C.M") + + Dim v0 = CompileAndVerify(compilation0) + Using md0 = ModuleMetadata.CreateFromImage(v0.EmittedAssemblyData) + + Dim reader0 = md0.MetadataReader + Dim generation0 = EmitBaseline.CreateInitialBaseline(md0, AddressOf v0.CreateSymReader().GetEncMethodDebugInfo) + + ' Notice encLocalSlotMap CDI on both M and MoveNext methods. + ' The former is used to calculate mapping for variables lifted to fields of the state machine, + ' the latter is used to map local variable slots in the MoveNext method. + ' Here, the variable lifted to the state machine field is the With statement storage. + v0.VerifyPdb(" + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +", options:=PdbValidationOptions.ExcludeDocuments Or PdbValidationOptions.ExcludeSequencePoints Or PdbValidationOptions.ExcludeNamespaces Or PdbValidationOptions.ExcludeScopes, + format:=DebugInformationFormat.PortablePdb) + + CheckNames(reader0, reader0.GetTypeDefNames(), "", "C", "VB$StateMachine_3_M") + CheckNames(reader0, reader0.GetFieldDefNames(), "X", "Y", "$State", "$Builder", "$W0", "$A0") + + Dim diff1 = compilation1.EmitDifference( + generation0, + ImmutableArray.Create( + SemanticEdit.Create(SemanticEditKind.Update, m0, m1, GetSyntaxMapFromMarkers(source0, source1), preserveLocalVariables:=True))) + + ' Notice that we reused field "$W0" (there is no "$W1"), which stores the closure pointer. + diff1.VerifySynthesizedMembers( + "C: {VB$StateMachine_3_M}", + "C.VB$StateMachine_3_M: {$State, $Builder, $W0, $A0, MoveNext, System.Runtime.CompilerServices.IAsyncStateMachine.SetStateMachine}") + End Using + End Sub + Public Sub HoistedAnonymousTypes1() Dim source0 = MarkedSource(" diff --git a/src/Compilers/VisualBasic/Test/Emit/Emit/EditAndContinue/EditAndContinueTestBase.vb b/src/Compilers/VisualBasic/Test/Emit/Emit/EditAndContinue/EditAndContinueTestBase.vb index 4230b60ec8e5b..dfe778f574f08 100644 --- a/src/Compilers/VisualBasic/Test/Emit/Emit/EditAndContinue/EditAndContinueTestBase.vb +++ b/src/Compilers/VisualBasic/Test/Emit/Emit/EditAndContinue/EditAndContinueTestBase.vb @@ -181,77 +181,117 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.UnitTests Return MetadataTokens.Handle(table, rowNumber) End Function - Friend Shared Sub CheckEncLog(reader As MetadataReader, ParamArray rows As EditAndContinueLogEntry()) - AssertEx.Equal(rows, reader.GetEditAndContinueLogEntries(), itemInspector:=AddressOf EncLogRowToString) - End Sub - - Friend Shared Sub CheckEncLogDefinitions(reader As MetadataReader, ParamArray rows As EditAndContinueLogEntry()) - AssertEx.Equal(rows, reader.GetEditAndContinueLogEntries().Where(Function(entry) IsDefinition(entry.Handle.Kind)), itemInspector:=AddressOf EncLogRowToString) - End Sub - Friend Shared Function IsDefinition(kind As HandleKind) As Boolean - Dim index As TableIndex - Assert.True(MetadataTokens.TryGetTableIndex(kind, index)) - - Select Case index - Case TableIndex.MethodDef, - TableIndex.Field, - TableIndex.Constant, - TableIndex.GenericParam, - TableIndex.GenericParamConstraint, - TableIndex.[Event], - TableIndex.CustomAttribute, - TableIndex.DeclSecurity, - TableIndex.Assembly, - TableIndex.MethodImpl, - TableIndex.Param, - TableIndex.[Property], - TableIndex.TypeDef, - TableIndex.ExportedType, - TableIndex.StandAloneSig, - TableIndex.ClassLayout, - TableIndex.FieldLayout, - TableIndex.FieldMarshal, - TableIndex.File, - TableIndex.ImplMap, - TableIndex.InterfaceImpl, - TableIndex.ManifestResource, - TableIndex.MethodSemantics, - TableIndex.[Module], - TableIndex.NestedClass, - TableIndex.EventMap, - TableIndex.PropertyMap + Select Case kind + Case HandleKind.AssemblyReference, HandleKind.ModuleReference, HandleKind.TypeReference, HandleKind.MemberReference, HandleKind.TypeSpecification, HandleKind.MethodSpecification + Return False + Case Else Return True End Select - - Return False End Function + ''' + ''' Checks that the EncLog contains specified rows. + ''' Any default values in the expected are ignored to facilitate conditional code. + ''' + Friend Shared Sub CheckEncLog(reader As MetadataReader, ParamArray rows As EditAndContinueLogEntry()) + AssertEx.Equal( + rows.Where(Function(r) r.Handle <> Nothing), + reader.GetEditAndContinueLogEntries(), itemInspector:=AddressOf EncLogRowToString) + End Sub + + ''' + ''' Checks that the EncLog contains specified definition rows. References are ignored as they are usually not interesting to validate. They are emitted as needed. + ''' Any default values in the expected are ignored to facilitate conditional code. + ''' + Friend Shared Sub CheckEncLogDefinitions(reader As MetadataReader, ParamArray rows As EditAndContinueLogEntry()) + AssertEx.Equal( + rows.Where(Function(r) r.Handle <> Nothing), + reader.GetEditAndContinueLogEntries().Where(Function(entry) IsDefinition(entry.Handle.Kind)), itemInspector:=AddressOf EncLogRowToString) + End Sub + ''' + ''' Checks that the EncMap contains specified handles. + ''' Any default values in the expected are ignored to facilitate conditional code. + ''' Friend Shared Sub CheckEncMap(reader As MetadataReader, ParamArray [handles] As EntityHandle()) - AssertEx.Equal([handles], reader.GetEditAndContinueMapEntries(), itemInspector:=AddressOf EncMapRowToString) + AssertEx.Equal( + [handles].Where(Function(h) h <> Nothing), + reader.GetEditAndContinueMapEntries(), itemInspector:=AddressOf EncMapRowToString) End Sub + ''' + ''' Checks that the EncMap contains specified definition handles. References are ignored as they are usually Not interesting to validate. They are emitted as needed. + ''' Any default values in the expected are ignored to facilitate conditional code. + ''' Friend Shared Sub CheckEncMapDefinitions(reader As MetadataReader, ParamArray [handles] As EntityHandle()) - AssertEx.Equal([handles], reader.GetEditAndContinueMapEntries().Where(Function(e) IsDefinition(e.Kind)), itemInspector:=AddressOf EncMapRowToString) + AssertEx.Equal( + [handles].Where(Function(h) h <> Nothing), + reader.GetEditAndContinueMapEntries().Where(Function(e) IsDefinition(e.Kind)), itemInspector:=AddressOf EncMapRowToString) End Sub - Friend Shared Sub CheckNames(reader As MetadataReader, [handles] As StringHandle(), ParamArray expectedNames As String()) + Friend Shared Sub CheckNames(reader As MetadataReader, [handles] As IEnumerable(Of StringHandle), ParamArray expectedNames As String()) CheckNames({reader}, [handles], expectedNames) End Sub - Friend Shared Sub CheckNames(readers As MetadataReader(), [handles] As StringHandle(), ParamArray expectedNames As String()) + Friend Shared Sub CheckNames(readers As MetadataReader(), [handles] As IEnumerable(Of StringHandle), ParamArray expectedNames As String()) Dim actualNames = readers.GetStrings([handles]) AssertEx.Equal(expectedNames, actualNames) End Sub - Friend Shared Sub CheckNamesSorted(readers As MetadataReader(), [handles] As StringHandle(), ParamArray expectedNames As String()) + Public Shared Sub CheckNames(readers As IList(Of MetadataReader), typeHandles As IEnumerable(Of TypeDefinitionHandle), ParamArray expectedNames As String()) + CheckNames(readers, typeHandles, Function(reader, handle) reader.GetTypeDefinition(CType(handle, TypeDefinitionHandle)).Name, Function(handle) handle, expectedNames) + End Sub + + Friend Shared Sub CheckNamesSorted(readers As MetadataReader(), [handles] As IEnumerable(Of StringHandle), ParamArray expectedNames As String()) Dim actualNames = readers.GetStrings([handles]) Array.Sort(actualNames) Array.Sort(expectedNames) AssertEx.Equal(expectedNames, actualNames) End Sub + Private Shared Sub CheckNames(Of THandle)( + readers As IList(Of MetadataReader), + entityHandles As IEnumerable(Of THandle), + getName As Func(Of MetadataReader, Handle, StringHandle), + toHandle As Func(Of THandle, Handle), + expectedNames As String()) + Dim aggregator = GetAggregator(readers) + + AssertEx.Equal(expectedNames, entityHandles.Select( + Function(handle) + Dim typeGeneration As Integer + Dim genEntityHandle = aggregator.GetGenerationHandle(toHandle(handle), typeGeneration) + Dim nameHandle = getName(readers(typeGeneration), genEntityHandle) + + Dim nameGeneration As Integer + Dim genNameHandle = CType(aggregator.GetGenerationHandle(nameHandle, nameGeneration), StringHandle) + Return readers(nameGeneration).GetString(genNameHandle) + End Function)) + End Sub + + Public Shared Sub CheckBlobValue(readers As IList(Of MetadataReader), valueHandle As BlobHandle, expectedValue As Byte()) + Dim aggregator = GetAggregator(readers) + + Dim generation As Integer + Dim genHandle = CType(aggregator.GetGenerationHandle(valueHandle, generation), BlobHandle) + Dim attributeData = readers(generation).GetBlobBytes(genHandle) + AssertEx.Equal(expectedValue, attributeData) + End Sub + + Public Shared Sub CheckStringValue(readers As IList(Of MetadataReader), valueHandle As StringHandle, expectedValue As String) + Dim aggregator = GetAggregator(readers) + + Dim generation As Integer + Dim genHandle = CType(aggregator.GetGenerationHandle(valueHandle, generation), StringHandle) + Dim attributeData = readers(generation).GetString(genHandle) + AssertEx.Equal(expectedValue, attributeData) + End Sub + + Public Shared Function GetAggregator(readers As IList(Of MetadataReader)) As MetadataAggregator + Return New MetadataAggregator(readers(0), readers.Skip(1).ToArray()) + End Function + Friend Shared Function EncLogRowToString(row As EditAndContinueLogEntry) As String Dim index As TableIndex = 0 MetadataTokens.TryGetTableIndex(row.Handle.Kind, index) diff --git a/src/Compilers/VisualBasic/Test/Emit/Emit/EditAndContinue/EditAndContinueTests.vb b/src/Compilers/VisualBasic/Test/Emit/Emit/EditAndContinue/EditAndContinueTests.vb index bdec6d82eab9c..111121bac33cd 100644 --- a/src/Compilers/VisualBasic/Test/Emit/Emit/EditAndContinue/EditAndContinueTests.vb +++ b/src/Compilers/VisualBasic/Test/Emit/Emit/EditAndContinue/EditAndContinueTests.vb @@ -1501,6 +1501,283 @@ End Class ") End Sub + + Public Sub UpdateType_AddAttributes() + Dim source0 = " +Class C +End Class +" + Dim source1 = " + +Class C +End Class +" + Dim source2 = " + + +Class C +End Class +" + + Dim compilation0 = CreateCompilation(source0, options:=TestOptions.DebugDll, TargetFramework:=TargetFramework.NetStandard20) + Dim compilation1 = compilation0.WithSource(source1) + Dim compilation2 = compilation1.WithSource(source2) + + Dim c0 = compilation0.GetMember(Of NamedTypeSymbol)("C") + Dim c1 = compilation1.GetMember(Of NamedTypeSymbol)("C") + Dim c2 = compilation2.GetMember(Of NamedTypeSymbol)("C") + + ' Verify full metadata contains expected rows. + Dim bytes0 = compilation0.EmitToArray() + Dim md0 = ModuleMetadata.CreateFromImage(bytes0) + Dim reader0 = md0.MetadataReader + + CheckNames(reader0, reader0.GetTypeDefNames(), "", "C") + + Assert.Equal(3, reader0.CustomAttributes.Count) + + Dim generation0 = EmitBaseline.CreateInitialBaseline( + md0, + EmptyLocalsProvider) + + Dim diff1 = compilation1.EmitDifference( + generation0, + ImmutableArray.Create(SemanticEdit.Create(SemanticEditKind.Update, c0, c1))) + + ' Verify delta metadata contains expected rows. + Dim md1 = diff1.GetMetadata() + Dim reader1 = md1.Reader + Dim readers = New MetadataReader() {reader0, reader1} + + CheckNames(readers, reader1.GetTypeDefNames(), "C") + + Assert.Equal(1, reader1.CustomAttributes.Count) + + CheckEncLogDefinitions(reader1, + Row(2, TableIndex.TypeDef, EditAndContinueOperation.Default), + Row(4, TableIndex.CustomAttribute, EditAndContinueOperation.Default)) + + CheckEncMapDefinitions(reader1, + Handle(2, TableIndex.TypeDef), + Handle(4, TableIndex.CustomAttribute)) + + Dim diff2 = compilation2.EmitDifference( + diff1.NextGeneration, + ImmutableArray.Create(SemanticEdit.Create(SemanticEditKind.Update, c1, c2))) + + ' Verify delta metadata contains expected rows. + Dim md2 = diff2.GetMetadata() + Dim reader2 = md2.Reader + readers = New MetadataReader() {reader0, reader1, reader2} + + CheckNames(readers, reader2.GetTypeDefNames(), "C") + + Assert.Equal(2, reader2.CustomAttributes.Count) + + CheckEncLogDefinitions(reader2, + Row(2, TableIndex.TypeDef, EditAndContinueOperation.Default), + Row(4, TableIndex.CustomAttribute, EditAndContinueOperation.Default), + Row(5, TableIndex.CustomAttribute, EditAndContinueOperation.Default)) + + CheckEncMapDefinitions(reader2, + Handle(2, TableIndex.TypeDef), + Handle(4, TableIndex.CustomAttribute), + Handle(5, TableIndex.CustomAttribute)) + End Sub + + Private Shared ReadOnly s_metadataUpdateOriginalTypeAttributeSource As String = " +Namespace System.Runtime.CompilerServices + + Public Class MetadataUpdateOriginalTypeAttribute + Inherits Attribute + + Public Sub New(originalType as Type) + Me.OriginalType = originalType + End Sub + + Public Readonly Property OriginalType As Type + End Class +End Namespace +" + + Private Shared ReadOnly s_badMetadataUpdateOriginalTypeAttributeSource As String = " +Namespace System.Runtime.CompilerServices + + Public Class MetadataUpdateOriginalTypeAttribute + Inherits Attribute + + Public Sub New(originalType as Object) + Me.OriginalType = originalType + End Sub + + Public Readonly Property OriginalType As Type + End Class +End Namespace +" + + + Public Sub ReplaceType(hasAttribute As Boolean) + ' using incorrect definition of the attribute so that it's easier to compare the two emit results (having and attribute and not having one): + Dim attributeSource = If(hasAttribute, s_metadataUpdateOriginalTypeAttributeSource, s_badMetadataUpdateOriginalTypeAttributeSource) + + Dim source0 = " +Class C + Sub F(x As Integer) + End Sub +End Class" & attributeSource + + Dim source1 = " +Class C + Sub F(x As Integer, y As Integer) + End Sub +End CLass" & attributeSource + + Dim source2 = " +Class C + Sub F(x As Integer, y As Integer) + System.Console.WriteLine(1) + End Sub +End Class" & attributeSource + + Dim source3 = " + +Class C + Sub F(x As Integer, y As Integer) + System.Console.WriteLine(2) + End Sub +End Class" & attributeSource + + Dim compilation0 = CreateCompilation(source0, options:=TestOptions.DebugDll, targetFramework:=TargetFramework.NetStandard20) + Dim compilation1 = compilation0.WithSource(source1) + Dim compilation2 = compilation1.WithSource(source2) + Dim compilation3 = compilation2.WithSource(source3) + + Dim c0 = compilation0.GetMember(Of NamedTypeSymbol)("C") + Dim c1 = compilation1.GetMember(Of NamedTypeSymbol)("C") + Dim c2 = compilation2.GetMember(Of NamedTypeSymbol)("C") + Dim c3 = compilation3.GetMember(Of NamedTypeSymbol)("C") + Dim f2 = c2.GetMember(Of MethodSymbol)("F") + Dim f3 = c3.GetMember(Of MethodSymbol)("F") + + ' Verify full metadata contains expected rows. + Dim bytes0 = compilation0.EmitToArray() + Dim md0 = ModuleMetadata.CreateFromImage(bytes0) + Dim reader0 = md0.MetadataReader + + CheckNames(reader0, reader0.GetTypeDefNames(), "", "C", "MetadataUpdateOriginalTypeAttribute") + + Dim generation0 = EmitBaseline.CreateInitialBaseline( + md0, + EmptyLocalsProvider) + + Dim baseTypeCount = reader0.TypeDefinitions.Count + Dim baseMethodCount = reader0.MethodDefinitions.Count + Dim baseAttributeCount = reader0.CustomAttributes.Count + Dim baseParameterCount = reader0.GetParameters().Count() + + Assert.Equal(3, baseTypeCount) + Assert.Equal(4, baseMethodCount) + Assert.Equal(7, baseAttributeCount) + Assert.Equal(2, baseParameterCount) + + Dim validateReplacedType = + Sub(diff As CompilationDifference, readers As MetadataReader()) + Dim generation = diff.NextGeneration.Ordinal + Dim reader = readers(generation) + + CheckNames(readers, diff.EmitResult.ChangedTypes, "C#" & generation) + CheckNames(readers, reader.GetTypeDefNames(), "C#" & generation) + + CheckEncLogDefinitions(reader, + Row(baseTypeCount + generation, TableIndex.TypeDef, EditAndContinueOperation.Default), ' adding a type def + Row(baseTypeCount + generation, TableIndex.TypeDef, EditAndContinueOperation.AddMethod), + Row(baseMethodCount + generation * 2 - 1, TableIndex.MethodDef, EditAndContinueOperation.Default), + Row(baseTypeCount + generation, TableIndex.TypeDef, EditAndContinueOperation.AddMethod), + Row(baseMethodCount + generation * 2, TableIndex.MethodDef, EditAndContinueOperation.Default), + Row(baseMethodCount + generation * 2, TableIndex.MethodDef, EditAndContinueOperation.AddParameter), + Row(baseParameterCount + generation * 2 - 1, TableIndex.Param, EditAndContinueOperation.Default), + Row(baseMethodCount + generation * 2, TableIndex.MethodDef, EditAndContinueOperation.AddParameter), + Row(baseParameterCount + generation * 2, TableIndex.Param, EditAndContinueOperation.Default), + If(hasAttribute, Row(baseAttributeCount + generation, TableIndex.CustomAttribute, EditAndContinueOperation.Default), Nothing)) ' adding a new attribute row for attribute on C#* definition + + CheckEncMapDefinitions(reader, + Handle(baseTypeCount + generation, TableIndex.TypeDef), + Handle(baseMethodCount + generation * 2 - 1, TableIndex.MethodDef), + Handle(baseMethodCount + generation * 2, TableIndex.MethodDef), + Handle(baseParameterCount + generation * 2 - 1, TableIndex.Param), + Handle(baseParameterCount + generation * 2, TableIndex.Param), + If(hasAttribute, Handle(baseAttributeCount + generation, TableIndex.CustomAttribute), Nothing)) + + Dim newTypeDefHandle = reader.TypeDefinitions.Single() + Dim newTypeDef = reader.GetTypeDefinition(newTypeDefHandle) + CheckStringValue(readers, newTypeDef.Name, "C#" & generation) + + If hasAttribute Then + Dim attribute = reader.GetCustomAttribute(reader.CustomAttributes.Single()) + + ' parent should be C#1 + Dim aggregator = GetAggregator(readers) + Dim parentGeneration As Integer + Dim parentHandle = aggregator.GetGenerationHandle(attribute.Parent, parentGeneration) + Assert.Equal(generation, parentGeneration) + Assert.Equal(newTypeDefHandle, parentHandle) + + ' The attribute value encodes the serialized type name. It should be the base name "C", not "C#1". + CheckBlobValue(readers, attribute.Value, New Byte() {&H1, &H0, &H1, AscW("C"c), &H0, &H0}) + End If + End Sub + + ' This update emulates "Reloadable" type behavior - a new type is generated instead of updating the existing one. + Dim diff1 = compilation1.EmitDifference( + generation0, + ImmutableArray.Create( + SemanticEdit.Create(SemanticEditKind.Replace, Nothing, c1))) + + Dim md1 = diff1.GetMetadata() + ValidateReplacedType(diff1, {reader0, md1.Reader}) + + Dim diff2 = compilation2.EmitDifference( + diff1.NextGeneration, + ImmutableArray.Create( + SemanticEdit.Create(SemanticEditKind.Replace, Nothing, c2))) + + Dim md2 = diff2.GetMetadata() + validateReplacedType(diff2, {reader0, md1.Reader, md2.Reader}) + + ' This update is an EnC update - even reloadable types are updated in-place + Dim diff3 = compilation3.EmitDifference( + diff2.NextGeneration, + ImmutableArray.Create( + SemanticEdit.Create(SemanticEditKind.Update, c2, c3), + SemanticEdit.Create(SemanticEditKind.Update, f2, f3))) + + ' Verify delta metadata contains expected rows. + Dim md3 = diff3.GetMetadata() + Dim reader3 = md3.Reader + Dim readers4 = {reader0, md1.Reader, md2.Reader, reader3} + + CheckNames(readers4, reader3.GetTypeDefNames(), "C#2") + CheckNames(readers4, diff3.EmitResult.ChangedTypes, "C#2") + + ' Obsolete attribute is added. MetadataUpdateOriginalTypeAttribute is still present on the type. + CheckEncLogDefinitions(reader3, + Row(5, TableIndex.TypeDef, EditAndContinueOperation.Default), + Row(8, TableIndex.MethodDef, EditAndContinueOperation.Default), + Row(5, TableIndex.Param, EditAndContinueOperation.Default), + Row(6, TableIndex.Param, EditAndContinueOperation.Default), + Row(If(hasAttribute, 9, 8), TableIndex.CustomAttribute, EditAndContinueOperation.Default)) + + CheckEncMapDefinitions(reader3, + Handle(5, TableIndex.TypeDef), + Handle(8, TableIndex.MethodDef), + Handle(5, TableIndex.Param), + Handle(6, TableIndex.Param), + Handle(If(hasAttribute, 9, 8), TableIndex.CustomAttribute)) + + ' Obsolete attribute: + CheckBlobValue(readers4, reader3.GetCustomAttribute(reader3.CustomAttributes.First()).Value, New Byte() {&H1, &H0, &H0, &H0}) + End Sub + ''' ''' Should use TypeDef rather than TypeRef for unrecognized ''' local of a type defined in the original assembly. diff --git a/src/Compilers/VisualBasic/Test/Semantic/Binding/ImplicitVariableTests.vb b/src/Compilers/VisualBasic/Test/Semantic/Binding/ImplicitVariableTests.vb index 9995a32e4dfeb..e9bf88640d864 100644 --- a/src/Compilers/VisualBasic/Test/Semantic/Binding/ImplicitVariableTests.vb +++ b/src/Compilers/VisualBasic/Test/Semantic/Binding/ImplicitVariableTests.vb @@ -937,7 +937,7 @@ done expression:="x + 1", expectedTypeName:="System.Int32", symbolKind:=SymbolKind.Method, - expectedSymbol:="Function System.Int32.op_Addition(left As System.Int32, right As System.Int32) As System.Int32") + expectedSymbol:="Function System.Int32.op_CheckedAddition(left As System.Int32, right As System.Int32) As System.Int32") End Sub #End Region diff --git a/src/Compilers/VisualBasic/Test/Semantic/Diagnostics/DiagnosticTests.vb b/src/Compilers/VisualBasic/Test/Semantic/Diagnostics/DiagnosticTests.vb index b26a37fb77b41..f6dc72e795929 100644 --- a/src/Compilers/VisualBasic/Test/Semantic/Diagnostics/DiagnosticTests.vb +++ b/src/Compilers/VisualBasic/Test/Semantic/Diagnostics/DiagnosticTests.vb @@ -108,7 +108,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.UnitTests Case < IdsStart Assert.True(False, GetErrorMessage(errString)) - Case IdsStart to ERRID.IDS_NextAvailable + Case IdsStart To ERRID.IDS_NextAvailable Assert.True(errString.StartsWith("IDS_"), GetErrorMessage(errString)) Case < FeatureStart @@ -136,6 +136,27 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.UnitTests Return $"{str} does not start with an approved prefix. Use ERR_ for errors, WRN_ for warnings, HDN_/INF_ for hidden or info diagnostics, IDS_ for ids, and FEATURE_ for feature codes" End If End Function + + + Public Sub TestIsBuildOnlyDiagnostic() + For Each errObj In [Enum].GetValues(GetType(ERRID)) + Dim err = DirectCast(errObj, ERRID) + + ' ErrorFacts.IsBuildOnlyDiagnostic with throw if any new ERRID + ' is added but not explicitly handled within it. + ' Update ErrorFacts.IsBuildOnlyDiagnostic if the below call throws. + Dim isBuildOnly = ErrorFacts.IsBuildOnlyDiagnostic(err) + + Select Case err + Case ERRID.ERR_TypeRefResolutionError3, + ERRID.ERR_MissingRuntimeHelper, + ERRID.ERR_CannotGotoNonScopeBlocksWithClosure + Assert.True(isBuildOnly, $"Check failed for ERRID.{err}") + Case Else + Assert.False(isBuildOnly, $"Check failed for ERRID.{err}") + End Select + Next + End Sub End Class End Namespace diff --git a/src/Compilers/VisualBasic/Test/Semantic/Semantics/BinaryOperators.vb b/src/Compilers/VisualBasic/Test/Semantic/Semantics/BinaryOperators.vb index e4a1f3f593367..caf7ef237d0ff 100644 --- a/src/Compilers/VisualBasic/Test/Semantic/Semantics/BinaryOperators.vb +++ b/src/Compilers/VisualBasic/Test/Semantic/Semantics/BinaryOperators.vb @@ -1104,7 +1104,7 @@ End Class Dim nonSpecialType = If(leftSpecial = SpecialType.System_Object, rightType, leftType) - For Each m In nonSpecialType.GetMembers(OverloadResolution.TryGetOperatorName(op)) + For Each m In nonSpecialType.GetMembers(OverloadResolution.TryGetOperatorName(op, isChecked:=False)) If m.Kind = SymbolKind.Method Then Dim method = DirectCast(m, MethodSymbol) If method.MethodKind = MethodKind.UserDefinedOperator AndAlso @@ -1203,7 +1203,7 @@ End Class OverloadResolution.TryGetOperatorName( If(op = BinaryOperatorKind.Add AndAlso resultType = SpecialType.System_String, BinaryOperatorKind.Concatenate, - op)), + op), symbol1.IsCheckedBuiltin), rightName, returnName), symbol1.ToTestDisplayString()) diff --git a/src/Compilers/VisualBasic/Test/Semantic/Semantics/GetExtendedSemanticInfoTests.vb b/src/Compilers/VisualBasic/Test/Semantic/Semantics/GetExtendedSemanticInfoTests.vb index a4b859d6ef3a3..fb5a5bf2da3b9 100644 --- a/src/Compilers/VisualBasic/Test/Semantic/Semantics/GetExtendedSemanticInfoTests.vb +++ b/src/Compilers/VisualBasic/Test/Semantic/Semantics/GetExtendedSemanticInfoTests.vb @@ -1376,7 +1376,7 @@ End Class Assert.Equal(TypeKind.Structure, semanticInfo.ConvertedType.TypeKind) Assert.Equal(ConversionKind.Identity, semanticInfo.ImplicitConversion.Kind) - Assert.Equal("Function System.Int32.op_Multiply(left As System.Int32, right As System.Int32) As System.Int32", + Assert.Equal("Function System.Int32.op_CheckedMultiply(left As System.Int32, right As System.Int32) As System.Int32", semanticInfo.Symbol.ToTestDisplayString()) Assert.Equal(CandidateReason.None, semanticInfo.CandidateReason) Assert.Equal(0, semanticInfo.CandidateSymbols.Length) @@ -5514,7 +5514,7 @@ End Class Assert.Equal(TypeKind.Class, semanticInfo.ConvertedType.TypeKind) Assert.Equal(ConversionKind.WideningValue, semanticInfo.ImplicitConversion.Kind) - Assert.Equal("Function System.Int32.op_Addition(left As System.Int32, right As System.Int32) As System.Int32", + Assert.Equal("Function System.Int32.op_CheckedAddition(left As System.Int32, right As System.Int32) As System.Int32", semanticInfo.Symbol.ToTestDisplayString()) Assert.Equal(CandidateReason.None, semanticInfo.CandidateReason) Assert.Equal(0, semanticInfo.CandidateSymbols.Length) @@ -5544,7 +5544,7 @@ End Class Assert.Equal(TypeKind.Class, semanticInfo.ConvertedType.TypeKind) Assert.Equal(ConversionKind.WideningValue, semanticInfo.ImplicitConversion.Kind) - Assert.Equal("Function System.Int32.op_Addition(left As System.Int32, right As System.Int32) As System.Int32", + Assert.Equal("Function System.Int32.op_CheckedAddition(left As System.Int32, right As System.Int32) As System.Int32", semanticInfo.Symbol.ToTestDisplayString()) Assert.Equal(CandidateReason.None, semanticInfo.CandidateReason) Assert.Equal(0, semanticInfo.CandidateSymbols.Length) diff --git a/src/Compilers/VisualBasic/Test/Semantic/Semantics/QueryExpressions_SemanticModel.vb b/src/Compilers/VisualBasic/Test/Semantic/Semantics/QueryExpressions_SemanticModel.vb index 6a80fd6ed12d0..7f028b103d16e 100644 --- a/src/Compilers/VisualBasic/Test/Semantic/Semantics/QueryExpressions_SemanticModel.vb +++ b/src/Compilers/VisualBasic/Test/Semantic/Semantics/QueryExpressions_SemanticModel.vb @@ -1151,7 +1151,7 @@ End Module Assert.Equal(TypeKind.Structure, semanticInfo.ConvertedType.TypeKind) Assert.Equal(ConversionKind.Identity, semanticInfo.ImplicitConversion.Kind) - Assert.Equal("Function System.Int32.op_Addition(left As System.Int32, right As System.Int32) As System.Int32", + Assert.Equal("Function System.Int32.op_CheckedAddition(left As System.Int32, right As System.Int32) As System.Int32", semanticInfo.Symbol.ToTestDisplayString()) Assert.Equal(CandidateReason.None, semanticInfo.CandidateReason) diff --git a/src/Compilers/VisualBasic/Test/Semantic/Semantics/RefFieldTests.vb b/src/Compilers/VisualBasic/Test/Semantic/Semantics/RefFieldTests.vb index 291b2da675598..59cddc11b7223 100644 --- a/src/Compilers/VisualBasic/Test/Semantic/Semantics/RefFieldTests.vb +++ b/src/Compilers/VisualBasic/Test/Semantic/Semantics/RefFieldTests.vb @@ -16,7 +16,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.UnitTests ''' ''' Ref field in ref struct. ''' - + Public Sub RefField_01() Dim sourceA = "public ref struct S @@ -88,7 +88,7 @@ End Module" Assert.Equal(expectedDisplayString, field.ToTestDisplayString()) End Sub - + Public Sub MemberRefMetadataDecoder_FindFieldBySignature() Dim sourceA = ".class public sealed R extends [mscorlib]System.ValueType diff --git a/src/Compilers/VisualBasic/Test/Semantic/Semantics/UnaryOperators.vb b/src/Compilers/VisualBasic/Test/Semantic/Semantics/UnaryOperators.vb index bbd6fb38bdf20..e57f8110e951d 100644 --- a/src/Compilers/VisualBasic/Test/Semantic/Semantics/UnaryOperators.vb +++ b/src/Compilers/VisualBasic/Test/Semantic/Semantics/UnaryOperators.vb @@ -751,7 +751,7 @@ End Class Assert.Equal(String.Format("Function {0}.{1}(value As {0}) As {2}", containerName, - OverloadResolution.TryGetOperatorName(op), + OverloadResolution.TryGetOperatorName(op, symbol1.IsCheckedBuiltin), returnName), symbol1.ToTestDisplayString()) diff --git a/src/Compilers/VisualBasic/Test/Semantic/SourceGeneration/GeneratorDriverTests_Attributes_FullyQualifiedName.vb b/src/Compilers/VisualBasic/Test/Semantic/SourceGeneration/GeneratorDriverTests_Attributes_FullyQualifiedName.vb index 137f4dea83982..89d00c4a1f098 100644 --- a/src/Compilers/VisualBasic/Test/Semantic/SourceGeneration/GeneratorDriverTests_Attributes_FullyQualifiedName.vb +++ b/src/Compilers/VisualBasic/Test/Semantic/SourceGeneration/GeneratorDriverTests_Attributes_FullyQualifiedName.vb @@ -18,17 +18,17 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Semantic.UnitTests.SourceGeneration Return context.SyntaxProvider.ForAttributeWithSimpleName( simpleName, - Function(node, c) TypeOf node Is T).Select(Function(node, c) DirectCast(node, T)) + Function(node, c) TypeOf node Is T).SelectMany(Function(tuple, c) tuple.matches.Cast(Of T)).WithTrackingName("result_ForAttribute") End Function - Public Function ForAttributeWithMetadataName(Of t As SyntaxNode)( - context As IncrementalGeneratorInitializationContext, fullyQualifiedMetadataName As String) As IncrementalValuesProvider(Of t) + Public Function ForAttributeWithMetadataName(Of T As SyntaxNode)( + context As IncrementalGeneratorInitializationContext, fullyQualifiedMetadataName As String) As IncrementalValuesProvider(Of T) Return context.SyntaxProvider.ForAttributeWithMetadataName( fullyQualifiedMetadataName, - Function(node, c) TypeOf node Is t, - Function(ctx, c) DirectCast(ctx.TargetNode, t)) + Function(node, c) TypeOf node Is T, + Function(ctx, c) DirectCast(ctx.TargetNode, T)) End Function End Module @@ -910,15 +910,13 @@ end class Assert.Collection(runResult.TrackedSteps("result_ForAttributeWithMetadataName"), Sub(_step) Assert.True(IsClassStatementWithName(_step.Outputs.Single().Value, "C"))) - Assert.Equal(IncrementalStepRunReason.Cached, runResult.TrackedSteps("individualFileGlobalAliases_ForAttribute").Single().Outputs.Single().Reason) - Assert.Equal(IncrementalStepRunReason.Cached, runResult.TrackedSteps("collectedGlobalAliases_ForAttribute").Single().Outputs.Single().Reason) + Assert.False(runResult.TrackedSteps.ContainsKey("individualFileGlobalAliases_ForAttribute")) + Assert.Equal(IncrementalStepRunReason.Unchanged, runResult.TrackedSteps("collectedGlobalAliases_ForAttribute").Single().Outputs.Single().Reason) Assert.Equal(IncrementalStepRunReason.Cached, runResult.TrackedSteps("compilationGlobalAliases_ForAttribute").Single().Outputs.Single().Reason) Assert.Equal(IncrementalStepRunReason.Cached, runResult.TrackedSteps("allUpGlobalAliases_ForAttribute").Single().Outputs.Single().Reason) Assert.Equal(IncrementalStepRunReason.Cached, runResult.TrackedSteps("compilationUnit_ForAttribute").Single().Outputs.Single().Reason) Assert.Equal(IncrementalStepRunReason.Cached, runResult.TrackedSteps("compilationUnitAndGlobalAliases_ForAttribute").Single().Outputs.Single().Reason) - Assert.Equal(IncrementalStepRunReason.Cached, runResult.TrackedSteps("result_ForAttribute").Single().Outputs.Single().Reason) - Assert.Equal(IncrementalStepRunReason.Cached, runResult.TrackedSteps("collectedNodes_ForAttributeWithMetadataName").Single().Outputs.Single().Reason) - Assert.Equal(IncrementalStepRunReason.Cached, runResult.TrackedSteps("groupedNodes_ForAttributeWithMetadataName").Single().Outputs.Single().Reason) + Assert.Equal(IncrementalStepRunReason.Cached, runResult.TrackedSteps("result_ForAttributeInternal").Single().Outputs.Single().Reason) Assert.Equal(IncrementalStepRunReason.Cached, runResult.TrackedSteps("compilationAndGroupedNodes_ForAttributeWithMetadataName").Single().Outputs.Single().Reason) Assert.Equal(IncrementalStepRunReason.Cached, runResult.TrackedSteps("result_ForAttributeWithMetadataName").Single().Outputs.Single().Reason) End Sub @@ -959,15 +957,13 @@ end class Assert.Collection(runResult.TrackedSteps("result_ForAttributeWithMetadataName"), Sub(_step) Assert.True(IsClassStatementWithName(_step.Outputs.Single().Value, "C"))) - Assert.Equal(IncrementalStepRunReason.Cached, runResult.TrackedSteps("individualFileGlobalAliases_ForAttribute").Single().Outputs.Single().Reason) - Assert.Equal(IncrementalStepRunReason.Cached, runResult.TrackedSteps("collectedGlobalAliases_ForAttribute").Single().Outputs.Single().Reason) + Assert.False(runResult.TrackedSteps.ContainsKey("individualFileGlobalAliases_ForAttribute")) + Assert.Equal(IncrementalStepRunReason.Unchanged, runResult.TrackedSteps("collectedGlobalAliases_ForAttribute").Single().Outputs.Single().Reason) Assert.Equal(IncrementalStepRunReason.Cached, runResult.TrackedSteps("compilationGlobalAliases_ForAttribute").Single().Outputs.Single().Reason) Assert.Equal(IncrementalStepRunReason.Cached, runResult.TrackedSteps("allUpGlobalAliases_ForAttribute").Single().Outputs.Single().Reason) Assert.Equal(IncrementalStepRunReason.Unchanged, runResult.TrackedSteps("compilationUnit_ForAttribute").Single().Outputs.Single().Reason) Assert.Equal(IncrementalStepRunReason.Cached, runResult.TrackedSteps("compilationUnitAndGlobalAliases_ForAttribute").Single().Outputs.Single().Reason) - Assert.Equal(IncrementalStepRunReason.Cached, runResult.TrackedSteps("result_ForAttribute").Single().Outputs.Single().Reason) - Assert.Equal(IncrementalStepRunReason.Cached, runResult.TrackedSteps("collectedNodes_ForAttributeWithMetadataName").Single().Outputs.Single().Reason) - Assert.Equal(IncrementalStepRunReason.Cached, runResult.TrackedSteps("groupedNodes_ForAttributeWithMetadataName").Single().Outputs.Single().Reason) + Assert.Equal(IncrementalStepRunReason.Cached, runResult.TrackedSteps("result_ForAttributeInternal").Single().Outputs.Single().Reason) Assert.Equal(IncrementalStepRunReason.Modified, runResult.TrackedSteps("compilationAndGroupedNodes_ForAttributeWithMetadataName").Single().Outputs.Single().Reason) Assert.Equal(IncrementalStepRunReason.Unchanged, runResult.TrackedSteps("result_ForAttributeWithMetadataName").Single().Outputs.Single().Reason) End Sub @@ -1007,19 +1003,14 @@ end class Assert.Collection(runResult.TrackedSteps("result_ForAttributeWithMetadataName"), Sub(_step) Assert.True(IsClassStatementWithName(_step.Outputs.Single().Value, "C"))) - Assert.Collection(runResult.TrackedSteps("individualFileGlobalAliases_ForAttribute"), - Sub(s) Assert.Equal(IncrementalStepRunReason.Cached, s.Outputs.Single().Reason), - Sub(s) Assert.Equal(IncrementalStepRunReason.New, s.Outputs.Single().Reason)) - Assert.Equal(IncrementalStepRunReason.Modified, runResult.TrackedSteps("collectedGlobalAliases_ForAttribute").Single().Outputs.Single().Reason) + Assert.False(runResult.TrackedSteps.ContainsKey("individualFileGlobalAliases_ForAttribute")) + Assert.Equal(IncrementalStepRunReason.Unchanged, runResult.TrackedSteps("collectedGlobalAliases_ForAttribute").Single().Outputs.Single().Reason) Assert.Equal(IncrementalStepRunReason.Cached, runResult.TrackedSteps("compilationGlobalAliases_ForAttribute").Single().Outputs.Single().Reason) - Assert.Equal(IncrementalStepRunReason.Unchanged, runResult.TrackedSteps("allUpGlobalAliases_ForAttribute").Single().Outputs.Single().Reason) + Assert.Equal(IncrementalStepRunReason.Cached, runResult.TrackedSteps("allUpGlobalAliases_ForAttribute").Single().Outputs.Single().Reason) Assert.Collection(runResult.TrackedSteps("compilationUnit_ForAttribute").Single().Outputs, - Sub(o) Assert.Equal(IncrementalStepRunReason.Unchanged, o.Reason), - Sub(o) Assert.Equal(IncrementalStepRunReason.Modified, o.Reason)) + Sub(o) Assert.Equal(IncrementalStepRunReason.Unchanged, o.Reason)) Assert.Equal(IncrementalStepRunReason.Cached, runResult.TrackedSteps("compilationUnitAndGlobalAliases_ForAttribute").Single().Outputs.Single().Reason) - Assert.Equal(IncrementalStepRunReason.Cached, runResult.TrackedSteps("result_ForAttribute").Single().Outputs.Single().Reason) - Assert.Equal(IncrementalStepRunReason.Unchanged, runResult.TrackedSteps("collectedNodes_ForAttributeWithMetadataName").Single().Outputs.Single().Reason) - Assert.Equal(IncrementalStepRunReason.Cached, runResult.TrackedSteps("groupedNodes_ForAttributeWithMetadataName").Single().Outputs.Single().Reason) + Assert.Equal(IncrementalStepRunReason.Cached, runResult.TrackedSteps("result_ForAttributeInternal").Single().Outputs.Single().Reason) Assert.Equal(IncrementalStepRunReason.Modified, runResult.TrackedSteps("compilationAndGroupedNodes_ForAttributeWithMetadataName").Single().Outputs.Single().Reason) Assert.Equal(IncrementalStepRunReason.Unchanged, runResult.TrackedSteps("result_ForAttributeWithMetadataName").Single().Outputs.Single().Reason) End Sub @@ -1058,19 +1049,14 @@ end class Assert.Collection(runResult.TrackedSteps("result_ForAttributeWithMetadataName"), Sub(_step) Assert.True(IsClassStatementWithName(_step.Outputs.Single().Value, "C"))) - Assert.Collection(runResult.TrackedSteps("individualFileGlobalAliases_ForAttribute"), - Sub(s) Assert.Equal(IncrementalStepRunReason.Cached, s.Outputs.Single().Reason), - Sub(s) Assert.Equal(IncrementalStepRunReason.New, s.Outputs.Single().Reason)) - Assert.Equal(IncrementalStepRunReason.Modified, runResult.TrackedSteps("collectedGlobalAliases_ForAttribute").Single().Outputs.Single().Reason) + Assert.False(runResult.TrackedSteps.ContainsKey("individualFileGlobalAliases_ForAttribute")) + Assert.Equal(IncrementalStepRunReason.Unchanged, runResult.TrackedSteps("collectedGlobalAliases_ForAttribute").Single().Outputs.Single().Reason) Assert.Equal(IncrementalStepRunReason.Cached, runResult.TrackedSteps("compilationGlobalAliases_ForAttribute").Single().Outputs.Single().Reason) - Assert.Equal(IncrementalStepRunReason.Unchanged, runResult.TrackedSteps("allUpGlobalAliases_ForAttribute").Single().Outputs.Single().Reason) + Assert.Equal(IncrementalStepRunReason.Cached, runResult.TrackedSteps("allUpGlobalAliases_ForAttribute").Single().Outputs.Single().Reason) Assert.Collection(runResult.TrackedSteps("compilationUnit_ForAttribute").Single().Outputs, - Sub(o) Assert.Equal(IncrementalStepRunReason.Unchanged, o.Reason), - Sub(o) Assert.Equal(IncrementalStepRunReason.Modified, o.Reason)) + Sub(o) Assert.Equal(IncrementalStepRunReason.Unchanged, o.Reason)) Assert.Equal(IncrementalStepRunReason.Cached, runResult.TrackedSteps("compilationUnitAndGlobalAliases_ForAttribute").Single().Outputs.Single().Reason) - Assert.Equal(IncrementalStepRunReason.Cached, runResult.TrackedSteps("result_ForAttribute").Single().Outputs.Single().Reason) - Assert.Equal(IncrementalStepRunReason.Unchanged, runResult.TrackedSteps("collectedNodes_ForAttributeWithMetadataName").Single().Outputs.Single().Reason) - Assert.Equal(IncrementalStepRunReason.Cached, runResult.TrackedSteps("groupedNodes_ForAttributeWithMetadataName").Single().Outputs.Single().Reason) + Assert.Equal(IncrementalStepRunReason.Cached, runResult.TrackedSteps("result_ForAttributeInternal").Single().Outputs.Single().Reason) Assert.Equal(IncrementalStepRunReason.Modified, runResult.TrackedSteps("compilationAndGroupedNodes_ForAttributeWithMetadataName").Single().Outputs.Single().Reason) Assert.Equal(IncrementalStepRunReason.Modified, runResult.TrackedSteps("result_ForAttributeWithMetadataName").Single().Outputs.Single().Reason) End Sub @@ -1113,21 +1099,15 @@ end class")))) Sub(t) Assert.True(IsClassStatementWithName(t.Value, "C1")), Sub(t) Assert.True(IsClassStatementWithName(t.Value, "C2")))) - Assert.Collection(runResult.TrackedSteps("individualFileGlobalAliases_ForAttribute"), - Sub(s) Assert.Equal(IncrementalStepRunReason.Cached, s.Outputs.Single().Reason), - Sub(s) Assert.Equal(IncrementalStepRunReason.New, s.Outputs.Single().Reason)) - Assert.Equal(IncrementalStepRunReason.Modified, runResult.TrackedSteps("collectedGlobalAliases_ForAttribute").Single().Outputs.Single().Reason) + Assert.False(runResult.TrackedSteps.ContainsKey("individualFileGlobalAliases_ForAttribute")) + Assert.Equal(IncrementalStepRunReason.Unchanged, runResult.TrackedSteps("collectedGlobalAliases_ForAttribute").Single().Outputs.Single().Reason) Assert.Equal(IncrementalStepRunReason.Cached, runResult.TrackedSteps("compilationGlobalAliases_ForAttribute").Single().Outputs.Single().Reason) - Assert.Equal(IncrementalStepRunReason.Unchanged, runResult.TrackedSteps("allUpGlobalAliases_ForAttribute").Single().Outputs.Single().Reason) + Assert.Equal(IncrementalStepRunReason.Cached, runResult.TrackedSteps("allUpGlobalAliases_ForAttribute").Single().Outputs.Single().Reason) Assert.Collection(runResult.TrackedSteps("compilationUnit_ForAttribute").Single().Outputs, - Sub(o) Assert.Equal(IncrementalStepRunReason.Unchanged, o.Reason), - Sub(o) Assert.Equal(IncrementalStepRunReason.Modified, o.Reason)) + Sub(o) Assert.Equal(IncrementalStepRunReason.Unchanged, o.Reason)) Assert.Equal(IncrementalStepRunReason.Cached, runResult.TrackedSteps("compilationUnitAndGlobalAliases_ForAttribute").Single().Outputs.Single().Reason) - Assert.Collection(runResult.TrackedSteps("result_ForAttribute").Single().Outputs, - Sub(t) Assert.Equal(IncrementalStepRunReason.Cached, t.Reason), + Assert.Collection(runResult.TrackedSteps("result_ForAttributeInternal").Single().Outputs, Sub(t) Assert.Equal(IncrementalStepRunReason.Cached, t.Reason)) - Assert.Equal(IncrementalStepRunReason.Unchanged, runResult.TrackedSteps("collectedNodes_ForAttributeWithMetadataName").Single().Outputs.Single().Reason) - Assert.Equal(IncrementalStepRunReason.Cached, runResult.TrackedSteps("groupedNodes_ForAttributeWithMetadataName").Single().Outputs.Single().Reason) Assert.Equal(IncrementalStepRunReason.Modified, runResult.TrackedSteps("compilationAndGroupedNodes_ForAttributeWithMetadataName").Single().Outputs.Single().Reason) Assert.Collection(runResult.TrackedSteps("result_ForAttributeWithMetadataName").Single().Outputs, Sub(t) Assert.Equal(IncrementalStepRunReason.Modified, t.Reason), @@ -1171,28 +1151,19 @@ end class")))) Sub(_step) Assert.Collection(_step.Outputs, Sub(t) Assert.True(IsClassStatementWithName(t.Value, "C1"))), Sub(_step) Assert.Collection(_step.Outputs, Sub(t) Assert.True(IsClassStatementWithName(t.Value, "C2")))) - Assert.Collection(runResult.TrackedSteps("individualFileGlobalAliases_ForAttribute"), - Sub(s) Assert.Equal(IncrementalStepRunReason.Cached, s.Outputs.Single().Reason), - Sub(s) Assert.Equal(IncrementalStepRunReason.Cached, s.Outputs.Single().Reason), - Sub(s) Assert.Equal(IncrementalStepRunReason.New, s.Outputs.Single().Reason)) - Assert.Equal(IncrementalStepRunReason.Modified, runResult.TrackedSteps("collectedGlobalAliases_ForAttribute").Single().Outputs.Single().Reason) + Assert.False(runResult.TrackedSteps.ContainsKey("individualFileGlobalAliases_ForAttribute")) + Assert.Equal(IncrementalStepRunReason.Unchanged, runResult.TrackedSteps("collectedGlobalAliases_ForAttribute").Single().Outputs.Single().Reason) Assert.Equal(IncrementalStepRunReason.Cached, runResult.TrackedSteps("compilationGlobalAliases_ForAttribute").Single().Outputs.Single().Reason) - Assert.Equal(IncrementalStepRunReason.Unchanged, runResult.TrackedSteps("allUpGlobalAliases_ForAttribute").Single().Outputs.Single().Reason) + Assert.Equal(IncrementalStepRunReason.Cached, runResult.TrackedSteps("allUpGlobalAliases_ForAttribute").Single().Outputs.Single().Reason) Assert.Collection(runResult.TrackedSteps("compilationUnit_ForAttribute").Single().Outputs, Sub(s) Assert.Equal(IncrementalStepRunReason.Unchanged, s.Reason), - Sub(s) Assert.Equal(IncrementalStepRunReason.Unchanged, s.Reason), - Sub(s) Assert.Equal(IncrementalStepRunReason.Modified, s.Reason)) + Sub(s) Assert.Equal(IncrementalStepRunReason.Unchanged, s.Reason)) Assert.Collection(runResult.TrackedSteps("compilationUnitAndGlobalAliases_ForAttribute"), Sub(s) Assert.Equal(IncrementalStepRunReason.Cached, s.Outputs.Single().Reason), Sub(s) Assert.Equal(IncrementalStepRunReason.Cached, s.Outputs.Single().Reason)) - Assert.Collection(runResult.TrackedSteps("result_ForAttribute"), + Assert.Collection(runResult.TrackedSteps("result_ForAttributeInternal"), Sub(s) Assert.Equal(IncrementalStepRunReason.Cached, s.Outputs.Single().Reason), Sub(s) Assert.Equal(IncrementalStepRunReason.Cached, s.Outputs.Single().Reason)) - Assert.Equal(IncrementalStepRunReason.Unchanged, runResult.TrackedSteps("collectedNodes_ForAttributeWithMetadataName").Single().Outputs.Single().Reason) - Assert.Collection(runResult.TrackedSteps("groupedNodes_ForAttributeWithMetadataName"), - Sub(s) Assert.Collection(s.Outputs, - Sub(t) Assert.Equal(IncrementalStepRunReason.Cached, t.Reason), - Sub(t) Assert.Equal(IncrementalStepRunReason.Cached, t.Reason))) Assert.Collection(runResult.TrackedSteps("compilationAndGroupedNodes_ForAttributeWithMetadataName"), Sub(s) Assert.Equal(IncrementalStepRunReason.Modified, s.Outputs.Single().Reason), Sub(s) Assert.Equal(IncrementalStepRunReason.Modified, s.Outputs.Single().Reason)) @@ -1245,16 +1216,13 @@ end class Assert.Collection(runResult.TrackedSteps("result_ForAttributeWithMetadataName"), Sub(_step) Assert.True(IsClassStatementWithName(_step.Outputs.Single().Value, "C"))) - Assert.Collection(runResult.TrackedSteps("individualFileGlobalAliases_ForAttribute"), - Sub(s) Assert.Equal(IncrementalStepRunReason.Unchanged, s.Outputs.Single().Reason)) - Assert.Equal(IncrementalStepRunReason.Cached, runResult.TrackedSteps("collectedGlobalAliases_ForAttribute").Single().Outputs.Single().Reason) + Assert.False(runResult.TrackedSteps.ContainsKey("individualFileGlobalAliases_ForAttribute")) + Assert.Equal(IncrementalStepRunReason.Unchanged, runResult.TrackedSteps("collectedGlobalAliases_ForAttribute").Single().Outputs.Single().Reason) Assert.Equal(IncrementalStepRunReason.Cached, runResult.TrackedSteps("compilationGlobalAliases_ForAttribute").Single().Outputs.Single().Reason) Assert.Equal(IncrementalStepRunReason.Cached, runResult.TrackedSteps("allUpGlobalAliases_ForAttribute").Single().Outputs.Single().Reason) Assert.Equal(IncrementalStepRunReason.Modified, runResult.TrackedSteps("compilationUnit_ForAttribute").Single().Outputs.Single().Reason) - Assert.Equal(IncrementalStepRunReason.Modified, runResult.TrackedSteps("compilationUnitAndGlobalAliases_ForAttribute").Single().Outputs.Single().Reason) - Assert.Equal(IncrementalStepRunReason.Modified, runResult.TrackedSteps("result_ForAttribute").Single().Outputs.Single().Reason) - Assert.Equal(IncrementalStepRunReason.Modified, runResult.TrackedSteps("collectedNodes_ForAttributeWithMetadataName").Single().Outputs.Single().Reason) - Assert.Equal(IncrementalStepRunReason.Modified, runResult.TrackedSteps("groupedNodes_ForAttributeWithMetadataName").Single().Outputs.Single().Reason) + Assert.Equal(IncrementalStepRunReason.New, runResult.TrackedSteps("compilationUnitAndGlobalAliases_ForAttribute").Single().Outputs.Single().Reason) + Assert.Equal(IncrementalStepRunReason.New, runResult.TrackedSteps("result_ForAttributeInternal").Single().Outputs.Single().Reason) Assert.Equal(IncrementalStepRunReason.New, runResult.TrackedSteps("compilationAndGroupedNodes_ForAttributeWithMetadataName").Single().Outputs.Single().Reason) Assert.Equal(IncrementalStepRunReason.New, runResult.TrackedSteps("result_ForAttributeWithMetadataName").Single().Outputs.Single().Reason) End Sub @@ -1298,19 +1266,14 @@ end class Assert.Collection(runResult.TrackedSteps("result_ForAttributeWithMetadataName"), Sub(_step) Assert.True(IsClassStatementWithName(_step.Outputs.Single().Value, "C"))) - Assert.Collection(runResult.TrackedSteps("individualFileGlobalAliases_ForAttribute"), - Sub(s) Assert.Equal(IncrementalStepRunReason.Unchanged, s.Outputs.Single().Reason), - Sub(s) Assert.Equal(IncrementalStepRunReason.Cached, s.Outputs.Single().Reason)) - Assert.Equal(IncrementalStepRunReason.Cached, runResult.TrackedSteps("collectedGlobalAliases_ForAttribute").Single().Outputs.Single().Reason) + Assert.False(runResult.TrackedSteps.ContainsKey("individualFileGlobalAliases_ForAttribute")) + Assert.Equal(IncrementalStepRunReason.Unchanged, runResult.TrackedSteps("collectedGlobalAliases_ForAttribute").Single().Outputs.Single().Reason) Assert.Equal(IncrementalStepRunReason.Cached, runResult.TrackedSteps("compilationGlobalAliases_ForAttribute").Single().Outputs.Single().Reason) Assert.Equal(IncrementalStepRunReason.Cached, runResult.TrackedSteps("allUpGlobalAliases_ForAttribute").Single().Outputs.Single().Reason) Assert.Collection(runResult.TrackedSteps("compilationUnit_ForAttribute").Single().Outputs, - Sub(o) Assert.Equal(IncrementalStepRunReason.Modified, o.Reason), - Sub(o) Assert.Equal(IncrementalStepRunReason.Unchanged, o.Reason)) - Assert.Equal(IncrementalStepRunReason.Modified, runResult.TrackedSteps("compilationUnitAndGlobalAliases_ForAttribute").Single().Outputs.Single().Reason) - Assert.Equal(IncrementalStepRunReason.Modified, runResult.TrackedSteps("result_ForAttribute").Single().Outputs.Single().Reason) - Assert.Equal(IncrementalStepRunReason.Modified, runResult.TrackedSteps("collectedNodes_ForAttributeWithMetadataName").Single().Outputs.Single().Reason) - Assert.Equal(IncrementalStepRunReason.Modified, runResult.TrackedSteps("groupedNodes_ForAttributeWithMetadataName").Single().Outputs.Single().Reason) + Sub(o) Assert.Equal(IncrementalStepRunReason.Modified, o.Reason)) + Assert.Equal(IncrementalStepRunReason.New, runResult.TrackedSteps("compilationUnitAndGlobalAliases_ForAttribute").Single().Outputs.Single().Reason) + Assert.Equal(IncrementalStepRunReason.New, runResult.TrackedSteps("result_ForAttributeInternal").Single().Outputs.Single().Reason) Assert.Equal(IncrementalStepRunReason.New, runResult.TrackedSteps("compilationAndGroupedNodes_ForAttributeWithMetadataName").Single().Outputs.Single().Reason) Assert.Equal(IncrementalStepRunReason.New, runResult.TrackedSteps("result_ForAttributeWithMetadataName").Single().Outputs.Single().Reason) 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 2f95cdbbf421a..d89ef1d11a824 100644 --- a/src/Compilers/VisualBasic/Test/Semantic/SourceGeneration/GeneratorDriverTests_Attributes_SimpleName.vb +++ b/src/Compilers/VisualBasic/Test/Semantic/SourceGeneration/GeneratorDriverTests_Attributes_SimpleName.vb @@ -1090,8 +1090,8 @@ end class Assert.Collection(runResult.TrackedSteps("result_ForAttribute"), Sub(_step) Assert.True(IsClassStatementWithName(_step.Outputs.Single().Value, "C"))) - Assert.Equal(IncrementalStepRunReason.Cached, runResult.TrackedSteps("individualFileGlobalAliases_ForAttribute").Single().Outputs.Single().Reason) - Assert.Equal(IncrementalStepRunReason.Cached, runResult.TrackedSteps("collectedGlobalAliases_ForAttribute").Single().Outputs.Single().Reason) + Assert.False(runResult.TrackedSteps.ContainsKey("individualFileGlobalAliases_ForAttribute")) + Assert.Equal(IncrementalStepRunReason.Unchanged, runResult.TrackedSteps("collectedGlobalAliases_ForAttribute").Single().Outputs.Single().Reason) Assert.Equal(IncrementalStepRunReason.Cached, runResult.TrackedSteps("allUpGlobalAliases_ForAttribute").Single().Outputs.Single().Reason) Assert.Equal(IncrementalStepRunReason.Cached, runResult.TrackedSteps("compilationUnit_ForAttribute").Single().Outputs.Single().Reason) Assert.Equal(IncrementalStepRunReason.Cached, runResult.TrackedSteps("compilationUnitAndGlobalAliases_ForAttribute").Single().Outputs.Single().Reason) @@ -1130,8 +1130,8 @@ end class Assert.Collection(runResult.TrackedSteps("result_ForAttribute"), Sub(_step) Assert.True(IsClassStatementWithName(_step.Outputs.Single().Value, "C"))) - Assert.Equal(IncrementalStepRunReason.Cached, runResult.TrackedSteps("individualFileGlobalAliases_ForAttribute").Single().Outputs.Single().Reason) - Assert.Equal(IncrementalStepRunReason.Cached, runResult.TrackedSteps("collectedGlobalAliases_ForAttribute").Single().Outputs.Single().Reason) + Assert.False(runResult.TrackedSteps.ContainsKey("individualFileGlobalAliases_ForAttribute")) + Assert.Equal(IncrementalStepRunReason.Unchanged, runResult.TrackedSteps("collectedGlobalAliases_ForAttribute").Single().Outputs.Single().Reason) Assert.Equal(IncrementalStepRunReason.Cached, runResult.TrackedSteps("allUpGlobalAliases_ForAttribute").Single().Outputs.Single().Reason) Assert.Equal(IncrementalStepRunReason.Unchanged, runResult.TrackedSteps("compilationUnit_ForAttribute").Single().Outputs.Single().Reason) Assert.Equal(IncrementalStepRunReason.Cached, runResult.TrackedSteps("compilationUnitAndGlobalAliases_ForAttribute").Single().Outputs.Single().Reason) @@ -1168,14 +1168,10 @@ end class driver = driver.RunGenerators(compilation.RemoveSyntaxTrees(compilation.SyntaxTrees.Last())) runResult = driver.GetRunResult().Results(0) - Assert.Collection(runResult.TrackedSteps("individualFileGlobalAliases_ForAttribute"), - Sub(_step) Assert.Equal(IncrementalStepRunReason.Removed, _step.Outputs.Single().Reason)) + Assert.False(runResult.TrackedSteps.ContainsKey("individualFileGlobalAliases_ForAttribute")) - ' the per-file global aliases get changed (because the last file is removed). - Assert.Equal(IncrementalStepRunReason.Modified, runResult.TrackedSteps("collectedGlobalAliases_ForAttribute").Single().Outputs.Single().Reason) - - ' however, the collected global aliases stays the same. - Assert.Equal(IncrementalStepRunReason.Unchanged, runResult.TrackedSteps("allUpGlobalAliases_ForAttribute").Single().Outputs.Single().Reason) + Assert.Equal(IncrementalStepRunReason.Unchanged, runResult.TrackedSteps("collectedGlobalAliases_ForAttribute").Single().Outputs.Single().Reason) + Assert.Equal(IncrementalStepRunReason.Cached, runResult.TrackedSteps("allUpGlobalAliases_ForAttribute").Single().Outputs.Single().Reason) Assert.Equal(IncrementalStepRunReason.Removed, runResult.TrackedSteps("compilationUnit_ForAttribute").Single().Outputs.Single().Reason) Assert.Equal(IncrementalStepRunReason.Removed, runResult.TrackedSteps("compilationUnitAndGlobalAliases_ForAttribute").Single().Outputs.Single().Reason) @@ -1216,13 +1212,12 @@ end class ")))) runResult = driver.GetRunResult().Results(0) - Assert.Collection(runResult.TrackedSteps("individualFileGlobalAliases_ForAttribute"), - Sub(_step) Assert.Equal(IncrementalStepRunReason.Unchanged, _step.Outputs.Single().Reason)) - Assert.Equal(IncrementalStepRunReason.Cached, runResult.TrackedSteps("collectedGlobalAliases_ForAttribute").Single().Outputs.Single().Reason) + Assert.False(runResult.TrackedSteps.ContainsKey("individualFileGlobalAliases_ForAttribute")) + Assert.Equal(IncrementalStepRunReason.Unchanged, runResult.TrackedSteps("collectedGlobalAliases_ForAttribute").Single().Outputs.Single().Reason) Assert.Equal(IncrementalStepRunReason.Cached, runResult.TrackedSteps("allUpGlobalAliases_ForAttribute").Single().Outputs.Single().Reason) - Assert.Equal(IncrementalStepRunReason.Modified, runResult.TrackedSteps("compilationUnit_ForAttribute").Single().Outputs.Single().Reason) - Assert.Equal(IncrementalStepRunReason.Modified, runResult.TrackedSteps("compilationUnitAndGlobalAliases_ForAttribute").Single().Outputs.Single().Reason) + Assert.Equal(IncrementalStepRunReason.Removed, runResult.TrackedSteps("compilationUnit_ForAttribute").Single().Outputs.Single().Reason) + Assert.Equal(IncrementalStepRunReason.Removed, runResult.TrackedSteps("compilationUnitAndGlobalAliases_ForAttribute").Single().Outputs.Single().Reason) Assert.Equal(IncrementalStepRunReason.Removed, runResult.TrackedSteps("result_ForAttribute").Single().Outputs.Single().Reason) End Sub @@ -1259,14 +1254,13 @@ end class ")))) runResult = driver.GetRunResult().Results(0) - Assert.Collection(runResult.TrackedSteps("individualFileGlobalAliases_ForAttribute"), - Sub(_step) Assert.Equal(IncrementalStepRunReason.Unchanged, _step.Outputs.Single().Reason)) - Assert.Equal(IncrementalStepRunReason.Cached, runResult.TrackedSteps("collectedGlobalAliases_ForAttribute").Single().Outputs.Single().Reason) + Assert.False(runResult.TrackedSteps.ContainsKey("individualFileGlobalAliases_ForAttribute")) + Assert.Equal(IncrementalStepRunReason.Unchanged, runResult.TrackedSteps("collectedGlobalAliases_ForAttribute").Single().Outputs.Single().Reason) Assert.Equal(IncrementalStepRunReason.Cached, runResult.TrackedSteps("allUpGlobalAliases_ForAttribute").Single().Outputs.Single().Reason) Assert.Equal(IncrementalStepRunReason.Modified, runResult.TrackedSteps("compilationUnit_ForAttribute").Single().Outputs.Single().Reason) - Assert.Equal(IncrementalStepRunReason.Modified, runResult.TrackedSteps("compilationUnitAndGlobalAliases_ForAttribute").Single().Outputs.Single().Reason) - Assert.Equal(IncrementalStepRunReason.Modified, runResult.TrackedSteps("result_ForAttribute").Single().Outputs.Single().Reason) + Assert.Equal(IncrementalStepRunReason.New, runResult.TrackedSteps("compilationUnitAndGlobalAliases_ForAttribute").Single().Outputs.Single().Reason) + Assert.Equal(IncrementalStepRunReason.New, runResult.TrackedSteps("result_ForAttribute").Single().Outputs.Single().Reason) Assert.Collection(runResult.TrackedSteps("result_ForAttribute"), Sub(_step) Assert.True(IsClassStatementWithName(_step.Outputs.Single().Value, "C"))) @@ -1302,9 +1296,8 @@ end class GlobalImport.Parse("BAttribute = AAttribute")))) runResult = driver.GetRunResult().Results(0) - Assert.Collection(runResult.TrackedSteps("individualFileGlobalAliases_ForAttribute"), - Sub(_step) Assert.Equal(IncrementalStepRunReason.Cached, _step.Outputs.Single().Reason)) - Assert.Equal(IncrementalStepRunReason.Cached, runResult.TrackedSteps("collectedGlobalAliases_ForAttribute").Single().Outputs.Single().Reason) + Assert.False(runResult.TrackedSteps.ContainsKey("individualFileGlobalAliases_ForAttribute")) + Assert.Equal(IncrementalStepRunReason.Unchanged, runResult.TrackedSteps("collectedGlobalAliases_ForAttribute").Single().Outputs.Single().Reason) Assert.Equal(IncrementalStepRunReason.Cached, runResult.TrackedSteps("allUpGlobalAliases_ForAttribute").Single().Outputs.Single().Reason) Assert.Equal(IncrementalStepRunReason.Unchanged, runResult.TrackedSteps("compilationUnit_ForAttribute").Single().Outputs.Single().Reason) @@ -1341,14 +1334,13 @@ end class runResult = driver.GetRunResult().Results(0) - Assert.Collection(runResult.TrackedSteps("individualFileGlobalAliases_ForAttribute"), - Sub(_step) Assert.Equal(IncrementalStepRunReason.Cached, _step.Outputs.Single().Reason)) - Assert.Equal(IncrementalStepRunReason.Cached, runResult.TrackedSteps("collectedGlobalAliases_ForAttribute").Single().Outputs.Single().Reason) + Assert.False(runResult.TrackedSteps.ContainsKey("individualFileGlobalAliases_ForAttribute")) + Assert.Equal(IncrementalStepRunReason.Unchanged, runResult.TrackedSteps("collectedGlobalAliases_ForAttribute").Single().Outputs.Single().Reason) Assert.Equal(IncrementalStepRunReason.Cached, runResult.TrackedSteps("allUpGlobalAliases_ForAttribute").Single().Outputs.Single().Reason) Assert.Equal(IncrementalStepRunReason.Unchanged, runResult.TrackedSteps("compilationUnit_ForAttribute").Single().Outputs.Single().Reason) Assert.Equal(IncrementalStepRunReason.Modified, runResult.TrackedSteps("compilationUnitAndGlobalAliases_ForAttribute").Single().Outputs.Single().Reason) - Assert.Equal(IncrementalStepRunReason.Modified, runResult.TrackedSteps("result_ForAttribute").Single().Outputs.Single().Reason) + Assert.Equal(IncrementalStepRunReason.New, runResult.TrackedSteps("result_ForAttribute").Single().Outputs.Single().Reason) Assert.Collection(runResult.TrackedSteps("result_ForAttribute"), Sub(_step) Assert.True(IsClassStatementWithName(_step.Outputs.Single().Value, "C"))) @@ -1380,14 +1372,13 @@ end class compilation.Options.GlobalImports.Add(GlobalImport.Parse("BAttribute = XAttribute"))))) runResult = driver.GetRunResult().Results(0) - Assert.Collection(runResult.TrackedSteps("individualFileGlobalAliases_ForAttribute"), - Sub(_step) Assert.Equal(IncrementalStepRunReason.Cached, _step.Outputs.Single().Reason)) - Assert.Equal(IncrementalStepRunReason.Cached, runResult.TrackedSteps("collectedGlobalAliases_ForAttribute").Single().Outputs.Single().Reason) + Assert.False(runResult.TrackedSteps.ContainsKey("individualFileGlobalAliases_ForAttribute")) + Assert.Equal(IncrementalStepRunReason.Unchanged, runResult.TrackedSteps("collectedGlobalAliases_ForAttribute").Single().Outputs.Single().Reason) Assert.Equal(IncrementalStepRunReason.Cached, runResult.TrackedSteps("allUpGlobalAliases_ForAttribute").Single().Outputs.Single().Reason) Assert.Equal(IncrementalStepRunReason.Unchanged, runResult.TrackedSteps("compilationUnit_ForAttribute").Single().Outputs.Single().Reason) Assert.Equal(IncrementalStepRunReason.Modified, runResult.TrackedSteps("compilationUnitAndGlobalAliases_ForAttribute").Single().Outputs.Single().Reason) - Assert.Equal(IncrementalStepRunReason.Modified, runResult.TrackedSteps("result_ForAttribute").Single().Outputs.Single().Reason) + Assert.Equal(IncrementalStepRunReason.New, runResult.TrackedSteps("result_ForAttribute").Single().Outputs.Single().Reason) Assert.Collection(runResult.TrackedSteps("result_ForAttribute"), Sub(_step) Assert.True(IsClassStatementWithName(_step.Outputs.Single().Value, "C"))) @@ -1425,15 +1416,12 @@ class D end class")))) runResult = driver.GetRunResult().Results(0) - Assert.Collection(runResult.TrackedSteps("individualFileGlobalAliases_ForAttribute"), - Sub(_step) Assert.Equal(IncrementalStepRunReason.Cached, _step.Outputs.Single().Reason), - Sub(_step) Assert.Equal(IncrementalStepRunReason.New, _step.Outputs.Single().Reason)) - Assert.Equal(IncrementalStepRunReason.Modified, runResult.TrackedSteps("collectedGlobalAliases_ForAttribute").Single().Outputs.Single().Reason) - Assert.Equal(IncrementalStepRunReason.Unchanged, runResult.TrackedSteps("allUpGlobalAliases_ForAttribute").Single().Outputs.Single().Reason) + Assert.False(runResult.TrackedSteps.ContainsKey("individualFileGlobalAliases_ForAttribute")) + Assert.Equal(IncrementalStepRunReason.Unchanged, runResult.TrackedSteps("collectedGlobalAliases_ForAttribute").Single().Outputs.Single().Reason) + Assert.Equal(IncrementalStepRunReason.Cached, runResult.TrackedSteps("allUpGlobalAliases_ForAttribute").Single().Outputs.Single().Reason) Assert.Collection(runResult.TrackedSteps("compilationUnit_ForAttribute").Single().Outputs, - Sub(o) Assert.Equal(IncrementalStepRunReason.Unchanged, o.Reason), - Sub(o) Assert.Equal(IncrementalStepRunReason.Modified, o.Reason)) + Sub(o) Assert.Equal(IncrementalStepRunReason.Unchanged, o.Reason)) Assert.Equal(IncrementalStepRunReason.Cached, runResult.TrackedSteps("compilationUnitAndGlobalAliases_ForAttribute").Single().Outputs.Single().Reason) Assert.Equal(IncrementalStepRunReason.Cached, runResult.TrackedSteps("result_ForAttribute").Single().Outputs.Single().Reason) End Sub @@ -1471,11 +1459,9 @@ class D end class")))) runResult = driver.GetRunResult().Results(0) - Assert.Collection(runResult.TrackedSteps("individualFileGlobalAliases_ForAttribute"), - Sub(_step) Assert.Equal(IncrementalStepRunReason.Cached, _step.Outputs.Single().Reason), - Sub(_step) Assert.Equal(IncrementalStepRunReason.New, _step.Outputs.Single().Reason)) - Assert.Equal(IncrementalStepRunReason.Modified, runResult.TrackedSteps("collectedGlobalAliases_ForAttribute").Single().Outputs.Single().Reason) - Assert.Equal(IncrementalStepRunReason.Unchanged, runResult.TrackedSteps("allUpGlobalAliases_ForAttribute").Single().Outputs.Single().Reason) + Assert.False(runResult.TrackedSteps.ContainsKey("individualFileGlobalAliases_ForAttribute")) + Assert.Equal(IncrementalStepRunReason.Unchanged, runResult.TrackedSteps("collectedGlobalAliases_ForAttribute").Single().Outputs.Single().Reason) + Assert.Equal(IncrementalStepRunReason.Cached, runResult.TrackedSteps("allUpGlobalAliases_ForAttribute").Single().Outputs.Single().Reason) Assert.Collection(runResult.TrackedSteps("compilationUnit_ForAttribute").Single().Outputs, Sub(_step) Assert.Equal(IncrementalStepRunReason.Unchanged, _step.Reason), @@ -1526,9 +1512,8 @@ class D end class")))) runResult = driver.GetRunResult().Results(0) - Assert.Collection(runResult.TrackedSteps("individualFileGlobalAliases_ForAttribute"), - Sub(_step) Assert.Equal(IncrementalStepRunReason.Unchanged, _step.Outputs.Single().Reason)) - Assert.Equal(IncrementalStepRunReason.Cached, runResult.TrackedSteps("collectedGlobalAliases_ForAttribute").Single().Outputs.Single().Reason) + Assert.False(runResult.TrackedSteps.ContainsKey("individualFileGlobalAliases_ForAttribute")) + Assert.Equal(IncrementalStepRunReason.Unchanged, runResult.TrackedSteps("collectedGlobalAliases_ForAttribute").Single().Outputs.Single().Reason) Assert.Equal(IncrementalStepRunReason.Cached, runResult.TrackedSteps("allUpGlobalAliases_ForAttribute").Single().Outputs.Single().Reason) Assert.Equal(IncrementalStepRunReason.Modified, runResult.TrackedSteps("compilationUnit_ForAttribute").Single().Outputs.Single().Reason) diff --git a/src/Compilers/VisualBasic/Test/Symbol/SymbolDisplay/SymbolDisplayTests.vb b/src/Compilers/VisualBasic/Test/Symbol/SymbolDisplay/SymbolDisplayTests.vb index 0abaf62ee07e1..e2b1cdd3c6310 100644 --- a/src/Compilers/VisualBasic/Test/Symbol/SymbolDisplay/SymbolDisplayTests.vb +++ b/src/Compilers/VisualBasic/Test/Symbol/SymbolDisplay/SymbolDisplayTests.vb @@ -5283,7 +5283,12 @@ ref struct S ref readonly T F2; }" Dim comp = CreateCSharpCompilation(GetUniqueName(), source, parseOptions:=New CSharp.CSharpParseOptions(CSharp.LanguageVersion.Preview)) - comp.VerifyDiagnostics() + ' error CS9064: Target runtime doesn't support ref fields. + comp.VerifyDiagnostics( + { + Diagnostic(9064, "F1").WithLocation(4, 11), + Diagnostic(9064, "F2").WithLocation(5, 20) + }) Dim type = comp.GlobalNamespace.GetTypeMembers("S").Single() @@ -5329,7 +5334,7 @@ ref struct S "ref struct R { } class Program { - static void F(scoped R r1, in scoped R r2, scoped ref R r3) { } + static void F(scoped R r1, scoped ref R r3) { } }" Dim comp = CreateCSharpCompilation(GetUniqueName(), source, parseOptions:=New CSharp.CSharpParseOptions(CSharp.LanguageVersion.Preview)) comp.VerifyDiagnostics() @@ -5341,7 +5346,7 @@ class Program End If Verify(SymbolDisplay.ToDisplayParts(method, format), - "Sub Program.F(r1 As R, r2 As R, r3 As R)", + "Sub Program.F(r1 As R, r3 As R)", SymbolDisplayPartKind.Keyword, SymbolDisplayPartKind.Space, SymbolDisplayPartKind.ClassName, @@ -5360,13 +5365,6 @@ class Program SymbolDisplayPartKind.Keyword, SymbolDisplayPartKind.Space, SymbolDisplayPartKind.StructName, - SymbolDisplayPartKind.Punctuation, - SymbolDisplayPartKind.Space, - SymbolDisplayPartKind.ParameterName, - SymbolDisplayPartKind.Space, - SymbolDisplayPartKind.Keyword, - SymbolDisplayPartKind.Space, - SymbolDisplayPartKind.StructName, SymbolDisplayPartKind.Punctuation) End Sub @@ -5383,9 +5381,8 @@ class Program { static void M(R r0) { - scoped R r1; - ref readonly scoped R r2 = ref r1; - scoped ref R r3 = ref r0; + scoped R r1 = r0; + scoped ref readonly R r3 = ref r0; } }" Dim comp = CreateCSharpCompilation(GetUniqueName(), source, parseOptions:=New CSharp.CSharpParseOptions(CSharp.LanguageVersion.Preview)) @@ -5409,14 +5406,6 @@ class Program SymbolDisplayPartKind.StructName) Verify(SymbolDisplay.ToDisplayParts(locals(1), format), - "r2 As R", - SymbolDisplayPartKind.LocalName, - SymbolDisplayPartKind.Space, - SymbolDisplayPartKind.Keyword, - SymbolDisplayPartKind.Space, - SymbolDisplayPartKind.StructName) - - Verify(SymbolDisplay.ToDisplayParts(locals(2), format), "r3 As R", SymbolDisplayPartKind.LocalName, SymbolDisplayPartKind.Space, diff --git a/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/Metadata/PE/NoPia.vb b/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/Metadata/PE/NoPia.vb index 0d5e9629e8a30..20b7a83d0527a 100644 --- a/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/Metadata/PE/NoPia.vb +++ b/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/Metadata/PE/NoPia.vb @@ -1249,6 +1249,80 @@ Derived ]]>) End Sub + + + Public Sub ExplicitInterfaceImplementations() + Dim sourcePIA = +"Imports System.Runtime.InteropServices + + + + +public interface I1 + Function F1() As Integer +end interface +" + Dim sourceBase = +" +public class C + public Function F1() As Long + Return 0 + End Function +end class + +public class Base + Inherits C + Implements I1 + + Function I1F1() As Integer Implements I1.F1 + throw new System.NotImplementedException() + end Function +end class +" + Dim verify = Sub(compilationDerived As VisualBasicCompilation) + Dim i1F1 = compilationDerived.GetTypeByMetadataName("I1").GetMember(Of MethodSymbol)("F1") + Dim baseI1F1 = compilationDerived.GetTypeByMetadataName("Base").GetMember(Of MethodSymbol)("I1F1") + Assert.Same(i1F1, baseI1F1.ExplicitInterfaceImplementations.Single()) + compilationDerived.AssertNoDiagnostics() + End Sub + + + Dim compilationPIA = CreateCompilation(sourcePIA, options:=TestOptions.DebugDll) + compilationPIA.AssertNoDiagnostics() + + Dim referencePIAImage = compilationPIA.EmitToImageReference(embedInteropTypes:=true) + Dim referencePIASource = compilationPIA.ToMetadataReference(embedInteropTypes:=True) + + Dim compilationBase = CreateCompilation(sourceBase, {referencePIASource}, TestOptions.DebugDll) + compilationBase.AssertNoDiagnostics() + + Dim referenceBaseImage = compilationBase.EmitToImageReference() + Dim referenceBaseSource = compilationBase.ToMetadataReference() + + Dim sourceDerived = +" +public interface I2 + Inherits I1 +End Interface + +public class Derived + Inherits Base + Implements I2 +end class +" + Dim compilationDerived1 = CreateCompilation(sourceDerived, {referencePIASource, referenceBaseSource}, TestOptions.DebugDll) + verify(compilationDerived1) + + Dim compilationDerived2 = CreateCompilation(sourceDerived, {referencePIAImage, referenceBaseSource}, TestOptions.DebugDll) + verify(compilationDerived2) + + Dim compilationDerived3 = CreateCompilation(sourceDerived, {referencePIASource, referenceBaseImage}, TestOptions.DebugDll) + verify(compilationDerived3) + + Dim compilationDerived4 = CreateCompilation(sourceDerived, {referencePIAImage, referenceBaseImage}, TestOptions.DebugDll) + verify(compilationDerived4) + End Sub + End Class End Namespace diff --git a/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/WellKnownTypeValidationTests.vb b/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/WellKnownTypeValidationTests.vb index 77ead726d1968..17e19e02660bc 100644 --- a/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/WellKnownTypeValidationTests.vb +++ b/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/WellKnownTypeValidationTests.vb @@ -551,8 +551,10 @@ End Namespace WellKnownType.System_Diagnostics_CodeAnalysis_SetsRequiredMembersAttribute, WellKnownType.System_MemoryExtensions, WellKnownType.System_Runtime_CompilerServices_CompilerFeatureRequiredAttribute, - WellKnownType.System_Runtime_CompilerServices_LifetimeAnnotationAttribute, - WellKnownType.System_MemoryExtensions + WellKnownType.System_Runtime_CompilerServices_ScopedRefAttribute, + WellKnownType.System_Diagnostics_CodeAnalysis_UnscopedRefAttribute, + WellKnownType.System_MemoryExtensions, + WellKnownType.System_Runtime_CompilerServices_MetadataUpdateOriginalTypeAttribute ' Not available on all platforms. Continue For Case WellKnownType.ExtSentinel @@ -623,7 +625,9 @@ End Namespace WellKnownType.System_Diagnostics_CodeAnalysis_SetsRequiredMembersAttribute, WellKnownType.System_MemoryExtensions, WellKnownType.System_Runtime_CompilerServices_CompilerFeatureRequiredAttribute, - WellKnownType.System_Runtime_CompilerServices_LifetimeAnnotationAttribute + WellKnownType.System_Runtime_CompilerServices_ScopedRefAttribute, + WellKnownType.System_Diagnostics_CodeAnalysis_UnscopedRefAttribute, + WellKnownType.System_Runtime_CompilerServices_MetadataUpdateOriginalTypeAttribute ' Not available on all platforms. Continue For Case WellKnownType.ExtSentinel @@ -715,11 +719,13 @@ End Namespace WellKnownMember.System_Runtime_CompilerServices_DefaultInterpolatedStringHandler__ToStringAndClear, WellKnownMember.System_Runtime_CompilerServices_RequiredMemberAttribute__ctor, WellKnownMember.System_Diagnostics_CodeAnalysis_SetsRequiredMembersAttribute__ctor, - WellKnownMember.System_Runtime_CompilerServices_LifetimeAnnotationAttribute__ctor, + WellKnownMember.System_Runtime_CompilerServices_ScopedRefAttribute__ctor, WellKnownMember.System_MemoryExtensions__SequenceEqual_Span_T, WellKnownMember.System_MemoryExtensions__SequenceEqual_ReadOnlySpan_T, WellKnownMember.System_MemoryExtensions__AsSpan_String, - WellKnownMember.System_Runtime_CompilerServices_CompilerFeatureRequiredAttribute__ctor + WellKnownMember.System_Runtime_CompilerServices_CompilerFeatureRequiredAttribute__ctor, + WellKnownMember.System_Diagnostics_CodeAnalysis_UnscopedRefAttribute__ctor, + WellKnownMember.System_Runtime_CompilerServices_MetadataUpdateOriginalTypeAttribute__ctor ' Not available yet, but will be in upcoming release. Continue For Case WellKnownMember.Microsoft_CodeAnalysis_Runtime_Instrumentation__CreatePayloadForMethodsSpanningSingleFile, @@ -867,11 +873,13 @@ End Namespace WellKnownMember.System_Runtime_CompilerServices_DefaultInterpolatedStringHandler__ToStringAndClear, WellKnownMember.System_Runtime_CompilerServices_RequiredMemberAttribute__ctor, WellKnownMember.System_Diagnostics_CodeAnalysis_SetsRequiredMembersAttribute__ctor, - WellKnownMember.System_Runtime_CompilerServices_LifetimeAnnotationAttribute__ctor, + WellKnownMember.System_Runtime_CompilerServices_ScopedRefAttribute__ctor, WellKnownMember.System_MemoryExtensions__SequenceEqual_Span_T, WellKnownMember.System_MemoryExtensions__SequenceEqual_ReadOnlySpan_T, WellKnownMember.System_MemoryExtensions__AsSpan_String, - WellKnownMember.System_Runtime_CompilerServices_CompilerFeatureRequiredAttribute__ctor + WellKnownMember.System_Runtime_CompilerServices_CompilerFeatureRequiredAttribute__ctor, + WellKnownMember.System_Diagnostics_CodeAnalysis_UnscopedRefAttribute__ctor, + WellKnownMember.System_Runtime_CompilerServices_MetadataUpdateOriginalTypeAttribute__ctor ' Not available yet, but will be in upcoming release. Continue For Case WellKnownMember.Microsoft_CodeAnalysis_Runtime_Instrumentation__CreatePayloadForMethodsSpanningSingleFile, diff --git a/src/Compilers/VisualBasic/Test/Syntax/Scanner/ScannerTests.vb b/src/Compilers/VisualBasic/Test/Syntax/Scanner/ScannerTests.vb index 6ff532af2dd16..d3c1b05e71550 100644 --- a/src/Compilers/VisualBasic/Test/Syntax/Scanner/ScannerTests.vb +++ b/src/Compilers/VisualBasic/Test/Syntax/Scanner/ScannerTests.vb @@ -388,6 +388,313 @@ Public Class ScannerTests Assert.Equal(ERRID.ERR_Merge_conflict_marker_encountered, err.Code) End Sub + + Public Sub TestEqualsConflictMarker3() + Dim token = SyntaxFactory.ParseTokens("======= trailing chars" & vbCrLf & "======= more trailing chars").First() + Assert.Equal(SyntaxKind.EndOfFileToken, token.Kind()) + Assert.True(token.HasLeadingTrivia) + Assert.Equal(3, token.LeadingTrivia.Count) + + Dim trivia = token.LeadingTrivia(0) + Assert.True(trivia.Kind() = SyntaxKind.ConflictMarkerTrivia) + Assert.Equal(trivia.Span.Length, 22) + Assert.Equal("======= trailing chars", trivia.ToFullString()) + Assert.True(trivia.ContainsDiagnostics) + Assert.Equal(ERRID.ERR_Merge_conflict_marker_encountered, trivia.Errors().First().Code) + + trivia = token.LeadingTrivia(1) + Assert.True(trivia.Kind() = SyntaxKind.EndOfLineTrivia) + Assert.Equal(trivia.Span.Start, 22) + Assert.Equal(trivia.Span.Length, 2) + + trivia = token.LeadingTrivia(2) + Assert.True(trivia.Kind() = SyntaxKind.DisabledTextTrivia) + Assert.Equal(trivia.Span.Start, 24) + Assert.Equal(trivia.Span.Length, 27) + Assert.Equal("======= more trailing chars", trivia.ToFullString()) + End Sub + + + Public Sub TestPipeConflictMarker1() + ' Has to be the start of a line. + Dim token = SyntaxFactory.ParseTokens(" |||||||").First() + Assert.Equal(SyntaxKind.BadToken, token.Kind()) + Assert.True(token.HasLeadingTrivia) + Assert.True(token.LeadingTrivia.Single().Kind() = SyntaxKind.WhitespaceTrivia) + + ' Has to have at least seven characters. + token = SyntaxFactory.ParseTokens("|||||| ").First() + Assert.Equal(SyntaxKind.BadToken, token.Kind()) + + ' Start of line, seven characters + token = SyntaxFactory.ParseTokens("|||||||").First() + Assert.Equal(SyntaxKind.EndOfFileToken, token.Kind()) + Assert.True(token.HasLeadingTrivia) + Assert.True(token.LeadingTrivia.Single().Kind() = SyntaxKind.ConflictMarkerTrivia) + + ' Start of line, seven characters + token = SyntaxFactory.ParseTokens("||||||| trailing chars").First() + Assert.Equal(SyntaxKind.EndOfFileToken, token.Kind()) + Assert.True(token.HasLeadingTrivia) + Dim trivia = token.LeadingTrivia.Single() + Assert.True(trivia.Kind() = SyntaxKind.ConflictMarkerTrivia) + Assert.Equal(trivia.Span.Length, 22) + + Assert.True(trivia.ContainsDiagnostics) + Dim err = trivia.Errors().First + Assert.Equal(ERRID.ERR_Merge_conflict_marker_encountered, err.Code) + + token = SyntaxFactory.ParseTokens("||||||| Trailing" & vbCrLf & "disabled text").First() + Assert.Equal(SyntaxKind.EndOfFileToken, token.Kind()) + Assert.True(token.HasLeadingTrivia) + Assert.Equal(3, token.LeadingTrivia.Count) + trivia = token.LeadingTrivia(0) + Assert.True(trivia.Kind() = SyntaxKind.ConflictMarkerTrivia) + Assert.Equal(trivia.Span.Length, 16) + + Assert.True(trivia.ContainsDiagnostics) + err = trivia.Errors().First + Assert.Equal(ERRID.ERR_Merge_conflict_marker_encountered, err.Code) + + trivia = token.LeadingTrivia(1) + Assert.True(trivia.Kind() = SyntaxKind.EndOfLineTrivia) + Assert.Equal(trivia.Span.Start, 16) + Assert.Equal(trivia.Span.Length, 2) + + trivia = token.LeadingTrivia(2) + Assert.True(trivia.Kind() = SyntaxKind.DisabledTextTrivia) + Assert.Equal(trivia.Span.Start, 18) + Assert.Equal(trivia.Span.Length, 13) + + token = SyntaxFactory.ParseTokens("||||||| Trailing" & vbCrLf & "disabled text" & vbCrLf & ">>>> still disabled").First() + Assert.Equal(SyntaxKind.EndOfFileToken, token.Kind()) + Assert.True(token.HasLeadingTrivia) + Assert.Equal(3, token.LeadingTrivia.Count) + + trivia = token.LeadingTrivia(0) + Assert.True(trivia.Kind() = SyntaxKind.ConflictMarkerTrivia) + Assert.Equal(trivia.Span.Length, 16) + + Assert.True(trivia.ContainsDiagnostics) + err = trivia.Errors().First + Assert.Equal(ERRID.ERR_Merge_conflict_marker_encountered, err.Code) + + trivia = token.LeadingTrivia(1) + Assert.True(trivia.Kind() = SyntaxKind.EndOfLineTrivia) + Assert.Equal(trivia.Span.Length, 2) + + trivia = token.LeadingTrivia(2) + Assert.True(trivia.Kind() = SyntaxKind.DisabledTextTrivia) + Assert.Equal(trivia.Span.Length, 34) + + + token = SyntaxFactory.ParseTokens("||||||| Trailing" & vbCrLf & "disabled text" & vbCrLf & ">>>>>>> Actually the end").First() + Assert.Equal(SyntaxKind.EndOfFileToken, token.Kind()) + Assert.True(token.HasLeadingTrivia) + Assert.Equal(token.LeadingTrivia.Count, 4) + Dim trivia1 = token.LeadingTrivia(0) + Assert.True(trivia1.Kind() = SyntaxKind.ConflictMarkerTrivia) + Assert.Equal(trivia1.Span.Length, 16) + + Assert.True(trivia1.ContainsDiagnostics) + err = trivia1.Errors().First + Assert.Equal(ERRID.ERR_Merge_conflict_marker_encountered, err.Code) + + Dim trivia2 = token.LeadingTrivia(1) + Assert.True(trivia2.Kind() = SyntaxKind.EndOfLineTrivia) + Assert.Equal(trivia2.Span.Start, 16) + Assert.Equal(trivia2.Span.Length, 2) + + Dim trivia3 = token.LeadingTrivia(2) + Assert.True(trivia3.Kind() = SyntaxKind.DisabledTextTrivia) + Assert.Equal(trivia3.Span.Start, 18) + Assert.Equal(trivia3.Span.Length, 15) + + Dim trivia4 = token.LeadingTrivia(3) + Assert.True(trivia4.Kind() = SyntaxKind.ConflictMarkerTrivia) + Assert.Equal(trivia4.Span.Start, 33) + Assert.Equal(trivia4.Span.Length, 24) + + Assert.True(trivia4.ContainsDiagnostics) + err = trivia4.Errors().First + Assert.Equal(ERRID.ERR_Merge_conflict_marker_encountered, err.Code) + End Sub + + + Public Sub TestPipeConflictMarker2() + ' Has to be the start of a line. + Dim token = SyntaxFactory.ParseTokens("{" & vbCrLf & " |||||||").Skip(2).First() + Assert.Equal(SyntaxKind.BadToken, token.Kind()) + Assert.True(token.HasLeadingTrivia) + Assert.True(token.LeadingTrivia.Single().Kind() = SyntaxKind.WhitespaceTrivia) + + ' Has to have at least seven characters. + token = SyntaxFactory.ParseTokens("{" & vbCrLf & "|||||| ").Skip(2).First() + Assert.Equal(SyntaxKind.BadToken, token.Kind()) + + ' Start of line, seven characters + token = SyntaxFactory.ParseTokens("{" & vbCrLf & "|||||||").Skip(2).First() + Assert.Equal(SyntaxKind.EndOfFileToken, token.Kind()) + Assert.True(token.HasLeadingTrivia) + Dim trivia = token.LeadingTrivia.Single() + Assert.True(trivia.Kind() = SyntaxKind.ConflictMarkerTrivia) + + Assert.True(trivia.ContainsDiagnostics) + Dim err = trivia.Errors().First + Assert.Equal(ERRID.ERR_Merge_conflict_marker_encountered, err.Code) + + + ' Start of line, seven characters + token = SyntaxFactory.ParseTokens("{" & vbCrLf & "||||||| trailing chars").Skip(2).First() + Assert.Equal(SyntaxKind.EndOfFileToken, token.Kind()) + Assert.True(token.HasLeadingTrivia) + trivia = token.LeadingTrivia.Single() + Assert.True(trivia.Kind() = SyntaxKind.ConflictMarkerTrivia) + Assert.Equal(trivia.Span.Length, 22) + + Assert.True(trivia.ContainsDiagnostics) + err = trivia.Errors().First + Assert.Equal(ERRID.ERR_Merge_conflict_marker_encountered, err.Code) + + token = SyntaxFactory.ParseTokens("{" & vbCrLf & "||||||| Trailing" & vbCrLf & "disabled text").Skip(2).First() + Assert.Equal(SyntaxKind.EndOfFileToken, token.Kind()) + Assert.True(token.HasLeadingTrivia) + Assert.Equal(3, token.LeadingTrivia.Count) + trivia = token.LeadingTrivia(0) + Assert.True(trivia.Kind() = SyntaxKind.ConflictMarkerTrivia) + Assert.Equal(trivia.Span.Length, 16) + + Assert.True(trivia.ContainsDiagnostics) + err = trivia.Errors().First + Assert.Equal(ERRID.ERR_Merge_conflict_marker_encountered, err.Code) + + trivia = token.LeadingTrivia(1) + Assert.True(trivia.Kind() = SyntaxKind.EndOfLineTrivia) + Assert.Equal(trivia.Span.Start, 19) + Assert.Equal(trivia.Span.Length, 2) + + trivia = token.LeadingTrivia(2) + Assert.True(trivia.Kind() = SyntaxKind.DisabledTextTrivia) + Assert.Equal(trivia.Span.Start, 21) + Assert.Equal(trivia.Span.Length, 13) + + token = SyntaxFactory.ParseTokens("{" & vbCrLf & "||||||| Trailing" & vbCrLf & "disabled text" & vbCrLf & ">>>> still disabled").Skip(2).First() + Assert.Equal(SyntaxKind.EndOfFileToken, token.Kind()) + Assert.True(token.HasLeadingTrivia) + Assert.Equal(3, token.LeadingTrivia.Count) + + trivia = token.LeadingTrivia(0) + Assert.True(trivia.Kind() = SyntaxKind.ConflictMarkerTrivia) + Assert.Equal(trivia.Span.Length, 16) + + Assert.True(trivia.ContainsDiagnostics) + err = trivia.Errors().First + Assert.Equal(ERRID.ERR_Merge_conflict_marker_encountered, err.Code) + + trivia = token.LeadingTrivia(1) + Assert.True(trivia.Kind() = SyntaxKind.EndOfLineTrivia) + Assert.Equal(trivia.Span.Length, 2) + + trivia = token.LeadingTrivia(2) + Assert.True(trivia.Kind() = SyntaxKind.DisabledTextTrivia) + Assert.Equal(trivia.Span.Length, 34) + + + token = SyntaxFactory.ParseTokens("{" & vbCrLf & "||||||| Trailing" & vbCrLf & "disabled text" & vbCrLf & ">>>>>>> Actually the end").Skip(2).First() + Assert.Equal(SyntaxKind.EndOfFileToken, token.Kind()) + Assert.True(token.HasLeadingTrivia) + Assert.Equal(token.LeadingTrivia.Count, 4) + Dim trivia1 = token.LeadingTrivia(0) + Assert.True(trivia1.Kind() = SyntaxKind.ConflictMarkerTrivia) + Assert.Equal(trivia1.Span.Length, 16) + + Assert.True(trivia1.ContainsDiagnostics) + err = trivia1.Errors().First + Assert.Equal(ERRID.ERR_Merge_conflict_marker_encountered, err.Code) + + Dim trivia2 = token.LeadingTrivia(1) + Assert.True(trivia2.Kind() = SyntaxKind.EndOfLineTrivia) + Assert.Equal(trivia2.Span.Start, 19) + Assert.Equal(trivia2.Span.Length, 2) + + Dim trivia3 = token.LeadingTrivia(2) + Assert.True(trivia3.Kind() = SyntaxKind.DisabledTextTrivia) + Assert.Equal(trivia3.Span.Start, 21) + Assert.Equal(trivia3.Span.Length, 15) + + Dim trivia4 = token.LeadingTrivia(3) + Assert.True(trivia4.Kind() = SyntaxKind.ConflictMarkerTrivia) + Assert.Equal(trivia4.Span.Start, 36) + Assert.Equal(trivia4.Span.Length, 24) + + Assert.True(trivia4.ContainsDiagnostics) + err = trivia4.Errors().First + Assert.Equal(ERRID.ERR_Merge_conflict_marker_encountered, err.Code) + End Sub + + + Public Sub TestPipeConflictMarker3() + Dim token = SyntaxFactory.ParseTokens("||||||| trailing chars" & vbCrLf & "||||||| more trailing chars").First() + Assert.Equal(SyntaxKind.EndOfFileToken, token.Kind()) + Assert.True(token.HasLeadingTrivia) + Assert.Equal(3, token.LeadingTrivia.Count) + + Dim trivia = token.LeadingTrivia(0) + Assert.True(trivia.Kind() = SyntaxKind.ConflictMarkerTrivia) + Assert.Equal(trivia.Span.Length, 22) + Assert.Equal("||||||| trailing chars", trivia.ToFullString()) + Assert.True(trivia.ContainsDiagnostics) + Assert.Equal(ERRID.ERR_Merge_conflict_marker_encountered, trivia.Errors().First().Code) + + trivia = token.LeadingTrivia(1) + Assert.True(trivia.Kind() = SyntaxKind.EndOfLineTrivia) + Assert.Equal(trivia.Span.Start, 22) + Assert.Equal(trivia.Span.Length, 2) + + trivia = token.LeadingTrivia(2) + Assert.True(trivia.Kind() = SyntaxKind.DisabledTextTrivia) + Assert.Equal(trivia.Span.Start, 24) + Assert.Equal(trivia.Span.Length, 27) + Assert.Equal("||||||| more trailing chars", trivia.ToFullString()) + End Sub + + + Public Sub TestPipeConflictMarker4() + Dim token = SyntaxFactory.ParseTokens("||||||| trailing chars" & vbCrLf & "disabled text" & vbCrLf & "======= more trailing chars" & vbCrLf & "more disabled text" & vbCrLf & ">>>>>>> end trailing chars").First() + Assert.Equal(SyntaxKind.EndOfFileToken, token.Kind()) + Assert.True(token.HasLeadingTrivia) + Assert.Equal(7, token.LeadingTrivia.Count) + + Dim trivia = token.LeadingTrivia(0) + Assert.True(trivia.Kind() = SyntaxKind.ConflictMarkerTrivia) + Assert.Equal("||||||| trailing chars", trivia.ToFullString()) + Assert.Equal(ERRID.ERR_Merge_conflict_marker_encountered, trivia.Errors().First().Code) + + trivia = token.LeadingTrivia(1) + Assert.True(trivia.Kind() = SyntaxKind.EndOfLineTrivia) + + trivia = token.LeadingTrivia(2) + Assert.True(trivia.Kind() = SyntaxKind.DisabledTextTrivia) + Assert.Equal("disabled text" & vbCrLf, trivia.ToFullString()) + + trivia = token.LeadingTrivia(3) + Assert.True(trivia.Kind() = SyntaxKind.ConflictMarkerTrivia) + Assert.Equal("======= more trailing chars", trivia.ToFullString()) + Assert.Equal(ERRID.ERR_Merge_conflict_marker_encountered, trivia.Errors().First().Code) + + trivia = token.LeadingTrivia(4) + Assert.True(trivia.Kind() = SyntaxKind.EndOfLineTrivia) + + trivia = token.LeadingTrivia(5) + Assert.True(trivia.Kind() = SyntaxKind.DisabledTextTrivia) + Assert.Equal("more disabled text" & vbCrLf, trivia.ToFullString()) + + trivia = token.LeadingTrivia(6) + Assert.True(trivia.Kind() = SyntaxKind.ConflictMarkerTrivia) + Assert.Equal(">>>>>>> end trailing chars", trivia.ToFullString()) + Assert.Equal(ERRID.ERR_Merge_conflict_marker_encountered, trivia.Errors().First().Code) + End Sub + Public Sub Scanner_EndOfText() Dim tk = ScanOnce("") diff --git a/src/Compilers/VisualBasic/vbc/VbcCommandLine.shproj b/src/Compilers/VisualBasic/vbc/VbcCommandLine.shproj index 933268ed79293..6ddb4dd2ca08e 100644 --- a/src/Compilers/VisualBasic/vbc/VbcCommandLine.shproj +++ b/src/Compilers/VisualBasic/vbc/VbcCommandLine.shproj @@ -11,6 +11,7 @@ Condition="Exists('$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\CodeSharing\Microsoft.CodeSharing.Common.Default.props')" /> + \ No newline at end of file diff --git a/src/EditorFeatures/CSharp/AutomaticCompletion/AutomaticLineEnderCommandHandler.cs b/src/EditorFeatures/CSharp/AutomaticCompletion/AutomaticLineEnderCommandHandler.cs index 568b79df42ad0..14b8ea2c5527a 100644 --- a/src/EditorFeatures/CSharp/AutomaticCompletion/AutomaticLineEnderCommandHandler.cs +++ b/src/EditorFeatures/CSharp/AutomaticCompletion/AutomaticLineEnderCommandHandler.cs @@ -56,8 +56,8 @@ internal partial class AutomaticLineEnderCommandHandler : AbstractAutomaticLineE public AutomaticLineEnderCommandHandler( ITextUndoHistoryRegistry undoRegistry, IEditorOperationsFactoryService editorOperations, - IGlobalOptionService globalOptions) - : base(undoRegistry, editorOperations, globalOptions) + EditorOptionsService editorOptionsService) + : base(undoRegistry, editorOperations, editorOptionsService) { } @@ -327,7 +327,7 @@ protected override void ModifySelectedNode( CancellationToken cancellationToken) { var root = document.GetRequiredSyntaxRootSynchronously(cancellationToken); - var formattingOptions = document.GetSyntaxFormattingOptionsAsync(GlobalOptions, cancellationToken).AsTask().WaitAndGetResult(cancellationToken); + var formattingOptions = args.SubjectBuffer.GetSyntaxFormattingOptions(EditorOptionsService, document.Project.Services, explicitFormat: false); // Add braces for the selected node if (addBrace) diff --git a/src/EditorFeatures/CSharp/AutomaticCompletion/AutomaticLineEnderCommandHandler_Helpers.cs b/src/EditorFeatures/CSharp/AutomaticCompletion/AutomaticLineEnderCommandHandler_Helpers.cs index 240d5c1d99d0f..60063fb902e03 100644 --- a/src/EditorFeatures/CSharp/AutomaticCompletion/AutomaticLineEnderCommandHandler_Helpers.cs +++ b/src/EditorFeatures/CSharp/AutomaticCompletion/AutomaticLineEnderCommandHandler_Helpers.cs @@ -31,7 +31,7 @@ private static (SyntaxNode newRoot, int nextCaretPosition) ReplaceStatementOwner SyntaxFormattingOptions formattingOptions, CancellationToken cancellationToken) { - var services = document.Project.Solution.Workspace.Services; + var services = document.Project.Solution.Services; var rootEditor = new SyntaxEditor(root, services); // 1. Insert the node before anchor node @@ -79,7 +79,7 @@ private static SyntaxNode ReplaceNodeAndFormat( var formattedNewRoot = Formatter.Format( newRoot, newNodeAfterInsertion.Span, - document.Project.Solution.Workspace.Services, + document.Project.Solution.Services, formattingOptions, cancellationToken); diff --git a/src/EditorFeatures/CSharp/CommentSelection/CSharpToggleBlockCommentCommandHandler.cs b/src/EditorFeatures/CSharp/CommentSelection/CSharpToggleBlockCommentCommandHandler.cs index 7049d35a3718b..23db743bda3dc 100644 --- a/src/EditorFeatures/CSharp/CommentSelection/CSharpToggleBlockCommentCommandHandler.cs +++ b/src/EditorFeatures/CSharp/CommentSelection/CSharpToggleBlockCommentCommandHandler.cs @@ -16,6 +16,7 @@ using Microsoft.CodeAnalysis.Text; using Microsoft.VisualStudio.Commanding; using Microsoft.VisualStudio.Text; +using Microsoft.VisualStudio.Text.Editor; using Microsoft.VisualStudio.Text.Operations; using Microsoft.VisualStudio.Utilities; using Roslyn.Utilities; @@ -34,8 +35,8 @@ public CSharpToggleBlockCommentCommandHandler( ITextUndoHistoryRegistry undoHistoryRegistry, IEditorOperationsFactoryService editorOperationsFactoryService, ITextStructureNavigatorSelectorService navigatorSelectorService, - IGlobalOptionService globalOptions) - : base(undoHistoryRegistry, editorOperationsFactoryService, navigatorSelectorService, globalOptions) + EditorOptionsService editorOptionsService) + : base(undoHistoryRegistry, editorOperationsFactoryService, navigatorSelectorService, editorOptionsService) { } @@ -43,10 +44,10 @@ public CSharpToggleBlockCommentCommandHandler( /// Retrieves block comments near the selection in the document. /// Uses the CSharp syntax tree to find the commented spans. /// - protected override async Task> GetBlockCommentsInDocumentAsync(Document document, ITextSnapshot snapshot, + protected override ImmutableArray GetBlockCommentsInDocument(Document document, ITextSnapshot snapshot, TextSpan linesContainingSelections, CommentSelectionInfo commentInfo, CancellationToken cancellationToken) { - var root = await document.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false); + var root = document.GetRequiredSyntaxRootSynchronously(cancellationToken); // Only search for block comments intersecting the lines in the selections. return root.DescendantTrivia(linesContainingSelections) .Where(trivia => trivia.IsKind(SyntaxKind.MultiLineCommentTrivia) || trivia.IsKind(SyntaxKind.MultiLineDocumentationCommentTrivia)) diff --git a/src/EditorFeatures/CSharp/CompleteStatement/CompleteStatementCommandHandler.cs b/src/EditorFeatures/CSharp/CompleteStatement/CompleteStatementCommandHandler.cs index 71248fcde3133..eef79e691c42d 100644 --- a/src/EditorFeatures/CSharp/CompleteStatement/CompleteStatementCommandHandler.cs +++ b/src/EditorFeatures/CSharp/CompleteStatement/CompleteStatementCommandHandler.cs @@ -15,7 +15,7 @@ using Microsoft.CodeAnalysis.Editor.Shared.Utilities; using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.Internal.Log; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Text; @@ -155,6 +155,11 @@ private static bool TryGetStartingNode( delimiters = startingNode.GetBrackets(); } + if (delimiters == default) + { + delimiters = startingNode.GetBraces(); + } + var (openingDelimiter, closingDelimiter) = delimiters; if (!openingDelimiter.IsKind(SyntaxKind.None) && openingDelimiter.Span.Start >= caretPosition || !closingDelimiter.IsKind(SyntaxKind.None) && closingDelimiter.Span.End <= caretPosition) @@ -194,7 +199,8 @@ private static bool MoveCaretToSemicolonPosition( SyntaxKind.CheckedExpression, SyntaxKind.UncheckedExpression, SyntaxKind.TypeOfExpression, - SyntaxKind.TupleExpression)) + SyntaxKind.TupleExpression, + SyntaxKind.SwitchExpression)) { // make sure the closing delimiter exists if (RequiredDelimiterIsMissing(currentNode)) @@ -460,7 +466,8 @@ private static bool StatementClosingDelimiterIsMissing(SyntaxNode currentNode) private static bool RequiredDelimiterIsMissing(SyntaxNode currentNode) { return currentNode.GetBrackets().closeBracket.IsMissing || - currentNode.GetParentheses().closeParen.IsMissing; + currentNode.GetParentheses().closeParen.IsMissing || + currentNode.GetBraces().closeBrace.IsMissing; } } } diff --git a/src/EditorFeatures/CSharp/ConvertNamespace/ConvertNamespaceCommandHandler.cs b/src/EditorFeatures/CSharp/ConvertNamespace/ConvertNamespaceCommandHandler.cs index 2dc085774397a..988705a995c3a 100644 --- a/src/EditorFeatures/CSharp/ConvertNamespace/ConvertNamespaceCommandHandler.cs +++ b/src/EditorFeatures/CSharp/ConvertNamespace/ConvertNamespaceCommandHandler.cs @@ -27,6 +27,8 @@ using Microsoft.VisualStudio.Text.Operations; using Microsoft.VisualStudio.Utilities; using Roslyn.Utilities; +using Microsoft.CodeAnalysis.Diagnostics; +using Microsoft.VisualStudio.Text.Editor; namespace Microsoft.CodeAnalysis.Editor.CSharp.CompleteStatement { @@ -50,17 +52,24 @@ internal sealed class ConvertNamespaceCommandHandler : IChainedCommandHandler nextCommandHandler) @@ -122,10 +131,10 @@ public void ExecuteCommand(TypeCharCommandArgs args, Action nextCommandHandler, return default; var cancellationToken = executionContext.OperationContext.UserCancellationToken; - var root = (CompilationUnitSyntax)document.GetRequiredSyntaxRootSynchronously(cancellationToken); + var parsedDocument = ParsedDocument.CreateSynchronously(document, cancellationToken); // User has to be *after* an identifier token. - var token = root.FindToken(caret); + var token = parsedDocument.Root.FindToken(caret); if (token.Kind() != SyntaxKind.IdentifierToken) return default; @@ -144,13 +153,11 @@ public void ExecuteCommand(TypeCharCommandArgs args, Action nextCommandHandler, return default; // Pass in our special options, and C#10 so that if we can convert this to file-scoped, we will. - if (!ConvertNamespaceAnalysis.CanOfferUseFileScoped(s_fileScopedNamespacePreferenceOption, root, namespaceDecl, forAnalyzer: true, LanguageVersion.CSharp10)) + if (!ConvertNamespaceAnalysis.CanOfferUseFileScoped(s_fileScopedNamespacePreferenceOption, (CompilationUnitSyntax)parsedDocument.Root, namespaceDecl, forAnalyzer: true, LanguageVersion.CSharp10)) return default; - var formattingOptions = document.GetSyntaxFormattingOptionsAsync(_globalOptions, cancellationToken).AsTask().WaitAndGetResult(cancellationToken); - var (converted, semicolonSpan) = ConvertNamespaceTransform.ConvertNamespaceDeclarationAsync(document, namespaceDecl, formattingOptions, cancellationToken).WaitAndGetResult(cancellationToken); - var text = converted.GetTextSynchronously(cancellationToken); - return (text, semicolonSpan); + var formattingOptions = subjectBuffer.GetSyntaxFormattingOptions(_editorOptionsService, document.Project.Services, explicitFormat: false); + return ConvertNamespaceTransform.ConvertNamespaceDeclaration(parsedDocument, namespaceDecl, formattingOptions, cancellationToken); } } } diff --git a/src/EditorFeatures/CSharp/DocumentationComments/DocumentationCommentCommandHandler.cs b/src/EditorFeatures/CSharp/DocumentationComments/DocumentationCommentCommandHandler.cs index de54c6c2ef306..7774c0c59432b 100644 --- a/src/EditorFeatures/CSharp/DocumentationComments/DocumentationCommentCommandHandler.cs +++ b/src/EditorFeatures/CSharp/DocumentationComments/DocumentationCommentCommandHandler.cs @@ -11,6 +11,7 @@ using Microsoft.CodeAnalysis.Options; using Microsoft.VisualStudio.Commanding; using Microsoft.VisualStudio.Language.Intellisense.AsyncCompletion; +using Microsoft.VisualStudio.Text.Editor; using Microsoft.VisualStudio.Text.Operations; using Microsoft.VisualStudio.Utilities; @@ -30,8 +31,8 @@ public DocumentationCommentCommandHandler( IUIThreadOperationExecutor uiThreadOperationExecutor, ITextUndoHistoryRegistry undoHistoryRegistry, IEditorOperationsFactoryService editorOperationsFactoryService, - IGlobalOptionService globalOptions) - : base(uiThreadOperationExecutor, undoHistoryRegistry, editorOperationsFactoryService, globalOptions) + EditorOptionsService editorOptionsService) + : base(uiThreadOperationExecutor, undoHistoryRegistry, editorOperationsFactoryService, editorOptionsService) { } diff --git a/src/EditorFeatures/CSharp/EventHookup/EventHookupCommandHandler_TabKeyCommand.cs b/src/EditorFeatures/CSharp/EventHookup/EventHookupCommandHandler_TabKeyCommand.cs index b597251b2495f..95737e769801e 100644 --- a/src/EditorFeatures/CSharp/EventHookup/EventHookupCommandHandler_TabKeyCommand.cs +++ b/src/EditorFeatures/CSharp/EventHookup/EventHookupCommandHandler_TabKeyCommand.cs @@ -19,7 +19,7 @@ using Microsoft.CodeAnalysis.Editor.Shared.Options; using Microsoft.CodeAnalysis.Formatting; using Microsoft.CodeAnalysis.Internal.Log; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Rename; using Microsoft.CodeAnalysis.Shared.Extensions; diff --git a/src/EditorFeatures/CSharp/EventHookup/EventHookupSessionManager_EventHookupSession.cs b/src/EditorFeatures/CSharp/EventHookup/EventHookupSessionManager_EventHookupSession.cs index 0b15a219962aa..97b124651ee57 100644 --- a/src/EditorFeatures/CSharp/EventHookup/EventHookupSessionManager_EventHookupSession.cs +++ b/src/EditorFeatures/CSharp/EventHookup/EventHookupSessionManager_EventHookupSession.cs @@ -18,7 +18,7 @@ using Microsoft.CodeAnalysis.Editor.Shared.Utilities; using Microsoft.CodeAnalysis.ErrorReporting; using Microsoft.CodeAnalysis.Internal.Log; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Shared.TestHooks; @@ -113,7 +113,8 @@ public EventHookupSession( this.TESTSessionHookupMutex = testSessionHookupMutex; var document = textView.TextSnapshot.GetOpenDocumentInCurrentContextWithChanges(); - if (document != null && document.Project.Solution.Workspace.CanApplyChange(ApplyChangesKind.ChangeDocument)) + var workspace = textView.TextSnapshot.TextBuffer.GetWorkspace(); + if (document != null && workspace != null && workspace.CanApplyChange(ApplyChangesKind.ChangeDocument)) { var position = textView.GetCaretPoint(subjectBuffer).Value.Position; _trackingPoint = textView.TextSnapshot.CreateTrackingPoint(position, PointTrackingMode.Negative); diff --git a/src/EditorFeatures/CSharp/Formatting/CSharpFormattingInteractionService.cs b/src/EditorFeatures/CSharp/Formatting/CSharpFormattingInteractionService.cs index fb1bd597a45ba..30f87d8702c57 100644 --- a/src/EditorFeatures/CSharp/Formatting/CSharpFormattingInteractionService.cs +++ b/src/EditorFeatures/CSharp/Formatting/CSharpFormattingInteractionService.cs @@ -28,17 +28,13 @@ internal partial class CSharpFormattingInteractionService : IFormattingInteracti // All the characters that might potentially trigger formatting when typed private static readonly char[] _supportedChars = ";{}#nte:)".ToCharArray(); - private readonly IIndentationManagerService _indentationManager; - private readonly IEditorOptionsFactoryService _editorOptionsFactory; - private readonly IGlobalOptionService _globalOptions; + private readonly EditorOptionsService _editorOptionsService; [ImportingConstructor] [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] - public CSharpFormattingInteractionService(IIndentationManagerService indentationManager, IEditorOptionsFactoryService editorOptionsFactory, IGlobalOptionService globalOptions) + public CSharpFormattingInteractionService(EditorOptionsService editorOptionsService) { - _indentationManager = indentationManager; - _editorOptionsFactory = editorOptionsFactory; - _globalOptions = globalOptions; + _editorOptionsService = editorOptionsService; } public bool SupportsFormatDocument => true; @@ -48,7 +44,7 @@ public CSharpFormattingInteractionService(IIndentationManagerService indentation public bool SupportsFormattingOnTypedCharacter(Document document, char ch) { - var isSmartIndent = _globalOptions.GetOption(IndentationOptionsStorage.SmartIndent, LanguageNames.CSharp) == FormattingOptions2.IndentStyle.Smart; + var isSmartIndent = _editorOptionsService.GlobalOptions.GetOption(IndentationOptionsStorage.SmartIndent, LanguageNames.CSharp) == FormattingOptions2.IndentStyle.Smart; // We consider the proper placement of a close curly or open curly when it is typed at // the start of the line to be a smart-indentation operation. As such, even if "format @@ -61,7 +57,7 @@ public bool SupportsFormattingOnTypedCharacter(Document document, char ch) return true; } - var options = _globalOptions.GetAutoFormattingOptions(LanguageNames.CSharp); + var options = _editorOptionsService.GlobalOptions.GetAutoFormattingOptions(LanguageNames.CSharp); // If format-on-typing is not on, then we don't support formatting on any other characters. var autoFormattingOnTyping = options.FormatOnTyping; @@ -89,56 +85,44 @@ public bool SupportsFormattingOnTypedCharacter(Document document, char ch) return _supportedChars.Contains(ch); } - public async Task> GetFormattingChangesAsync( + public Task> GetFormattingChangesAsync( Document document, ITextBuffer textBuffer, TextSpan? textSpan, CancellationToken cancellationToken) { - var fallbackOptions = _globalOptions.GetCSharpSyntaxFormattingOptions(); - var options = _indentationManager.GetInferredFormattingOptions(textBuffer, _editorOptionsFactory, document.Project.LanguageServices, fallbackOptions, explicitFormat: true); + var parsedDocument = ParsedDocument.CreateSynchronously(document, cancellationToken); + var options = textBuffer.GetSyntaxFormattingOptions(_editorOptionsService, parsedDocument.LanguageServices, explicitFormat: true); - var root = await document.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false); - var span = textSpan ?? new TextSpan(0, root.FullSpan.Length); - var formattingSpan = CommonFormattingHelpers.GetFormattingSpan(root, span); + var span = textSpan ?? new TextSpan(0, parsedDocument.Root.FullSpan.Length); + var formattingSpan = CommonFormattingHelpers.GetFormattingSpan(parsedDocument.Root, span); - var services = document.Project.Solution.Workspace.Services; - return Formatter.GetFormattedTextChanges(root, SpecializedCollections.SingletonEnumerable(formattingSpan), services, options, cancellationToken).ToImmutableArray(); + return Task.FromResult(Formatter.GetFormattedTextChanges(parsedDocument.Root, SpecializedCollections.SingletonEnumerable(formattingSpan), document.Project.Solution.Services, options, cancellationToken).ToImmutableArray()); } - public async Task> GetFormattingChangesOnPasteAsync(Document document, ITextBuffer textBuffer, TextSpan textSpan, CancellationToken cancellationToken) + public Task> GetFormattingChangesOnPasteAsync(Document document, ITextBuffer textBuffer, TextSpan textSpan, CancellationToken cancellationToken) { - var fallbackOptions = _globalOptions.GetCSharpSyntaxFormattingOptions(); - var options = _indentationManager.GetInferredFormattingOptions(textBuffer, _editorOptionsFactory, document.Project.LanguageServices, fallbackOptions, explicitFormat: true); - var service = document.GetRequiredLanguageService(); - var documentSyntax = await ParsedDocument.CreateAsync(document, cancellationToken).ConfigureAwait(false); - return service.GetFormattingChangesOnPaste(documentSyntax, textSpan, options, cancellationToken); + var parsedDocument = ParsedDocument.CreateSynchronously(document, cancellationToken); + var options = textBuffer.GetSyntaxFormattingOptions(_editorOptionsService, parsedDocument.LanguageServices, explicitFormat: true); + var service = parsedDocument.LanguageServices.GetRequiredService(); + return Task.FromResult(service.GetFormattingChangesOnPaste(parsedDocument, textSpan, options, cancellationToken)); } - Task> IFormattingInteractionService.GetFormattingChangesOnReturnAsync( - Document document, int caretPosition, CancellationToken cancellationToken) + public Task> GetFormattingChangesOnReturnAsync(Document document, int caretPosition, CancellationToken cancellationToken) => SpecializedTasks.EmptyImmutableArray(); - public async Task> GetFormattingChangesAsync(Document document, ITextBuffer textBuffer, char typedChar, int position, CancellationToken cancellationToken) + public Task> GetFormattingChangesAsync(Document document, ITextBuffer textBuffer, char typedChar, int position, CancellationToken cancellationToken) { - var service = document.GetRequiredLanguageService(); - var documentSyntax = await ParsedDocument.CreateAsync(document, cancellationToken).ConfigureAwait(false); + var parsedDocument = ParsedDocument.CreateSynchronously(document, cancellationToken); + var service = parsedDocument.LanguageServices.GetRequiredService(); - if (service.ShouldFormatOnTypedCharacter(documentSyntax, typedChar, position, cancellationToken)) + if (service.ShouldFormatOnTypedCharacter(parsedDocument, typedChar, position, cancellationToken)) { - var fallbackOptions = _globalOptions.GetCSharpSyntaxFormattingOptions(); - var formattingOptions = _indentationManager.GetInferredFormattingOptions(textBuffer, _editorOptionsFactory, document.Project.LanguageServices, fallbackOptions, explicitFormat: false); - - var indentationOptions = new IndentationOptions(formattingOptions) - { - AutoFormattingOptions = _globalOptions.GetAutoFormattingOptions(LanguageNames.CSharp), - IndentStyle = _globalOptions.GetOption(IndentationOptionsStorage.SmartIndent, LanguageNames.CSharp) - }; - - return service.GetFormattingChangesOnTypedCharacter(documentSyntax, position, indentationOptions, cancellationToken); + var indentationOptions = textBuffer.GetIndentationOptions(_editorOptionsService, parsedDocument.LanguageServices, explicitFormat: false); + return Task.FromResult(service.GetFormattingChangesOnTypedCharacter(parsedDocument, position, indentationOptions, cancellationToken)); } - return ImmutableArray.Empty; + return SpecializedTasks.EmptyImmutableArray(); } } } diff --git a/src/EditorFeatures/CSharp/RawStringLiteral/RawStringLiteralCommandHandler.cs b/src/EditorFeatures/CSharp/RawStringLiteral/RawStringLiteralCommandHandler.cs index c50a8d6a1d503..5b326335ba55d 100644 --- a/src/EditorFeatures/CSharp/RawStringLiteral/RawStringLiteralCommandHandler.cs +++ b/src/EditorFeatures/CSharp/RawStringLiteral/RawStringLiteralCommandHandler.cs @@ -8,6 +8,7 @@ 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; @@ -22,17 +23,23 @@ internal partial class RawStringLiteralCommandHandler private readonly ITextUndoHistoryRegistry _undoHistoryRegistry; private readonly IGlobalOptionService _globalOptions; private readonly IEditorOperationsFactoryService _editorOperationsFactoryService; + private readonly EditorOptionsService _editorOptionsService; + private readonly IIndentationManagerService _indentationManager; [ImportingConstructor] [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] public RawStringLiteralCommandHandler( ITextUndoHistoryRegistry undoHistoryRegistry, IGlobalOptionService globalOptions, - IEditorOperationsFactoryService editorOperationsFactoryService) + IEditorOperationsFactoryService editorOperationsFactoryService, + EditorOptionsService editorOptionsService, + IIndentationManagerService indentationManager) { _undoHistoryRegistry = undoHistoryRegistry; _globalOptions = globalOptions; _editorOperationsFactoryService = editorOperationsFactoryService; + _editorOptionsService = editorOptionsService; + _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 70b96ea23d97f..fd4d38290fcb2 100644 --- a/src/EditorFeatures/CSharp/RawStringLiteral/RawStringLiteralCommandHandler_Return.cs +++ b/src/EditorFeatures/CSharp/RawStringLiteral/RawStringLiteralCommandHandler_Return.cs @@ -9,6 +9,7 @@ using Microsoft.CodeAnalysis.Editor.Shared.Utilities; using Microsoft.CodeAnalysis.Formatting; using Microsoft.CodeAnalysis.Indentation; +using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Text; using Microsoft.VisualStudio.Commanding; @@ -87,8 +88,9 @@ private bool SplitRawString(ITextView textView, ITextBuffer subjectBuffer, int p if (document == null) return false; - var root = document.GetRequiredSyntaxRootSynchronously(cancellationToken); - var token = root.FindToken(position); + var parsedDocument = ParsedDocument.CreateSynchronously(document, cancellationToken); + + var token = parsedDocument.Root.FindToken(position); if (token.Kind() is not (SyntaxKind.SingleLineRawStringLiteralToken or SyntaxKind.MultiLineRawStringLiteralToken or SyntaxKind.InterpolatedSingleLineRawStringStartToken or @@ -97,8 +99,8 @@ SyntaxKind.InterpolatedSingleLineRawStringStartToken or return false; } - var indentationOptions = document.GetIndentationOptionsAsync(_globalOptions, cancellationToken).WaitAndGetResult(cancellationToken); - var indentation = token.GetPreferredIndentation(document, indentationOptions, cancellationToken); + var indentationOptions = subjectBuffer.GetIndentationOptions(_editorOptionsService, document.Project.Services, explicitFormat: false); + var indentation = token.GetPreferredIndentation(parsedDocument, indentationOptions, cancellationToken); var newLine = indentationOptions.FormattingOptions.NewLine; @@ -107,11 +109,8 @@ SyntaxKind.InterpolatedSingleLineRawStringStartToken or var edit = subjectBuffer.CreateEdit(); - var sourceText = document.GetTextSynchronously(cancellationToken); - var textToInsert = $"{newLine}{newLine}{indentation}"; - // apply the change: - edit.Insert(position, textToInsert); + edit.Insert(position, newLine + newLine + indentation); var snapshot = edit.Apply(); // move caret: diff --git a/src/EditorFeatures/CSharp/SplitStringLiteral/SplitStringLiteralCommandHandler.cs b/src/EditorFeatures/CSharp/SplitStringLiteral/SplitStringLiteralCommandHandler.cs index 01a7a3e82eab1..23403b2c9398e 100644 --- a/src/EditorFeatures/CSharp/SplitStringLiteral/SplitStringLiteralCommandHandler.cs +++ b/src/EditorFeatures/CSharp/SplitStringLiteral/SplitStringLiteralCommandHandler.cs @@ -33,19 +33,19 @@ namespace Microsoft.CodeAnalysis.Editor.CSharp.SplitStringLiteral internal partial class SplitStringLiteralCommandHandler : ICommandHandler { private readonly ITextUndoHistoryRegistry _undoHistoryRegistry; - private readonly IGlobalOptionService _globalOptions; private readonly IEditorOperationsFactoryService _editorOperationsFactoryService; + private readonly EditorOptionsService _editorOptionsService; [ImportingConstructor] [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] public SplitStringLiteralCommandHandler( ITextUndoHistoryRegistry undoHistoryRegistry, - IGlobalOptionService globalOptions, - IEditorOperationsFactoryService editorOperationsFactoryService) + IEditorOperationsFactoryService editorOperationsFactoryService, + EditorOptionsService editorOptionsService) { _undoHistoryRegistry = undoHistoryRegistry; - _globalOptions = globalOptions; _editorOperationsFactoryService = editorOperationsFactoryService; + _editorOptionsService = editorOptionsService; } public string DisplayName => CSharpEditorResources.Split_string; @@ -58,7 +58,7 @@ public bool ExecuteCommand(ReturnKeyCommandArgs args, CommandExecutionContext co public bool ExecuteCommandWorker(ReturnKeyCommandArgs args) { - if (!_globalOptions.GetOption(SplitStringLiteralOptions.Enabled, LanguageNames.CSharp)) + if (!_editorOptionsService.GlobalOptions.GetOption(SplitStringLiteralOptions.Enabled, LanguageNames.CSharp)) { return false; } @@ -92,8 +92,7 @@ public bool ExecuteCommandWorker(ReturnKeyCommandArgs args) } } - var useTabs = !textView.Options.IsConvertTabsToSpacesEnabled(); - var tabSize = textView.Options.GetTabSize(); + IndentationOptions? lazyOptions = null; // We now go through the verified string literals and split each of them. // The list of spans is traversed in reverse order so we do not have to @@ -101,7 +100,7 @@ public bool ExecuteCommandWorker(ReturnKeyCommandArgs args) // from splitting at earlier caret positions. foreach (var span in spans.Reverse()) { - if (!SplitString(textView, subjectBuffer, span.Start.Position, useTabs, tabSize, CancellationToken.None)) + if (!SplitString(textView, subjectBuffer, span.Start.Position, ref lazyOptions, CancellationToken.None)) { return false; } @@ -110,7 +109,7 @@ public bool ExecuteCommandWorker(ReturnKeyCommandArgs args) return true; } - private bool SplitString(ITextView textView, ITextBuffer subjectBuffer, int position, bool useTabs, int tabSize, CancellationToken cancellationToken) + private bool SplitString(ITextView textView, ITextBuffer subjectBuffer, int position, ref IndentationOptions? lazyOptions, CancellationToken cancellationToken) { var document = subjectBuffer.CurrentSnapshot.GetOpenDocumentInCurrentContextWithChanges(); if (document == null) @@ -118,19 +117,20 @@ private bool SplitString(ITextView textView, ITextBuffer subjectBuffer, int posi return false; } - // TODO: read option from textView.Options (https://devdiv.visualstudio.com/DevDiv/_workitems/edit/1412138) - var options = document.GetIndentationOptionsAsync(_globalOptions, cancellationToken).WaitAndGetResult(cancellationToken); + lazyOptions ??= subjectBuffer.GetIndentationOptions(_editorOptionsService, document.Project.Services, explicitFormat: false); using var transaction = CaretPreservingEditTransaction.TryCreate( CSharpEditorResources.Split_string, textView, _undoHistoryRegistry, _editorOperationsFactoryService); - var splitter = StringSplitter.TryCreate(document, position, options, useTabs, tabSize, cancellationToken); - if (splitter?.TrySplit(out var newDocument, out var newPosition) != true) + var parsedDocument = ParsedDocument.CreateSynchronously(document, CancellationToken.None); + var splitter = StringSplitter.TryCreate(parsedDocument, position, lazyOptions.Value, cancellationToken); + if (splitter?.TrySplit(out var newRoot, out var newPosition) != true) { return false; } // apply the change: + var newDocument = document.WithSyntaxRoot(newRoot!); var workspace = newDocument.Project.Solution.Workspace; workspace.TryApplyChanges(newDocument.Project.Solution); diff --git a/src/EditorFeatures/CSharp/StringCopyPaste/StringCopyPasteCommandHandler.cs b/src/EditorFeatures/CSharp/StringCopyPaste/StringCopyPasteCommandHandler.cs index afedeee6fbb9e..d135dba48c01e 100644 --- a/src/EditorFeatures/CSharp/StringCopyPaste/StringCopyPasteCommandHandler.cs +++ b/src/EditorFeatures/CSharp/StringCopyPaste/StringCopyPasteCommandHandler.cs @@ -20,6 +20,7 @@ using Microsoft.CodeAnalysis.Text.Shared.Extensions; using Microsoft.VisualStudio.Commanding; using Microsoft.VisualStudio.Text; +using Microsoft.VisualStudio.Text.Editor; using Microsoft.VisualStudio.Text.Editor.Commanding.Commands; using Microsoft.VisualStudio.Text.Editor.OptionsExtensionMethods; using Microsoft.VisualStudio.Text.Operations; @@ -57,6 +58,8 @@ internal partial class StringCopyPasteCommandHandler : private readonly IThreadingContext _threadingContext; private readonly ITextUndoHistoryRegistry _undoHistoryRegistry; private readonly IEditorOperationsFactoryService _editorOperationsFactoryService; + private readonly EditorOptionsService _editorOptionsService; + private readonly IIndentationManagerService _indentationManager; private readonly IGlobalOptionService _globalOptions; private readonly ITextBufferFactoryService2 _textBufferFactoryService; @@ -67,13 +70,17 @@ public StringCopyPasteCommandHandler( ITextUndoHistoryRegistry undoHistoryRegistry, IEditorOperationsFactoryService editorOperationsFactoryService, IGlobalOptionService globalOptions, - ITextBufferFactoryService2 textBufferFactoryService) + ITextBufferFactoryService2 textBufferFactoryService, + EditorOptionsService editorOptionsService, + IIndentationManagerService indentationManager) { _threadingContext = threadingContext; _undoHistoryRegistry = undoHistoryRegistry; _editorOperationsFactoryService = editorOperationsFactoryService; _globalOptions = globalOptions; _textBufferFactoryService = textBufferFactoryService; + _editorOptionsService = editorOptionsService; + _indentationManager = indentationManager; } public string DisplayName => nameof(StringCopyPasteCommandHandler); @@ -122,12 +129,12 @@ public void ExecuteCommand(PasteCommandArgs args, Action nextCommandHandler, Com return; var cancellationToken = executionContext.OperationContext.UserCancellationToken; + var parsedDocumentBeforePaste = ParsedDocument.CreateSynchronously(documentBeforePaste, cancellationToken); // When pasting, only do anything special if the user selections were entirely inside a single string // token/expression. Otherwise, we have a multi-selection across token kinds which will be extremely // complex to try to reconcile. - var stringExpressionBeforePaste = TryGetCompatibleContainingStringExpression( - documentBeforePaste, selectionsBeforePaste, cancellationToken); + var stringExpressionBeforePaste = TryGetCompatibleContainingStringExpression(parsedDocumentBeforePaste, selectionsBeforePaste); if (stringExpressionBeforePaste == null) return; @@ -135,7 +142,7 @@ public void ExecuteCommand(PasteCommandArgs args, Action nextCommandHandler, Com // token/expression. If the editor decided to make changes outside of the string, we definitely do not want // to do anything here. var stringExpressionBeforePasteFromChanges = TryGetCompatibleContainingStringExpression( - documentBeforePaste, new NormalizedSnapshotSpanCollection(snapshotBeforePaste, snapshotBeforePaste.Version.Changes.Select(c => c.OldSpan)), cancellationToken); + parsedDocumentBeforePaste, new NormalizedSnapshotSpanCollection(snapshotBeforePaste, snapshotBeforePaste.Version.Changes.Select(c => c.OldSpan))); if (stringExpressionBeforePaste != stringExpressionBeforePasteFromChanges) return; @@ -191,7 +198,7 @@ ImmutableArray GetEdits(CancellationToken cancellationToken) { var newLine = textView.Options.GetNewLineCharacter(); var indentationWhitespace = DetermineIndentationWhitespace( - documentBeforePaste, snapshotBeforePaste.AsText(), stringExpressionBeforePaste, cancellationToken); + parsedDocumentBeforePaste, subjectBuffer, snapshotBeforePaste.AsText(), stringExpressionBeforePaste, cancellationToken); // See if this is a paste of the last copy that we heard about. var edits = TryGetEditsFromKnownCopySource(newLine, indentationWhitespace); @@ -217,7 +224,7 @@ ImmutableArray TryGetEditsFromKnownCopySource( if (selectionsBeforePaste.Count != 1) return default; - var copyPasteService = documentBeforePaste.Project.Solution.Workspace.Services.GetRequiredService(); + var copyPasteService = documentBeforePaste.Project.Solution.Services.GetRequiredService(); var clipboardData = copyPasteService.TryGetClipboardData(KeyAndVersion); var copyPasteData = StringCopyPasteData.FromJson(clipboardData); @@ -236,7 +243,8 @@ ImmutableArray TryGetEditsFromKnownCopySource( } private string DetermineIndentationWhitespace( - Document documentBeforePaste, + ParsedDocument documentBeforePaste, + ITextBuffer textBuffer, SourceText textBeforePaste, ExpressionSyntax stringExpressionBeforePaste, CancellationToken cancellationToken) @@ -256,7 +264,7 @@ private string DetermineIndentationWhitespace( // Otherwise, we have a single-line raw string. Determine the default indentation desired here. // We'll use that if we have to convert this single-line raw string to a multi-line one. - var indentationOptions = documentBeforePaste.GetIndentationOptionsAsync(_globalOptions, cancellationToken).WaitAndGetResult(cancellationToken); + var indentationOptions = textBuffer.GetIndentationOptions(_editorOptionsService, documentBeforePaste.LanguageServices, explicitFormat: false); return stringExpressionBeforePaste.GetFirstToken().GetPreferredIndentation(documentBeforePaste, indentationOptions, cancellationToken); } @@ -318,18 +326,15 @@ private static bool ContentsAreSame( /// anything special as trying to correct in this scenario is too difficult. /// private static ExpressionSyntax? TryGetCompatibleContainingStringExpression( - Document document, NormalizedSnapshotSpanCollection spans, CancellationToken cancellationToken) + ParsedDocument document, NormalizedSnapshotSpanCollection spans) { if (spans.Count == 0) return null; var snapshot = spans[0].Snapshot; - var root = document.GetSyntaxRootSynchronously(cancellationToken); - if (root == null) - return null; // First, try to see if all the selections are at least contained within a single string literal expression. - var stringExpression = FindCommonContainingStringExpression(root, spans); + var stringExpression = FindCommonContainingStringExpression(document.Root, spans); if (stringExpression == null) return null; diff --git a/src/EditorFeatures/CSharp/StringCopyPaste/StringCopyPasteCommandHandler_CutCopy.cs b/src/EditorFeatures/CSharp/StringCopyPaste/StringCopyPasteCommandHandler_CutCopy.cs index eee60f8462d26..04f63ea216d8d 100644 --- a/src/EditorFeatures/CSharp/StringCopyPaste/StringCopyPasteCommandHandler_CutCopy.cs +++ b/src/EditorFeatures/CSharp/StringCopyPaste/StringCopyPasteCommandHandler_CutCopy.cs @@ -54,8 +54,7 @@ private void ExecuteCutOrCopyCommand(ITextView textView, ITextBuffer subjectBuff // Always try to store our data to the clipboard (if we have access to the clipboard service). Even if we // didn't capture any useful data, we want to store that to blow away any prior stored data we have. - if (copyPasteService != null) - copyPasteService.TrySetClipboardData(KeyAndVersion, dataToStore ?? ""); + copyPasteService?.TrySetClipboardData(KeyAndVersion, dataToStore ?? ""); } private static (string? dataToStore, IStringCopyPasteService service) CaptureCutCopyInformation( @@ -65,10 +64,12 @@ private static (string? dataToStore, IStringCopyPasteService service) CaptureCut if (document == null) return default; - var copyPasteService = document.Project.Solution.Workspace.Services.GetService(); + var copyPasteService = document.Project.Solution.Services.GetService(); if (copyPasteService == null) return default; + var parsedDocument = ParsedDocument.CreateSynchronously(document, cancellationToken); + var spans = textView.Selection.GetSnapshotSpansOnBuffer(subjectBuffer); // We only support smart copy/paste when a single selection is copied (and a single selection is pasted @@ -87,7 +88,7 @@ private static (string? dataToStore, IStringCopyPasteService service) CaptureCut } var stringExpression = TryGetCompatibleContainingStringExpression( - document, new NormalizedSnapshotSpanCollection(span), cancellationToken); + parsedDocument, new NormalizedSnapshotSpanCollection(span)); if (stringExpression is null) return default; diff --git a/src/EditorFeatures/CSharp/StringCopyPaste/StringCopyPasteHelpers.cs b/src/EditorFeatures/CSharp/StringCopyPaste/StringCopyPasteHelpers.cs index 9b434a5f8a6ca..7ddac4fb0b695 100644 --- a/src/EditorFeatures/CSharp/StringCopyPaste/StringCopyPasteHelpers.cs +++ b/src/EditorFeatures/CSharp/StringCopyPaste/StringCopyPasteHelpers.cs @@ -415,6 +415,18 @@ private static string EscapeForNonRawVerbatimStringLiteral(bool isInterpolated, { using var _ = PooledStringBuilder.GetInstance(out var builder); + // First, go through and see if we're escaping *anything* in the original. If so, then we'll escape + // everything. In other words, say we're pasting `[SuppressMessage("", "CA2013")]`. We technically don't + // need to escape the `""` (since that is legal in a verbatim string). However, we will be escaping the + // quotes in teh `"CA2013"` to become `""CA2013""`. Once we decide we're escaping some quotes, we should + // then realize that we *should* escape the `""` to `""""` to be consistent. + + // So if we determine that we will be escaping all code, then just recurse, this time setting + // trySkipExistingEscapes to false. That will prevent calling back into this check and it means whatever we + // run into we will escape. + if (trySkipExistingEscapes && WillEscapeAnyCharacters(isInterpolated, value)) + return EscapeForNonRawVerbatimStringLiteral(isInterpolated, trySkipExistingEscapes: false, value); + for (var i = 0; i < value.Length; i++) { var ch = value[i]; @@ -426,21 +438,55 @@ private static string EscapeForNonRawVerbatimStringLiteral(bool isInterpolated, // Otherwise, if it's not already escaped, then escape it. if (ch == '"') { + builder.Append(ch); + if (trySkipExistingEscapes && nextCh == ch) i++; - else - builder.Append(ch); } else if (isInterpolated && ch is '{' or '}') { + builder.Append(ch); + if (trySkipExistingEscapes && nextCh == ch) i++; - else - builder.Append(ch); } } return builder.ToString(); + + static bool WillEscapeAnyCharacters(bool isInterpolated, string value) + { + for (var i = 0; i < value.Length; i++) + { + var ch = value[i]; + var nextCh = i == value.Length - 1 ? 0 : value[i + 1]; + + if (ch == '"') + { + // we have an isolated quote. we will need to escape it (and thus should escape everything in + // the string. + if (nextCh != ch) + return true; + + // Quotes are paired. This is already escaped fine. Skip both quotes. + i++; + } + else if (isInterpolated && ch is '{' or '}') + { + // we have an isolated brace. we will need to escape it (and thus should escape everything in + // the string. + if (nextCh != ch) + return true; + + // Braces are paired. This is already escaped fine. Skip both braces. + i++; + } + + // continue looking forward. + } + + return false; + } } /// diff --git a/src/EditorFeatures/CSharpTest/AddUsing/AddUsingNuGetTests.cs b/src/EditorFeatures/CSharpTest/AddUsing/AddUsingNuGetTests.cs index 899397848d526..a349a04e9c233 100644 --- a/src/EditorFeatures/CSharpTest/AddUsing/AddUsingNuGetTests.cs +++ b/src/EditorFeatures/CSharpTest/AddUsing/AddUsingNuGetTests.cs @@ -57,7 +57,7 @@ public async Task TestSearchPackageCustomFeedName() var installerServiceMock = new Mock(MockBehavior.Strict); installerServiceMock.Setup(i => i.IsEnabled(It.IsAny())).Returns(true); - installerServiceMock.Setup(i => i.IsInstalled(It.IsAny(), It.IsAny(), "NuGetPackage")).Returns(false); + installerServiceMock.Setup(i => i.IsInstalled(It.IsAny(), "NuGetPackage")).Returns(false); installerServiceMock.Setup(i => i.GetInstalledVersions("NuGetPackage")).Returns(ImmutableArray.Empty); installerServiceMock.Setup(i => i.TryGetPackageSources()).Returns(packageSources); installerServiceMock.Setup(s => s.TryInstallPackageAsync(It.IsAny(), It.IsAny(), It.IsAny(), "NuGetPackage", It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) @@ -90,7 +90,7 @@ public async Task TestSearchPackageFakeNugetFeed() var installerServiceMock = new Mock(MockBehavior.Strict); installerServiceMock.Setup(i => i.IsEnabled(It.IsAny())).Returns(true); - installerServiceMock.Setup(i => i.IsInstalled(It.IsAny(), It.IsAny(), "NuGetPackage")).Returns(false); + installerServiceMock.Setup(i => i.IsInstalled(It.IsAny(), "NuGetPackage")).Returns(false); installerServiceMock.Setup(i => i.GetInstalledVersions("NuGetPackage")).Returns(ImmutableArray.Empty); installerServiceMock.Setup(i => i.TryGetPackageSources()).Returns(packageSources); installerServiceMock.Setup(s => s.TryInstallPackageAsync(It.IsAny(), It.IsAny(), It.IsAny(), "NuGetPackage", It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) @@ -121,7 +121,7 @@ public async Task TestSearchPackageSingleName() { var installerServiceMock = new Mock(MockBehavior.Strict); installerServiceMock.Setup(i => i.IsEnabled(It.IsAny())).Returns(true); - installerServiceMock.Setup(i => i.IsInstalled(It.IsAny(), It.IsAny(), "NuGetPackage")).Returns(false); + installerServiceMock.Setup(i => i.IsInstalled(It.IsAny(), "NuGetPackage")).Returns(false); installerServiceMock.Setup(i => i.GetInstalledVersions("NuGetPackage")).Returns(ImmutableArray.Empty); installerServiceMock.Setup(i => i.TryGetPackageSources()).Returns(NugetPackageSources); installerServiceMock.Setup(s => s.TryInstallPackageAsync(It.IsAny(), It.IsAny(), It.IsAny(), "NuGetPackage", It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) @@ -152,7 +152,7 @@ public async Task TestSearchPackageMultipleNames() { var installerServiceMock = new Mock(MockBehavior.Strict); installerServiceMock.Setup(i => i.IsEnabled(It.IsAny())).Returns(true); - installerServiceMock.Setup(i => i.IsInstalled(It.IsAny(), It.IsAny(), "NuGetPackage")).Returns(false); + installerServiceMock.Setup(i => i.IsInstalled(It.IsAny(), "NuGetPackage")).Returns(false); installerServiceMock.Setup(i => i.GetInstalledVersions("NuGetPackage")).Returns(ImmutableArray.Empty); installerServiceMock.Setup(i => i.TryGetPackageSources()).Returns(NugetPackageSources); installerServiceMock.Setup(s => s.TryInstallPackageAsync(It.IsAny(), It.IsAny(), It.IsAny(), "NuGetPackage", It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) @@ -184,7 +184,7 @@ public async Task TestMissingIfPackageAlreadyInstalled() var installerServiceMock = new Mock(MockBehavior.Strict); installerServiceMock.Setup(i => i.IsEnabled(It.IsAny())).Returns(true); installerServiceMock.Setup(i => i.TryGetPackageSources()).Returns(NugetPackageSources); - installerServiceMock.Setup(s => s.IsInstalled(It.IsAny(), It.IsAny(), "NuGetPackage")) + installerServiceMock.Setup(s => s.IsInstalled(It.IsAny(), "NuGetPackage")) .Returns(true); var packageServiceMock = new Mock(MockBehavior.Strict); @@ -206,7 +206,7 @@ public async Task TestOptionsOffered() { var installerServiceMock = new Mock(MockBehavior.Strict); installerServiceMock.Setup(i => i.IsEnabled(It.IsAny())).Returns(true); - installerServiceMock.Setup(i => i.IsInstalled(It.IsAny(), It.IsAny(), "NuGetPackage")).Returns(false); + installerServiceMock.Setup(i => i.IsInstalled(It.IsAny(), "NuGetPackage")).Returns(false); installerServiceMock.Setup(i => i.GetProjectsWithInstalledPackage(It.IsAny(), "NuGetPackage", "1.0")).Returns(ImmutableArray.Empty); installerServiceMock.Setup(i => i.GetProjectsWithInstalledPackage(It.IsAny(), "NuGetPackage", "2.0")).Returns(ImmutableArray.Empty); installerServiceMock.Setup(i => i.TryGetPackageSources()).Returns(NugetPackageSources); @@ -251,7 +251,7 @@ public async Task TestInstallGetsCalledNoVersion() { var installerServiceMock = new Mock(MockBehavior.Strict); installerServiceMock.Setup(i => i.IsEnabled(It.IsAny())).Returns(true); - installerServiceMock.Setup(i => i.IsInstalled(It.IsAny(), It.IsAny(), "NuGetPackage")).Returns(false); + installerServiceMock.Setup(i => i.IsInstalled(It.IsAny(), "NuGetPackage")).Returns(false); installerServiceMock.Setup(i => i.GetInstalledVersions("NuGetPackage")).Returns(ImmutableArray.Empty); installerServiceMock.Setup(i => i.TryGetPackageSources()).Returns(NugetPackageSources); installerServiceMock.Setup(s => s.TryInstallPackageAsync(It.IsAny(), It.IsAny(), It.IsAny(), "NuGetPackage", /*versionOpt*/ null, It.IsAny(), It.IsAny(), It.IsAny())) @@ -283,7 +283,7 @@ public async Task TestInstallGetsCalledWithVersion() { var installerServiceMock = new Mock(MockBehavior.Strict); installerServiceMock.Setup(i => i.IsEnabled(It.IsAny())).Returns(true); - installerServiceMock.Setup(i => i.IsInstalled(It.IsAny(), It.IsAny(), "NuGetPackage")).Returns(false); + installerServiceMock.Setup(i => i.IsInstalled(It.IsAny(), "NuGetPackage")).Returns(false); installerServiceMock.Setup(i => i.GetProjectsWithInstalledPackage(It.IsAny(), "NuGetPackage", "1.0")).Returns(ImmutableArray.Empty); installerServiceMock.Setup(i => i.TryGetPackageSources()).Returns(NugetPackageSources); installerServiceMock.Setup(s => s.GetInstalledVersions("NuGetPackage")) @@ -317,7 +317,7 @@ public async Task TestFailedInstallRollsBackFile() { var installerServiceMock = new Mock(MockBehavior.Strict); installerServiceMock.Setup(i => i.IsEnabled(It.IsAny())).Returns(true); - installerServiceMock.Setup(i => i.IsInstalled(It.IsAny(), It.IsAny(), "NuGetPackage")).Returns(false); + installerServiceMock.Setup(i => i.IsInstalled(It.IsAny(), "NuGetPackage")).Returns(false); installerServiceMock.Setup(i => i.GetProjectsWithInstalledPackage(It.IsAny(), "NuGetPackage", "1.0")).Returns(ImmutableArray.Empty); installerServiceMock.Setup(i => i.TryGetPackageSources()).Returns(NugetPackageSources); installerServiceMock.Setup(s => s.GetInstalledVersions("NuGetPackage")) diff --git a/src/EditorFeatures/CSharpTest/AutomaticCompletion/AutomaticBraceCompletionTests.cs b/src/EditorFeatures/CSharpTest/AutomaticCompletion/AutomaticBraceCompletionTests.cs index 96153086229fa..79d3f66e1eb67 100644 --- a/src/EditorFeatures/CSharpTest/AutomaticCompletion/AutomaticBraceCompletionTests.cs +++ b/src/EditorFeatures/CSharpTest/AutomaticCompletion/AutomaticBraceCompletionTests.cs @@ -7,10 +7,12 @@ using Microsoft.CodeAnalysis.BraceCompletion; using Microsoft.CodeAnalysis.CSharp.Formatting; using Microsoft.CodeAnalysis.Editor.UnitTests.AutomaticCompletion; +using Microsoft.CodeAnalysis.Editor.UnitTests.CodeActions; using Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces; using Microsoft.CodeAnalysis.Formatting; using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Test.Utilities; +using Microsoft.VisualStudio.Text.Editor; using Roslyn.Test.Utilities; using Xunit; using static Microsoft.CodeAnalysis.BraceCompletion.AbstractBraceCompletionService; @@ -784,11 +786,12 @@ public void man() } } }"; - var optionSet = new Dictionary - { - { CSharpFormattingOptions2.NewLinesForBracesInObjectCollectionArrayInitializers, false } - }; - using var session = CreateSession(code, optionSet); + var globalOptions = new OptionsCollection(LanguageNames.CSharp) + { + { CSharpFormattingOptions2.NewLinesForBracesInObjectCollectionArrayInitializers, false } + }; + + using var session = CreateSession(code, globalOptions); Assert.NotNull(session); CheckStart(session.Session); @@ -859,11 +862,12 @@ class Goo { public int bar; }"; - var optionSet = new Dictionary - { - { CSharpFormattingOptions2.NewLinesForBracesInObjectCollectionArrayInitializers, false } - }; - using var session = CreateSession(code, optionSet); + var globalOptions = new OptionsCollection(LanguageNames.CSharp) + { + { CSharpFormattingOptions2.NewLinesForBracesInObjectCollectionArrayInitializers, false } + }; + + using var session = CreateSession(code, globalOptions); Assert.NotNull(session); CheckStart(session.Session); @@ -930,11 +934,12 @@ public void man() } } }"; - var optionSet = new Dictionary - { - { CSharpFormattingOptions2.NewLinesForBracesInObjectCollectionArrayInitializers, false } - }; - using var session = CreateSession(code, optionSet); + var globalOptions = new OptionsCollection(LanguageNames.CSharp) + { + { CSharpFormattingOptions2.NewLinesForBracesInObjectCollectionArrayInitializers, false } + }; + + using var session = CreateSession(code, globalOptions); Assert.NotNull(session); CheckStart(session.Session); @@ -991,11 +996,12 @@ public void man() } } }"; - var optionSet = new Dictionary - { - { CSharpFormattingOptions2.NewLinesForBracesInObjectCollectionArrayInitializers, false } - }; - using var session = CreateSession(code, optionSet); + var globalOptions = new OptionsCollection(LanguageNames.CSharp) + { + { CSharpFormattingOptions2.NewLinesForBracesInObjectCollectionArrayInitializers, false } + }; + + using var session = CreateSession(code, globalOptions); Assert.NotNull(session); CheckStart(session.Session); @@ -1052,11 +1058,11 @@ public void man() } } }"; - var optionSet = new Dictionary - { - { CSharpFormattingOptions2.NewLinesForBracesInObjectCollectionArrayInitializers, false } - }; - using var session = CreateSession(code, optionSet); + var globalOptions = new OptionsCollection(LanguageNames.CSharp) + { + { CSharpFormattingOptions2.NewLinesForBracesInObjectCollectionArrayInitializers, false } + }; + using var session = CreateSession(code, globalOptions); Assert.NotNull(session); CheckStart(session.Session); @@ -1116,13 +1122,15 @@ public void X() } }"; + var globalOptions = new OptionsCollection(LanguageNames.CSharp) + { + { AutoFormattingOptionsStorage.FormatOnCloseBrace, false }, + { FormattingOptions2.SmartIndent, FormattingOptions2.IndentStyle.Block }, + }; - using var session = CreateSession(code); + using var session = CreateSession(code, globalOptions); Assert.NotNull(session); - session.Workspace.GlobalOptions.SetGlobalOption(new OptionKey(AutoFormattingOptionsStorage.FormatOnCloseBrace, LanguageNames.CSharp), false); - session.Workspace.GlobalOptions.SetGlobalOption(new OptionKey(FormattingOptions.SmartIndent, LanguageNames.CSharp), FormattingOptions.IndentStyle.Block); - CheckStart(session.Session); Assert.Equal(expected, session.Session.SubjectBuffer.CurrentSnapshot.GetText()); @@ -1145,10 +1153,13 @@ public class C1 { } }"; - using var session = CreateSession(code); - Assert.NotNull(session); + var globalOptions = new OptionsCollection(LanguageNames.CSharp) + { + { FormattingOptions2.SmartIndent, FormattingOptions2.IndentStyle.None }, + }; - session.Workspace.GlobalOptions.SetGlobalOption(new OptionKey(FormattingOptions.SmartIndent, LanguageNames.CSharp), FormattingOptions.IndentStyle.None); + using var session = CreateSession(code, globalOptions); + Assert.NotNull(session); CheckStart(session.Session); Assert.Equal(expected, session.Session.SubjectBuffer.CurrentSnapshot.GetText()); @@ -1178,10 +1189,13 @@ public class C1 } }"; - using var session = CreateSession(code); - Assert.NotNull(session); + var globalOptions = new OptionsCollection(LanguageNames.CSharp) + { + { FormattingOptions2.SmartIndent, FormattingOptions2.IndentStyle.Block }, + }; - session.Workspace.GlobalOptions.SetGlobalOption(new OptionKey(FormattingOptions.SmartIndent, LanguageNames.CSharp), FormattingOptions.IndentStyle.Block); + using var session = CreateSession(code, globalOptions); + Assert.NotNull(session); CheckStart(session.Session); Assert.Equal(expected, session.Session.SubjectBuffer.CurrentSnapshot.GetText()); @@ -1219,10 +1233,13 @@ public class C1 } }"; - using var session = CreateSession(code); - Assert.NotNull(session); + var globalOptions = new OptionsCollection(LanguageNames.CSharp) + { + { FormattingOptions2.SmartIndent, FormattingOptions2.IndentStyle.Block }, + }; - session.Workspace.GlobalOptions.SetGlobalOption(new OptionKey(FormattingOptions.SmartIndent, LanguageNames.CSharp), FormattingOptions.IndentStyle.Block); + using var session = CreateSession(code, globalOptions); + Assert.NotNull(session); CheckStart(session.Session); Assert.Equal(expected, session.Session.SubjectBuffer.CurrentSnapshot.GetText()); @@ -1323,11 +1340,11 @@ public void CurlyBraceFormatting_InsertsCorrectNewLine() { var code = @"class C $$"; - var optionSet = new Dictionary + var globalOptions = new OptionsCollection(LanguageNames.CSharp) { - { new OptionKey2(FormattingOptions2.NewLine, LanguageNames.CSharp), "\r" } + { FormattingOptions2.NewLine, "\r" } }; - using var session = CreateSession(code, optionSet); + using var session = CreateSession(code, globalOptions); Assert.NotNull(session); CheckStart(session.Session); @@ -1366,11 +1383,11 @@ public void man(R r) } } }"; - var optionSet = new Dictionary - { - { CSharpFormattingOptions2.NewLinesForBracesInObjectCollectionArrayInitializers, bracesOnNewLine } - }; - using var session = CreateSession(code, optionSet); + var globalOptions = new OptionsCollection(LanguageNames.CSharp) + { + { CSharpFormattingOptions2.NewLinesForBracesInObjectCollectionArrayInitializers, bracesOnNewLine } + }; + using var session = CreateSession(code, globalOptions); Assert.NotNull(session); CheckStart(session.Session); @@ -1410,11 +1427,11 @@ public void man() } } }"; - var optionSet = new Dictionary - { - { CSharpFormattingOptions2.NewLinesForBracesInObjectCollectionArrayInitializers, bracesOnNewLine } - }; - using var session = CreateSession(code, optionSet); + var globalOptions = new OptionsCollection(LanguageNames.CSharp) + { + { CSharpFormattingOptions2.NewLinesForBracesInObjectCollectionArrayInitializers, bracesOnNewLine } + }; + using var session = CreateSession(code, globalOptions); Assert.NotNull(session); CheckStart(session.Session); @@ -1454,11 +1471,11 @@ public int I } } }"; - var optionSet = new Dictionary - { - { CSharpFormattingOptions2.NewLinesForBracesInAccessors, bracesOnNewLine } - }; - using var session = CreateSession(code, optionSet); + var globalOptions = new OptionsCollection(LanguageNames.CSharp) + { + { CSharpFormattingOptions2.NewLinesForBracesInAccessors, bracesOnNewLine } + }; + using var session = CreateSession(code, globalOptions); Assert.NotNull(session); CheckStart(session.Session); @@ -1498,11 +1515,11 @@ public void man() } } }"; - var optionSet = new Dictionary - { - { CSharpFormattingOptions2.NewLinesForBracesInAnonymousMethods, bracesOnNewLine } - }; - using var session = CreateSession(code, optionSet); + var globalOptions = new OptionsCollection(LanguageNames.CSharp) + { + { CSharpFormattingOptions2.NewLinesForBracesInAnonymousMethods, bracesOnNewLine } + }; + using var session = CreateSession(code, globalOptions); Assert.NotNull(session); CheckStart(session.Session); @@ -1542,11 +1559,11 @@ public void man() } } }"; - var optionSet = new Dictionary - { - { CSharpFormattingOptions2.NewLinesForBracesInAnonymousTypes, bracesOnNewLine } - }; - using var session = CreateSession(code, optionSet); + var globalOptions = new OptionsCollection(LanguageNames.CSharp) + { + { CSharpFormattingOptions2.NewLinesForBracesInAnonymousTypes, bracesOnNewLine } + }; + using var session = CreateSession(code, globalOptions); Assert.NotNull(session); CheckStart(session.Session); @@ -1587,11 +1604,11 @@ public void man() } }"; - var optionSet = new Dictionary - { - { CSharpFormattingOptions2.NewLinesForBracesInControlBlocks, bracesOnNewLine } - }; - using var session = CreateSession(code, optionSet); + var globalOptions = new OptionsCollection(LanguageNames.CSharp) + { + { CSharpFormattingOptions2.NewLinesForBracesInControlBlocks, bracesOnNewLine } + }; + using var session = CreateSession(code, globalOptions); Assert.NotNull(session); CheckStart(session.Session); @@ -1638,22 +1655,22 @@ public void man() } }"; - var optionSet = new Dictionary - { - { CSharpFormattingOptions2.NewLinesForBracesInControlBlocks, bracesOnNewLine } - }; - using var session = CreateSession(code, optionSet); + var globalOptions = new OptionsCollection(LanguageNames.CSharp) + { + { CSharpFormattingOptions2.NewLinesForBracesInControlBlocks, bracesOnNewLine } + }; + using var session = CreateSession(code, globalOptions); Assert.NotNull(session); CheckStart(session.Session); CheckReturn(session.Session, 12, expected); } - internal static Holder CreateSession(string code, Dictionary? optionSet = null) + internal static Holder CreateSession(string code, OptionsCollection? globalOptions = null) { return CreateSession( TestWorkspace.CreateCSharp(code), - CurlyBrace.OpenCharacter, CurlyBrace.CloseCharacter, optionSet); + CurlyBrace.OpenCharacter, CurlyBrace.CloseCharacter, globalOptions); } } } diff --git a/src/EditorFeatures/CSharpTest/Classification/SemanticClassifierTests.cs b/src/EditorFeatures/CSharpTest/Classification/SemanticClassifierTests.cs index 792372436708b..85b8620c205da 100644 --- a/src/EditorFeatures/CSharpTest/Classification/SemanticClassifierTests.cs +++ b/src/EditorFeatures/CSharpTest/Classification/SemanticClassifierTests.cs @@ -209,7 +209,7 @@ class C dynamic d; }", testHost, - Record("dynamic")); + RecordClass("dynamic")); } [Theory] @@ -5576,7 +5576,7 @@ await TestAsync( R() { } }", testHost, - Record("R")); + RecordClass("R")); } [Theory] @@ -5592,7 +5592,7 @@ class C R r; }", testHost, - Record("R")); + RecordClass("R")); } [Theory] @@ -5607,7 +5607,7 @@ await TestAsync( R() { } }", testHost, - Record("R")); + RecordClass("R")); } [Theory] diff --git a/src/EditorFeatures/CSharpTest/Classification/SyntacticClassifierTests.cs b/src/EditorFeatures/CSharpTest/Classification/SyntacticClassifierTests.cs index 9e30aed37c8b9..f0f71f5aea8e7 100644 --- a/src/EditorFeatures/CSharpTest/Classification/SyntacticClassifierTests.cs +++ b/src/EditorFeatures/CSharpTest/Classification/SyntacticClassifierTests.cs @@ -355,7 +355,8 @@ public async Task VerbatimStringLiteralsUtf8_01(TestHost testHost) { await TestInMethodAsync(@"@""goo""u8", testHost, - Verbatim(@"@""goo""u8")); + Verbatim(@"@""goo""u8"), + Keyword("u8")); } [Theory] @@ -364,7 +365,8 @@ public async Task VerbatimStringLiteralsUtf8_02(TestHost testHost) { await TestInMethodAsync(@"@""goo""U8", testHost, - Verbatim(@"@""goo""U8")); + Verbatim(@"@""goo""U8"), + Keyword("U8")); } /// @@ -445,6 +447,7 @@ await TestInMethodAsync(code, Verbatim(@"@"" goo bar and on a new line ""u8"), + Keyword("u8"), Identifier("more"), Local("stuff")); } @@ -464,6 +467,7 @@ await TestInMethodAsync(code, Verbatim(@"@"" goo bar and on a new line ""U8"), + Keyword("U8"), Identifier("more"), Local("stuff")); } @@ -506,6 +510,7 @@ await TestAsync( script ? Field("s") : Local("s"), Operators.Equals, Verbatim(@"@""""""/*""u8"), + Keyword("u8"), Punctuation.Semicolon); } @@ -526,6 +531,7 @@ await TestAsync( script ? Field("s") : Local("s"), Operators.Equals, Verbatim(@"@""""""/*""u8"), + Keyword("u8"), Punctuation.Semicolon); } @@ -544,7 +550,8 @@ public async Task StringLiteralUtf8_01(TestHost testHost) { await TestAsync(@"""goo""u8", testHost, - String(@"""goo""u8")); + String(@"""goo""u8"), + Keyword("u8")); } [Theory] @@ -553,7 +560,8 @@ public async Task StringLiteralUtf8_02(TestHost testHost) { await TestAsync(@"""goo""U8", testHost, - String(@"""goo""U8")); + String(@"""goo""U8"), + Keyword("U8")); } [Theory] @@ -571,7 +579,8 @@ public async Task StringLiteralUtf8_03(TestHost testHost) { await TestAsync(@"""""u8", testHost, - String(@"""""u8")); + String(@"""""u8"), + Keyword("u8")); } [Theory] @@ -580,7 +589,8 @@ public async Task StringLiteralUtf8_04(TestHost testHost) { await TestAsync(@"""""U8", testHost, - String(@"""""U8")); + String(@"""""U8"), + Keyword("U8")); } [Theory] @@ -4541,6 +4551,47 @@ await TestAsync( Punctuation.CloseCurly); } + [Theory] + [CombinatorialData] + public async Task TestConflictMarkers2(TestHost testHost) + { + await TestAsync( +@"class C +{ +<<<<<<< Start + public void Goo(); +||||||| Baseline + int removed; +======= + public void Bar(); +>>>>>>> End +}", + testHost, + Keyword("class"), + Class("C"), + Punctuation.OpenCurly, + Comment("<<<<<<< Start"), + Keyword("public"), + Keyword("void"), + Method("Goo"), + Punctuation.OpenParen, + Punctuation.CloseParen, + Punctuation.Semicolon, + Comment("||||||| Baseline"), + Keyword("int"), + Identifier("removed"), + Punctuation.Semicolon, + Comment("======="), + Keyword("public"), + Keyword("void"), + Identifier("Bar"), + Punctuation.OpenParen, + Punctuation.CloseParen, + Punctuation.Semicolon, + Comment(">>>>>>> End"), + Punctuation.CloseCurly); + } + [Theory] [CombinatorialData] public async Task TestUnmanagedConstraint_InsideMethod(TestHost testHost) @@ -5967,6 +6018,7 @@ await TestAsync(code, Local("s"), Operators.Equals, String("\"\"\"Hello world\"\"\"u8"), + Keyword("u8"), Punctuation.Semicolon, Punctuation.CloseCurly, Punctuation.CloseCurly); @@ -6004,6 +6056,7 @@ await TestAsync(code, Local("s"), Operators.Equals, String("\"\"\"Hello world\"\"\"U8"), + Keyword("U8"), Punctuation.Semicolon, Punctuation.CloseCurly, Punctuation.CloseCurly); @@ -6086,6 +6139,7 @@ await TestAsync(code, String(@""""""" Hello world """"""u8"), + Keyword("u8"), Punctuation.Semicolon, Punctuation.CloseCurly, Punctuation.CloseCurly); @@ -6127,6 +6181,7 @@ await TestAsync(code, String(@""""""" Hello world """"""U8"), + Keyword("U8"), Punctuation.Semicolon, Punctuation.CloseCurly, Punctuation.CloseCurly); diff --git a/src/EditorFeatures/CSharpTest/Classification/TotalClassifierTests.cs b/src/EditorFeatures/CSharpTest/Classification/TotalClassifierTests.cs index 751d1a920de57..30cb692222006 100644 --- a/src/EditorFeatures/CSharpTest/Classification/TotalClassifierTests.cs +++ b/src/EditorFeatures/CSharpTest/Classification/TotalClassifierTests.cs @@ -189,9 +189,9 @@ await TestAsync( testHost, Keyword("record"), Keyword("class"), - Record("R"), + RecordClass("R"), Punctuation.OpenCurly, - Record("R"), + RecordClass("R"), Punctuation.OpenParen, Punctuation.CloseParen, Punctuation.OpenCurly, diff --git a/src/EditorFeatures/CSharpTest/CodeActions/ApplyChangesOperationTests.cs b/src/EditorFeatures/CSharpTest/CodeActions/ApplyChangesOperationTests.cs new file mode 100644 index 0000000000000..73ca22fec77ab --- /dev/null +++ b/src/EditorFeatures/CSharpTest/CodeActions/ApplyChangesOperationTests.cs @@ -0,0 +1,265 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.CodeActions; +using Microsoft.CodeAnalysis.CodeRefactorings; +using Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.CodeRefactorings; +using Microsoft.CodeAnalysis.Shared.Utilities; +using Microsoft.CodeAnalysis.Text; +using Roslyn.Test.Utilities; +using Xunit; + +namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.CodeActions +{ + public class ApplyChangesOperationTests : AbstractCSharpCodeActionTest + { + protected override CodeRefactoringProvider CreateCodeRefactoringProvider(Workspace workspace, TestParameters parameters) + => new MyCodeRefactoringProvider((Func)parameters.fixProviderData); + + private class MyCodeRefactoringProvider : CodeRefactoringProvider + { + private readonly Func _changeSolution; + + public MyCodeRefactoringProvider(Func changeSolution) + { + _changeSolution = changeSolution; + } + + public sealed override Task ComputeRefactoringsAsync(CodeRefactoringContext context) + { + var codeAction = new TestCodeAction(_changeSolution(context.Document.Project.Solution)); + context.RegisterRefactoring(codeAction); + return Task.CompletedTask; + } + + private sealed class TestCodeAction : CodeAction + { + private readonly Solution _changedSolution; + + public TestCodeAction(Solution changedSolution) + { + _changedSolution = changedSolution; + } + + public override string Title => "Title"; + + protected override Task GetChangedSolutionAsync(CancellationToken cancellationToken) + => Task.FromResult(_changedSolution); + } + } + + [WpfFact, WorkItem(1419139, "https://devdiv.visualstudio.com/DevDiv/_queries/edit/1419139")] + public async Task TestMakeTextChangeWithInterveningEditToDifferentFile() + { + // This should succeed as the code action is trying to edit a file that is not touched by the actual + // workspace edit that already went in. + await TestSuccessfulApplicationAsync( +@" + + +class Program1 +{ +} + + +class Program2 +{ +} + + +", + codeActionTransform: solution => + { + var document1 = solution.Projects.Single().Documents.Single(d => d.FilePath!.Contains("Program1")); + return solution.WithDocumentText(document1.Id, SourceText.From("NewProgram1Content")); + }, + intermediaryTransform: solution => + { + var document2 = solution.Projects.Single().Documents.Single(d => d.FilePath!.Contains("Program2")); + return solution.WithDocumentText(document2.Id, SourceText.From("NewProgram2Content")); + }); + } + + [WpfFact, WorkItem(1419139, "https://devdiv.visualstudio.com/DevDiv/_queries/edit/1419139")] + public async Task TestMakeTextChangeWithInterveningRemovalToDifferentFile() + { + // This should succeed as the code action is trying to edit a file that is not touched by the actual + // workspace edit that already went in. + await TestSuccessfulApplicationAsync( +@" + + +class Program1 +{ +} + + +class Program2 +{ +} + + +", + codeActionTransform: solution => + { + var document1 = solution.Projects.Single().Documents.Single(d => d.FilePath!.Contains("Program1")); + return solution.WithDocumentText(document1.Id, SourceText.From("NewProgram1Content")); + }, + intermediaryTransform: solution => + { + var document2 = solution.Projects.Single().Documents.Single(d => d.FilePath!.Contains("Program2")); + return solution.RemoveDocument(document2.Id); + }); + } + + [WpfFact, WorkItem(1419139, "https://devdiv.visualstudio.com/DevDiv/_queries/edit/1419139")] + public async Task TestMakeTextChangeWithInterveningEditToSameFile() + { + // This should fail as the code action is trying to edit a file that is was already edited by the actual + // workspace edit that already went in. + await TestFailureApplicationAsync( +@" + + +class Program1 +{ +} + + +class Program2 +{ +} + + +", + codeActionTransform: solution => + { + var document1 = solution.Projects.Single().Documents.Single(d => d.FilePath!.Contains("Program1")); + return solution.WithDocumentText(document1.Id, SourceText.From("NewProgram1Content1")); + }, + intermediaryTransform: solution => + { + var document1 = solution.Projects.Single().Documents.Single(d => d.FilePath!.Contains("Program1")); + return solution.WithDocumentText(document1.Id, SourceText.From("NewProgram1Content2")); + }); + } + + [WpfFact, WorkItem(1419139, "https://devdiv.visualstudio.com/DevDiv/_queries/edit/1419139")] + public async Task TestMakeTextChangeWithInterveningRemovalOfThatFile() + { + // This should fail as the code action is trying to edit a file that is subsequently removed. + await TestFailureApplicationAsync( +@" + + +class Program1 +{ +} + + +class Program2 +{ +} + + +", + codeActionTransform: solution => + { + var document1 = solution.Projects.Single().Documents.Single(d => d.FilePath!.Contains("Program1")); + return solution.WithDocumentText(document1.Id, SourceText.From("NewProgram1Content1")); + }, + intermediaryTransform: solution => + { + var document1 = solution.Projects.Single().Documents.Single(d => d.FilePath!.Contains("Program1")); + return solution.RemoveDocument(document1.Id); + }); + } + + [WpfFact, WorkItem(1419139, "https://devdiv.visualstudio.com/DevDiv/_queries/edit/1419139")] + public async Task TestMakeProjectChangeWithInterveningTextEdit() + { + // This should fail as we don't want to make non-text changes that may have undesirable results to the solution + // given the intervening edits. + await TestFailureApplicationAsync( +@" + + +class Program1 +{ +} + + +class Program2 +{ +} + + +", + codeActionTransform: solution => + { + var document1 = solution.Projects.Single().Documents.Single(d => d.FilePath!.Contains("Program1")); + return solution.RemoveDocument(document1.Id); + }, + intermediaryTransform: solution => + { + var document2 = solution.Projects.Single().Documents.Single(d => d.FilePath!.Contains("Program2")); + return solution.WithDocumentText(document2.Id, SourceText.From("NewProgram1Content2")); + }); + } + + private async Task TestSuccessfulApplicationAsync( + string workspaceXml, + Func codeActionTransform, + Func intermediaryTransform) + { + await TestApplicationAsync(workspaceXml, codeActionTransform, intermediaryTransform, success: true); + } + + private async Task TestFailureApplicationAsync( + string workspaceXml, + Func codeActionTransform, + Func intermediaryTransform) + { + await TestApplicationAsync(workspaceXml, codeActionTransform, intermediaryTransform, success: false); + } + + private async Task TestApplicationAsync( + string workspaceXml, + Func codeActionTransform, + Func intermediaryTransform, + bool success) + { + var parameters = new TestParameters(fixProviderData: codeActionTransform); + using var workspace = CreateWorkspaceFromOptions(workspaceXml, parameters); + + var originalSolution = workspace.CurrentSolution; + + var document = GetDocument(workspace); + var provider = CreateCodeRefactoringProvider(workspace, parameters); + + var refactorings = new List(); + var context = new CodeRefactoringContext(document, new TextSpan(), refactorings.Add, CancellationToken.None); + + // Compute refactorings based on the original solution. + await provider.ComputeRefactoringsAsync(context); + var action = refactorings.Single(); + var operations = await action.GetOperationsAsync(CancellationToken.None); + var operation = operations.Single(); + + // Now make an intermediary edit to the workspace that is applied back in. + var changedSolution = intermediaryTransform(originalSolution); + Assert.True(workspace.TryApplyChanges(changedSolution)); + + // Now try to apply the refactoring, even though an intervening edit happened. + var result = await operation.TryApplyAsync(workspace, originalSolution, new ProgressTracker(), CancellationToken.None); + + Assert.Equal(success, result); + } + } +} diff --git a/src/EditorFeatures/CSharpTest/CodeActions/MoveType/MoveTypeTests.MoveToNewFile.cs b/src/EditorFeatures/CSharpTest/CodeActions/MoveType/MoveTypeTests.MoveToNewFile.cs index 3061500938ecb..fe746aca9129c 100644 --- a/src/EditorFeatures/CSharpTest/CodeActions/MoveType/MoveTypeTests.MoveToNewFile.cs +++ b/src/EditorFeatures/CSharpTest/CodeActions/MoveType/MoveTypeTests.MoveToNewFile.cs @@ -1655,5 +1655,36 @@ class A await TestMoveTypeToNewFileAsync(code, codeAfterMove, expectedDocumentName, destinationDocumentText); } + + [WpfTheory, Trait(Traits.Feature, Traits.Features.CodeActionsMoveType)] + [WorkItem(63114, "https://github.com/dotnet/roslyn/issues/63114")] + [InlineData("class")] + [InlineData("struct")] + [InlineData("interface")] + [InlineData("enum")] + [InlineData("record")] + public async Task MoveNestedTypeFromInterface(string memberType) + { + var code = $@" +interface I +{{ + {memberType} [||]Member + {{ + }} +}}"; + var codeAfterMove = @" +partial interface I +{ +}"; + var expectedDocumentName = "Member.cs"; + var destinationDocumentText = $@" +partial interface I +{{ + {memberType} Member + {{ + }} +}}"; + await TestMoveTypeToNewFileAsync(code, codeAfterMove, expectedDocumentName, destinationDocumentText); + } } } diff --git a/src/EditorFeatures/CSharpTest/CodeActions/Preview/PreviewExceptionTests.cs b/src/EditorFeatures/CSharpTest/CodeActions/Preview/PreviewExceptionTests.cs index 8f0061371aedd..00380d1127ff5 100644 --- a/src/EditorFeatures/CSharpTest/CodeActions/Preview/PreviewExceptionTests.cs +++ b/src/EditorFeatures/CSharpTest/CodeActions/Preview/PreviewExceptionTests.cs @@ -72,7 +72,7 @@ private static async Task GetPreview(TestWorkspace workspace, CodeRefactoringPro var suggestedAction = new CodeRefactoringSuggestedAction( workspace.ExportProvider.GetExportedValue(), workspace.ExportProvider.GetExportedValue(), - workspace, textBuffer, provider, codeActions.First(), fixAllFlavors: null); + workspace, workspace.CurrentSolution, textBuffer, provider, codeActions.First(), fixAllFlavors: null); await suggestedAction.GetPreviewAsync(CancellationToken.None); Assert.True(extensionManager.IsDisabled(provider)); Assert.False(extensionManager.IsIgnored(provider)); @@ -85,7 +85,7 @@ private static void DisplayText(TestWorkspace workspace, CodeRefactoringProvider var suggestedAction = new CodeRefactoringSuggestedAction( workspace.ExportProvider.GetExportedValue(), workspace.ExportProvider.GetExportedValue(), - workspace, textBuffer, provider, codeActions.First(), fixAllFlavors: null); + workspace, workspace.CurrentSolution, textBuffer, provider, codeActions.First(), fixAllFlavors: null); _ = suggestedAction.DisplayText; Assert.True(extensionManager.IsDisabled(provider)); Assert.False(extensionManager.IsIgnored(provider)); @@ -98,7 +98,7 @@ private static async Task ActionSets(TestWorkspace workspace, CodeRefactoringPro var suggestedAction = new CodeRefactoringSuggestedAction( workspace.ExportProvider.GetExportedValue(), workspace.ExportProvider.GetExportedValue(), - workspace, textBuffer, provider, codeActions.First(), fixAllFlavors: null); + workspace, workspace.CurrentSolution, textBuffer, provider, codeActions.First(), fixAllFlavors: null); _ = await suggestedAction.GetActionSetsAsync(CancellationToken.None); Assert.True(extensionManager.IsDisabled(provider)); Assert.False(extensionManager.IsIgnored(provider)); @@ -115,7 +115,7 @@ private static void RefactoringSetup( var context = new CodeRefactoringContext(document, span, (a) => codeActions.Add(a), CancellationToken.None); provider.ComputeRefactoringsAsync(context).Wait(); var action = codeActions.Single(); - extensionManager = document.Project.Solution.Workspace.Services.GetService() as EditorLayerExtensionManager.ExtensionManager; + extensionManager = document.Project.Solution.Services.GetService() as EditorLayerExtensionManager.ExtensionManager; } } } diff --git a/src/EditorFeatures/CSharpTest/CommentSelection/CSharpCommentSelectionTests.cs b/src/EditorFeatures/CSharpTest/CommentSelection/CSharpCommentSelectionTests.cs index e2b9883499aa6..53d6786c41398 100644 --- a/src/EditorFeatures/CSharpTest/CommentSelection/CSharpCommentSelectionTests.cs +++ b/src/EditorFeatures/CSharpTest/CommentSelection/CSharpCommentSelectionTests.cs @@ -10,6 +10,7 @@ using Microsoft.CodeAnalysis.CommentSelection; using Microsoft.CodeAnalysis.Editor.UnitTests.Utilities; using Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces; +using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Test.Utilities; using Microsoft.VisualStudio.Text; using Microsoft.VisualStudio.Text.Editor; @@ -119,7 +120,7 @@ private static void UncommentSelection(string markup, string expected) var commandHandler = new CommentUncommentSelectionCommandHandler( workspace.GetService(), workspace.GetService(), - workspace.GlobalOptions); + workspace.GetService()); var textView = doc.GetTextView(); var textBuffer = doc.GetTextBuffer(); diff --git a/src/EditorFeatures/CSharpTest/CompleteStatement/CSharpCompleteStatementCommandHandlerTests.cs b/src/EditorFeatures/CSharpTest/CompleteStatement/CSharpCompleteStatementCommandHandlerTests.cs index a0dc626ee8d0f..a7f28f7d37c32 100644 --- a/src/EditorFeatures/CSharpTest/CompleteStatement/CSharpCompleteStatementCommandHandlerTests.cs +++ b/src/EditorFeatures/CSharpTest/CompleteStatement/CSharpCompleteStatementCommandHandlerTests.cs @@ -4245,6 +4245,60 @@ public int XValue globalOptions.SetGlobalOption(new OptionKey(FeatureOnOffOptions.AutomaticallyCompleteStatementOnSemicolon), false); }); } + + [WpfFact] + public void TestSwitchExpression() + { + var code = @" +public class Bar +{ + public void Test(string myString) + { + var a = myString switch + { + ""Hello"" => 1, + ""World"" => 2, + _ => 3$$ + } + } +}"; + + var expected = @" +public class Bar +{ + public void Test(string myString) + { + var a = myString switch + { + ""Hello"" => 1, + ""World"" => 2, + _ => 3 + };$$ + } +}"; + VerifyTypingSemicolon(code, expected); + } + + [WpfFact] + public void TestNotInBracesSwitchExpression() + { + var code = @" +public class Bar +{ + public void Test(string myString) + { + var a = myString switch + $${ + ""Hello"" => 1, + ""World"" => 2, + _ => 3 + } + } +}"; + + VerifyNoSpecialSemicolonHandling(code); + } + protected override TestWorkspace CreateTestWorkspace(string code) => TestWorkspace.CreateCSharp(code); } diff --git a/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/CompletionProviderOrderTests.cs b/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/CompletionProviderOrderTests.cs index 74fa9db644188..9493420581e9b 100644 --- a/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/CompletionProviderOrderTests.cs +++ b/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/CompletionProviderOrderTests.cs @@ -6,6 +6,7 @@ using System.Linq; using Microsoft.CodeAnalysis.Completion; using Microsoft.CodeAnalysis.Completion.Providers; +using Microsoft.CodeAnalysis.CSharp.Completion.CompletionProviders.Snippets; using Microsoft.CodeAnalysis.CSharp.Completion.Providers; using Microsoft.CodeAnalysis.Editor.UnitTests; using Microsoft.CodeAnalysis.Shared.Utilities; @@ -64,6 +65,7 @@ public void TestCompletionProviderOrder() typeof(ExtensionMethodImportCompletionProvider), typeof(AggregateEmbeddedLanguageCompletionProvider), typeof(FunctionPointerUnmanagedCallingConventionCompletionProvider), + typeof(CSharpSnippetCompletionProvider), // Built-in interactive providers typeof(LoadDirectiveCompletionProvider), diff --git a/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/KeywordCompletionProviderTests.cs b/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/KeywordCompletionProviderTests.cs index 5c3d6722ef93b..a82e059d390cd 100644 --- a/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/KeywordCompletionProviderTests.cs +++ b/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/KeywordCompletionProviderTests.cs @@ -550,7 +550,7 @@ class C {{ void M() {{ - var data = (n$$) { (hasNewline ? Environment.NewLine : string.Empty) } M(); + var data = (n$$) {(hasNewline ? Environment.NewLine : string.Empty)} M(); }} }}"; @@ -588,7 +588,7 @@ public async Task TestInCastExpressionThatMightBeParenthesizedExpression2(bool h var markup = $@"class C {{ - bool Prop => (t$$) { (hasExpression ? "n" : string.Empty) } + bool Prop => (t$$) {(hasExpression ? "n" : string.Empty)} private int n; }}"; if (hasExpression) @@ -620,7 +620,9 @@ public async Task TestInCastExpressionThatMightBeParenthesizedExpression2(bool h [Theory] [InlineData("class")] [InlineData("struct")] - public async Task SuggestRequiredInClassOrStruct(string type) + [InlineData("record")] + [InlineData("record struct")] + public async Task SuggestRequiredInClassOrStructOrRecord(string type) { var markup = $$""" {{type}} C @@ -684,5 +686,151 @@ class C await VerifyItemIsAbsentAsync(markup, "required"); } + + [Fact] + public async Task SuggestFileOnTypes() + { + var markup = $$""" + $$ class C { } + """; + + await VerifyItemExistsAsync(markup, "file"); + } + + [Fact] + public async Task DoNotSuggestFileAfterFile() + { + var markup = $$""" + file $$ + """; + + await VerifyItemIsAbsentAsync(markup, "file"); + } + + [Fact] + public async Task SuggestFileAfterReadonly() + { + // e.g. 'readonly file struct X { }' + var markup = $$""" + readonly $$ + """; + + await VerifyItemExistsAsync(markup, "file"); + } + + [Fact] + public async Task SuggestFileBeforeFileType() + { + var markup = $$""" + $$ + + file class C { } + """; + + // it might seem like we want to prevent 'file file class', + // but it's likely the user is declaring a file-local type above an existing file-local type here. + await VerifyItemExistsAsync(markup, "file"); + } + + [Fact] + public async Task SuggestFileBeforeDelegate() + { + var markup = $$""" + $$ delegate + """; + + await VerifyItemExistsAsync(markup, "file"); + } + + [Fact] + public async Task DoNotSuggestFileOnNestedTypes() + { + var markup = $$""" + class Outer + { + $$ class C { } + } + """; + + await VerifyItemIsAbsentAsync(markup, "file"); + } + + [Fact] + public async Task DoNotSuggestFileOnNonTypeMembers() + { + var markup = $$""" + class C + { + $$ + } + """; + + await VerifyItemIsAbsentAsync(markup, "file"); + } + + [Theory] + [InlineData("public")] + [InlineData("internal")] + [InlineData("protected")] + [InlineData("private")] + public async Task DoNotSuggestFileAfterFilteredKeywords(string keyword) + { + var markup = $$""" + {{keyword}} $$ + """; + + await VerifyItemIsAbsentAsync(markup, "file"); + } + + [Theory] + [InlineData("public")] + [InlineData("internal")] + [InlineData("protected")] + [InlineData("private")] + public async Task DoNotSuggestFilteredKeywordsAfterFile(string keyword) + { + var markup = $$""" + file $$ + """; + + await VerifyItemIsAbsentAsync(markup, keyword); + } + + [Fact] + public async Task SuggestFileInFileScopedNamespace() + { + var markup = $$""" + namespace NS; + + $$ + """; + + await VerifyItemExistsAsync(markup, "file"); + } + + [Fact] + public async Task SuggestFileInNamespace() + { + var markup = $$""" + namespace NS + { + $$ + } + """; + + await VerifyItemExistsAsync(markup, "file"); + } + + [Fact] + public async Task SuggestFileAfterClass() + { + var markup = $$""" + file class C { } + + $$ + """; + + await VerifyItemExistsAsync(markup, "file"); + } } } diff --git a/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/LoadDirectiveCompletionProviderTests.cs b/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/LoadDirectiveCompletionProviderTests.cs index cfde13317732a..ae5391dc6fad0 100644 --- a/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/LoadDirectiveCompletionProviderTests.cs +++ b/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/LoadDirectiveCompletionProviderTests.cs @@ -80,7 +80,7 @@ public void ShouldTriggerCompletion(string textWithPositionMarker, bool expected using var workspace = new TestWorkspace(composition: FeaturesTestCompositions.Features); var provider = workspace.ExportProvider.GetExports().Single(p => p.Metadata.Language == LanguageNames.CSharp && p.Metadata.Name == nameof(LoadDirectiveCompletionProvider)).Value; var languageServices = workspace.Services.GetLanguageServices(LanguageNames.CSharp); - Assert.Equal(expectedResult, provider.ShouldTriggerCompletion(languageServices, SourceText.From(text), position, trigger: default, CompletionOptions.Default, OptionValueSet.Empty)); + Assert.Equal(expectedResult, provider.ShouldTriggerCompletion(languageServices.LanguageServices, SourceText.From(text), position, trigger: default, CompletionOptions.Default, OptionValueSet.Empty)); } } } diff --git a/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/ObjectInitializerCompletionProviderTests.cs b/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/ObjectInitializerCompletionProviderTests.cs index 34e0458e21273..ba8e49f9aa0f5 100644 --- a/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/ObjectInitializerCompletionProviderTests.cs +++ b/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/ObjectInitializerCompletionProviderTests.cs @@ -996,6 +996,28 @@ static void Main(string[] args) await VerifyItemIsAbsentAsync(markup, "this"); } + [Fact, Trait(Traits.Feature, Traits.Features.Completion)] + public async Task RequiredMembersLabeledAndSelected() + { + var markup = @" +class C +{ + public required int RequiredField; + public required int RequiredProperty { get; set; } +} + +class D +{ + static void Main(string[] args) + { + var t = new C() { $$ }; + } +}"; + + await VerifyItemExistsAsync(markup, "RequiredField", inlineDescription: FeaturesResources.Required, matchPriority: MatchPriority.Preselect); + await VerifyItemExistsAsync(markup, "RequiredProperty", inlineDescription: FeaturesResources.Required); + } + [WorkItem(15205, "https://github.com/dotnet/roslyn/issues/15205")] [Fact, Trait(Traits.Feature, Traits.Features.Completion)] public async Task NestedPropertyInitializers1() @@ -1208,7 +1230,7 @@ private async Task VerifyExclusiveAsync(string markup, bool exclusive) if (!completionList.IsEmpty) { - Assert.True(exclusive == completionList.GetTestAccessor().IsExclusive, "group.IsExclusive == " + completionList.GetTestAccessor().IsExclusive); + Assert.True(exclusive == completionList.IsExclusive, "group.IsExclusive == " + completionList.IsExclusive); } } } diff --git a/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/OperatorCompletionProviderTests.cs b/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/OperatorCompletionProviderTests.cs index 5869337fe5125..c101644ed83ba 100644 --- a/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/OperatorCompletionProviderTests.cs +++ b/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/OperatorCompletionProviderTests.cs @@ -666,7 +666,7 @@ public static void Main() s.$$ }} }}"; - await VerifyItemExistsAsync(string.Format(template, $"public static bool operator {operatorSign}(S a, S b)"), operatorSign, inlineDescription: $"x { operatorSign } y"); + await VerifyItemExistsAsync(string.Format(template, $"public static bool operator {operatorSign}(S a, S b)"), operatorSign, inlineDescription: $"x {operatorSign} y"); await VerifyNoItemsExistAsync(string.Format(template, $"public static int operator {operatorSign}(S a, S b)")); await VerifyNoItemsExistAsync(string.Format(template, $"public static bool operator {operatorSign}(S a, S b, S c)")); await VerifyNoItemsExistAsync(string.Format(template, $"public static bool operator {operatorSign}(S a, object b)")); diff --git a/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/OverrideCompletionProviderTests.cs b/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/OverrideCompletionProviderTests.cs index bf9b80b7f84f0..f94790ce86ec8 100644 --- a/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/OverrideCompletionProviderTests.cs +++ b/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/OverrideCompletionProviderTests.cs @@ -2376,7 +2376,7 @@ public override void set_Bar(int bay, int value) var completionList = await GetCompletionListAsync(service, document, position, triggerInfo); var completionItem = completionList.ItemsList.First(i => CompareItems(i.DisplayText, "Bar[int bay]")); - if (service.GetProvider(completionItem) is ICustomCommitCompletionProvider customCommitCompletionProvider) + if (service.GetProvider(completionItem, document.Project) is ICustomCommitCompletionProvider customCommitCompletionProvider) { var textView = testWorkspace.GetTestDocument(documentId).GetTextView(); customCommitCompletionProvider.Commit(completionItem, textView, textView.TextBuffer, textView.TextSnapshot, '\t'); @@ -2633,7 +2633,7 @@ public override bool Equals(object obj) var completionList = await GetCompletionListAsync(service, document, position, triggerInfo); var completionItem = completionList.ItemsList.First(i => CompareItems(i.DisplayText, "Equals(object obj)")); - if (service.GetProvider(completionItem) is ICustomCommitCompletionProvider customCommitCompletionProvider) + if (service.GetProvider(completionItem, document.Project) is ICustomCommitCompletionProvider customCommitCompletionProvider) { var textView = testWorkspace.GetTestDocument(documentId).GetTextView(); customCommitCompletionProvider.Commit(completionItem, textView, textView.TextBuffer, textView.TextSnapshot, '\t'); @@ -2689,7 +2689,7 @@ public override bool Equals(object obj) var completionList = await GetCompletionListAsync(service, document, cursorPosition, triggerInfo); var completionItem = completionList.ItemsList.First(i => CompareItems(i.DisplayText, "Equals(object obj)")); - if (service.GetProvider(completionItem) is ICustomCommitCompletionProvider customCommitCompletionProvider) + if (service.GetProvider(completionItem, document.Project) is ICustomCommitCompletionProvider customCommitCompletionProvider) { var textView = testWorkspace.GetTestDocument(documentId).GetTextView(); customCommitCompletionProvider.Commit(completionItem, textView, textView.TextBuffer, textView.TextSnapshot, '\t'); @@ -2743,7 +2743,7 @@ public override required int Prop public async Task CommitRequiredKeywordPreserved(string ordering) { var markupBeforeCommit = $@" - + class Base {{ public virtual required int Prop {{ get; }} @@ -2782,7 +2782,7 @@ public override required int Prop public async Task CommitRequiredKeywordPreservedWhenBaseIsNotRequired(string ordering) { var markupBeforeCommit = $@" - + class Base {{ public virtual int Prop {{ get; }} diff --git a/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/PartialMethodCompletionProviderTests.cs b/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/PartialMethodCompletionProviderTests.cs index 3c25273d529b6..a97e57b113c82 100644 --- a/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/PartialMethodCompletionProviderTests.cs +++ b/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/PartialMethodCompletionProviderTests.cs @@ -9,6 +9,7 @@ using Microsoft.CodeAnalysis.CodeStyle; using Microsoft.CodeAnalysis.CSharp.CodeStyle; using Microsoft.CodeAnalysis.CSharp.Completion.Providers; +using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Test.Utilities; using Roslyn.Test.Utilities; using Xunit; @@ -780,9 +781,9 @@ public async Task ExpressionBodyMethod() using var workspaceFixture = GetOrCreateWorkspaceFixture(); var workspace = workspaceFixture.Target.GetWorkspace(ExportProvider); - workspace.TryApplyChanges(workspace.CurrentSolution.WithOptions(workspace.Options.WithChangedOption( - CSharpCodeStyleOptions.PreferExpressionBodiedMethods, - new CodeStyleOption2(ExpressionBodyPreference.WhenPossible, NotificationOption2.Silent)))); + workspace.GlobalOptions.SetGlobalOption( + new OptionKey(CSharpCodeStyleOptions.PreferExpressionBodiedMethods), + new CodeStyleOption2(ExpressionBodyPreference.WhenPossible, NotificationOption2.Silent)); var text = @"using System; partial class Bar @@ -811,9 +812,9 @@ public async Task ExpressionBodyMethodExtended() using var workspaceFixture = GetOrCreateWorkspaceFixture(); var workspace = workspaceFixture.Target.GetWorkspace(ExportProvider); - workspace.TryApplyChanges(workspace.CurrentSolution.WithOptions(workspace.Options.WithChangedOption( - CSharpCodeStyleOptions.PreferExpressionBodiedMethods, - new CodeStyleOption2(ExpressionBodyPreference.WhenPossible, NotificationOption2.Silent)))); + workspace.GlobalOptions.SetGlobalOption( + new OptionKey(CSharpCodeStyleOptions.PreferExpressionBodiedMethods), + new CodeStyleOption2(ExpressionBodyPreference.WhenPossible, NotificationOption2.Silent)); var text = @"using System; partial class Bar diff --git a/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/ReferenceDirectiveCompletionProviderTests.cs b/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/ReferenceDirectiveCompletionProviderTests.cs index c6de0cddb6809..1da0bb07f6c39 100644 --- a/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/ReferenceDirectiveCompletionProviderTests.cs +++ b/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/ReferenceDirectiveCompletionProviderTests.cs @@ -117,7 +117,7 @@ public void ShouldTriggerCompletion(string textWithPositionMarker, bool expected using var workspace = new TestWorkspace(composition: FeaturesTestCompositions.Features); var provider = workspace.ExportProvider.GetExports().Single(p => p.Metadata.Language == LanguageNames.CSharp && p.Metadata.Name == nameof(ReferenceDirectiveCompletionProvider)).Value; var languageServices = workspace.Services.GetLanguageServices(LanguageNames.CSharp); - Assert.Equal(expectedResult, provider.ShouldTriggerCompletion(languageServices, SourceText.From(text), position, trigger: default, CompletionOptions.Default, OptionValueSet.Empty)); + Assert.Equal(expectedResult, provider.ShouldTriggerCompletion(languageServices.LanguageServices, SourceText.From(text), position, trigger: default, CompletionOptions.Default, OptionValueSet.Empty)); } } } diff --git a/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/Snippets/AbstractCSharpSnippetCompletionProviderTests.cs b/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/Snippets/AbstractCSharpSnippetCompletionProviderTests.cs new file mode 100644 index 0000000000000..d885da86b410d --- /dev/null +++ b/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/Snippets/AbstractCSharpSnippetCompletionProviderTests.cs @@ -0,0 +1,30 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.Completion; +using Microsoft.CodeAnalysis.CSharp.Completion.CompletionProviders.Snippets; +using Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces; +using Microsoft.CodeAnalysis.Snippets; +using Microsoft.CodeAnalysis.Test.Utilities; + +namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.Completion.CompletionProviders.Snippets +{ + public abstract class AbstractCSharpSnippetCompletionProviderTests : AbstractCSharpCompletionProviderTests + { + protected abstract string ItemToCommit { get; } + + protected AbstractCSharpSnippetCompletionProviderTests() + { + ShowNewSnippetExperience = true; + } + + internal override Type GetCompletionProviderType() + => typeof(CSharpSnippetCompletionProvider); + } +} diff --git a/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/Snippets/CSharpConsoleSnippetCompletionProviderTests.cs b/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/Snippets/CSharpConsoleSnippetCompletionProviderTests.cs new file mode 100644 index 0000000000000..6fa41fb375c5e --- /dev/null +++ b/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/Snippets/CSharpConsoleSnippetCompletionProviderTests.cs @@ -0,0 +1,423 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.CSharp.Completion.CompletionProviders.Snippets; +using Microsoft.CodeAnalysis.Test.Utilities; +using Roslyn.Test.Utilities; +using Xunit; + +namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.Completion.CompletionProviders.Snippets +{ + public class CSharpConsoleSnippetCompletionProviderTests : AbstractCSharpSnippetCompletionProviderTests + { + protected override string ItemToCommit => "cw"; + + [WpfFact, Trait(Traits.Feature, Traits.Features.Completion)] + public async Task InsertConsoleSnippetInMethodTest() + { + var markupBeforeCommit = +@"class Program +{ + public void Method() + { + Wr$$ + } +}"; + + var expectedCodeAfterCommit = +@"using System; + +class Program +{ + public void Method() + { + Console.WriteLine($$); + } +}"; + await VerifyCustomCommitProviderAsync(markupBeforeCommit, ItemToCommit, expectedCodeAfterCommit); + } + + [WpfFact, Trait(Traits.Feature, Traits.Features.Completion)] + public async Task InsertAsyncConsoleSnippetTest() + { + var markupBeforeCommit = +@"class Program +{ + public async Task MethodAsync() + { + Wr$$ + } +}"; + + var expectedCodeAfterCommit = +@"using System; + +class Program +{ + public async Task MethodAsync() + { + await Console.Out.WriteLineAsync($$); + } +}"; + await VerifyCustomCommitProviderAsync(markupBeforeCommit, ItemToCommit, expectedCodeAfterCommit); + } + + [WpfFact, Trait(Traits.Feature, Traits.Features.Completion)] + public async Task InsertConsoleSnippetGlobalTest() + { + var markupBeforeCommit = +@"$$ +class Program +{ + public async Task MethodAsync() + { + } +}"; + + var expectedCodeAfterCommit = +@"using System; + +Console.WriteLine($$); + +class Program +{ + public async Task MethodAsync() + { + } +}"; + await VerifyCustomCommitProviderAsync(markupBeforeCommit, ItemToCommit, expectedCodeAfterCommit); + } + + [WpfFact, Trait(Traits.Feature, Traits.Features.Completion)] + public async Task NoConsoleSnippetInBlockNamespaceTest() + { + var markupBeforeCommit = +@" +namespace Namespace +{ + $$ + class Program + { + public async Task MethodAsync() + { + } + } +}"; + await VerifyItemIsAbsentAsync(markupBeforeCommit, ItemToCommit); + } + + [WpfFact, Trait(Traits.Feature, Traits.Features.Completion)] + public async Task NoConsoleSnippetInFileScopedNamespaceTest() + { + var markupBeforeCommit = +@" +namespace Namespace; +$$ +class Program +{ + public async Task MethodAsync() + { + } +} +"; + await VerifyItemIsAbsentAsync(markupBeforeCommit, ItemToCommit); + } + + [WpfFact, Trait(Traits.Feature, Traits.Features.Completion)] + public async Task InsertConsoleSnippetInConstructorTest() + { + var markupBeforeCommit = +@"class Program +{ + public Program() + { + var x = 5; + $$ + } +}"; + + var expectedCodeAfterCommit = +@"using System; + +class Program +{ + public Program() + { + var x = 5; + Console.WriteLine($$); + } +}"; + await VerifyCustomCommitProviderAsync(markupBeforeCommit, ItemToCommit, expectedCodeAfterCommit); + } + + /// + /// Simplifier does not work as intended, once that changes this outcome + /// should be able to simplify the inserted snippet. + /// + [WpfFact, Trait(Traits.Feature, Traits.Features.Completion)] + public async Task InsertConsoleSnippetInLocalFunctionTest() + { + var markupBeforeCommit = +@"class Program +{ + public void Method() + { + var x = 5; + void LocalMethod() + { + $$ + } + } +}"; + + var expectedCodeAfterCommit = +@"using System; + +class Program +{ + public void Method() + { + var x = 5; + void LocalMethod() + { + global::System.Console.WriteLine($$); + } + } +}"; + await VerifyCustomCommitProviderAsync(markupBeforeCommit, ItemToCommit, expectedCodeAfterCommit); + } + + /// + /// Simplifier does not work as intended, once that changes this outcome + /// should be able to simplify the inserted snippet. + /// + [WpfFact, Trait(Traits.Feature, Traits.Features.Completion)] + public async Task InsertConsoleSnippetInAnonymousFunctionTest() + { + var markupBeforeCommit = +@"public delegate void Print(int value); + +static void Main(string[] args) +{ + Print print = delegate(int val) { + $$ + }; + +}"; + + var expectedCodeAfterCommit = +@"using System; + +public delegate void Print(int value); + +static void Main(string[] args) +{ + Print print = delegate(int val) { + global::System.Console.WriteLine($$); + }; + +}"; + await VerifyCustomCommitProviderAsync(markupBeforeCommit, ItemToCommit, expectedCodeAfterCommit); + } + + /// + /// Simplifier does not work as intended, once that changes this outcome + /// should be able to simplify the inserted snippet. + /// + [WpfFact, Trait(Traits.Feature, Traits.Features.Completion)] + public async Task InsertConsoleSnippetInParenthesizedLambdaExpressionTest() + { + var markupBeforeCommit = +@" +Func testForEquality = (x, y) => +{ + $$ + return x == y; +};"; + + var expectedCodeAfterCommit = +@" +using System; + +Func testForEquality = (x, y) => +{ + global::System.Console.WriteLine($$); + return x == y; +};"; + await VerifyCustomCommitProviderAsync(markupBeforeCommit, ItemToCommit, expectedCodeAfterCommit); + } + + [WpfFact, Trait(Traits.Feature, Traits.Features.Completion)] + public async Task NoConsoleSnippetInSwitchExpression() + { + var markupBeforeCommit = +@"class Program +{ + public void Method() + { + var operation = 2; + + var result = operation switch + { + $$ + 1 => ""Case 1"", + 2 => ""Case 2"", + 3 => ""Case 3"", + 4 => ""Case 4"", + }; + } +}"; + await VerifyItemIsAbsentAsync(markupBeforeCommit, ItemToCommit); + } + + [WpfFact, Trait(Traits.Feature, Traits.Features.Completion)] + public async Task NoConsoleSnippetInSingleLambdaExpression() + { + var markupBeforeCommit = +@"class Program +{ + public void Method() + { + Func f = x => $$; + } +}"; + await VerifyItemIsAbsentAsync(markupBeforeCommit, ItemToCommit); + } + + [WpfFact, Trait(Traits.Feature, Traits.Features.Completion)] + public async Task NoConsoleSnippetInStringTest() + { + var markupBeforeCommit = +@"class Program +{ + public void Method() + { + var str = ""$$""; + } +}"; + + await VerifyItemIsAbsentAsync(markupBeforeCommit, ItemToCommit); + } + + [WpfFact, Trait(Traits.Feature, Traits.Features.Completion)] + public async Task NoConsoleSnippetInObjectInitializerTest() + { + var markupBeforeCommit = +@"class Program +{ + public void Method() + { + var str = new Test($$); + } +} + +class Test +{ + private string val; + + public Test(string val) + { + this.val = val; + } +}"; + + await VerifyItemIsAbsentAsync(markupBeforeCommit, ItemToCommit); + } + + [WpfFact, Trait(Traits.Feature, Traits.Features.Completion)] + public async Task NoConsoleSnippetInParameterListTest() + { + var markupBeforeCommit = +@"class Program +{ + public void Method(int x, $$) + { + } +}"; + + await VerifyItemIsAbsentAsync(markupBeforeCommit, ItemToCommit); + } + + [WpfFact, Trait(Traits.Feature, Traits.Features.Completion)] + public async Task NoConsoleSnippetInRecordDeclarationTest() + { + var markupBeforeCommit = +@"public record Person +{ + $$ + public string FirstName { get; init; } = default!; + public string LastName { get; init; } = default!; +};"; + + await VerifyItemIsAbsentAsync(markupBeforeCommit, ItemToCommit); + } + + [WpfFact, Trait(Traits.Feature, Traits.Features.Completion)] + public async Task NoConsoleSnippetInVariableDeclarationTest() + { + var markupBeforeCommit = +@"class Program +{ + public void Method() + { + var x = $$ + } +}"; + + await VerifyItemIsAbsentAsync(markupBeforeCommit, ItemToCommit); + } + + [WpfFact, Trait(Traits.Feature, Traits.Features.Completion)] + public async Task InsertConsoleSnippetWithInvocationBeforeAndAfterCursorTest() + { + var markupBeforeCommit = +@"class Program +{ + public void Method() + { + Wr$$Blah + } +}"; + + var expectedCodeAfterCommit = +@"using System; + +class Program +{ + public void Method() + { + Console.WriteLine($$); + } +}"; + await VerifyCustomCommitProviderAsync(markupBeforeCommit, ItemToCommit, expectedCodeAfterCommit); + } + + [WpfFact, Trait(Traits.Feature, Traits.Features.Completion)] + public async Task InsertConsoleSnippetWithInvocationUnderscoreBeforeAndAfterCursorTest() + { + var markupBeforeCommit = +@"class Program +{ + public void Method() + { + _Wr$$Blah_ + } +}"; + + var expectedCodeAfterCommit = +@"using System; + +class Program +{ + public void Method() + { + Console.WriteLine($$); + } +}"; + await VerifyCustomCommitProviderAsync(markupBeforeCommit, ItemToCommit, expectedCodeAfterCommit); + } + } +} diff --git a/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/Snippets/CSharpIfSnippetCompletionProviderTests.cs b/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/Snippets/CSharpIfSnippetCompletionProviderTests.cs new file mode 100644 index 0000000000000..86c9e3cc44f74 --- /dev/null +++ b/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/Snippets/CSharpIfSnippetCompletionProviderTests.cs @@ -0,0 +1,388 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation 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.Text; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.Completion; +using Microsoft.CodeAnalysis.CSharp.Completion.CompletionProviders.Snippets; +using Microsoft.CodeAnalysis.Snippets; +using Microsoft.CodeAnalysis.Test.Utilities; +using Roslyn.Test.Utilities; +using Xunit; + +namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.Completion.CompletionProviders.Snippets +{ + public class CSharpIfSnippetCompletionProviderTests : AbstractCSharpSnippetCompletionProviderTests + { + protected override string ItemToCommit => "if"; + + [WpfFact, Trait(Traits.Feature, Traits.Features.Completion)] + public async Task InsertIfSnippetInMethodTest() + { + var markupBeforeCommit = +@"class Program +{ + public void Method() + { + $$ + } +}"; + + var expectedCodeAfterCommit = +@"class Program +{ + public void Method() + { + if (true) + { + $$ + } + } +}"; + await VerifyCustomCommitProviderAsync(markupBeforeCommit, ItemToCommit, expectedCodeAfterCommit); + } + + [WpfFact, Trait(Traits.Feature, Traits.Features.Completion)] + public async Task InsertIfSnippetInGlobalContextTest() + { + var markupBeforeCommit = +@"Ins$$ +"; + + var expectedCodeAfterCommit = +@"if (true) +{ + $$ +} +"; + await VerifyCustomCommitProviderAsync(markupBeforeCommit, ItemToCommit, expectedCodeAfterCommit); + } + + [WpfFact, Trait(Traits.Feature, Traits.Features.Completion)] + public async Task NoIfSnippetInBlockNamespaceTest() + { + var markupBeforeCommit = +@" +namespace Namespace +{ + $$ + class Program + { + public async Task MethodAsync() + { + } + } +}"; + await VerifyItemIsAbsentAsync(markupBeforeCommit, ItemToCommit); + } + + [WpfFact, Trait(Traits.Feature, Traits.Features.Completion)] + public async Task NoIfSnippetInFileScopedNamespaceTest() + { + var markupBeforeCommit = +@" +namespace Namespace; +$$ +class Program +{ + public async Task MethodAsync() + { + } +} +"; + await VerifyItemIsAbsentAsync(markupBeforeCommit, ItemToCommit); + } + + [WpfFact, Trait(Traits.Feature, Traits.Features.Completion)] + public async Task InsertIfSnippetInConstructorTest() + { + var markupBeforeCommit = +@"class Program +{ + public Program() + { + var x = 5; + $$ + } +}"; + + var expectedCodeAfterCommit = +@"class Program +{ + public Program() + { + var x = 5; + if (true) + { + $$ + } + } +}"; + await VerifyCustomCommitProviderAsync(markupBeforeCommit, ItemToCommit, expectedCodeAfterCommit); + } + + [WpfFact, Trait(Traits.Feature, Traits.Features.Completion)] + public async Task InsertIfSnippettInLocalFunctionTest() + { + var markupBeforeCommit = +@"class Program +{ + public void Method() + { + var x = 5; + void LocalMethod() + { + $$ + } + } +}"; + + var expectedCodeAfterCommit = +@"class Program +{ + public void Method() + { + var x = 5; + void LocalMethod() + { + if (true) + { + $$ + } + } + } +}"; + await VerifyCustomCommitProviderAsync(markupBeforeCommit, ItemToCommit, expectedCodeAfterCommit); + } + + [WpfFact, Trait(Traits.Feature, Traits.Features.Completion)] + public async Task InsertIfSnippetInAnonymousFunctionTest() + { + var markupBeforeCommit = +@"public delegate void Print(int value); + +static void Main(string[] args) +{ + Print print = delegate(int val) { + $$ + }; + +}"; + + var expectedCodeAfterCommit = +@"public delegate void Print(int value); + +static void Main(string[] args) +{ + Print print = delegate(int val) { + if (true) + { + $$ + } + }; + +}"; + await VerifyCustomCommitProviderAsync(markupBeforeCommit, ItemToCommit, expectedCodeAfterCommit); + } + + [WpfFact, Trait(Traits.Feature, Traits.Features.Completion)] + public async Task InsertIfSnippetInParenthesizedLambdaExpressionTest() + { + var markupBeforeCommit = +@"Func testForEquality = (x, y) => +{ + $$ + return x == y; +};"; + + var expectedCodeAfterCommit = +@"Func testForEquality = (x, y) => +{ + if (true) + { + $$ + } + + return x == y; +};"; + await VerifyCustomCommitProviderAsync(markupBeforeCommit, ItemToCommit, expectedCodeAfterCommit); + } + + [WpfFact, Trait(Traits.Feature, Traits.Features.Completion)] + public async Task NoIfSnippetInSwitchExpression() + { + var markupBeforeCommit = +@"class Program +{ + public void Method() + { + var operation = 2; + + var result = operation switch + { + $$ + 1 => ""Case 1"", + 2 => ""Case 2"", + 3 => ""Case 3"", + 4 => ""Case 4"", + }; + } +}"; + await VerifyItemIsAbsentAsync(markupBeforeCommit, ItemToCommit); + } + + [WpfFact, Trait(Traits.Feature, Traits.Features.Completion)] + public async Task NoIfSnippetInSingleLambdaExpression() + { + var markupBeforeCommit = +@"class Program +{ + public void Method() + { + Func f = x => $$; + } +}"; + await VerifyItemIsAbsentAsync(markupBeforeCommit, ItemToCommit); + } + + [WpfFact, Trait(Traits.Feature, Traits.Features.Completion)] + public async Task NoIfSnippetInStringTest() + { + var markupBeforeCommit = +@"class Program +{ + public void Method() + { + var str = ""$$""; + } +}"; + + await VerifyItemIsAbsentAsync(markupBeforeCommit, ItemToCommit); + } + + [WpfFact, Trait(Traits.Feature, Traits.Features.Completion)] + public async Task NoIfSnippetInObjectInitializerTest() + { + var markupBeforeCommit = +@"class Program +{ + public void Method() + { + var str = new Test($$); + } +} + +class Test +{ + private string val; + + public Test(string val) + { + this.val = val; + } +}"; + + await VerifyItemIsAbsentAsync(markupBeforeCommit, ItemToCommit); + } + + [WpfFact, Trait(Traits.Feature, Traits.Features.Completion)] + public async Task NoIfSnippetInParameterListTest() + { + var markupBeforeCommit = +@"class Program +{ + public void Method(int x, $$) + { + } +}"; + + await VerifyItemIsAbsentAsync(markupBeforeCommit, ItemToCommit); + } + + [WpfFact, Trait(Traits.Feature, Traits.Features.Completion)] + public async Task NoIfSnippetInRecordDeclarationTest() + { + var markupBeforeCommit = +@"public record Person +{ + $$ + public string FirstName { get; init; } = default!; + public string LastName { get; init; } = default!; +};"; + + await VerifyItemIsAbsentAsync(markupBeforeCommit, ItemToCommit); + } + + [WpfFact, Trait(Traits.Feature, Traits.Features.Completion)] + public async Task NoIfSnippetInVariableDeclarationTest() + { + var markupBeforeCommit = +@"class Program +{ + public void Method() + { + var x = $$ + } +}"; + + await VerifyItemIsAbsentAsync(markupBeforeCommit, ItemToCommit); + } + + [WpfFact, Trait(Traits.Feature, Traits.Features.Completion)] + public async Task InsertIfSnippetWithInvocationBeforeAndAfterCursorTest() + { + var markupBeforeCommit = +@"class Program +{ + public void Method() + { + Wr$$Blah + } +}"; + + var expectedCodeAfterCommit = +@"class Program +{ + public void Method() + { + if (true) + { + $$ + } + } +}"; + await VerifyCustomCommitProviderAsync(markupBeforeCommit, ItemToCommit, expectedCodeAfterCommit); + } + + [WpfFact, Trait(Traits.Feature, Traits.Features.Completion)] + public async Task InsertIfSnippetWithInvocationUnderscoreBeforeAndAfterCursorTest() + { + var markupBeforeCommit = +@"class Program +{ + public void Method() + { + _Wr$$Blah_ + } +}"; + + var expectedCodeAfterCommit = +@"class Program +{ + public void Method() + { + if (true) + { + $$ + } + } +}"; + await VerifyCustomCommitProviderAsync(markupBeforeCommit, ItemToCommit, expectedCodeAfterCommit); + } + } +} diff --git a/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/SymbolCompletionProviderTests.cs b/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/SymbolCompletionProviderTests.cs index 7934a8dd8be98..10678041484e5 100644 --- a/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/SymbolCompletionProviderTests.cs +++ b/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/SymbolCompletionProviderTests.cs @@ -8361,7 +8361,7 @@ void goo() "; - var expectedDescription = $"({ FeaturesResources.field }) int C.x"; + var expectedDescription = $"({FeaturesResources.field}) int C.x"; await VerifyItemInLinkedFilesAsync(markup, "x", expectedDescription); } @@ -12108,7 +12108,7 @@ void M(int parameter) { } "; await VerifyItemExistsAsync(MakeMarkup(source), "parameter"); - await VerifyItemIsAbsentAsync(MakeMarkup(source, languageVersion: "10"), "parameter"); + await VerifyItemExistsAsync(MakeMarkup(source, languageVersion: "10"), "parameter"); } [Fact] @@ -12154,7 +12154,7 @@ void local(int parameter) { } // Tracked by https://github.com/dotnet/roslyn/issues/60801 await VerifyItemExistsAsync(MakeMarkup(source), "parameter", skipSpeculation: true); - await VerifyItemIsAbsentAsync(MakeMarkup(source, languageVersion: "10"), "parameter"); + await VerifyItemExistsAsync(MakeMarkup(source, languageVersion: "10"), "parameter", skipSpeculation: true); } [Fact] @@ -12173,7 +12173,7 @@ void local([Some(nameof(p$$))] int parameter) { } // Tracked by https://github.com/dotnet/roslyn/issues/60801 await VerifyItemExistsAsync(MakeMarkup(source), "parameter", skipSpeculation: true); - await VerifyItemIsAbsentAsync(MakeMarkup(source, languageVersion: "10"), "parameter"); + await VerifyItemExistsAsync(MakeMarkup(source, languageVersion: "10"), "parameter", skipSpeculation: true); } [Fact] @@ -12192,7 +12192,7 @@ void M() // Tracked by https://github.com/dotnet/roslyn/issues/60801 await VerifyItemExistsAsync(MakeMarkup(source), "parameter", skipSpeculation: true); - await VerifyItemIsAbsentAsync(MakeMarkup(source, languageVersion: "10"), "parameter"); + await VerifyItemExistsAsync(MakeMarkup(source, languageVersion: "10"), "parameter", skipSpeculation: true); } [Fact] @@ -12211,7 +12211,7 @@ void M() // Tracked by https://github.com/dotnet/roslyn/issues/60801 await VerifyItemExistsAsync(MakeMarkup(source), "parameter", skipSpeculation: true); - await VerifyItemIsAbsentAsync(MakeMarkup(source, languageVersion: "10"), "parameter"); + await VerifyItemExistsAsync(MakeMarkup(source, languageVersion: "10"), "parameter", skipSpeculation: true); } [Fact] @@ -12223,7 +12223,7 @@ public async Task ParameterAvailableInDelegateAttributeNameof() "; await VerifyItemExistsAsync(MakeMarkup(source), "parameter"); - await VerifyItemIsAbsentAsync(MakeMarkup(source, languageVersion: "10"), "parameter"); + await VerifyItemExistsAsync(MakeMarkup(source, languageVersion: "10"), "parameter"); } [Fact] @@ -12236,7 +12236,7 @@ public async Task ParameterAvailableInDelegateParameterAttributeNameof() // Tracked by https://github.com/dotnet/roslyn/issues/60801 await VerifyItemExistsAsync(MakeMarkup(source), "parameter", skipSpeculation: true); - await VerifyItemIsAbsentAsync(MakeMarkup(source, languageVersion: "10"), "parameter"); + await VerifyItemExistsAsync(MakeMarkup(source, languageVersion: "10"), "parameter", skipSpeculation: true); } private static string MakeMarkup(string source, string languageVersion = "Preview") diff --git a/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/SymbolCompletionProviderTests_NoInteractive.cs b/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/SymbolCompletionProviderTests_NoInteractive.cs index c7fa60b0e0706..1bac83582961a 100644 --- a/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/SymbolCompletionProviderTests_NoInteractive.cs +++ b/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/SymbolCompletionProviderTests_NoInteractive.cs @@ -12,7 +12,7 @@ using Microsoft.CodeAnalysis.CSharp.Completion.Providers; using Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.Completion.CompletionProviders; using Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Test.Utilities; using Microsoft.VisualStudio.Language.Intellisense.AsyncCompletion.Data; diff --git a/src/EditorFeatures/CSharpTest/ConflictMarkerResolution/ConflictMarkerResolutionTests.cs b/src/EditorFeatures/CSharpTest/ConflictMarkerResolution/ConflictMarkerResolutionTests.cs index 1ce40c2ed94f9..dce77df282827 100644 --- a/src/EditorFeatures/CSharpTest/ConflictMarkerResolution/ConflictMarkerResolutionTests.cs +++ b/src/EditorFeatures/CSharpTest/ConflictMarkerResolution/ConflictMarkerResolutionTests.cs @@ -577,7 +577,7 @@ public void M() [WorkItem(23847, "https://github.com/dotnet/roslyn/issues/23847")] [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsResolveConflictMarker)] - public async Task TestTakeTop_MiddleAndBottomCommentedOut() + public async Task TestTakeTop_SecondMiddleAndBottomCommentedOut() { var source = @" public class Class1 @@ -713,6 +713,21 @@ class X { }.RunAsync(); } + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsResolveConflictMarker)] + public async Task TestMissingWithFirstMiddleMarkerAtBottomOfFile() + { + var source = @"{|CS8300:<<<<<<<|} working copy +class X { +} +{|CS8300:||||||||}"; + + await new VerifyCS.Test + { + TestCode = source, + FixedCode = source, + }.RunAsync(); + } + [WorkItem(21107, "https://github.com/dotnet/roslyn/issues/21107")] [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsResolveConflictMarker)] public async Task TestFixAll1() @@ -851,6 +866,694 @@ class Program4 var fixedSource = @" using System; +namespace N +{ + class Program + { + } + class Program2 + { + } + + class Program3 + { + } + class Program4 + { + } +}"; + + await new VerifyCS.Test + { + TestCode = source, + FixedCode = fixedSource, + NumberOfIncrementalIterations = 2, + CodeActionIndex = 2, + CodeActionEquivalenceKey = AbstractResolveConflictMarkerCodeFixProvider.TakeBothEquivalenceKey, + }.RunAsync(); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsResolveConflictMarker)] + public async Task TestTakeTop_WithBaseline() + { + var source = @" +using System; + +namespace N +{ +{|CS8300:<<<<<<<|} This is mine! + class Program + { + static void Main(string[] args) + { + Program p; + Console.WriteLine(""My section""); + } + } +{|CS8300:||||||||} Baseline! + class Removed { } +{|CS8300:=======|} + class Program2 + { + static void Main2(string[] args) + { + Program2 p; + Console.WriteLine(""Their section""); + } + } +{|CS8300:>>>>>>>|} This is theirs! +}"; + var fixedSource = @" +using System; + +namespace N +{ + class Program + { + static void Main(string[] args) + { + Program p; + Console.WriteLine(""My section""); + } + } +}"; + + await new VerifyCS.Test + { + TestCode = source, + FixedCode = fixedSource, + NumberOfIncrementalIterations = 1, + CodeActionIndex = 0, + CodeActionEquivalenceKey = AbstractResolveConflictMarkerCodeFixProvider.TakeTopEquivalenceKey, + }.RunAsync(); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsResolveConflictMarker)] + public async Task TestTakeBottom1_WithBaseline() + { + var source = @" +using System; + +namespace N +{ +{|CS8300:<<<<<<<|} This is mine! + class Program + { + static void Main(string[] args) + { + Program p; + Console.WriteLine(""My section""); + } + } +{|CS8300:||||||||} Baseline! + class Removed { } +{|CS8300:=======|} + class Program2 + { + static void Main2(string[] args) + { + Program2 p; + Console.WriteLine(""Their section""); + } + } +{|CS8300:>>>>>>>|} This is theirs! +}"; + var fixedSource = @" +using System; + +namespace N +{ + class Program2 + { + static void Main2(string[] args) + { + Program2 p; + Console.WriteLine(""Their section""); + } + } +}"; + + await new VerifyCS.Test + { + TestCode = source, + FixedCode = fixedSource, + NumberOfIncrementalIterations = 1, + CodeActionIndex = 1, + CodeActionEquivalenceKey = AbstractResolveConflictMarkerCodeFixProvider.TakeBottomEquivalenceKey, + }.RunAsync(); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsResolveConflictMarker)] + public async Task TestTakeBoth1_WithBaseline() + { + var source = @" +using System; + +namespace N +{ +{|CS8300:<<<<<<<|} This is mine! + class Program + { + static void Main(string[] args) + { + Program p; + Console.WriteLine(""My section""); + } + } +{|CS8300:||||||||} Baseline! + class Removed { } +{|CS8300:=======|} + class Program2 + { + static void Main2(string[] args) + { + Program2 p; + Console.WriteLine(""Their section""); + } + } +{|CS8300:>>>>>>>|} This is theirs! +}"; + var fixedSource = @" +using System; + +namespace N +{ + class Program + { + static void Main(string[] args) + { + Program p; + Console.WriteLine(""My section""); + } + } + class Program2 + { + static void Main2(string[] args) + { + Program2 p; + Console.WriteLine(""Their section""); + } + } +}"; + + await new VerifyCS.Test + { + TestCode = source, + FixedCode = fixedSource, + NumberOfIncrementalIterations = 1, + CodeActionIndex = 2, + CodeActionEquivalenceKey = AbstractResolveConflictMarkerCodeFixProvider.TakeBothEquivalenceKey, + }.RunAsync(); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsResolveConflictMarker)] + public async Task TestEmptyTop_TakeTop_WithBaseline() + { + var source = @" +using System; + +namespace N +{ +{|CS8300:<<<<<<<|} This is mine! +{|CS8300:||||||||} Baseline! + class Removed { } +{|CS8300:=======|} + class Program2 + { + static void Main2(string[] args) + { + Program2 p; + Console.WriteLine(""Their section""); + } + } +{|CS8300:>>>>>>>|} This is theirs! +}"; + var fixedSource = @" +using System; + +namespace N +{ +}"; + + await new VerifyCS.Test + { + TestCode = source, + FixedCode = fixedSource, + NumberOfIncrementalIterations = 1, + CodeActionIndex = 0, + CodeActionEquivalenceKey = AbstractResolveConflictMarkerCodeFixProvider.TakeTopEquivalenceKey, + }.RunAsync(); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsResolveConflictMarker)] + public async Task TestEmptyTop_TakeBottom_WithBaseline() + { + var source = @" +using System; + +namespace N +{ +{|CS8300:<<<<<<<|} This is mine! +{|CS8300:||||||||} Baseline! + class Removed { } +{|CS8300:=======|} + class Program2 + { + static void Main2(string[] args) + { + Program2 p; + Console.WriteLine(""Their section""); + } + } +{|CS8300:>>>>>>>|} This is theirs! +}"; + var fixedSource = @" +using System; + +namespace N +{ + class Program2 + { + static void Main2(string[] args) + { + Program2 p; + Console.WriteLine(""Their section""); + } + } +}"; + + await new VerifyCS.Test + { + TestCode = source, + FixedCode = fixedSource, + NumberOfIncrementalIterations = 1, + CodeActionIndex = 1, + CodeActionEquivalenceKey = AbstractResolveConflictMarkerCodeFixProvider.TakeBottomEquivalenceKey, + }.RunAsync(); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsResolveConflictMarker)] + public async Task TestEmptyBottom_TakeTop_WithBaseline() + { + var source = @" +using System; + +namespace N +{ +{|CS8300:<<<<<<<|} This is mine! + class Program + { + static void Main(string[] args) + { + Program p; + Console.WriteLine(""My section""); + } + } +{|CS8300:||||||||} Baseline! + class Removed { } +{|CS8300:=======|} +{|CS8300:>>>>>>>|} This is theirs! +}"; + var fixedSource = @" +using System; + +namespace N +{ + class Program + { + static void Main(string[] args) + { + Program p; + Console.WriteLine(""My section""); + } + } +}"; + + await new VerifyCS.Test + { + TestCode = source, + FixedCode = fixedSource, + NumberOfIncrementalIterations = 1, + CodeActionIndex = 0, + CodeActionEquivalenceKey = AbstractResolveConflictMarkerCodeFixProvider.TakeTopEquivalenceKey, + }.RunAsync(); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsResolveConflictMarker)] + public async Task TestEmptyBottom_TakeBottom_WithBaseline() + { + var source = @" +using System; + +namespace N +{ +{|CS8300:<<<<<<<|} This is mine! + class Program + { + static void Main(string[] args) + { + Program p; + Console.WriteLine(""My section""); + } + } +{|CS8300:||||||||} Baseline! + class Removed { } +{|CS8300:=======|} +{|CS8300:>>>>>>>|} This is theirs! +}"; + var fixedSource = @" +using System; + +namespace N +{ +}"; + + await new VerifyCS.Test + { + TestCode = source, + FixedCode = fixedSource, + NumberOfIncrementalIterations = 1, + CodeActionIndex = 1, + CodeActionEquivalenceKey = AbstractResolveConflictMarkerCodeFixProvider.TakeBottomEquivalenceKey, + }.RunAsync(); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsResolveConflictMarker)] + public async Task TestTakeTop_TopCommentedOut_WithBaseline() + { + var source = @" +public class Class1 +{ + public void M() + { + /* +<<<<<<< dest + * a thing + */ +{|CS8300:||||||||} Baseline! + * previous thing + */ +{|CS8300:=======|} + * another thing + */ +{|CS8300:>>>>>>>|} source + // */ + } +}"; + var fixedSource = @" +public class Class1 +{ + public void M() + { + /* + * a thing + */ + // */ + } +}"; + + await new VerifyCS.Test + { + TestCode = source, + FixedCode = fixedSource, + NumberOfIncrementalIterations = 1, + CodeActionIndex = 0, + CodeActionEquivalenceKey = AbstractResolveConflictMarkerCodeFixProvider.TakeTopEquivalenceKey, + }.RunAsync(); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsResolveConflictMarker)] + public async Task TestTakeTop_FirstMiddleAndSecondMiddleAndBottomCommentedOut() + { + var source = @" +public class Class1 +{ + public void M() + { +{|CS8300:<<<<<<<|} dest + /* + * a thing +|||||||| Baseline! + * previous thing +======= + * + * another thing +>>>>>>> source + */ + } +}"; + var fixedSource = @" +public class Class1 +{ + public void M() + { + /* + * a thing + */ + } +}"; + + await new VerifyCS.Test + { + TestCode = source, + FixedCode = fixedSource, + NumberOfIncrementalIterations = 1, + CodeActionIndex = 0, + CodeActionEquivalenceKey = AbstractResolveConflictMarkerCodeFixProvider.TakeTopEquivalenceKey, + }.RunAsync(); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsResolveConflictMarker)] + public async Task TestTakeTop_TopInString_WithBaseline() + { + var source = @" +class X { + void x() { + var x = @"" +<<<<<<< working copy +a""; +{|CS8300:||||||||} baseline +previous""; +{|CS8300:=======|} +b""; +{|CS8300:>>>>>>>|} merge rev + } +}"; + var fixedSource = @" +class X { + void x() { + var x = @"" +a""; + } +}"; + + await new VerifyCS.Test + { + TestCode = source, + FixedCode = fixedSource, + NumberOfIncrementalIterations = 1, + CodeActionIndex = 0, + CodeActionEquivalenceKey = AbstractResolveConflictMarkerCodeFixProvider.TakeTopEquivalenceKey, + }.RunAsync(); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsResolveConflictMarker)] + public async Task TestTakeBottom_TopInString_WithBaseline() + { + var source = @" +class X { + void x() { + var x = @"" +<<<<<<< working copy +a""; +{|CS8300:||||||||} baseline +previous""; +{|CS8300:=======|} +b""; +{|CS8300:>>>>>>>|} merge rev + } +}"; + var fixedSource = @" +class X { + void x() { + var x = @"" +b""; + } +}"; + + await new VerifyCS.Test + { + TestCode = source, + FixedCode = fixedSource, + NumberOfIncrementalIterations = 1, + CodeActionIndex = 1, + CodeActionEquivalenceKey = AbstractResolveConflictMarkerCodeFixProvider.TakeBottomEquivalenceKey, + }.RunAsync(); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsResolveConflictMarker)] + public async Task TestMissingWithFirstMiddleMarkerAtTopOfFile() + { + var source = @"{|CS8300:||||||||} baseline +{|CS8300:=======|} +class X { +} +{|CS8300:>>>>>>>|} merge rev"; + + await new VerifyCS.Test + { + TestCode = source, + FixedCode = source, + }.RunAsync(); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsResolveConflictMarker)] + public async Task TestFixAll1_WithBaseline() + { + var source = @" +using System; + +namespace N +{ +{|CS8300:<<<<<<<|} This is mine! + class Program + { + } +{|CS8300:||||||||} baseline + class Removed { } +{|CS8300:=======|} + class Program2 + { + } +{|CS8300:>>>>>>>|} This is theirs! + +{|CS8300:<<<<<<<|} This is mine! + class Program3 + { + } +{|CS8300:||||||||} baseline + class Removed2 { } +{|CS8300:=======|} + class Program4 + { + } +{|CS8300:>>>>>>>|} This is theirs! +}"; + var fixedSource = @" +using System; + +namespace N +{ + class Program + { + } + + class Program3 + { + } +}"; + + await new VerifyCS.Test + { + TestCode = source, + FixedCode = fixedSource, + NumberOfIncrementalIterations = 2, + CodeActionIndex = 0, + CodeActionEquivalenceKey = AbstractResolveConflictMarkerCodeFixProvider.TakeTopEquivalenceKey, + }.RunAsync(); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsResolveConflictMarker)] + public async Task TestFixAll2_WithBaseline() + { + var source = @" +using System; + +namespace N +{ +{|CS8300:<<<<<<<|} This is mine! + class Program + { + } +{|CS8300:||||||||} baseline + class Removed { } +{|CS8300:=======|} + class Program2 + { + } +{|CS8300:>>>>>>>|} This is theirs! + +{|CS8300:<<<<<<<|} This is mine! + class Program3 + { + } +{|CS8300:||||||||} baseline + class Removed2 { } +{|CS8300:=======|} + class Program4 + { + } +{|CS8300:>>>>>>>|} This is theirs! +}"; + var fixedSource = @" +using System; + +namespace N +{ + class Program2 + { + } + + class Program4 + { + } +}"; + + await new VerifyCS.Test + { + TestCode = source, + FixedCode = fixedSource, + NumberOfIncrementalIterations = 2, + CodeActionIndex = 1, + CodeActionEquivalenceKey = AbstractResolveConflictMarkerCodeFixProvider.TakeBottomEquivalenceKey, + }.RunAsync(); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsResolveConflictMarker)] + public async Task TestFixAll3_WithBaseline() + { + var source = @" +using System; + +namespace N +{ +{|CS8300:<<<<<<<|} This is mine! + class Program + { + } +{|CS8300:||||||||} baseline + class Removed { } +{|CS8300:=======|} + class Program2 + { + } +{|CS8300:>>>>>>>|} This is theirs! + +{|CS8300:<<<<<<<|} This is mine! + class Program3 + { + } +{|CS8300:||||||||} baseline + class Removed2 { } +{|CS8300:=======|} + class Program4 + { + } +{|CS8300:>>>>>>>|} This is theirs! +}"; + var fixedSource = @" +using System; + namespace N { class Program diff --git a/src/EditorFeatures/CSharpTest/ConvertCast/ConvertDirectCastToTryCastTests.cs b/src/EditorFeatures/CSharpTest/ConvertCast/ConvertDirectCastToTryCastTests.cs index 9265b9e572c80..2283783f1251c 100644 --- a/src/EditorFeatures/CSharpTest/ConvertCast/ConvertDirectCastToTryCastTests.cs +++ b/src/EditorFeatures/CSharpTest/ConvertCast/ConvertDirectCastToTryCastTests.cs @@ -296,7 +296,7 @@ class Program {{ public static void Main() {{ - var x = { cast }; + var x = {cast}; }} }} "; @@ -307,7 +307,7 @@ class Program {{ public static void Main() {{ - var x = { asExpression }; + var x = {asExpression}; }} }} "; @@ -350,7 +350,7 @@ class Program {{ public static void Main() {{ - var x = { cast }; + var x = {cast}; }} }} "; @@ -359,7 +359,7 @@ class Program {{ public static void Main() {{ - var x = { asExpression }; + var x = {asExpression}; }} }} "; diff --git a/src/EditorFeatures/CSharpTest/ConvertCast/ConvertTryCastToDirectCastTests.cs b/src/EditorFeatures/CSharpTest/ConvertCast/ConvertTryCastToDirectCastTests.cs index c293fb5596ed4..f68a30c5bdf42 100644 --- a/src/EditorFeatures/CSharpTest/ConvertCast/ConvertTryCastToDirectCastTests.cs +++ b/src/EditorFeatures/CSharpTest/ConvertCast/ConvertTryCastToDirectCastTests.cs @@ -97,7 +97,7 @@ class Program {{ public static void Main() {{ - var x = { asExpression }; + var x = {asExpression}; }} }} "; @@ -108,7 +108,7 @@ class Program {{ public static void Main() {{ - var x = { cast }; + var x = {cast}; }} }} "; @@ -132,7 +132,7 @@ class Program {{ public static void Main() {{ - var x = { asExpression }; + var x = {asExpression}; }} }} "; @@ -141,7 +141,7 @@ class Program {{ public static void Main() {{ - var x = { cast }; + var x = {cast}; }} }} "; @@ -171,7 +171,7 @@ class Program {{ public static void Main() {{ - var x = { asExpression }; + var x = {asExpression}; }} }} "; @@ -180,7 +180,7 @@ class Program {{ public static void Main() {{ - var x = { cast }; + var x = {cast}; }} }} "; diff --git a/src/EditorFeatures/CSharpTest/ConvertProgram/ConvertToProgramMainAnalyzerTests.cs b/src/EditorFeatures/CSharpTest/ConvertProgram/ConvertToProgramMainAnalyzerTests.cs index 93a7bcb562ded..1abb5e278a9e2 100644 --- a/src/EditorFeatures/CSharpTest/ConvertProgram/ConvertToProgramMainAnalyzerTests.cs +++ b/src/EditorFeatures/CSharpTest/ConvertProgram/ConvertToProgramMainAnalyzerTests.cs @@ -598,6 +598,7 @@ private static void Main(string[] args) } [Fact] + [WorkItem(62943, "https://github.com/dotnet/roslyn/issues/62943")] public async Task TestHasExistingPart() { await new VerifyCS.Test @@ -615,57 +616,55 @@ partial class Program FixedCode = @" using System; -internal partial class Program +partial class Program { + int x; + private static void Main(string[] args) { Console.WriteLine(0); } -} - -partial class Program -{ - int x; -} -", +}", LanguageVersion = LanguageVersion.CSharp9, TestState = { OutputKind = OutputKind.ConsoleApplication }, Options = { { CSharpCodeStyleOptions.PreferTopLevelStatements, false, NotificationOption2.Suggestion } }, }.RunAsync(); } - [Fact] - public async Task TestHasExistingPublicPart() + [Theory] + [WorkItem(62943, "https://github.com/dotnet/roslyn/issues/62943")] + [InlineData("public")] + [InlineData("internal")] + [InlineData("static")] + [InlineData("abstract")] + [InlineData("file")] + public async Task TestHasExistingPart_KeepsModifiers(string modifier) { await new VerifyCS.Test { - TestCode = @" + TestCode = $@" using System; -{|IDE0211:Console|}.WriteLine(0); +{{|IDE0211:Console|}}.WriteLine(0); -public partial class Program -{ - int x; -} +{modifier} partial class Program +{{ + static int x; +}} ", - FixedCode = @" + FixedCode = $@" using System; -public partial class Program -{ +{modifier} partial class Program +{{ + static int x; + private static void Main(string[] args) - { + {{ Console.WriteLine(0); - } -} - -public partial class Program -{ - int x; -} -", - LanguageVersion = LanguageVersion.CSharp9, + }} +}}", + LanguageVersion = LanguageVersion.CSharp11, TestState = { OutputKind = OutputKind.ConsoleApplication }, Options = { { CSharpCodeStyleOptions.PreferTopLevelStatements, false, NotificationOption2.Suggestion } }, }.RunAsync(); diff --git a/src/EditorFeatures/CSharpTest/ConvertToRawString/ConvertToRegularStringToRawStringStringTests.cs b/src/EditorFeatures/CSharpTest/ConvertToRawString/ConvertToRegularStringToRawStringStringTests.cs index 87f7a0b79ec2e..3955c80185e90 100644 --- a/src/EditorFeatures/CSharpTest/ConvertToRawString/ConvertToRegularStringToRawStringStringTests.cs +++ b/src/EditorFeatures/CSharpTest/ConvertToRawString/ConvertToRegularStringToRawStringStringTests.cs @@ -3,6 +3,7 @@ // See the LICENSE file in the project root for more information. using System.Threading.Tasks; +using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.ConvertToRawString; using Microsoft.CodeAnalysis.CSharp.Shared.Extensions; using Microsoft.CodeAnalysis.Editor.UnitTests.CodeActions; @@ -22,7 +23,7 @@ private static async Task VerifyRefactoringAsync(string testCode, string fixedCo { TestCode = testCode, FixedCode = fixedCode, - LanguageVersion = LanguageVersionExtensions.CSharpNext, + LanguageVersion = LanguageVersion.CSharp11, CodeActionIndex = index, TestState = { diff --git a/src/EditorFeatures/CSharpTest/ConvertTupleToStruct/ConvertTupleToStructTests.cs b/src/EditorFeatures/CSharpTest/ConvertTupleToStruct/ConvertTupleToStructTests.cs index 17b3e42ce59f4..af24c7307c61c 100644 --- a/src/EditorFeatures/CSharpTest/ConvertTupleToStruct/ConvertTupleToStructTests.cs +++ b/src/EditorFeatures/CSharpTest/ConvertTupleToStruct/ConvertTupleToStructTests.cs @@ -2322,9 +2322,9 @@ public static implicit operator NewStruct((int a, int a) value) // /0/Test0.cs(13,16): error CS0102: The type 'NewStruct' already contains a definition for 'a' DiagnosticResult.CompilerError("CS0102").WithSpan(13, 16, 13, 17).WithArguments("NewStruct", "a"), // /0/Test0.cs(15,12): error CS0171: Field 'NewStruct.a' must be fully assigned before control is returned to the caller. Consider updating to language version 'preview' to auto-default the field. - DiagnosticResult.CompilerError("CS0171").WithSpan(15, 12, 15, 21).WithArguments("NewStruct.a", "preview"), + DiagnosticResult.CompilerError("CS0171").WithSpan(15, 12, 15, 21).WithArguments("NewStruct.a", "11.0"), // /0/Test0.cs(15,12): error CS0171: Field 'NewStruct.a' must be fully assigned before control is returned to the caller. Consider updating to language version 'preview' to auto-default the field. - DiagnosticResult.CompilerError("CS0171").WithSpan(15, 12, 15, 21).WithArguments("NewStruct.a", "preview"), + DiagnosticResult.CompilerError("CS0171").WithSpan(15, 12, 15, 21).WithArguments("NewStruct.a", "11.0"), // /0/Test0.cs(15,33): error CS0100: The parameter name 'a' is a duplicate DiagnosticResult.CompilerError("CS0100").WithSpan(15, 33, 15, 34).WithArguments("a"), // /0/Test0.cs(17,14): error CS0229: Ambiguity between 'NewStruct.a' and 'NewStruct.a' diff --git a/src/EditorFeatures/CSharpTest/Diagnostics/UpgradeProject/UpgradeProjectTests.cs b/src/EditorFeatures/CSharpTest/Diagnostics/UpgradeProject/UpgradeProjectTests.cs index c000f73e15c85..8e042eebac3e7 100644 --- a/src/EditorFeatures/CSharpTest/Diagnostics/UpgradeProject/UpgradeProjectTests.cs +++ b/src/EditorFeatures/CSharpTest/Diagnostics/UpgradeProject/UpgradeProjectTests.cs @@ -1100,7 +1100,7 @@ void M() [|}|]y""; } }", - expected: LanguageVersion.Preview, + expected: LanguageVersion.CSharp11, new CSharpParseOptions(LanguageVersion.CSharp8)); } @@ -1113,7 +1113,7 @@ struct Test public int X; public [|Test|]() { } }", - expected: LanguageVersion.Preview, + expected: LanguageVersion.CSharp11, new CSharpParseOptions(LanguageVersion.CSharp10)); } @@ -1126,7 +1126,7 @@ struct Test public int X; public [|Test|]() { this.ToString(); } }", - expected: LanguageVersion.Preview, + expected: LanguageVersion.CSharp11, new CSharpParseOptions(LanguageVersion.CSharp10)); } @@ -1139,7 +1139,7 @@ struct Test public int X { get; set; } public [|Test|]() { this.ToString(); } }", - expected: LanguageVersion.Preview, + expected: LanguageVersion.CSharp11, new CSharpParseOptions(LanguageVersion.CSharp10)); } } diff --git a/src/EditorFeatures/CSharpTest/DocumentationComments/DocumentationCommentTests.cs b/src/EditorFeatures/CSharpTest/DocumentationComments/DocumentationCommentTests.cs index 545ff1750236c..dd6c20cc9ca9f 100644 --- a/src/EditorFeatures/CSharpTest/DocumentationComments/DocumentationCommentTests.cs +++ b/src/EditorFeatures/CSharpTest/DocumentationComments/DocumentationCommentTests.cs @@ -4,7 +4,9 @@ #nullable disable +using Microsoft.CodeAnalysis.DocumentationComments; using Microsoft.CodeAnalysis.Editor.CSharp.DocumentationComments; +using Microsoft.CodeAnalysis.Editor.UnitTests.CodeActions; using Microsoft.CodeAnalysis.Editor.UnitTests.DocumentationComments; using Microsoft.CodeAnalysis.Editor.UnitTests.Extensions; using Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces; @@ -137,7 +139,10 @@ class C { }"; - VerifyTypingCharacter(code, expected, autoGenerateXmlDocComments: false); + VerifyTypingCharacter(code, expected, globalOptions: new OptionsCollection(LanguageNames.CSharp) + { + { DocumentationCommentOptionsStorage.AutoXmlDocCommentGeneration, false } + }); } [WpfFact, Trait(Traits.Feature, Traits.Features.DocumentationComments)] @@ -785,7 +790,10 @@ class C { }"; - VerifyPressingEnter(code, expected, autoGenerateXmlDocComments: false); + VerifyPressingEnter(code, expected, globalOptions: new OptionsCollection(LanguageNames.CSharp) + { + { DocumentationCommentOptionsStorage.AutoXmlDocCommentGeneration, false } + }); } [WpfFact, Trait(Traits.Feature, Traits.Features.DocumentationComments)] @@ -1344,7 +1352,10 @@ class C { }"; - VerifyPressingEnter(code, expected, autoGenerateXmlDocComments: false); + VerifyPressingEnter(code, expected, globalOptions: new OptionsCollection(LanguageNames.CSharp) + { + { DocumentationCommentOptionsStorage.AutoXmlDocCommentGeneration, false } + }); } [WpfFact, Trait(Traits.Feature, Traits.Features.DocumentationComments)] @@ -1787,7 +1798,10 @@ class C { }"; - VerifyInsertCommentCommand(code, expected, autoGenerateXmlDocComments: false); + VerifyInsertCommentCommand(code, expected, globalOptions: new OptionsCollection(LanguageNames.CSharp) + { + { DocumentationCommentOptionsStorage.AutoXmlDocCommentGeneration, false } + }); } [WorkItem(538714, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/538714")] @@ -2274,20 +2288,7 @@ class C { }"; /// class C { }"; - try - { - VerifyPressingEnter(code, expected, useTabs: true, setOptionsOpt: - workspace => - { - workspace.GetService().GlobalOptions - .SetOptionValue(DefaultOptions.TrimTrailingWhiteSpaceOptionName, true); - }); - } - finally - { - TestWorkspace.CreateCSharp("").GetService().GlobalOptions - .SetOptionValue(DefaultOptions.TrimTrailingWhiteSpaceOptionName, false); - } + VerifyPressingEnter(code, expected, useTabs: true, trimTrailingWhiteSpace: true); } [WpfFact, Trait(Traits.Feature, Traits.Features.DocumentationComments)] diff --git a/src/EditorFeatures/CSharpTest/EditAndContinue/ActiveStatementTests.Methods.cs b/src/EditorFeatures/CSharpTest/EditAndContinue/ActiveStatementTests.Methods.cs index 5ff1d656c7c7b..a39d40d978bc6 100644 --- a/src/EditorFeatures/CSharpTest/EditAndContinue/ActiveStatementTests.Methods.cs +++ b/src/EditorFeatures/CSharpTest/EditAndContinue/ActiveStatementTests.Methods.cs @@ -52,8 +52,43 @@ static void Main(string[] args) new[] { edits }, new[] { - DocumentResults(active, - new[] { SemanticEdit(SemanticEditKind.Delete, c => c.GetMember("C.Goo"), deletedSymbolContainerProvider: c => c.GetMember("C")) }) + DocumentResults( + active, + diagnostics: new[] { Diagnostic(RudeEditKind.Delete, "class C", DeletedSymbolDisplay(FeaturesResources.method, "Goo(int a)")) }) + }); + } + + [Fact] + public void Method_Rename_Leaf1() + { + var src1 = @" +class C +{ + static void Goo(int a) + { + Console.WriteLine(a); + } +}"; + var src2 = @" +class C +{ + static void Boo(int a) + { + Console.WriteLine(a); + } +} +"; + + var edits = GetTopEdits(src1, src2); + var active = GetActiveStatements(src1, src2); + + EditAndContinueValidation.VerifySemantics( + new[] { edits }, + new[] + { + DocumentResults( + active, + diagnostics: new[] {Diagnostic(RudeEditKind.UpdateAroundActiveStatement, "static void Boo(int a)", FeaturesResources.method) }) }); } @@ -607,8 +642,13 @@ public void Property_BlockBodyToExpressionBody2() var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); - edits.VerifySemanticDiagnostics(active, - Diagnostic(RudeEditKind.Delete, "int P", DeletedSymbolDisplay(CSharpFeaturesResources.property_setter, "P.set"))); + edits.VerifySemantics( + new[] + { + SemanticEdit(SemanticEditKind.Update, c => c.GetMember("C.get_P")), + SemanticEdit(SemanticEditKind.Delete, c => c.GetMember("C.set_P"), deletedSymbolContainerProvider: c => c.GetMember("C")), + }, + capabilities: EditAndContinueCapabilities.Baseline); } [Fact] @@ -688,8 +728,13 @@ public void Indexer_BlockBodyToExpressionBody2() var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); - edits.VerifySemanticDiagnostics(active, - Diagnostic(RudeEditKind.Delete, "int this[int a]", DeletedSymbolDisplay(CSharpFeaturesResources.indexer_setter, "this[int a].set"))); + edits.VerifySemantics( + new[] + { + SemanticEdit(SemanticEditKind.Update, c => c.GetMember("C.get_Item")), + SemanticEdit(SemanticEditKind.Delete, c => c.GetMember("C.set_Item"), deletedSymbolContainerProvider: c => c.GetMember("C")), + }, + capabilities: EditAndContinueCapabilities.Baseline); } [Fact] diff --git a/src/EditorFeatures/CSharpTest/EditAndContinue/ActiveStatementTests.cs b/src/EditorFeatures/CSharpTest/EditAndContinue/ActiveStatementTests.cs index c374754a9ca8f..4b4ba8928a8a5 100644 --- a/src/EditorFeatures/CSharpTest/EditAndContinue/ActiveStatementTests.cs +++ b/src/EditorFeatures/CSharpTest/EditAndContinue/ActiveStatementTests.cs @@ -2442,8 +2442,14 @@ class C var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); - edits.VerifySemanticDiagnostics(active, - Diagnostic(RudeEditKind.Delete, "class C", DeletedSymbolDisplay(FeaturesResources.auto_property, "a"))); + edits.VerifySemantics( + new[] + { + SemanticEdit(SemanticEditKind.Insert, c => c.GetMember("C.a")), + SemanticEdit(SemanticEditKind.Delete, c => c.GetMember("C.get_a"), deletedSymbolContainerProvider: c => c.GetMember("C")), + SemanticEdit(SemanticEditKind.Update, c => c.GetMember("C..ctor"), preserveLocalVariables: true), + }, + capabilities: EditAndContinueCapabilities.AddInstanceFieldToExistingType); } #endregion @@ -8712,6 +8718,56 @@ static void Main() edits.VerifySemanticDiagnostics(active); } + [Fact] + [WorkItem(61415, "https://github.com/dotnet/roslyn/issues/61415")] + public void Lambdas_EditAroundTry_WithActiveStatement() + { + var src1 = + """ + Action F = () => + { + try + { + G(); + } + catch + { + } + }; + + F(); + + void G() + { + } + """; + var src2 = + """ + Action F = () => + { + System.Console.WriteLine(1); + try + { + G(); + } + catch + { + } + }; + + F(); + + void G() + { + } + """; + + var edits = GetTopEdits(src1, src2); + var active = GetActiveStatements(src1, src2); + + edits.VerifySemanticDiagnostics(active); + } + [Fact] public void Lambdas_StatementsToExpression() { @@ -9924,6 +9980,56 @@ async Task f() Diagnostic(RudeEditKind.UpdatingStateMachineMethodAroundActiveStatement, "f")); } + [Fact] + [WorkItem(61415, "https://github.com/dotnet/roslyn/issues/61415")] + public void LocalFunction_EditAroundTry_WithActiveStatement() + { + var src1 = + """ + F(); + + void F() + { + try + { + G(); + } + catch + { + } + } + + void G() + { + } + """; + var src2 = + """ + F(); + + void F() + { + System.Console.WriteLine(1); + try + { + G(); + } + catch + { + } + } + + void G() + { + } + """; + + var edits = GetTopEdits(src1, src2); + var active = GetActiveStatements(src1, src2); + + edits.VerifySemanticDiagnostics(active); + } + [Fact] [WorkItem(37054, "https://github.com/dotnet/roslyn/issues/37054")] public void LocalFunctionToAsyncLocalFunction_ExpressionBody_WithActiveStatement() @@ -10677,13 +10783,13 @@ public void InsertDeleteMethod_Inactive() new[] { DocumentResults( - activeStatements: GetActiveStatements(srcA1, srcA2, path: "0"), + activeStatements: GetActiveStatements(srcA1, srcA2, documentIndex: 0), semanticEdits: new[] { SemanticEdit(SemanticEditKind.Update, c => c.GetMember("C").GetMember("F2")), }), DocumentResults( - activeStatements: GetActiveStatements(srcB1, srcB2, path: "1")) + activeStatements: GetActiveStatements(srcB1, srcB2, documentIndex: 1)) }); } @@ -10701,17 +10807,17 @@ public void InsertDeleteMethod_Active() var srcB2 = "partial class C { }"; EditAndContinueValidation.VerifySemantics( - new[] { GetTopEdits(srcA1, srcA2), GetTopEdits(srcB1, srcB2) }, + new[] { GetTopEdits(srcA1, srcA2, documentIndex: 0), GetTopEdits(srcB1, srcB2, documentIndex: 1) }, new[] { DocumentResults( - activeStatements: GetActiveStatements(srcA1, srcA2, path: "0"), + activeStatements: GetActiveStatements(srcA1, srcA2, documentIndex: 0), semanticEdits: new[] { SemanticEdit(SemanticEditKind.Update, c => c.GetMember("C").GetMember("F")), }), DocumentResults( - activeStatements: GetActiveStatements(srcB1, srcB2, path: "1"), + activeStatements: GetActiveStatements(srcB1, srcB2, documentIndex: 1), // TODO: this is odd AS location https://github.com/dotnet/roslyn/issues/54758 diagnostics: new[] { Diagnostic(RudeEditKind.DeleteActiveStatement, " partial c", DeletedSymbolDisplay(FeaturesResources.method, "F()")) }) }); diff --git a/src/EditorFeatures/CSharpTest/EditAndContinue/CSharpEditAndContinueAnalyzerTests.cs b/src/EditorFeatures/CSharpTest/EditAndContinue/CSharpEditAndContinueAnalyzerTests.cs index b5ec229d031ff..8618ad852b15f 100644 --- a/src/EditorFeatures/CSharpTest/EditAndContinue/CSharpEditAndContinueAnalyzerTests.cs +++ b/src/EditorFeatures/CSharpTest/EditAndContinue/CSharpEditAndContinueAnalyzerTests.cs @@ -7,9 +7,12 @@ using System; using System.Collections.Generic; using System.Collections.Immutable; +using System.IO; using System.Linq; +using System.Text; using System.Threading; using System.Threading.Tasks; +using EnvDTE; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.CSharp.Test.Utilities; using Microsoft.CodeAnalysis.Differencing; @@ -32,6 +35,18 @@ public class CSharpEditAndContinueAnalyzerTests #region Helpers + private static TestWorkspace CreateWorkspace() + => new(composition: s_composition); + + private static Solution AddDefaultTestProject(Solution solution, string source) + { + var projectId = ProjectId.CreateNewId(); + + return solution. + AddProject(ProjectInfo.Create(projectId, VersionStamp.Create(), "proj", "proj", LanguageNames.CSharp)).GetProject(projectId). + AddDocument("test.cs", SourceText.From(source, Encoding.UTF8), filePath: Path.Combine(TempRoot.Root, "test.cs")).Project.Solution; + } + private static void TestSpans(string source, Func hasLabel) { var tree = SyntaxFactory.ParseSyntaxTree(source); @@ -192,7 +207,7 @@ public void ErrorSpans_TopLevel() } "; - TestSpans(source, node => SyntaxComparer.TopLevel.HasLabel(node)); + TestSpans(source, SyntaxComparer.TopLevel.HasLabel); } [Fact] @@ -248,7 +263,7 @@ void M() // TODO: test // /**/F($$from a in b from c in d select a.x);/**/ // /**/F(from a in b $$from c in d select a.x);/**/ - TestSpans(source, kind => SyntaxComparer.Statement.HasLabel(kind)); + TestSpans(source, SyntaxComparer.Statement.HasLabel); } /// @@ -257,8 +272,8 @@ void M() [Fact] public void ErrorSpansAllKinds() { - TestErrorSpansAllKinds(kind => SyntaxComparer.Statement.HasLabel(kind)); - TestErrorSpansAllKinds(kind => SyntaxComparer.TopLevel.HasLabel(kind)); + TestErrorSpansAllKinds(SyntaxComparer.Statement.HasLabel); + TestErrorSpansAllKinds(SyntaxComparer.TopLevel.HasLabel); } [Fact] @@ -283,14 +298,14 @@ public static void Main() } "; - using var workspace = TestWorkspace.CreateCSharp(source1, composition: s_composition); - var oldSolution = workspace.CurrentSolution; + using var workspace = CreateWorkspace(); + var oldSolution = AddDefaultTestProject(workspace.CurrentSolution, source1); var oldProject = oldSolution.Projects.Single(); var oldDocument = oldProject.Documents.Single(); var oldText = await oldDocument.GetTextAsync(); var oldSyntaxRoot = await oldDocument.GetSyntaxRootAsync(); var documentId = oldDocument.Id; - var newSolution = workspace.CurrentSolution.WithDocumentText(documentId, SourceText.From(source2)); + var newSolution = oldSolution.WithDocumentText(documentId, SourceText.From(source2)); var newDocument = newSolution.GetDocument(documentId); var newText = await newDocument.GetTextAsync(); var newSyntaxRoot = await newDocument.GetSyntaxRootAsync(); @@ -350,12 +365,12 @@ public static void Main() } "; - using var workspace = TestWorkspace.CreateCSharp(source1, composition: s_composition); - var oldSolution = workspace.CurrentSolution; + using var workspace = CreateWorkspace(); + var oldSolution = AddDefaultTestProject(workspace.CurrentSolution, source1); var oldProject = oldSolution.Projects.Single(); var oldDocument = oldProject.Documents.Single(); var documentId = oldDocument.Id; - var newSolution = workspace.CurrentSolution.WithDocumentText(documentId, SourceText.From(source2)); + var newSolution = oldSolution.WithDocumentText(documentId, SourceText.From(source2)); var result = await AnalyzeDocumentAsync(oldProject, newSolution.GetDocument(documentId)); @@ -377,8 +392,9 @@ public static void Main() } "; - using var workspace = TestWorkspace.CreateCSharp(source, composition: s_composition); - var oldProject = workspace.CurrentSolution.Projects.Single(); + using var workspace = CreateWorkspace(); + var oldSolution = AddDefaultTestProject(workspace.CurrentSolution, source); + var oldProject = oldSolution.Projects.Single(); var oldDocument = oldProject.Documents.Single(); var result = await AnalyzeDocumentAsync(oldProject, oldDocument); @@ -410,14 +426,13 @@ public static void Main() } "; - using var workspace = TestWorkspace.CreateCSharp(source1, composition: s_composition); - - var oldSolution = workspace.CurrentSolution; + using var workspace = CreateWorkspace(); + var oldSolution = AddDefaultTestProject(workspace.CurrentSolution, source1); var oldProject = oldSolution.Projects.Single(); var oldDocument = oldProject.Documents.Single(); var documentId = oldDocument.Id; - var newSolution = workspace.CurrentSolution.WithDocumentText(documentId, SourceText.From(source2)); + var newSolution = oldSolution.WithDocumentText(documentId, SourceText.From(source2)); var result = await AnalyzeDocumentAsync(oldProject, newSolution.GetDocument(documentId)); @@ -440,11 +455,15 @@ public static void Main() "; var experimentalFeatures = new Dictionary(); // no experimental features to enable var experimental = TestOptions.Regular.WithFeatures(experimentalFeatures); + var root = SyntaxFactory.ParseCompilationUnit(source, options: experimental); - using var workspace = TestWorkspace.CreateCSharp( - source, parseOptions: experimental, compilationOptions: null, composition: s_composition); + using var workspace = CreateWorkspace(); + + var projectId = ProjectId.CreateNewId(); + var oldSolution = workspace.CurrentSolution. + AddProject(ProjectInfo.Create(projectId, VersionStamp.Create(), "proj", "proj", LanguageNames.CSharp)).GetProject(projectId). + AddDocument("test.cs", root, filePath: Path.Combine(TempRoot.Root, "test.cs")).Project.Solution; - var oldSolution = workspace.CurrentSolution; var oldProject = oldSolution.Projects.Single(); var oldDocument = oldProject.Documents.Single(); var documentId = oldDocument.Id; @@ -520,9 +539,9 @@ public static void Main() } "; - using var workspace = TestWorkspace.CreateCSharp(source, composition: s_composition); + using var workspace = CreateWorkspace(); + var oldSolution = AddDefaultTestProject(workspace.CurrentSolution, source); - var oldSolution = workspace.CurrentSolution; var oldProject = oldSolution.Projects.Single(); var oldDocument = oldProject.Documents.Single(); var documentId = oldDocument.Id; @@ -558,14 +577,13 @@ public static void Main() } "; - using var workspace = TestWorkspace.CreateCSharp(source1, composition: s_composition); - - var oldSolution = workspace.CurrentSolution; + using var workspace = CreateWorkspace(); + var oldSolution = AddDefaultTestProject(workspace.CurrentSolution, source1); var oldProject = oldSolution.Projects.Single(); var oldDocument = oldProject.Documents.Single(); var documentId = oldDocument.Id; - var newSolution = workspace.CurrentSolution.WithDocumentText(documentId, SourceText.From(source2)); + var newSolution = oldSolution.WithDocumentText(documentId, SourceText.From(source2)); var result = await AnalyzeDocumentAsync(oldProject, newSolution.GetDocument(documentId)); @@ -598,14 +616,13 @@ public static void Main(Bar x) } "; - using var workspace = TestWorkspace.CreateCSharp(source1, composition: s_composition); - - var oldSolution = workspace.CurrentSolution; + using var workspace = CreateWorkspace(); + var oldSolution = AddDefaultTestProject(workspace.CurrentSolution, source1); var oldProject = oldSolution.Projects.Single(); var oldDocument = oldProject.Documents.Single(); var documentId = oldDocument.Id; - var newSolution = workspace.CurrentSolution.WithDocumentText(documentId, SourceText.From(source2)); + var newSolution = oldSolution.WithDocumentText(documentId, SourceText.From(source2)); var result = await AnalyzeDocumentAsync(oldProject, newSolution.GetDocument(documentId)); @@ -640,14 +657,13 @@ public class D } "; - using var workspace = TestWorkspace.CreateCSharp(source1, composition: s_composition); + using var workspace = CreateWorkspace(); + var oldSolution = AddDefaultTestProject(workspace.CurrentSolution, source1); + // fork the solution to introduce a change - var oldProject = workspace.CurrentSolution.Projects.Single(); + var oldProject = oldSolution.Projects.Single(); var newDocId = DocumentId.CreateNewId(oldProject.Id); - var oldSolution = workspace.CurrentSolution; - var newSolution = oldSolution.AddDocument(newDocId, "goo.cs", SourceText.From(source2)); - - workspace.TryApplyChanges(newSolution); + var newSolution = oldSolution.AddDocument(newDocId, "goo.cs", SourceText.From(source2), filePath: Path.Combine(TempRoot.Root, "goo.cs")); var newProject = newSolution.Projects.Single(); var changes = newProject.GetChanges(oldProject); @@ -688,14 +704,12 @@ class D } "; - using var workspace = TestWorkspace.CreateCSharp(source1, composition: s_composition); + using var workspace = CreateWorkspace(); + var oldSolution = AddDefaultTestProject(workspace.CurrentSolution, source1); - var oldSolution = workspace.CurrentSolution; var oldProject = oldSolution.Projects.Single(); var newDocId = DocumentId.CreateNewId(oldProject.Id); - var newSolution = oldSolution.AddDocument(newDocId, "goo.cs", SourceText.From(source2)); - - workspace.TryApplyChanges(newSolution); + var newSolution = oldSolution.AddDocument(newDocId, "goo.cs", SourceText.From(source2), filePath: Path.Combine(TempRoot.Root, "goo.cs")); var newProject = newSolution.Projects.Single(); var changes = newProject.GetChanges(oldProject); @@ -722,17 +736,17 @@ public async Task AnalyzeDocumentAsync_InternalError(bool outOfMemory) var source1 = @"class C {}"; var source2 = @"class C { int x; }"; - using var workspace = TestWorkspace.CreateCSharp(source1, composition: s_composition); - var oldProject = workspace.CurrentSolution.Projects.Single(); + var filePath = Path.Combine(TempRoot.Root, "src.cs"); + + using var workspace = CreateWorkspace(); + var oldSolution = AddDefaultTestProject(workspace.CurrentSolution, source1); + var oldProject = oldSolution.Projects.Single(); var documentId = DocumentId.CreateNewId(oldProject.Id); - var oldSolution = workspace.CurrentSolution; - var newSolution = oldSolution.AddDocument(documentId, "goo.cs", SourceText.From(source2), filePath: "src.cs"); + var newSolution = oldSolution.AddDocument(documentId, "goo.cs", SourceText.From(source2), filePath: filePath); var newProject = newSolution.Projects.Single(); var newDocument = newProject.GetDocument(documentId); var newSyntaxTree = await newDocument.GetSyntaxTreeAsync().ConfigureAwait(false); - workspace.TryApplyChanges(newSolution); - var baseActiveStatements = AsyncLazy.Create(ActiveStatementsMap.Empty); var capabilities = AsyncLazy.Create(EditAndContinueTestHelpers.Net5RuntimeCapabilities); @@ -747,10 +761,10 @@ public async Task AnalyzeDocumentAsync_InternalError(bool outOfMemory) var result = await analyzer.AnalyzeDocumentAsync(oldProject, baseActiveStatements, newDocument, ImmutableArray.Empty, capabilities, CancellationToken.None); var expectedDiagnostic = outOfMemory ? - $"ENC0089: {string.Format(FeaturesResources.Modifying_source_file_0_requires_restarting_the_application_because_the_file_is_too_big, "src.cs")}" : + $"ENC0089: {string.Format(FeaturesResources.Modifying_source_file_0_requires_restarting_the_application_because_the_file_is_too_big, filePath)}" : // Because the error message that is formatted into this template string includes a stacktrace with newlines, we need to replicate that behavior // here so that any trailing punctuation is removed from the translated template string. - $"ENC0080: {string.Format(FeaturesResources.Modifying_source_file_0_requires_restarting_the_application_due_to_internal_error_1, "src.cs", "System.NullReferenceException: NullRef!\n")}".Split('\n').First(); + $"ENC0080: {string.Format(FeaturesResources.Modifying_source_file_0_requires_restarting_the_application_due_to_internal_error_1, filePath, "System.NullReferenceException: NullRef!\n")}".Split('\n').First(); AssertEx.Equal(new[] { expectedDiagnostic }, result.RudeEditErrors.Select(d => d.ToDiagnostic(newSyntaxTree)) .Select(d => $"{d.Id}: {d.GetMessage().Split(new[] { Environment.NewLine }, StringSplitOptions.None).First()}")); @@ -778,12 +792,12 @@ public static void Main() } "; - using var workspace = TestWorkspace.CreateCSharp(source1, composition: s_composition); + using var workspace = CreateWorkspace(); + var oldSolution = AddDefaultTestProject(workspace.CurrentSolution, source1); - var oldSolution = workspace.CurrentSolution; var oldProject = oldSolution.Projects.Single(); var documentId = oldProject.Documents.Single().Id; - var newSolution = workspace.CurrentSolution.WithDocumentText(documentId, SourceText.From(source2)); + var newSolution = oldSolution.WithDocumentText(documentId, SourceText.From(source2)); var newDocument = newSolution.GetDocument(documentId); var result = await AnalyzeDocumentAsync(oldProject, newDocument, capabilities: EditAndContinueCapabilities.None); diff --git a/src/EditorFeatures/CSharpTest/EditAndContinue/Helpers/CSharpEditAndContinueTestHelpers.cs b/src/EditorFeatures/CSharpTest/EditAndContinue/Helpers/CSharpEditAndContinueTestHelpers.cs index e69d2782a50b4..cf2b28addd041 100644 --- a/src/EditorFeatures/CSharpTest/EditAndContinue/Helpers/CSharpEditAndContinueTestHelpers.cs +++ b/src/EditorFeatures/CSharpTest/EditAndContinue/Helpers/CSharpEditAndContinueTestHelpers.cs @@ -23,6 +23,7 @@ public CSharpEditAndContinueTestHelpers(Action? faultInjector = null public override AbstractEditAndContinueAnalyzer Analyzer => _analyzer; public override string LanguageName => LanguageNames.CSharp; + public override string ProjectFileExtension => ".csproj"; public override TreeComparer TopSyntaxComparer => SyntaxComparer.TopLevel; public override ImmutableArray GetDeclarators(ISymbol method) diff --git a/src/EditorFeatures/CSharpTest/EditAndContinue/Helpers/EditingTestBase.cs b/src/EditorFeatures/CSharpTest/EditAndContinue/Helpers/EditingTestBase.cs index 57fcddedcdaf2..8739a02a80cb5 100644 --- a/src/EditorFeatures/CSharpTest/EditAndContinue/Helpers/EditingTestBase.cs +++ b/src/EditorFeatures/CSharpTest/EditAndContinue/Helpers/EditingTestBase.cs @@ -5,6 +5,7 @@ using System; using System.Collections.Generic; using System.Collections.Immutable; +using System.IO; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.CSharp.Test.Utilities; using Microsoft.CodeAnalysis.CSharp.UnitTests; @@ -14,6 +15,7 @@ using Microsoft.CodeAnalysis.EditAndContinue.UnitTests; using Microsoft.CodeAnalysis.Emit; using Microsoft.CodeAnalysis.PooledObjects; +using Microsoft.CodeAnalysis.Test.Utilities; using Microsoft.CodeAnalysis.Text; using Roslyn.Utilities; using Xunit; @@ -73,11 +75,14 @@ internal static DocumentAnalysisResultsDescription DocumentResults( RudeEditDiagnosticDescription[]? diagnostics = null) => new(activeStatements, semanticEdits, lineEdits: null, diagnostics); + internal static string GetDocumentFilePath(int documentIndex) + => Path.Combine(TempRoot.Root, documentIndex.ToString() + ".cs"); + private static SyntaxTree ParseSource(string markedSource, int documentIndex = 0) => SyntaxFactory.ParseSyntaxTree( ActiveStatementsDescription.ClearTags(markedSource), CSharpParseOptions.Default.WithLanguageVersion(LanguageVersion.Preview), - path: documentIndex.ToString()); + path: GetDocumentFilePath(documentIndex)); internal static EditScript GetTopEdits(string src1, string src2, int documentIndex = 0) { @@ -173,8 +178,8 @@ internal static string WrapMethodBodyWithClass(string bodySource, MethodKind kin _ => "class C { void F() { " + bodySource + " } }", }; - internal static ActiveStatementsDescription GetActiveStatements(string oldSource, string newSource, ActiveStatementFlags[] flags = null, string path = "0") - => new(oldSource, newSource, source => SyntaxFactory.ParseSyntaxTree(source, path: path), flags); + internal static ActiveStatementsDescription GetActiveStatements(string oldSource, string newSource, ActiveStatementFlags[] flags = null, int documentIndex = 0) + => new(oldSource, newSource, source => SyntaxFactory.ParseSyntaxTree(source, path: GetDocumentFilePath(documentIndex)), flags); internal static SyntaxMapDescription GetSyntaxMap(string oldSource, string newSource) => new(oldSource, newSource); diff --git a/src/EditorFeatures/CSharpTest/EditAndContinue/TopLevelEditingTests.cs b/src/EditorFeatures/CSharpTest/EditAndContinue/TopLevelEditingTests.cs index 06778b10ff5db..54e6e82b026fa 100644 --- a/src/EditorFeatures/CSharpTest/EditAndContinue/TopLevelEditingTests.cs +++ b/src/EditorFeatures/CSharpTest/EditAndContinue/TopLevelEditingTests.cs @@ -1846,13 +1846,13 @@ enum E { } Diagnostic(RudeEditKind.InsertVirtual, "abstract void AbstractMethod()", FeaturesResources.method), Diagnostic(RudeEditKind.InsertIntoInterface, "sealed void NonVirtualMethod()", FeaturesResources.method), Diagnostic(RudeEditKind.InsertOperator, "public static int operator +(I a, I b)", FeaturesResources.operator_), - Diagnostic(RudeEditKind.InsertIntoInterface, "static int StaticProperty1", FeaturesResources.auto_property), + Diagnostic(RudeEditKind.InsertIntoInterface, "static int StaticProperty1", FeaturesResources.property_), Diagnostic(RudeEditKind.InsertIntoInterface, "static int StaticProperty2", FeaturesResources.property_), Diagnostic(RudeEditKind.InsertIntoInterface, "static int StaticProperty2", CSharpFeaturesResources.property_getter), - Diagnostic(RudeEditKind.InsertVirtual, "virtual int VirtualProperty1", FeaturesResources.auto_property), - Diagnostic(RudeEditKind.InsertVirtual, "virtual int VirtualProperty2", FeaturesResources.auto_property), - Diagnostic(RudeEditKind.InsertVirtual, "int VirtualProperty3", FeaturesResources.auto_property), - Diagnostic(RudeEditKind.InsertVirtual, "int VirtualProperty4", FeaturesResources.auto_property), + Diagnostic(RudeEditKind.InsertVirtual, "virtual int VirtualProperty1", FeaturesResources.property_), + Diagnostic(RudeEditKind.InsertVirtual, "virtual int VirtualProperty2", FeaturesResources.property_), + Diagnostic(RudeEditKind.InsertVirtual, "int VirtualProperty3", FeaturesResources.property_), + Diagnostic(RudeEditKind.InsertVirtual, "int VirtualProperty4", FeaturesResources.property_), Diagnostic(RudeEditKind.InsertVirtual, "abstract int AbstractProperty1", FeaturesResources.property_), Diagnostic(RudeEditKind.InsertVirtual, "abstract int AbstractProperty2", FeaturesResources.property_), Diagnostic(RudeEditKind.InsertIntoInterface, "sealed int NonVirtualProperty", FeaturesResources.property_), @@ -1938,7 +1938,7 @@ class D {} edits.VerifySemanticDiagnostics( Diagnostic(RudeEditKind.InsertIntoGenericType, "void M()", FeaturesResources.method), Diagnostic(RudeEditKind.InsertIntoGenericType, "int P1", FeaturesResources.auto_property), - Diagnostic(RudeEditKind.InsertIntoGenericType, "int P2", FeaturesResources.auto_property), + Diagnostic(RudeEditKind.InsertIntoGenericType, "int P2", FeaturesResources.property_), Diagnostic(RudeEditKind.InsertIntoGenericType, "int this[int i]", FeaturesResources.indexer_), Diagnostic(RudeEditKind.InsertIntoGenericType, "event Action E", FeaturesResources.event_), Diagnostic(RudeEditKind.InsertIntoGenericType, "EF", CSharpFeaturesResources.event_field), @@ -3233,8 +3233,13 @@ public void Record_DeleteProperty_NotPrimary() var edits = GetTopEdits(src1, src2); - edits.VerifySemanticDiagnostics( - Diagnostic(RudeEditKind.Delete, "record C", DeletedSymbolDisplay(FeaturesResources.auto_property, "P"))); + edits.VerifySemantics( + new[] + { + SemanticEdit(SemanticEditKind.Delete, c => c.GetMember("C.get_P"), deletedSymbolContainerProvider: c => c.GetMember("C")), + SemanticEdit(SemanticEditKind.Delete, c => c.GetMember("C.set_P"), deletedSymbolContainerProvider: c => c.GetMember("C")), + }, + capabilities: EditAndContinueCapabilities.Baseline); } [Fact] @@ -3627,8 +3632,13 @@ record C(int X) var edits = GetTopEdits(src1, src2); - edits.VerifySemanticDiagnostics( - Diagnostic(RudeEditKind.Delete, "record C", DeletedSymbolDisplay(FeaturesResources.auto_property, "Y"))); + edits.VerifySemantics( + new[] + { + SemanticEdit(SemanticEditKind.Delete, c => c.GetMember("C.get_Y"), deletedSymbolContainerProvider: c => c.GetMember("C")), + SemanticEdit(SemanticEditKind.Delete, c => c.GetMember("C.set_Y"), deletedSymbolContainerProvider: c => c.GetMember("C")), + }, + capabilities: EditAndContinueCapabilities.Baseline); } [Fact] @@ -6414,34 +6424,27 @@ public void PartialNestedType_InsertDeleteAndChange() [Fact, WorkItem(51011, "https://github.com/dotnet/roslyn/issues/51011")] public void PartialMember_RenameInsertDelete() { - // The syntactic analysis for A and B produce rename edits since it doesn't see that the member was in fact moved. - // TODO: Currently, we don't even pass rename edits to semantic analysis where we could handle them as updates. - var srcA1 = "partial class C { void F1() {} }"; var srcB1 = "partial class C { void F2() {} }"; var srcA2 = "partial class C { void F2() {} }"; var srcB2 = "partial class C { void F1() {} }"; - // current outcome: - GetTopEdits(srcA1, srcA2).VerifySemanticDiagnostics(Diagnostic(RudeEditKind.Renamed, "void F2()", FeaturesResources.method)); - GetTopEdits(srcB1, srcB2).VerifySemanticDiagnostics(Diagnostic(RudeEditKind.Renamed, "void F1()", FeaturesResources.method)); + EditAndContinueValidation.VerifySemantics( + new[] { GetTopEdits(srcA1, srcA2), GetTopEdits(srcB1, srcB2) }, + new[] + { + DocumentResults(semanticEdits: new[] + { + SemanticEdit(SemanticEditKind.Update, c => c.GetMember("C").GetMember("F2")), + }), - // correct outcome: - //EditAndContinueValidation.VerifySemantics( - // new[] { GetTopEdits(srcA1, srcA2), GetTopEdits(srcB1, srcB2) }, - // new[] - // { - // DocumentResults(semanticEdits: new[] - // { - // SemanticEdit(SemanticEditKind.Update, c => c.GetMember("C").GetMember("F2")), - // }), - - // DocumentResults( - // semanticEdits: new[] - // { - // SemanticEdit(SemanticEditKind.Update, c => c.GetMember("C").GetMember("F1")), - // }) - // }); + DocumentResults( + semanticEdits: new[] + { + SemanticEdit(SemanticEditKind.Update, c => c.GetMember("C").GetMember("F1")), + }) + }, + capabilities: EditAndContinueCapabilities.AddMethodToExistingType); } [Fact] @@ -7614,8 +7617,236 @@ static void Main(string[] args) edits.VerifyEdits( "Insert [string[] args]@35"); + edits.VerifySemantics( + new[] + { + SemanticEdit(SemanticEditKind.Delete, c => c.GetMembers("C.Main").FirstOrDefault(m => m.GetParameterCount() == 0)?.ISymbol, deletedSymbolContainerProvider: c => c.GetMember("C")), + SemanticEdit(SemanticEditKind.Insert, c => c.GetMembers("C.Main").FirstOrDefault(m => m.GetParameterCount() == 1)?.ISymbol) + }, + capabilities: EditAndContinueCapabilities.AddMethodToExistingType); + + edits.VerifySemanticDiagnostics( + new[] { Diagnostic(RudeEditKind.InsertNotSupportedByRuntime, "string[] args", FeaturesResources.parameter) }, + capabilities: EditAndContinueCapabilities.Baseline); + } + + [Fact] + public void MethodUpdate_AddParameters() + { + var src1 = @" +class C +{ + void M(int a) + { + } +}"; + var src2 = @" +class C +{ + void M(int a, int b, int c) + { + } +}"; + var edits = GetTopEdits(src1, src2); + + edits.VerifySemantics( + new[] + { + SemanticEdit(SemanticEditKind.Delete, c => c.GetMembers("C.M").FirstOrDefault(m => m.GetParameterCount() == 1)?.ISymbol, deletedSymbolContainerProvider: c => c.GetMember("C")), + SemanticEdit(SemanticEditKind.Insert, c => c.GetMembers("C.M").FirstOrDefault(m => m.GetParameterCount() == 3)?.ISymbol) + }, + capabilities: EditAndContinueCapabilities.AddMethodToExistingType); + + edits.VerifySemanticDiagnostics( + new[] + { + Diagnostic(RudeEditKind.InsertNotSupportedByRuntime, "int b", FeaturesResources.parameter), + Diagnostic(RudeEditKind.InsertNotSupportedByRuntime, "int c", FeaturesResources.parameter) + }, + capabilities: EditAndContinueCapabilities.Baseline); + } + + [Fact] + public void MethodUpdate_AddParameter_Partial() + { + var src1 = @" +class C +{ + partial void M(int a); + + partial void M(int a) + { + } +}"; + var src2 = @" +class C +{ + partial void M(int a, int b, int c); + + partial void M(int a, int b, int c) + { + } +}"; + var edits = GetTopEdits(src1, src2); + + edits.VerifySemantics( + new[] + { + SemanticEdit(SemanticEditKind.Delete, c => c.GetMembers("C.M").FirstOrDefault(m => m.GetParameterCount() == 1)?.ISymbol, deletedSymbolContainerProvider: c => c.GetMember("C")), + SemanticEdit(SemanticEditKind.Insert, c => ((IMethodSymbol)c.GetMembers("C.M").FirstOrDefault(m => m.GetParameterCount() == 3)?.ISymbol)?.PartialImplementationPart) + }, + capabilities: EditAndContinueCapabilities.AddMethodToExistingType); + + edits.VerifySemanticDiagnostics( + new[] + { + Diagnostic(RudeEditKind.InsertNotSupportedByRuntime, "int b", FeaturesResources.parameter), + Diagnostic(RudeEditKind.InsertNotSupportedByRuntime, "int c", FeaturesResources.parameter) + }, + capabilities: EditAndContinueCapabilities.Baseline); + } + + [Fact] + public void MethodUpdate_ChangeParameterType() + { + var src1 = @" +class C +{ + static void Main(bool x) + { + + } +}"; + var src2 = @" +class C +{ + static void Main(int x) + { + + } +}"; + var edits = GetTopEdits(src1, src2); + + edits.VerifyEdits( + "Update [bool x]@35 -> [int x]@35"); + + edits.VerifySemantics( + new[] + { + SemanticEdit(SemanticEditKind.Delete, c => c.GetMembers("C.Main").FirstOrDefault(m => m.GetParameterTypes().Any(t => t.SpecialType == SpecialType.System_Boolean))?.ISymbol, deletedSymbolContainerProvider: c => c.GetMember("C")), + SemanticEdit(SemanticEditKind.Insert, c => c.GetMembers("C.Main").FirstOrDefault(m => m.GetParameterTypes().Any(t => t.SpecialType == SpecialType.System_Int32))?.ISymbol) + }, + capabilities: EditAndContinueCapabilities.AddMethodToExistingType); + + edits.VerifySemanticDiagnostics( + new[] { Diagnostic(RudeEditKind.ChangingTypeNotSupportedByRuntime, "int x", FeaturesResources.parameter) }, + capabilities: EditAndContinueCapabilities.Baseline); + } + + [Fact] + public void MethodUpdate_ChangeParameterTypeAndRename() + { + var src1 = @" +class C +{ + static void Main(bool someBool) + { + + } +}"; + var src2 = @" +class C +{ + static void Main(int someInt) + { + + } +}"; + var edits = GetTopEdits(src1, src2); + + edits.VerifyEdits( + "Update [bool someBool]@35 -> [int someInt]@35"); + + edits.VerifySemantics( + new[] + { + SemanticEdit(SemanticEditKind.Delete, c => c.GetMembers("C.Main").FirstOrDefault(m => m.GetParameterTypes().Any(t => t.SpecialType == SpecialType.System_Boolean))?.ISymbol, deletedSymbolContainerProvider: c => c.GetMember("C")), + SemanticEdit(SemanticEditKind.Insert, c => c.GetMembers("C.Main").FirstOrDefault(m => m.GetParameterTypes().Any(t => t.SpecialType == SpecialType.System_Int32))?.ISymbol) + }, + capabilities: EditAndContinueCapabilities.AddMethodToExistingType); + } + + [Fact] + public void MethodUpdate_DeleteParameter() + { + var src1 = @" +class C +{ + static void Main(string[] args) + { + + } +}"; + var src2 = @" +class C +{ + static void Main() + { + + } +}"; + var edits = GetTopEdits(src1, src2); + + edits.VerifyEdits( + "Delete [string[] args]@35"); + + edits.VerifySemantics( + new[] + { + SemanticEdit(SemanticEditKind.Delete, c => c.GetMembers("C.Main").FirstOrDefault(m => m.GetParameterCount() == 1)?.ISymbol, deletedSymbolContainerProvider: c => c.GetMember("C")), + SemanticEdit(SemanticEditKind.Insert, c => c.GetMembers("C.Main").FirstOrDefault(m => m.GetParameterCount() == 0)?.ISymbol) + }, + capabilities: EditAndContinueCapabilities.AddMethodToExistingType); + + edits.VerifySemanticDiagnostics( + new[] { Diagnostic(RudeEditKind.DeleteNotSupportedByRuntime, "static void Main()", DeletedSymbolDisplay(FeaturesResources.parameter, "string[] args")) }, + capabilities: EditAndContinueCapabilities.Baseline); + } + + [Fact] + public void MethodUpdate_DeleteParameters() + { + var src1 = @" +class C +{ + void M(int a, int b, int c) + { + } +}"; + var src2 = @" +class C +{ + void M(int a) + { + } +}"; + var edits = GetTopEdits(src1, src2); + + edits.VerifySemantics( + new[] + { + SemanticEdit(SemanticEditKind.Delete, c => c.GetMembers("C.M").FirstOrDefault(m => m.GetParameterCount() == 3)?.ISymbol, deletedSymbolContainerProvider: c => c.GetMember("C")), + SemanticEdit(SemanticEditKind.Insert, c => c.GetMembers("C.M").FirstOrDefault(m => m.GetParameterCount() == 1)?.ISymbol) + }, + capabilities: EditAndContinueCapabilities.AddMethodToExistingType); + edits.VerifySemanticDiagnostics( - Diagnostic(RudeEditKind.Insert, "string[] args", FeaturesResources.parameter)); + new[] + { + Diagnostic(RudeEditKind.DeleteNotSupportedByRuntime, "void M(int a)", DeletedSymbolDisplay(FeaturesResources.parameter, "int b")), + Diagnostic(RudeEditKind.DeleteNotSupportedByRuntime, "void M(int a)", DeletedSymbolDisplay(FeaturesResources.parameter, "int c")) + }, + capabilities: EditAndContinueCapabilities.Baseline); } [Fact] @@ -7688,7 +7919,7 @@ static void Main(string[] b) } [Fact] - public void Method_Name_Update() + public void Method_Rename() { var src1 = @" class C @@ -7718,8 +7949,55 @@ static void EntryPoint(string[] args) edits.VerifyEdits(expectedEdit); + edits.VerifySemantics( + new[] + { + SemanticEdit(SemanticEditKind.Delete, c => c.GetMember("C.Main"), deletedSymbolContainerProvider: c => c.GetMember("C")), + SemanticEdit(SemanticEditKind.Insert, c => c.GetMember("C.EntryPoint")) + }, + capabilities: EditAndContinueCapabilities.AddMethodToExistingType); + + edits.VerifySemanticDiagnostics( + new[] { Diagnostic(RudeEditKind.RenamingNotSupportedByRuntime, "static void EntryPoint(string[] args)", FeaturesResources.method) }, + capabilities: EditAndContinueCapabilities.Baseline); + } + + [Theory] + [InlineData("virtual")] + [InlineData("abstract")] + [InlineData("override")] + public void Method_Rename_Modifiers(string modifier) + { + /* TODO: https://github.com/dotnet/roslyn/issues/59264 + + This should be a supported edit. Consider the following inheritance chain: + + public class C { public virtual void M() => Console.WriteLine("C"); } + public class D : C { public override void M() { base.M(); Console.WriteLine("D"); } } + public class E : D { public override void M() { base.M(); Console.WriteLine("E"); } } + + If D.M is deleted we expect E.M to print "C E" and not throw. + + */ + var src1 = $$""" + class C + { + {{modifier}} void goo() { } + } + """; + var src2 = $$""" + class C + { + {{modifier}} void boo() { } + } + """; + var edits = GetTopEdits(src1, src2); + + edits.VerifyEdits( + $"Update [{modifier} void goo() {{ }}]@16 -> [{modifier} void boo() {{ }}]@16"); + edits.VerifySemanticDiagnostics( - Diagnostic(RudeEditKind.Renamed, "static void EntryPoint(string[] args)", FeaturesResources.method)); + Diagnostic(RudeEditKind.Renamed, $"{modifier} void boo()", FeaturesResources.method)); } [Fact] @@ -8643,8 +8921,17 @@ public void Method_ReadOnlyRef_Parameter_InsertParameter() edits.VerifyEdits( "Insert [in int b]@19"); - edits.VerifySemanticDiagnostics( - Diagnostic(RudeEditKind.Insert, "in int b", FeaturesResources.parameter)); + edits.VerifySemantics( + new[] + { + SemanticEdit(SemanticEditKind.Delete, c => c.GetMembers("Test.M").FirstOrDefault(m => m.GetParameterCount() == 0)?.ISymbol, deletedSymbolContainerProvider: c => c.GetMember("Test")), + SemanticEdit(SemanticEditKind.Insert, c => c.GetMembers("Test.M").FirstOrDefault(m => m.GetParameterCount() == 1)?.ISymbol) + }, + capabilities: EditAndContinueCapabilities.AddMethodToExistingType); + + edits.VerifySemanticDiagnostics( + new[] { Diagnostic(RudeEditKind.InsertNotSupportedByRuntime, "in int b", FeaturesResources.parameter) }, + capabilities: EditAndContinueCapabilities.Baseline); } [Fact] @@ -9037,9 +9324,13 @@ class C }"; var edits = GetTopEdits(src1, src2); - edits.VerifySemanticDiagnostics( - Diagnostic(RudeEditKind.Delete, "class C", DeletedSymbolDisplay(CSharpFeaturesResources.conversion_operator, "implicit operator bool(C c)")), - Diagnostic(RudeEditKind.Delete, "class C", DeletedSymbolDisplay(FeaturesResources.operator_, "operator +(C c, C d)"))); + edits.VerifySemantics( + new[] + { + SemanticEdit(SemanticEditKind.Delete, c => c.GetMember("C.op_Implicit"), deletedSymbolContainerProvider: c => c.GetMember("C")), + SemanticEdit(SemanticEditKind.Delete, c => c.GetMember("C.op_Addition"), deletedSymbolContainerProvider: c => c.GetMember("C")), + }, + capabilities: EditAndContinueCapabilities.Baseline); } [Fact] @@ -9175,6 +9466,30 @@ public void OperatorWithBlockBody_ToExpressionBody() }); } + [Fact] + public void Operator_Rename() + { + var src1 = @" +class C +{ + public static C operator +(C c, C d) { return c; } +} +"; + var src2 = @" +class C +{ + public static C operator -(C c, C d) { return d; } +}"; + var edits = GetTopEdits(src1, src2); + + edits.VerifySemantics(ActiveStatementsDescription.Empty, new[] + { + SemanticEdit(SemanticEditKind.Delete, c => c.GetMember("C.op_Addition"), deletedSymbolContainerProvider: c => c.GetMember("C")), + SemanticEdit(SemanticEditKind.Insert, c => c.GetMember("C.op_Subtraction")) + }, + capabilities: EditAndContinueCapabilities.AddMethodToExistingType); + } + [Fact] public void OperatorReorder1() { @@ -9255,6 +9570,19 @@ public void Operator_ReadOnlyRef_Parameter_Update() Diagnostic(RudeEditKind.ModifiersUpdate, "in Test b", FeaturesResources.parameter)); } + [Fact] + public void Operator_Delete() + { + var src1 = "class C { public static bool operator !(C b) => true; }"; + var src2 = "class C { }"; + + var edits = GetTopEdits(src1, src2); + + edits.VerifySemantics( + new[] { SemanticEdit(SemanticEditKind.Delete, c => c.GetMember("C.op_LogicalNot"), deletedSymbolContainerProvider: c => c.GetMember("C")) }, + capabilities: EditAndContinueCapabilities.Baseline); + } + #endregion #region Constructor, Destructor @@ -9296,6 +9624,38 @@ public C([System.Obsolete]int a) capabilities: EditAndContinueCapabilities.ChangeCustomAttributes); } + [Fact] + public void Constructor_ChangeParameterType() + { + var src1 = @" +class C +{ + public C(bool x) + { + } +}"; + var src2 = @" +class C +{ + public C(int x) + { + } +}"; + var edits = GetTopEdits(src1, src2); + + edits.VerifySemantics( + new[] + { + SemanticEdit(SemanticEditKind.Delete, c => c.GetMembers("C..ctor").FirstOrDefault(m => m.GetParameterTypes().Any(t => t.SpecialType == SpecialType.System_Boolean))?.ISymbol, deletedSymbolContainerProvider: c => c.GetMember("C")), + SemanticEdit(SemanticEditKind.Insert, c => c.GetMembers("C..ctor").FirstOrDefault(m => m.GetParameterTypes().Any(t => t.SpecialType == SpecialType.System_Int32))?.ISymbol) + }, + capabilities: EditAndContinueCapabilities.AddMethodToExistingType); + + edits.VerifySemanticDiagnostics( + new[] { Diagnostic(RudeEditKind.ChangingTypeNotSupportedByRuntime, "int x", FeaturesResources.parameter) }, + capabilities: EditAndContinueCapabilities.Baseline); + } + [Fact] [WorkItem(2068, "https://github.com/dotnet/roslyn/issues/2068")] public void Constructor_ExternModifier_Add() @@ -9420,8 +9780,17 @@ public C(int a, int b) { } "Update [(int a)]@26 -> [(int a, int b)]@26", "Insert [int b]@34"); + edits.VerifySemantics( + new[] + { + SemanticEdit(SemanticEditKind.Delete, c => c.GetMembers("C..ctor").FirstOrDefault(m => m.GetParameterCount() == 1)?.ISymbol, deletedSymbolContainerProvider: c => c.GetMember("C")), + SemanticEdit(SemanticEditKind.Insert, c => c.GetMembers("C..ctor").FirstOrDefault(m => m.GetParameterCount() == 2)?.ISymbol) + }, + capabilities: EditAndContinueCapabilities.AddMethodToExistingType); + edits.VerifySemanticDiagnostics( - Diagnostic(RudeEditKind.Insert, "int b", FeaturesResources.parameter)); + new[] { Diagnostic(RudeEditKind.InsertNotSupportedByRuntime, "int b", FeaturesResources.parameter) }, + capabilities: EditAndContinueCapabilities.Baseline); } [Fact] @@ -9470,6 +9839,19 @@ public void ConstructorUpdate_AnonymousTypeInFieldInitializer() edits.VerifySemanticDiagnostics(); } + [Fact] + public void Constructor_Delete() + { + var src1 = "class C { public C(int x) { } }"; + var src2 = "class C { }"; + + var edits = GetTopEdits(src1, src2); + + edits.VerifySemantics( + new[] { SemanticEdit(SemanticEditKind.Delete, c => c.GetMember("C").InstanceConstructors.FirstOrDefault(c => c.Parameters.Length == 1), deletedSymbolContainerProvider: c => c.GetMember("C")) }, + capabilities: EditAndContinueCapabilities.Baseline); + } + [Fact] public void Constructor_Static_Delete() { @@ -10826,8 +11208,17 @@ public void Constructor_ReadOnlyRef_Parameter_InsertParameter() edits.VerifyEdits( "Insert [in int b]@18"); + edits.VerifySemantics( + new[] + { + SemanticEdit(SemanticEditKind.Delete, c => c.GetMembers("Test..ctor").FirstOrDefault(m => m.GetParameterCount() == 0)?.ISymbol, deletedSymbolContainerProvider: c => c.GetMember("Test")), + SemanticEdit(SemanticEditKind.Insert, c => c.GetMembers("Test..ctor").FirstOrDefault(m => m.GetParameterCount() == 1)?.ISymbol) + }, + capabilities: EditAndContinueCapabilities.AddMethodToExistingType); + edits.VerifySemanticDiagnostics( - Diagnostic(RudeEditKind.Insert, "in int b", FeaturesResources.parameter)); + new[] { Diagnostic(RudeEditKind.InsertNotSupportedByRuntime, "in int b", FeaturesResources.parameter) }, + capabilities: EditAndContinueCapabilities.Baseline); } [Fact] @@ -13255,6 +13646,48 @@ public void Field_Type_Update_ReorderRemoveAdd() Diagnostic(RudeEditKind.Delete, "string G, F", DeletedSymbolDisplay(FeaturesResources.field, "H"))); } + [Fact] + public void Event_Rename1() + { + var src1 = "class C { event int E { remove { } add { } } }"; + var src2 = "class C { event int F { remove { } add { } } }"; + + var edits = GetTopEdits(src1, src2); + + edits.VerifySemantics( + new[] + { + SemanticEdit(SemanticEditKind.Delete, c => c.GetMember("C.add_E"), deletedSymbolContainerProvider: c => c.GetMember("C")), + SemanticEdit(SemanticEditKind.Delete, c => c.GetMember("C.remove_E"), deletedSymbolContainerProvider: c => c.GetMember("C")), + SemanticEdit(SemanticEditKind.Insert, c => c.GetMember("C.add_F")), + SemanticEdit(SemanticEditKind.Insert, c => c.GetMember("C.remove_F")), + }, + capabilities: EditAndContinueCapabilities.AddMethodToExistingType); + + edits.VerifySemanticDiagnostics( + new[] { Diagnostic(RudeEditKind.RenamingNotSupportedByRuntime, "event int F", FeaturesResources.event_) }, + capabilities: EditAndContinueCapabilities.Baseline); + } + + [Fact] + public void Event_Rename2() + { + var src1 = "class C { event int E; }"; + var src2 = "class C { event int F; }"; + + var edits = GetTopEdits(src1, src2); + + edits.VerifySemantics( + new[] + { + SemanticEdit(SemanticEditKind.Delete, c => c.GetMember("C.add_E"), deletedSymbolContainerProvider: c => c.GetMember("C")), + SemanticEdit(SemanticEditKind.Delete, c => c.GetMember("C.remove_E"), deletedSymbolContainerProvider: c => c.GetMember("C")), + SemanticEdit(SemanticEditKind.Insert, c => c.GetMember("C.add_F")), + SemanticEdit(SemanticEditKind.Insert, c => c.GetMember("C.remove_F")), + }, + capabilities: EditAndContinueCapabilities.AddMethodToExistingType); + } + [Fact] public void Field_Event_Reorder() { @@ -13334,8 +13767,13 @@ public void Property_ExpressionBody_Rename() var edits = GetTopEdits(src1, src2); - edits.VerifySemanticDiagnostics( - Diagnostic(RudeEditKind.Renamed, "int Q", FeaturesResources.property_)); + edits.VerifySemantics( + new[] + { + SemanticEdit(SemanticEditKind.Delete, c => c.GetMember("C.get_P"), deletedSymbolContainerProvider: c => c.GetMember("C")), + SemanticEdit(SemanticEditKind.Insert, c => c.GetMember("C.get_Q")), + }, + capabilities: EditAndContinueCapabilities.AddMethodToExistingType); } [Fact] @@ -13448,8 +13886,13 @@ public void Property_BlockBodyToExpressionBody2() "Delete [get { return 2; }]@18", "Delete [set { }]@36"); - edits.VerifySemanticDiagnostics( - Diagnostic(RudeEditKind.Delete, "int P", DeletedSymbolDisplay(CSharpFeaturesResources.property_setter, "P.set"))); + edits.VerifySemantics( + new[] + { + SemanticEdit(SemanticEditKind.Update, c => c.GetMember("C.get_P"), preserveLocalVariables: false), + SemanticEdit(SemanticEditKind.Delete, c => c.GetMember("C.set_P"), deletedSymbolContainerProvider: c => c.GetMember("C")), + }, + capabilities: EditAndContinueCapabilities.Baseline); } [Fact, WorkItem(17681, "https://github.com/dotnet/roslyn/issues/17681")] @@ -13595,15 +14038,35 @@ public void Property_Rename1() var edits = GetTopEdits(src1, src2); + edits.VerifySemantics( + new[] + { + SemanticEdit(SemanticEditKind.Delete, c => c.GetMember("C.get_P"), deletedSymbolContainerProvider: c => c.GetMember("C")), + SemanticEdit(SemanticEditKind.Insert, c => c.GetMember("C.get_Q")) + }, + capabilities: EditAndContinueCapabilities.AddMethodToExistingType); + edits.VerifySemanticDiagnostics( - Diagnostic(RudeEditKind.Renamed, "int Q", FeaturesResources.property_)); + new[] { Diagnostic(RudeEditKind.RenamingNotSupportedByRuntime, "int Q", FeaturesResources.property_) }, + capabilities: EditAndContinueCapabilities.Baseline); } [Fact] public void Property_Rename2() { - var src1 = "class C { int I.P { get { return 1; } } }"; - var src2 = "class C { int J.P { get { return 1; } } }"; + var interfaces = """ + interface I + { + int P { get; } + } + + interface J + { + int P { get; } + } + """; + var src1 = "class C { int I.P { get { return 1; } } } " + interfaces; + var src2 = "class C { int J.P { get { return 1; } } } " + interfaces; var edits = GetTopEdits(src1, src2); @@ -13611,6 +14074,44 @@ public void Property_Rename2() Diagnostic(RudeEditKind.Renamed, "int J.P", FeaturesResources.property_)); } + [Fact] + public void Property_Rename3() + { + var src1 = "class C { int P { get { return 1; } set { } } }"; + var src2 = "class C { int Q { get { return 1; } set { } } }"; + + var edits = GetTopEdits(src1, src2); + + edits.VerifySemantics( + new[] + { + SemanticEdit(SemanticEditKind.Delete, c => c.GetMember("C.get_P"), deletedSymbolContainerProvider: c => c.GetMember("C")), + SemanticEdit(SemanticEditKind.Delete, c => c.GetMember("C.set_P"), deletedSymbolContainerProvider: c => c.GetMember("C")), + SemanticEdit(SemanticEditKind.Insert, c => c.GetMember("C.get_Q")), + SemanticEdit(SemanticEditKind.Insert, c => c.GetMember("C.set_Q")) + }, + capabilities: EditAndContinueCapabilities.AddMethodToExistingType); + } + + [Fact] + public void Property_Rename4() + { + var src1 = "class C { int P { get; set; } }"; + var src2 = "class C { int Q { get; set; } }"; + + var edits = GetTopEdits(src1, src2); + + edits.VerifySemantics( + new[] + { + SemanticEdit(SemanticEditKind.Delete, c => c.GetMember("C.get_P"), deletedSymbolContainerProvider: c => c.GetMember("C")), + SemanticEdit(SemanticEditKind.Delete, c => c.GetMember("C.set_P"), deletedSymbolContainerProvider: c => c.GetMember("C")), + SemanticEdit(SemanticEditKind.Insert, c => c.GetMember("C.get_Q")), + SemanticEdit(SemanticEditKind.Insert, c => c.GetMember("C.set_Q")) + }, + capabilities: EditAndContinueCapabilities.AddMethodToExistingType | EditAndContinueCapabilities.AddInstanceFieldToExistingType); + } + [Fact] public void Property_RenameAndUpdate() { @@ -13619,20 +14120,78 @@ public void Property_RenameAndUpdate() var edits = GetTopEdits(src1, src2); - edits.VerifySemanticDiagnostics( - Diagnostic(RudeEditKind.Renamed, "int Q", FeaturesResources.property_)); + edits.VerifySemantics( + new[] + { + SemanticEdit(SemanticEditKind.Delete, c => c.GetMember("C.get_P"), deletedSymbolContainerProvider: c => c.GetMember("C")), + SemanticEdit(SemanticEditKind.Insert, c => c.GetMember("C.get_Q")) + }, + capabilities: EditAndContinueCapabilities.AddMethodToExistingType); } [Fact] public void PropertyDelete() + { + var src1 = "class C { int P { get { return 1; } set { } } }"; + var src2 = "class C { }"; + + var edits = GetTopEdits(src1, src2); + + edits.VerifySemantics( + new[] + { + SemanticEdit(SemanticEditKind.Delete, c => c.GetMember("C.get_P"), deletedSymbolContainerProvider: c => c.GetMember("C")), + SemanticEdit(SemanticEditKind.Delete, c => c.GetMember("C.set_P"), deletedSymbolContainerProvider: c => c.GetMember("C")), + }, + capabilities: EditAndContinueCapabilities.Baseline); + } + + [Fact] + public void PropertyDelete_GetOnly() { var src1 = "class C { int P { get { return 1; } } }"; var src2 = "class C { }"; var edits = GetTopEdits(src1, src2); - edits.VerifySemanticDiagnostics( - Diagnostic(RudeEditKind.Delete, "class C", DeletedSymbolDisplay(FeaturesResources.property_, "P"))); + edits.VerifySemantics( + new[] + { + SemanticEdit(SemanticEditKind.Delete, c => c.GetMember("C.get_P"), deletedSymbolContainerProvider: c => c.GetMember("C")) + }, + capabilities: EditAndContinueCapabilities.Baseline); + } + + [Fact] + public void PropertyAccessorDelete1() + { + var src1 = "class C { int P { get { return 1; } set { } } }"; + var src2 = "class C { int P { get { return 1; } } }"; + + var edits = GetTopEdits(src1, src2); + + edits.VerifySemantics( + new[] + { + SemanticEdit(SemanticEditKind.Delete, c => c.GetMember("C.set_P"), deletedSymbolContainerProvider: c => c.GetMember("C")) + }, + capabilities: EditAndContinueCapabilities.Baseline); + } + + [Fact] + public void PropertyAccessorDelete2() + { + var src1 = "class C { int P { set { } get { return 1; } } }"; + var src2 = "class C { int P { set { } } }"; + + var edits = GetTopEdits(src1, src2); + + edits.VerifySemantics( + new[] + { + SemanticEdit(SemanticEditKind.Delete, c => c.GetMember("C.get_P"), deletedSymbolContainerProvider: c => c.GetMember("C")) + }, + capabilities: EditAndContinueCapabilities.Baseline); } [Fact] @@ -13790,7 +14349,7 @@ public void PropertyAccessorUpdate_AddAttribute_SupportedByRuntime2() } [Fact] - public void PropertyInsert() + public void Property_Insert() { var src1 = "class C { }"; var src2 = "class C { int P { get => 1; set { } } }"; @@ -13802,6 +14361,19 @@ public void PropertyInsert() capabilities: EditAndContinueCapabilities.AddMethodToExistingType); } + [Fact] + public void Property_Insert_Static() + { + var src1 = "class C { }"; + var src2 = "class C { static int P { get => 1; set { } } }"; + + var edits = GetTopEdits(src1, src2); + + edits.VerifySemantics( + new[] { SemanticEdit(SemanticEditKind.Insert, c => c.GetMember("C").GetMember("P")) }, + capabilities: EditAndContinueCapabilities.AddMethodToExistingType); + } + [Fact] public void PropertyInsert_NotSupportedByRuntime() { @@ -13811,13 +14383,28 @@ public void PropertyInsert_NotSupportedByRuntime() var edits = GetTopEdits(src1, src2); edits.VerifySemanticDiagnostics( - new[] { Diagnostic(RudeEditKind.InsertNotSupportedByRuntime, "int P", FeaturesResources.auto_property) }, + new[] { Diagnostic(RudeEditKind.InsertNotSupportedByRuntime, "int P", FeaturesResources.property_) }, capabilities: EditAndContinueCapabilities.Baseline); } + [WorkItem(992578, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/992578")] + [Fact] + public void Property_Insert_Incomplete() + { + var src1 = "class C { }"; + var src2 = "class C { public int P { } }"; + + var edits = GetTopEdits(src1, src2); + + edits.VerifyEdits("Insert [public int P { }]@10", "Insert [{ }]@23"); + + edits.VerifySemanticDiagnostics( + capabilities: EditAndContinueCapabilities.AddMethodToExistingType); + } + [WorkItem(835827, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/835827")] [Fact] - public void PropertyInsert_PInvoke() + public void Property_Insert_PInvoke() { var src1 = @" using System; @@ -13847,7 +14434,7 @@ class C } [Fact] - public void PropertyInsert_IntoStruct() + public void Property_Insert_IntoStruct() { var src1 = @" struct S @@ -13866,6 +14453,8 @@ struct S private static int g { get; } = 1; private static int i { get; set; } = 1; private static int k => 1; + private static int l { get => 1; set {} } + private static int m { get => 1; set => k; } public S(int z) { a = z; } } "; @@ -13879,7 +14468,7 @@ struct S } [Fact] - public void PropertyInsert_IntoLayoutClass_Sequential() + public void Property_Insert_IntoLayoutClass_Sequential() { var src1 = @" using System.Runtime.InteropServices; @@ -13907,7 +14496,11 @@ class C private static int i { get; set; } = 1; private int j => 1; private static int k => 1; -} + private int l { get => 1; set { } } + private static int m { get => 1; set { } } + private int n { get { return 1; } set => a; } + private static int o { get { return 1; } set => a; } +} "; var edits = GetTopEdits(src1, src2); @@ -13921,10 +14514,36 @@ class C Diagnostic(RudeEditKind.InsertIntoClassWithLayout, "private static int i { get; set; } = 1;", FeaturesResources.auto_property, FeaturesResources.class_)); } + [Fact] + public void Property_Insert_Auto() + { + var src1 = "class C { }"; + var src2 = "class C { int P { get; set; } }"; + + var edits = GetTopEdits(src1, src2); + + edits.VerifySemantics( + new[] { SemanticEdit(SemanticEditKind.Insert, c => c.GetMember("C").GetMember("P")) }, + capabilities: EditAndContinueCapabilities.AddMethodToExistingType | EditAndContinueCapabilities.AddInstanceFieldToExistingType); + } + + [Fact] + public void Property_Insert_Auto_Static() + { + var src1 = "class C { }"; + var src2 = "class C { static int P { get; set; } }"; + + var edits = GetTopEdits(src1, src2); + + edits.VerifySemantics( + new[] { SemanticEdit(SemanticEditKind.Insert, c => c.GetMember("C").GetMember("P")) }, + capabilities: EditAndContinueCapabilities.AddMethodToExistingType | EditAndContinueCapabilities.AddStaticFieldToExistingType); + } + // Design: Adding private accessors should also be allowed since we now allow adding private methods // and adding public properties and/or public accessors are not allowed. [Fact] - public void PrivateProperty_AccessorAdd() + public void Property_Private_AccessorAdd() { var src1 = "class C { int _p; int P { get { return 1; } } }"; var src2 = "class C { int _p; int P { get { return 1; } set { _p = value; } } }"; @@ -13939,7 +14558,7 @@ public void PrivateProperty_AccessorAdd() [WorkItem(755975, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/755975")] [Fact] - public void PrivatePropertyAccessorDelete() + public void Property_Private_AccessorDelete() { var src1 = "class C { int _p; int P { get { return 1; } set { _p = value; } } }"; var src2 = "class C { int _p; int P { get { return 1; } } }"; @@ -13948,12 +14567,16 @@ public void PrivatePropertyAccessorDelete() edits.VerifyEdits("Delete [set { _p = value; }]@44"); - edits.VerifySemanticDiagnostics( - Diagnostic(RudeEditKind.Delete, "int P", DeletedSymbolDisplay(CSharpFeaturesResources.property_setter, "P.set"))); + edits.VerifySemantics( + new[] + { + SemanticEdit(SemanticEditKind.Delete, c => c.GetMember("C.set_P"), deletedSymbolContainerProvider: c => c.GetMember("C")), + }, + capabilities: EditAndContinueCapabilities.Baseline); } [Fact] - public void PrivateAutoPropertyAccessorAdd1() + public void Property_Auto_Private_AccessorAdd1() { var src1 = "class C { int P { get; } }"; var src2 = "class C { int P { get; set; } }"; @@ -13967,7 +14590,7 @@ public void PrivateAutoPropertyAccessorAdd1() } [Fact] - public void PrivateAutoPropertyAccessorAdd2() + public void Property_Auto_Private_AccessorAdd2() { var src1 = "class C { public int P { get; } }"; var src2 = "class C { public int P { get; private set; } }"; @@ -13981,7 +14604,7 @@ public void PrivateAutoPropertyAccessorAdd2() } [Fact] - public void PrivateAutoPropertyAccessorAdd4() + public void Property_Auto_Private_AccessorAdd4() { var src1 = "class C { public int P { get; } }"; var src2 = "class C { public int P { get; set; } }"; @@ -13995,7 +14618,7 @@ public void PrivateAutoPropertyAccessorAdd4() } [Fact] - public void PrivateAutoPropertyAccessorAdd5() + public void Property_Auto_Private_AccessorAdd5() { var src1 = "class C { public int P { get; } }"; var src2 = "class C { public int P { get; internal set; } }"; @@ -14009,7 +14632,7 @@ public void PrivateAutoPropertyAccessorAdd5() } [Fact] - public void PrivateAutoPropertyAccessorAdd6() + public void Property_Auto_Private_AccessorAdd6() { var src1 = "class C { int P { get; } = 1; }"; var src2 = "class C { int P { get; set; } = 1; }"; @@ -14023,7 +14646,7 @@ public void PrivateAutoPropertyAccessorAdd6() } [Fact] - public void PrivateAutoPropertyAccessorAdd_Init() + public void Property_Auto_Private_AccessorAdd_Init() { var src1 = "class C { int P { get; } = 1; }"; var src2 = "class C { int P { get; init; } = 1; }"; @@ -14038,7 +14661,7 @@ public void PrivateAutoPropertyAccessorAdd_Init() [WorkItem(755975, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/755975")] [Fact] - public void PrivateAutoPropertyAccessorDelete_Get() + public void Property_Auto_Private_AccessorDelete_Get() { var src1 = "class C { int P { get; set; } }"; var src2 = "class C { int P { set; } }"; @@ -14047,12 +14670,16 @@ public void PrivateAutoPropertyAccessorDelete_Get() edits.VerifyEdits("Delete [get;]@18"); - edits.VerifySemanticDiagnostics( - Diagnostic(RudeEditKind.Delete, "int P", DeletedSymbolDisplay(CSharpFeaturesResources.property_getter, "P.get"))); + edits.VerifySemantics( + new[] + { + SemanticEdit(SemanticEditKind.Delete, c => c.GetMember("C.get_P"), deletedSymbolContainerProvider: c => c.GetMember("C")), + }, + capabilities: EditAndContinueCapabilities.Baseline); } [Fact] - public void AutoPropertyAccessor_SetToInit() + public void Property_Auto_Accessor_SetToInit() { var src1 = "class C { int P { get; set; } }"; var src2 = "class C { int P { get; init; } }"; @@ -14068,7 +14695,7 @@ public void AutoPropertyAccessor_SetToInit() } [Fact] - public void AutoPropertyAccessor_InitToSet() + public void Property_Auto_Accessor_InitToSet() { var src1 = "class C { int P { get; init; } }"; var src2 = "class C { int P { get; set; } }"; @@ -14084,7 +14711,7 @@ public void AutoPropertyAccessor_InitToSet() } [Fact] - public void PrivateAutoPropertyAccessorDelete_Set() + public void Propert_Auto_Private_AccessorDelete_Set() { var src1 = "class C { int P { get; set; } = 1; }"; var src2 = "class C { int P { get; } = 1; }"; @@ -14093,12 +14720,17 @@ public void PrivateAutoPropertyAccessorDelete_Set() edits.VerifyEdits("Delete [set;]@23"); - edits.VerifySemanticDiagnostics( - Diagnostic(RudeEditKind.Delete, "int P", DeletedSymbolDisplay(CSharpFeaturesResources.property_setter, "P.set"))); + edits.VerifySemantics( + new[] + { + SemanticEdit(SemanticEditKind.Delete, c => c.GetMember("C.set_P"), deletedSymbolContainerProvider: c => c.GetMember("C")), + SemanticEdit(SemanticEditKind.Update, c => c.GetMember("C..ctor"), preserveLocalVariables: true), + }, + capabilities: EditAndContinueCapabilities.Baseline); } [Fact] - public void PrivateAutoPropertyAccessorDelete_Init() + public void Propert_Auto_Private_AccessorDelete_Init() { var src1 = "class C { int P { get; init; } = 1; }"; var src2 = "class C { int P { get; } = 1; }"; @@ -14107,12 +14739,17 @@ public void PrivateAutoPropertyAccessorDelete_Init() edits.VerifyEdits("Delete [init;]@23"); - edits.VerifySemanticDiagnostics( - Diagnostic(RudeEditKind.Delete, "int P", DeletedSymbolDisplay(CSharpFeaturesResources.property_setter, "P.init"))); + edits.VerifySemantics( + new[] + { + SemanticEdit(SemanticEditKind.Delete, c => c.GetMember("C.set_P"), deletedSymbolContainerProvider: c => c.GetMember("C")), + SemanticEdit(SemanticEditKind.Update, c => c.GetMember("C..ctor"), preserveLocalVariables: true), + }, + capabilities: EditAndContinueCapabilities.Baseline); } [Fact] - public void AutoPropertyAccessorUpdate() + public void Property_Auto_AccessorUpdate() { var src1 = "class C { int P { get; } }"; var src2 = "class C { int P { set; } }"; @@ -14125,21 +14762,6 @@ public void AutoPropertyAccessorUpdate() Diagnostic(RudeEditKind.AccessorKindUpdate, "set", CSharpFeaturesResources.property_setter)); } - [WorkItem(992578, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/992578")] - [Fact] - public void InsertIncompleteProperty() - { - var src1 = "class C { }"; - var src2 = "class C { public int P { } }"; - - var edits = GetTopEdits(src1, src2); - - edits.VerifyEdits("Insert [public int P { }]@10", "Insert [{ }]@23"); - - edits.VerifySemanticDiagnostics( - capabilities: EditAndContinueCapabilities.AddMethodToExistingType); - } - [Fact] public void Property_ReadOnlyRef_Insert() { @@ -14154,7 +14776,7 @@ public void Property_ReadOnlyRef_Insert() "Insert [get;]@34"); edits.VerifySemanticDiagnostics( - capabilities: EditAndContinueCapabilities.AddMethodToExistingType); + capabilities: EditAndContinueCapabilities.AddMethodToExistingType | EditAndContinueCapabilities.AddInstanceFieldToExistingType); } [Fact] @@ -14221,7 +14843,7 @@ public void PropertyInit_Partial_InsertDelete() } [Fact] - public void AutoProperty_Partial_InsertDelete() + public void Property_Auto_Partial_InsertDelete() { var srcA1 = "partial class C { }"; var srcB1 = "partial class C { int P { get; set; } int Q { get; init; } }"; @@ -14248,7 +14870,7 @@ public void AutoProperty_Partial_InsertDelete() } [Fact] - public void AutoPropertyWithInitializer_Partial_InsertDelete() + public void Property_AutoWithInitializer_Partial_InsertDelete() { var srcA1 = "partial class C { }"; var srcB1 = "partial class C { int P { get; set; } = 1; }"; @@ -14275,7 +14897,7 @@ public void AutoPropertyWithInitializer_Partial_InsertDelete() } [Fact] - public void PropertyWithExpressionBody_Partial_InsertDeleteUpdate() + public void Property_WithExpressionBody_Partial_InsertDeleteUpdate() { var srcA1 = "partial class C { }"; var srcB1 = "partial class C { int P => 1; }"; @@ -14295,7 +14917,7 @@ public void PropertyWithExpressionBody_Partial_InsertDeleteUpdate() } [Fact] - public void AutoProperty_ReadOnly_Add() + public void Property_Auto_ReadOnly_Add() { var src1 = @" struct S @@ -14774,8 +15396,13 @@ public void Indexer_GetterAndSetterBlockBodiesToExpressionBody() "Delete [get { return 1; }]@28", "Delete [set { Console.WriteLine(0); }]@46"); - edits.VerifySemanticDiagnostics( - Diagnostic(RudeEditKind.Delete, "int this[int a]", DeletedSymbolDisplay(CSharpFeaturesResources.indexer_setter, "this[int a].set"))); + edits.VerifySemantics( + new[] + { + SemanticEdit(SemanticEditKind.Update, c => c.GetMember("C.get_Item")), + SemanticEdit(SemanticEditKind.Delete, c => c.GetMember("C.set_Item"), deletedSymbolContainerProvider: c => c.GetMember("C")), + }, + capabilities: EditAndContinueCapabilities.Baseline); } [Fact, WorkItem(17681, "https://github.com/dotnet/roslyn/issues/17681")] @@ -14805,8 +15432,19 @@ public void Indexer_ExpressionBodyToGetterAndSetterBlockBodies() [Fact] public void Indexer_Rename() { - var src1 = "class C { int I.this[int a] { get { return 1; } } }"; - var src2 = "class C { int J.this[int a] { get { return 1; } } }"; + var interfaces = """ + interface I + { + int this[int a] { get; } + } + + interface J + { + int this[int a] { get; } + } + """; + var src1 = "class C { int I.this[int a] { get { return 1; } } } " + interfaces; + var src2 = "class C { int J.this[int a] { get { return 1; } } } " + interfaces; var edits = GetTopEdits(src1, src2); @@ -14912,6 +15550,63 @@ public void Indexer_ParameterUpdate() edits.VerifySemanticDiagnostics( Diagnostic(RudeEditKind.TypeUpdate, "string a", FeaturesResources.parameter)); + + // TODO: + // edits.VerifySemantics( + // new[] + // { + // SemanticEdit(SemanticEditKind.Delete, c => c.GetMembers("C.get_Item").FirstOrDefault(m => m.GetParameterTypes()[0].SpecialType == SpecialType.System_Int32)?.ISymbol, deletedSymbolContainerProvider: c => c.GetMember("C")), + // SemanticEdit(SemanticEditKind.Delete, c => c.GetMembers("C.set_Item").FirstOrDefault(m => m.GetParameterTypes()[0].SpecialType == SpecialType.System_Int32)?.ISymbol, deletedSymbolContainerProvider: c => c.GetMember("C")), + // SemanticEdit(SemanticEditKind.Insert, c => c.GetMembers("C.get_Item").FirstOrDefault(m => m.GetParameterTypes()[0].SpecialType == SpecialType.System_String)?.ISymbol), + // SemanticEdit(SemanticEditKind.Insert, c => c.GetMembers("C.set_Item").FirstOrDefault(m => m.GetParameterTypes()[0].SpecialType == SpecialType.System_String)?.ISymbol) + // }, + // capabilities: EditAndContinueCapabilities.AddMethodToExistingType); + } + + [Fact] + public void Indexer_ParameterInsert() + { + var src1 = "class C { int this[int a] { get; set; } }"; + var src2 = "class C { int this[int a, string b] { get; set; } }"; + + var edits = GetTopEdits(src1, src2); + + edits.VerifySemanticDiagnostics( + Diagnostic(RudeEditKind.Insert, "string b", FeaturesResources.parameter)); + + // TODO: + // edits.VerifySemantics( + // new[] + // { + // SemanticEdit(SemanticEditKind.Delete, c => c.GetMembers("C.get_Item").FirstOrDefault(m => m.GetParameterCount() == 1)?.ISymbol, deletedSymbolContainerProvider: c => c.GetMember("C")), + // SemanticEdit(SemanticEditKind.Delete, c => c.GetMembers("C.set_Item").FirstOrDefault(m => m.GetParameterCount() == 2)?.ISymbol, deletedSymbolContainerProvider: c => c.GetMember("C")), + // SemanticEdit(SemanticEditKind.Insert, c => c.GetMembers("C.get_Item").FirstOrDefault(m => m.GetParameterCount() == 2)?.ISymbol), + // SemanticEdit(SemanticEditKind.Insert, c => c.GetMembers("C.set_Item").FirstOrDefault(m => m.GetParameterCount() == 3)?.ISymbol) + // }, + // capabilities: EditAndContinueCapabilities.AddMethodToExistingType); + } + + [Fact] + public void Indexer_ParameterDelete() + { + var src1 = "class C { int this[int a, string b] { get; set; } }"; + var src2 = "class C { int this[int a] { get; set; } }"; + + var edits = GetTopEdits(src1, src2); + + edits.VerifySemanticDiagnostics( + Diagnostic(RudeEditKind.Delete, "int this[int a]", DeletedSymbolDisplay(FeaturesResources.parameter, "string b"))); + + // TODO: + // edits.VerifySemantics( + // new[] + // { + // SemanticEdit(SemanticEditKind.Delete, c => c.GetMembers("C.get_Item").FirstOrDefault(m => m.GetParameterCount() == 2)?.ISymbol, deletedSymbolContainerProvider: c => c.GetMember("C")), + // SemanticEdit(SemanticEditKind.Delete, c => c.GetMembers("C.set_Item").FirstOrDefault(m => m.GetParameterCount() == 3)?.ISymbol, deletedSymbolContainerProvider: c => c.GetMember("C")), + // SemanticEdit(SemanticEditKind.Insert, c => c.GetMembers("C.get_Item").FirstOrDefault(m => m.GetParameterCount() == 1)?.ISymbol), + // SemanticEdit(SemanticEditKind.Insert, c => c.GetMembers("C.set_Item").FirstOrDefault(m => m.GetParameterCount() == 2)?.ISymbol) + // }, + // capabilities: EditAndContinueCapabilities.AddMethodToExistingType); } [Fact] @@ -15005,6 +15700,33 @@ class C Diagnostic(RudeEditKind.InsertIntoGenericType, "set", CSharpFeaturesResources.indexer_setter)); } + [Fact] + public void Indexer_Delete() + { + var src1 = @" +class C +{ + public T this[int i] + { + get { return arr[i]; } + set { arr[i] = value; } + } +}"; + var src2 = @" +class C +{ +}"; + var edits = GetTopEdits(src1, src2); + + edits.VerifySemantics( + new[] + { + SemanticEdit(SemanticEditKind.Delete, c => c.GetMember("C.get_Item"), deletedSymbolContainerProvider: c => c.GetMember("C")), + SemanticEdit(SemanticEditKind.Delete, c => c.GetMember("C.set_Item"), deletedSymbolContainerProvider: c => c.GetMember("C")), + }, + capabilities: EditAndContinueCapabilities.Baseline); + } + [WorkItem(750109, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/750109")] [Fact] public void Indexer_DeleteGetAccessor() @@ -15028,10 +15750,12 @@ public T this[int i] }"; var edits = GetTopEdits(src1, src2); - edits.VerifyEdits("Delete [get { return arr[i]; }]@58"); - - edits.VerifySemanticDiagnostics( - Diagnostic(RudeEditKind.Delete, "public T this[int i]", DeletedSymbolDisplay(CSharpFeaturesResources.indexer_getter, "this[int i].get"))); + edits.VerifySemantics( + new[] + { + SemanticEdit(SemanticEditKind.Delete, c => c.GetMember("C.get_Item"), deletedSymbolContainerProvider: c => c.GetMember("C")), + }, + capabilities: EditAndContinueCapabilities.Baseline); } [Fact] @@ -15049,10 +15773,12 @@ class C }"; var edits = GetTopEdits(src1, src2); - edits.VerifyEdits("Delete [set { }]@61"); - - edits.VerifySemanticDiagnostics( - Diagnostic(RudeEditKind.Delete, "public int this[int i]", DeletedSymbolDisplay(CSharpFeaturesResources.indexer_setter, "this[int i].set"))); + edits.VerifySemantics( + new[] + { + SemanticEdit(SemanticEditKind.Delete, c => c.GetMember("C.set_Item"), deletedSymbolContainerProvider: c => c.GetMember("C")), + }, + capabilities: EditAndContinueCapabilities.Baseline); } [Fact, WorkItem(1174850, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/1174850")] @@ -15399,19 +16125,45 @@ public void Event_Insert() var edits = GetTopEdits(src1, src2); edits.VerifySemantics( - SemanticEdit(SemanticEditKind.Insert, c => c.GetMember("C").GetMember("E"))); + new[] + { + SemanticEdit(SemanticEditKind.Insert, c => c.GetMember("C").GetMember("E")) + }, + capabilities: EditAndContinueCapabilities.AddMethodToExistingType); } [Fact] - public void Event_Delete() + public void Event_Delete1() { var src1 = "class C { event int E { remove { } add { } } }"; var src2 = "class C { }"; var edits = GetTopEdits(src1, src2); - edits.VerifySemanticDiagnostics( - Diagnostic(RudeEditKind.Delete, "class C", DeletedSymbolDisplay(FeaturesResources.event_, "E"))); + edits.VerifySemantics( + new[] + { + SemanticEdit(SemanticEditKind.Delete, c => c.GetMember("C.add_E"), deletedSymbolContainerProvider: c => c.GetMember("C")), + SemanticEdit(SemanticEditKind.Delete, c => c.GetMember("C.remove_E"), deletedSymbolContainerProvider: c => c.GetMember("C")), + }, + capabilities: EditAndContinueCapabilities.Baseline); + } + + [Fact] + public void Event_Delete2() + { + var src1 = "class C { event int E; }"; + var src2 = "class C { }"; + + var edits = GetTopEdits(src1, src2); + + edits.VerifySemantics( + new[] + { + SemanticEdit(SemanticEditKind.Delete, c => c.GetMember("C.add_E"), deletedSymbolContainerProvider: c => c.GetMember("C")), + SemanticEdit(SemanticEditKind.Delete, c => c.GetMember("C.remove_E"), deletedSymbolContainerProvider: c => c.GetMember("C")), + }, + capabilities: EditAndContinueCapabilities.Baseline); } [Fact] @@ -15439,7 +16191,7 @@ private event Action c { add { } remove { } } var edits = GetTopEdits(src1, src2); - edits.VerifySemanticDiagnostics(); + edits.VerifySemanticDiagnostics(capabilities: EditAndContinueCapabilities.AddMethodToExistingType); } [Fact, WorkItem(17681, "https://github.com/dotnet/roslyn/issues/17681")] @@ -15897,21 +16649,6 @@ public void Parameter_Type_Update_RuntimeTypeUnchanged(string oldType, string ne SemanticEdit(SemanticEditKind.Update, c => c.GetMember("C.M"))); } - [Theory] - [InlineData("int", "string")] - [InlineData("int", "int?")] - [InlineData("(int a, int b)", "(int a, double b)")] - public void Parameter_Type_Update_RuntimeTypeChanged(string oldType, string newType) - { - var src1 = "class C { static void M(" + oldType + " a) {} }"; - var src2 = "class C { static void M(" + newType + " a) {} }"; - - var edits = GetTopEdits(src1, src2); - - edits.VerifySemanticDiagnostics( - Diagnostic(RudeEditKind.TypeUpdate, newType + " a", FeaturesResources.parameter)); - } - [Fact] public void Parameter_Type_Nullable() { diff --git a/src/EditorFeatures/CSharpTest/EditorConfigSettings/Updater/SettingsUpdaterTests.cs b/src/EditorFeatures/CSharpTest/EditorConfigSettings/Updater/SettingsUpdaterTests.cs index 9d222a586b960..5067ad6a8b1c8 100644 --- a/src/EditorFeatures/CSharpTest/EditorConfigSettings/Updater/SettingsUpdaterTests.cs +++ b/src/EditorFeatures/CSharpTest/EditorConfigSettings/Updater/SettingsUpdaterTests.cs @@ -433,7 +433,7 @@ public async Task TestNamingStyleSettingsUpdater() dotnet_naming_rule.{(CompilerExtensionsResources.Types + "_should_be_" + CompilerExtensionsResources.Pascal_Case.Replace(' ', '_')).ToLowerInvariant()}.style = {CompilerExtensionsResources.Pascal_Case.Replace(' ', '_').ToLowerInvariant()} dotnet_naming_rule.{(CompilerExtensionsResources.Non_Field_Members.Replace(' ', '_').Replace('-', '_') + "_should_be_" + CompilerExtensionsResources.Pascal_Case.Replace(' ', '_')).ToLowerInvariant()}.severity = suggestion -dotnet_naming_rule.{(CompilerExtensionsResources.Non_Field_Members.Replace(' ', '_').Replace('-', '_') + "_should_be_" + CompilerExtensionsResources.Pascal_Case.Replace(' ', '_')).ToLowerInvariant()}.symbols = { CompilerExtensionsResources.Non_Field_Members.Replace(' ', '_').Replace('-', '_').ToLowerInvariant()} +dotnet_naming_rule.{(CompilerExtensionsResources.Non_Field_Members.Replace(' ', '_').Replace('-', '_') + "_should_be_" + CompilerExtensionsResources.Pascal_Case.Replace(' ', '_')).ToLowerInvariant()}.symbols = {CompilerExtensionsResources.Non_Field_Members.Replace(' ', '_').Replace('-', '_').ToLowerInvariant()} dotnet_naming_rule.{(CompilerExtensionsResources.Non_Field_Members.Replace(' ', '_').Replace('-', '_') + "_should_be_" + CompilerExtensionsResources.Pascal_Case.Replace(' ', '_')).ToLowerInvariant()}.style = {CompilerExtensionsResources.Pascal_Case.Replace(' ', '_').ToLowerInvariant()} # {CompilerExtensionsResources.Symbol_specifications} diff --git a/src/EditorFeatures/CSharpTest/EncapsulateField/EncapsulateFieldTestState.cs b/src/EditorFeatures/CSharpTest/EncapsulateField/EncapsulateFieldTestState.cs index 0a6f36ff347bd..265554d58dc92 100644 --- a/src/EditorFeatures/CSharpTest/EncapsulateField/EncapsulateFieldTestState.cs +++ b/src/EditorFeatures/CSharpTest/EncapsulateField/EncapsulateFieldTestState.cs @@ -14,6 +14,7 @@ using Microsoft.CodeAnalysis.Editor.UnitTests.Utilities; using Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces; using Microsoft.CodeAnalysis.Notification; +using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Shared.TestHooks; using Microsoft.VisualStudio.Text.Editor.Commanding.Commands; using Xunit; @@ -42,9 +43,8 @@ public static EncapsulateFieldTestState Create(string markup) { var workspace = TestWorkspace.CreateCSharp(markup, composition: EditorTestCompositions.EditorFeatures); - workspace.TryApplyChanges(workspace.CurrentSolution.WithOptions(workspace.Options - .WithChangedOption(CSharpCodeStyleOptions.PreferExpressionBodiedAccessors, CSharpCodeStyleOptions.NeverWithSilentEnforcement) - .WithChangedOption(CSharpCodeStyleOptions.PreferExpressionBodiedProperties, CSharpCodeStyleOptions.NeverWithSilentEnforcement))); + workspace.GlobalOptions.SetGlobalOption(new OptionKey(CSharpCodeStyleOptions.PreferExpressionBodiedAccessors), CSharpCodeStyleOptions.NeverWithSilentEnforcement); + workspace.GlobalOptions.SetGlobalOption(new OptionKey(CSharpCodeStyleOptions.PreferExpressionBodiedProperties), CSharpCodeStyleOptions.NeverWithSilentEnforcement); return new EncapsulateFieldTestState(workspace); } diff --git a/src/EditorFeatures/CSharpTest/EventHookup/EventHookupTestState.cs b/src/EditorFeatures/CSharpTest/EventHookup/EventHookupTestState.cs index 6f15921ec319f..795994e817064 100644 --- a/src/EditorFeatures/CSharpTest/EventHookup/EventHookupTestState.cs +++ b/src/EditorFeatures/CSharpTest/EventHookup/EventHookupTestState.cs @@ -41,7 +41,7 @@ public EventHookupTestState(XElement workspaceElement, OptionsCollection options _testSessionHookupMutex = new Mutex(false); _commandHandler.TESTSessionHookupMutex = _testSessionHookupMutex; - Workspace.ApplyOptions(options); + options?.SetGlobalOptions(Workspace.GlobalOptions); } public static EventHookupTestState CreateTestState(string markup, OptionsCollection options = null) diff --git a/src/EditorFeatures/CSharpTest/ExtractClass/ExtractClassTests.cs b/src/EditorFeatures/CSharpTest/ExtractClass/ExtractClassTests.cs index 2d99f75b04846..ca299c10f0fb7 100644 --- a/src/EditorFeatures/CSharpTest/ExtractClass/ExtractClassTests.cs +++ b/src/EditorFeatures/CSharpTest/ExtractClass/ExtractClassTests.cs @@ -19,6 +19,7 @@ using Microsoft.CodeAnalysis.ExtractClass; using Microsoft.CodeAnalysis.PullMemberUp; using Microsoft.CodeAnalysis.Test.Utilities; +using Microsoft.CodeAnalysis.Testing; using Roslyn.Test.Utilities; using Roslyn.Utilities; using Xunit; @@ -196,6 +197,170 @@ int Method2() }.RunAsync(); } + [Fact] + public async Task TestRecord_Method() + { + var input = """ + record R(string S) + { + void $$M() + { + } + } + """; + + var expected1 = """ + record R(string S) : MyBase + { + } + """; + + var expected2 = """ + internal record MyBase + { + void M() + { + } + } + + """; + + await new Test + { + TestCode = input, + LanguageVersion = LanguageVersion.CSharp9, + ReferenceAssemblies = ReferenceAssemblies.Net.Net50, + FixedState = + { + Sources = + { + expected1, + expected2, + } + }, + }.RunAsync(); + } + + [Fact] + public async Task TestRecord_Property() + { + var input = """ + record R + { + public string $$S { get; set; } + } + """; + + var expected1 = """ + record R : MyBase + { + } + """; + + var expected2 = """ + internal record MyBase + { + public string S { get; set; } + } + + """; + + await new Test + { + TestCode = input, + LanguageVersion = LanguageVersion.CSharp9, + ReferenceAssemblies = ReferenceAssemblies.Net.Net50, + FixedState = + { + Sources = + { + expected1, + expected2, + } + }, + }.RunAsync(); + } + + [Fact(Skip = "https://github.com/dotnet/roslyn/issues/62415")] + public async Task TestRecord_PropertyAndImplicitField() + { + var input = """ + record R(string S) + { + public string $$S { get; set; } = S; + } + """; + + var expected1 = """ + record R(string S) : MyBase(S) + { + } + """; + + var expected2 = """ + record MyBase(string S) + { + public string S { get; set; } = S; + } + + """; + + await new Test + { + TestCode = input, + LanguageVersion = LanguageVersion.CSharp9, + ReferenceAssemblies = ReferenceAssemblies.Net.Net50, + FixedState = + { + Sources = + { + expected1, + expected2, + } + }, + }.RunAsync(); + } + + [Fact] + public async Task TestRecordParam() + { + // https://github.com/dotnet/roslyn/issues/62415 to make this scenario work + var input = """ + record R(string $$S) + { + } + """; + + await new Test + { + TestCode = input, + FixedCode = input, + LanguageVersion = LanguageVersion.CSharp9, + ReferenceAssemblies = ReferenceAssemblies.Net.Net50, + }.RunAsync(); + } + + [Fact] + public async Task TestRecordStruct() + { + var input = """ + record struct R(string S) + { + void $$M() + { + } + } + """; + + await new Test + { + TestCode = input, + FixedCode = input, + LanguageVersion = LanguageVersion.CSharp10, + ReferenceAssemblies = ReferenceAssemblies.Net.Net50, + }.RunAsync(); + } + [Fact] public async Task TestInNamespace() { @@ -538,6 +703,168 @@ class Test : MyBase }.RunAsync(); } + [Fact] + public async Task TestFieldSelectInKeywords() + { + var input = @" +class Test +{ + priva[||]te int MyField; +}"; + + var expected1 = @" +class Test : MyBase +{ +}"; + var expected2 = @"internal class MyBase +{ + private int MyField; +}"; + + await new Test + { + TestCode = input, + FixedState = + { + Sources = + { + expected1, + expected2 + } + } + }.RunAsync(); + } + + [Fact] + public async Task TestFieldSelectAfterSemicolon() + { + var input = @" +class Test +{ + private int MyField;[||] +}"; + + var expected1 = @" +class Test : MyBase +{ +}"; + var expected2 = @"internal class MyBase +{ + private int MyField; +}"; + + await new Test + { + TestCode = input, + FixedState = + { + Sources = + { + expected1, + expected2 + } + } + }.RunAsync(); + } + + [Fact] + public async Task TestFieldSelectEntireDeclaration() + { + var input = @" +class Test +{ + [|private int MyField;|] +}"; + + var expected1 = @" +class Test : MyBase +{ +}"; + var expected2 = @"internal class MyBase +{ + private int MyField; +}"; + + await new Test + { + TestCode = input, + FixedState = + { + Sources = + { + expected1, + expected2 + } + } + }.RunAsync(); + } + + [Fact] + public async Task TestFieldSelectMultipleVariables1() + { + var input = @" +class Test +{ + [|private int MyField1, MyField2;|] +}"; + + var expected1 = @" +class Test : MyBase +{ +}"; + var expected2 = @"internal class MyBase +{ + private int MyField1; + private int MyField2; +}"; + + await new Test + { + TestCode = input, + FixedState = + { + Sources = + { + expected1, + expected2 + } + } + }.RunAsync(); + } + + [Fact] + public async Task TestFieldSelectMultipleVariables2() + { + var input = @" +class Test +{ + private int MyField1, [|MyField2;|] +}"; + + var expected1 = @" +class Test : MyBase +{ + private int MyField1; +}"; + var expected2 = @"internal class MyBase +{ + private int MyField2; +}"; + + await new Test + { + TestCode = input, + FixedState = + { + Sources = + { + expected1, + expected2 + } + } + }.RunAsync(); + } + [Fact] public async Task TestFileHeader_FromExistingFile() { @@ -2068,6 +2395,59 @@ public T3 Method() }.RunAsync(); } + [Fact] + public async Task TestIncompleteFieldSelection_NoAction1() + { + var input = @" +class C +{ + pub[||] {|CS1519:int|} Foo = 0; +} +"; + await new Test + { + TestCode = input, + FixedCode = input + }.RunAsync(); + } + + [Fact] + public async Task TestIncompleteMethodSelection_NoAction() + { + var input = @" +class C +{ + pub[||] {|CS1519:int|} Foo() + { + return 5; + } +} +"; + await new Test + { + TestCode = input, + FixedCode = input + }.RunAsync(); + } + + [Fact] + public async Task TestTopLevelStatementSelection_NoAction() + { + var input = @" +[||]_ = 42; +"; + await new Test + { + TestCode = input, + FixedCode = input, + LanguageVersion = LanguageVersion.CSharp10, + TestState = + { + OutputKind = OutputKind.ConsoleApplication + } + }.RunAsync(); + } + private static IEnumerable<(string name, bool makeAbstract)> MakeAbstractSelection(params string[] memberNames) => memberNames.Select(m => (m, true)); @@ -2090,7 +2470,7 @@ public TestExtractClassOptionsService(IEnumerable<(string name, bool makeAbstrac public string FileName { get; set; } = "MyBase.cs"; public string BaseName { get; set; } = "MyBase"; - public Task GetExtractClassOptionsAsync(Document document, INamedTypeSymbol originalSymbol, ISymbol? selectedMember, CancellationToken cancellationToken) + public Task GetExtractClassOptionsAsync(Document document, INamedTypeSymbol originalSymbol, ImmutableArray selectedMembers, CancellationToken cancellationToken) { var availableMembers = originalSymbol.GetMembers().Where(member => MemberAndDestinationValidator.IsMemberValid(member)); @@ -2098,7 +2478,7 @@ public TestExtractClassOptionsService(IEnumerable<(string name, bool makeAbstrac if (_dialogSelection == null) { - if (selectedMember is null) + if (selectedMembers.IsEmpty) { Assert.True(isClassDeclarationSelection); selections = availableMembers.Select(member => (member, makeAbstract: false)); @@ -2106,7 +2486,7 @@ public TestExtractClassOptionsService(IEnumerable<(string name, bool makeAbstrac else { Assert.False(isClassDeclarationSelection); - selections = new[] { (selectedMember, false) }; + selections = selectedMembers.Select(m => (m, makeAbstract: false)); } } else diff --git a/src/EditorFeatures/CSharpTest/ExtractMethod/ExtractMethodBase.cs b/src/EditorFeatures/CSharpTest/ExtractMethod/ExtractMethodBase.cs index 80e8731319772..7756de40437ea 100644 --- a/src/EditorFeatures/CSharpTest/ExtractMethod/ExtractMethodBase.cs +++ b/src/EditorFeatures/CSharpTest/ExtractMethod/ExtractMethodBase.cs @@ -131,7 +131,7 @@ protected static async Task ExtractMethodAsync( var document = workspace.CurrentSolution.GetDocument(testDocument.Id); Assert.NotNull(document); - var options = new ExtractMethodGenerationOptions(CodeGenerationOptions.GetDefault(document.Project.LanguageServices)) + var options = new ExtractMethodGenerationOptions(CodeGenerationOptions.GetDefault(document.Project.Services)) { ExtractOptions = new() { DontPutOutOrRefOnStruct = dontPutOutOrRefOnStruct } }; @@ -156,7 +156,7 @@ protected static async Task ExtractMethodAsync( result.SucceededWithSuggestion || (allowBestEffort && result.Status.HasBestEffort())); - var (doc, _) = await result.GetFormattedDocumentAsync(CodeCleanupOptions.GetDefault(document.Project.LanguageServices), CancellationToken.None); + var (doc, _) = await result.GetFormattedDocumentAsync(CodeCleanupOptions.GetDefault(document.Project.Services), CancellationToken.None); return doc == null ? null : await doc.GetSyntaxRootAsync(); diff --git a/src/EditorFeatures/CSharpTest/ExtractMethod/ExtractMethodTests.cs b/src/EditorFeatures/CSharpTest/ExtractMethod/ExtractMethodTests.cs index 4791bac6b8cdc..5408ac2343978 100644 --- a/src/EditorFeatures/CSharpTest/ExtractMethod/ExtractMethodTests.cs +++ b/src/EditorFeatures/CSharpTest/ExtractMethod/ExtractMethodTests.cs @@ -10391,7 +10391,7 @@ public async Task ExtractMethod_Argument2() var service = new CSharpExtractMethodService() as IExtractMethodService; - await service.ExtractMethodAsync(document, textSpan: default, localFunction: false, ExtractMethodGenerationOptions.GetDefault(project.LanguageServices), CancellationToken.None); + await service.ExtractMethodAsync(document, textSpan: default, localFunction: false, ExtractMethodGenerationOptions.GetDefault(project.Services), CancellationToken.None); } [WpfFact] diff --git a/src/EditorFeatures/CSharpTest/Formatting/CodeCleanupTests.cs b/src/EditorFeatures/CSharpTest/Formatting/CodeCleanupTests.cs index b9a2c1a17f0e5..2bd53b9a09814 100644 --- a/src/EditorFeatures/CSharpTest/Formatting/CodeCleanupTests.cs +++ b/src/EditorFeatures/CSharpTest/Formatting/CodeCleanupTests.cs @@ -579,8 +579,8 @@ public void VerifyAllCodeStyleFixersAreSupportedByCodeCleanup(string language) var expectedNumberOfUnsupportedDiagnosticIds = language switch { - LanguageNames.CSharp => 36, - LanguageNames.VisualBasic => 72, + LanguageNames.CSharp => 35, + LanguageNames.VisualBasic => 71, _ => throw ExceptionUtilities.UnexpectedValue(language), }; diff --git a/src/EditorFeatures/CSharpTest/Formatting/FormattingEngineTests.cs b/src/EditorFeatures/CSharpTest/Formatting/FormattingEngineTests.cs index 2f7422c142852..bd826d1a50ca3 100644 --- a/src/EditorFeatures/CSharpTest/Formatting/FormattingEngineTests.cs +++ b/src/EditorFeatures/CSharpTest/Formatting/FormattingEngineTests.cs @@ -20,7 +20,9 @@ using Microsoft.CodeAnalysis.Indentation; using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Test.Utilities; +using Microsoft.VisualStudio.Text.Editor; using Microsoft.VisualStudio.Text.Editor.Commanding.Commands; +using Newtonsoft.Json.Linq; using Roslyn.Test.Utilities; using Xunit; using Xunit.Abstractions; @@ -422,7 +424,7 @@ public void M() var document = workspace.CurrentSolution.Projects.Single().Documents.Single(); var syntaxRoot = await document.GetSyntaxRootAsync(); var options = CSharpSyntaxFormattingOptions.Default; - var node = Formatter.Format(syntaxRoot, spans, workspace.Services, options, rules: null, CancellationToken.None); + var node = Formatter.Format(syntaxRoot, spans, workspace.Services.SolutionServices, options, rules: null, CancellationToken.None); Assert.Equal(expected, node.ToFullString()); } @@ -2178,7 +2180,7 @@ public void SeparateGroups_KeepMultipleLinesBetweenGroups() using MS.B; "; - AssertFormatWithView(expected, code, (GenerationOptions.SeparateImportDirectiveGroups, true)); + AssertFormatWithView(expected, code, new OptionsCollection(LanguageNames.CSharp) { { GenerationOptions.SeparateImportDirectiveGroups, true } }); } [WorkItem(25003, "https://github.com/dotnet/roslyn/issues/25003")] @@ -2207,7 +2209,7 @@ namespace N; using MS.B; "; - AssertFormatWithView(expected, code, (GenerationOptions.SeparateImportDirectiveGroups, true)); + AssertFormatWithView(expected, code, new OptionsCollection(LanguageNames.CSharp) { { GenerationOptions.SeparateImportDirectiveGroups, true } }); } [WorkItem(25003, "https://github.com/dotnet/roslyn/issues/25003")] @@ -2228,7 +2230,7 @@ public void SeparateGroups_DoNotGroupIfNotSorted() using MS.A; "; - AssertFormatWithView(expected, code, (GenerationOptions.SeparateImportDirectiveGroups, true)); + AssertFormatWithView(expected, code, new OptionsCollection(LanguageNames.CSharp) { { GenerationOptions.SeparateImportDirectiveGroups, true } }); } [WorkItem(25003, "https://github.com/dotnet/roslyn/issues/25003")] @@ -2250,7 +2252,7 @@ public void SeparateGroups_GroupIfSorted() using MS.B; "; - AssertFormatWithView(expected, code, (GenerationOptions.SeparateImportDirectiveGroups, true)); + AssertFormatWithView(expected, code, new OptionsCollection(LanguageNames.CSharp) { { GenerationOptions.SeparateImportDirectiveGroups, true } }); } [WorkItem(25003, "https://github.com/dotnet/roslyn/issues/25003")] @@ -2272,7 +2274,7 @@ public void SeparateGroups_GroupIfSorted_RecognizeSystemNotFirst() using System.B; "; - AssertFormatWithView(expected, code, (GenerationOptions.SeparateImportDirectiveGroups, true)); + AssertFormatWithView(expected, code, new OptionsCollection(LanguageNames.CSharp) { { GenerationOptions.SeparateImportDirectiveGroups, true } }); } [WpfFact] @@ -2333,7 +2335,7 @@ class Test var options = CSharpSyntaxFormattingOptions.Default; - var formattedRoot = Formatter.Format(root, workspace.Services, options, CancellationToken.None); + var formattedRoot = Formatter.Format(root, workspace.Services.SolutionServices, options, CancellationToken.None); var annotatedTrivia = formattedRoot.GetAnnotatedTrivia("marker"); Assert.Single(annotatedTrivia); @@ -2616,13 +2618,16 @@ private static void AssertFormatAfterTypeChar(string code, string expected, Opti { using var workspace = TestWorkspace.CreateCSharp(code, parseOptions: parseOptions); - globalOptions?.SetGlobalOptions(workspace.GlobalOptions); - var subjectDocument = workspace.Documents.Single(); var commandHandler = workspace.GetService(); var typedChar = subjectDocument.GetTextBuffer().CurrentSnapshot.GetText(subjectDocument.CursorPosition.Value - 1, 1); - commandHandler.ExecuteCommand(new TypeCharCommandArgs(subjectDocument.GetTextView(), subjectDocument.GetTextBuffer(), typedChar[0]), () => { }, TestCommandExecutionContext.Create()); + var textView = subjectDocument.GetTextView(); + + globalOptions?.SetGlobalOptions(workspace.GlobalOptions); + workspace.GlobalOptions.SetEditorOptions(textView.Options.GlobalOptions, subjectDocument.Project.Language); + + commandHandler.ExecuteCommand(new TypeCharCommandArgs(textView, subjectDocument.GetTextBuffer(), typedChar[0]), () => { }, TestCommandExecutionContext.Create()); var newSnapshot = subjectDocument.GetTextBuffer().CurrentSnapshot; diff --git a/src/EditorFeatures/CSharpTest/Formatting/Indentation/CSharpFormatterTestsBase.cs b/src/EditorFeatures/CSharpTest/Formatting/Indentation/CSharpFormatterTestsBase.cs index 17dc9571e37a0..a37c65bd2b14f 100644 --- a/src/EditorFeatures/CSharpTest/Formatting/Indentation/CSharpFormatterTestsBase.cs +++ b/src/EditorFeatures/CSharpTest/Formatting/Indentation/CSharpFormatterTestsBase.cs @@ -14,6 +14,7 @@ using Microsoft.CodeAnalysis.CSharp.Formatting; using Microsoft.CodeAnalysis.CSharp.Indentation; using Microsoft.CodeAnalysis.CSharp.Syntax; +using Microsoft.CodeAnalysis.Editor.Shared.Extensions; using Microsoft.CodeAnalysis.Editor.UnitTests; using Microsoft.CodeAnalysis.Editor.UnitTests.Formatting; using Microsoft.CodeAnalysis.Editor.UnitTests.Utilities; @@ -99,18 +100,7 @@ private static async Task TokenFormatWorkerAsync(TestWorkspace workspace, ITextB var formatter = new CSharpSmartTokenFormatter(options, rules, (CompilationUnitSyntax)documentSyntax.Root, documentSyntax.Text); var changes = formatter.FormatToken(token, CancellationToken.None); - ApplyChanges(buffer, changes); - } - - private static void ApplyChanges(ITextBuffer buffer, IList changes) - { - using var edit = buffer.CreateEdit(); - foreach (var change in changes) - { - edit.Replace(change.Span.ToSpan(), change.NewText); - } - - edit.Apply(); + buffer.ApplyChanges(changes); } protected static async Task GetSmartTokenFormatterIndentationAsync( diff --git a/src/EditorFeatures/CSharpTest/Formatting/Indentation/SmartIndenterTests.cs b/src/EditorFeatures/CSharpTest/Formatting/Indentation/SmartIndenterTests.cs index 006ee56d8d55c..b4050f4f7c496 100644 --- a/src/EditorFeatures/CSharpTest/Formatting/Indentation/SmartIndenterTests.cs +++ b/src/EditorFeatures/CSharpTest/Formatting/Indentation/SmartIndenterTests.cs @@ -14,6 +14,7 @@ using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Test.Utilities; using Microsoft.VisualStudio.Text; +using Microsoft.VisualStudio.Text.Editor; using Roslyn.Test.Utilities; using Xunit; using Xunit.Abstractions; @@ -3522,11 +3523,6 @@ private static void AssertSmartIndentInProjection( { using var workspace = TestWorkspace.CreateCSharp(markup, parseOptions: option, composition: s_compositionWithTestFormattingRules); - workspace.TryApplyChanges(workspace.CurrentSolution.WithOptions(workspace.Options - .WithChangedOption(UseTabs, LanguageNames.CSharp, useTabs))); - - workspace.GlobalOptions.SetGlobalOption(new OptionKey(IndentationOptionsStorage.SmartIndent, LanguageNames.CSharp), indentStyle); - var subjectDocument = workspace.Documents.Single(); var projectedDocument = @@ -3536,12 +3532,23 @@ private static void AssertSmartIndentInProjection( provider.BaseIndentation = BaseIndentationOfNugget; provider.TextSpan = subjectDocument.SelectedSpans.Single(); + var editorOptionsService = workspace.GetService(); + var indentationLine = projectedDocument.GetTextBuffer().CurrentSnapshot.GetLineFromPosition(projectedDocument.CursorPosition.Value); - var point = projectedDocument.GetTextView().BufferGraph.MapDownToBuffer(indentationLine.Start, PointTrackingMode.Negative, subjectDocument.GetTextBuffer(), PositionAffinity.Predecessor); + var textView = projectedDocument.GetTextView(); + var buffer = subjectDocument.GetTextBuffer(); + var point = textView.BufferGraph.MapDownToBuffer(indentationLine.Start, PointTrackingMode.Negative, buffer, PositionAffinity.Predecessor); + + var editorOptions = editorOptionsService.Factory.GetOptions(buffer); + editorOptions.SetOptionValue(DefaultOptions.IndentStyleId, indentStyle.ToEditorIndentStyle()); + editorOptions.SetOptionValue(DefaultOptions.ConvertTabsToSpacesOptionId, !useTabs); TestIndentation( - point.Value, expectedIndentation, - projectedDocument.GetTextView(), subjectDocument, workspace.GlobalOptions); + point.Value, + expectedIndentation, + textView, + subjectDocument, + editorOptionsService); } } diff --git a/src/EditorFeatures/CSharpTest/Formatting/Indentation/SmartTokenFormatterFormatRangeTests.cs b/src/EditorFeatures/CSharpTest/Formatting/Indentation/SmartTokenFormatterFormatRangeTests.cs index dd7221eea0b44..4d161f57cfd25 100644 --- a/src/EditorFeatures/CSharpTest/Formatting/Indentation/SmartTokenFormatterFormatRangeTests.cs +++ b/src/EditorFeatures/CSharpTest/Formatting/Indentation/SmartTokenFormatterFormatRangeTests.cs @@ -24,6 +24,7 @@ using Microsoft.CodeAnalysis.Text; using Microsoft.CodeAnalysis.Text.Shared.Extensions; using Microsoft.VisualStudio.Text; +using Microsoft.VisualStudio.Text.Editor; using Microsoft.VisualStudio.Text.Editor.Commanding.Commands; using Roslyn.Test.Utilities; using Xunit; @@ -3538,16 +3539,17 @@ internal static void AutoFormatToken(string markup, string expected, bool useTab using var workspace = TestWorkspace.CreateCSharp(markup); - workspace.TryApplyChanges(workspace.CurrentSolution.WithOptions(workspace.Options - .WithChangedOption(FormattingOptions2.UseTabs, LanguageNames.CSharp, useTabs))); - var subjectDocument = workspace.Documents.Single(); + var textBuffer = subjectDocument.GetTextBuffer(); + var optionsService = workspace.GetService(); + var editorOptions = optionsService.Factory.GetOptions(textBuffer); + editorOptions.SetOptionValue(DefaultOptions.ConvertTabsToSpacesOptionId, !useTabs); var commandHandler = workspace.GetService(); - var typedChar = subjectDocument.GetTextBuffer().CurrentSnapshot.GetText(subjectDocument.CursorPosition.Value - 1, 1); - commandHandler.ExecuteCommand(new TypeCharCommandArgs(subjectDocument.GetTextView(), subjectDocument.GetTextBuffer(), typedChar[0]), () => { }, TestCommandExecutionContext.Create()); + var typedChar = textBuffer.CurrentSnapshot.GetText(subjectDocument.CursorPosition.Value - 1, 1); + commandHandler.ExecuteCommand(new TypeCharCommandArgs(subjectDocument.GetTextView(), textBuffer, typedChar[0]), () => { }, TestCommandExecutionContext.Create()); - var newSnapshot = subjectDocument.GetTextBuffer().CurrentSnapshot; + var newSnapshot = textBuffer.CurrentSnapshot; Assert.Equal(expected, newSnapshot.GetText()); } diff --git a/src/EditorFeatures/CSharpTest/GenerateFromMembers/GenerateConstructorFromMembers/GenerateConstructorFromMembersTests.cs b/src/EditorFeatures/CSharpTest/GenerateFromMembers/GenerateConstructorFromMembers/GenerateConstructorFromMembersTests.cs index f8c888d8a08e2..9a9813c242b87 100644 --- a/src/EditorFeatures/CSharpTest/GenerateFromMembers/GenerateConstructorFromMembers/GenerateConstructorFromMembersTests.cs +++ b/src/EditorFeatures/CSharpTest/GenerateFromMembers/GenerateConstructorFromMembers/GenerateConstructorFromMembersTests.cs @@ -798,6 +798,49 @@ public Program(int field{|Navigation:)|} }"); } + [WorkItem(62162, "https://github.com/dotnet/roslyn/issues/62162")] + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsGenerateConstructorFromMembers)] + public async Task TestUnderscoreInName_KeepIfNameWithoutUnderscoreIsInvalid() + { + await TestInRegularAndScriptAsync( +@"class Program +{ + [|int _0;|] +}", +@"class Program +{ + int _0; + + public Program(int _0{|Navigation:)|} + { + this._0 = _0; + } +}"); + } + + [WorkItem(62162, "https://github.com/dotnet/roslyn/issues/62162")] + [Theory, Trait(Traits.Feature, Traits.Features.CodeActionsGenerateConstructorFromMembers)] + [InlineData('m')] + [InlineData('s')] + [InlineData('t')] + public async Task TestCommonPatternInName_KeepUnderscoreIfNameWithoutItIsInvalid(char commonPatternChar) + { + await TestInRegularAndScriptAsync( +$@"class Program +{{ + [|int {commonPatternChar}_0;|] +}}", +$@"class Program +{{ + int {commonPatternChar}_0; + + public Program(int _0{{|Navigation:)|}} + {{ + {commonPatternChar}_0 = _0; + }} +}}"); + } + [WorkItem(14219, "https://github.com/dotnet/roslyn/issues/14219")] [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsGenerateConstructorFromMembers)] public async Task TestUnderscoreInName_PreferThis() diff --git a/src/EditorFeatures/CSharpTest/InitializeParameter/AddParameterCheckTests.cs b/src/EditorFeatures/CSharpTest/InitializeParameter/AddParameterCheckTests.cs index 83498a61bd282..d3fa76d2e5e7d 100644 --- a/src/EditorFeatures/CSharpTest/InitializeParameter/AddParameterCheckTests.cs +++ b/src/EditorFeatures/CSharpTest/InitializeParameter/AddParameterCheckTests.cs @@ -47,7 +47,7 @@ public C([||]string s) }"; await new VerifyCS.Test { - LanguageVersion = LanguageVersionExtensions.CSharpNext, + LanguageVersion = LanguageVersion.CSharp11, TestCode = testCode, FixedCode = testCode }.RunAsync(); @@ -231,7 +231,7 @@ class C [Theory] [Trait(Traits.Feature, Traits.Features.CodeActionsInitializeParameter)] - [InlineData(LanguageVersionExtensions.CSharpNext)] + [InlineData(LanguageVersion.CSharp11)] [InlineData(LanguageVersion.CSharp8)] public async Task TestNotOnPartialMethodDefinition1(LanguageVersion languageVersion) { @@ -278,7 +278,7 @@ public partial void M(string s) [Theory] [Trait(Traits.Feature, Traits.Features.CodeActionsInitializeParameter)] - [InlineData(LanguageVersionExtensions.CSharpNext)] + [InlineData(LanguageVersion.CSharp11)] [InlineData(LanguageVersion.CSharp8)] public async Task TestNotOnPartialMethodDefinition2(LanguageVersion languageVersion) { @@ -1560,7 +1560,7 @@ public async Task TestOnDiscardLambdaParameter1() { await new VerifyCS.Test { - LanguageVersion = LanguageVersionExtensions.CSharpNext, + LanguageVersion = LanguageVersion.CSharp11, TestCode = @" using System; @@ -1608,7 +1608,7 @@ public C() }"; await new VerifyCS.Test { - LanguageVersion = LanguageVersionExtensions.CSharpNext, + LanguageVersion = LanguageVersion.CSharp11, TestCode = testCode, FixedCode = testCode }.RunAsync(); diff --git a/src/EditorFeatures/CSharpTest/InlineDiagnostics/InlineDiagnosticsTaggerProviderTests.cs b/src/EditorFeatures/CSharpTest/InlineDiagnostics/InlineDiagnosticsTaggerProviderTests.cs index 4fb1e8e6dfd76..d3a9182971b5b 100644 --- a/src/EditorFeatures/CSharpTest/InlineDiagnostics/InlineDiagnosticsTaggerProviderTests.cs +++ b/src/EditorFeatures/CSharpTest/InlineDiagnostics/InlineDiagnosticsTaggerProviderTests.cs @@ -6,6 +6,7 @@ using System.Collections.Immutable; using System.Threading.Tasks; using Microsoft.CodeAnalysis.Editor.InlineDiagnostics; +using Microsoft.CodeAnalysis.Editor.UnitTests.CodeActions; using Microsoft.CodeAnalysis.Editor.UnitTests.Extensions; using Microsoft.CodeAnalysis.Editor.UnitTests.Squiggles; using Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces; @@ -55,7 +56,7 @@ private static async Task>> GetTag private static async Task>> GetTagSpansAsync(TestWorkspace workspace) { - workspace.ApplyOptions(new[] { KeyValuePairUtil.Create(new OptionKey2(InlineDiagnosticsOptions.EnableInlineDiagnostics, LanguageNames.CSharp), (object)true) }); + workspace.GlobalOptions.SetGlobalOption(new OptionKey(InlineDiagnosticsOptions.EnableInlineDiagnostics, LanguageNames.CSharp), true); return (await TestDiagnosticTagProducer.GetDiagnosticsAndErrorSpans(workspace)).Item2; } } diff --git a/src/EditorFeatures/CSharpTest/Intents/IntentTestsBase.cs b/src/EditorFeatures/CSharpTest/Intents/IntentTestsBase.cs index 503b898166e48..5df8cb07118ce 100644 --- a/src/EditorFeatures/CSharpTest/Intents/IntentTestsBase.cs +++ b/src/EditorFeatures/CSharpTest/Intents/IntentTestsBase.cs @@ -47,11 +47,9 @@ internal static async Task VerifyExpectedTextAsync( string? priorText = null) { var documentSet = additionalDocuments.Prepend(activeDocument).ToArray(); - using var workspace = TestWorkspace.CreateCSharp(documentSet, exportProvider: EditorTestCompositions.EditorFeatures.ExportProviderFactory.CreateExportProvider()); - if (options != null) - { - workspace.ApplyOptions(options!); - } + + using var workspace = TestWorkspace.CreateCSharp(documentSet, composition: EditorTestCompositions.EditorFeatures); + options?.SetGlobalOptions(workspace.GlobalOptions); var intentSource = workspace.ExportProvider.GetExportedValue(); diff --git a/src/EditorFeatures/CSharpTest/MoveStaticMembers/CSharpMoveStaticMembersTests.cs b/src/EditorFeatures/CSharpTest/MoveStaticMembers/CSharpMoveStaticMembersTests.cs index 06611eeb08b5f..b5650c4cdbf3b 100644 --- a/src/EditorFeatures/CSharpTest/MoveStaticMembers/CSharpMoveStaticMembersTests.cs +++ b/src/EditorFeatures/CSharpTest/MoveStaticMembers/CSharpMoveStaticMembersTests.cs @@ -8,6 +8,7 @@ using Microsoft.CodeAnalysis.MoveStaticMembers; using Microsoft.CodeAnalysis.Test.Utilities; using Microsoft.CodeAnalysis.Test.Utilities.MoveStaticMembers; +using Microsoft.CodeAnalysis.Testing; using Xunit; using VerifyCS = Microsoft.CodeAnalysis.Editor.UnitTests.CodeActions.CSharpCodeRefactoringVerifier< Microsoft.CodeAnalysis.CSharp.CodeRefactorings.MoveStaticMembers.CSharpMoveStaticMembersRefactoringProvider>; @@ -19,7 +20,7 @@ public class CSharpMoveStaticMembersTests { private static readonly TestComposition s_testServices = FeaturesTestCompositions.Features.AddParts(typeof(TestMoveStaticMembersService)); - #region Perform Actions From Options + #region Perform New Type Action From Options [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsMoveStaticMembers)] public async Task TestMoveField() { @@ -2193,17 +2194,605 @@ public static int TestMethod() } #endregion + #region Perform Existing Type Action From Options + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsMoveStaticMembers)] + public async Task TestMoveFieldToExistingType() + { + var initialSourceMarkup = @" +public class Class1 +{ + public static int Test[||]Field = 1; +}"; + var initialDestinationMarkup = @" +public class Class1Helpers +{ +}"; + var selectedDestinationName = "Class1Helpers"; + var selectedMembers = ImmutableArray.Create("TestField"); + var fixedSourceMarkup = @" +public class Class1 +{ +}"; + var fixedDestinationMarkup = @" +public class Class1Helpers +{ + public static int TestField = 1; +}"; + + await TestMovementExistingFileAsync( + initialSourceMarkup, + initialDestinationMarkup, + fixedSourceMarkup, + fixedDestinationMarkup, + selectedMembers, + selectedDestinationName).ConfigureAwait(false); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsMoveStaticMembers)] + public async Task TestMovePropertyToExistingType() + { + var initialSourceMarkup = @" +public class Class1 +{ + public static int Test[||]Property { get; set; } +}"; + var initialDestinationMarkup = @" +public class Class1Helpers +{ +}"; + var selectedDestinationName = "Class1Helpers"; + var selectedMembers = ImmutableArray.Create("TestProperty"); + var fixedSourceMarkup = @" +public class Class1 +{ +}"; + var fixedDestinationMarkup = @" +public class Class1Helpers +{ + public static int TestProperty { get; set; } +}"; + + await TestMovementExistingFileAsync( + initialSourceMarkup, + initialDestinationMarkup, + fixedSourceMarkup, + fixedDestinationMarkup, + selectedMembers, + selectedDestinationName).ConfigureAwait(false); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsMoveStaticMembers)] + public async Task TestMoveEventToExistingType() + { + var initialSourceMarkup = @" +using System; + +public class Class1 +{ + public static event EventHandler Test[||]Event; +}"; + var initialDestinationMarkup = @" +public class Class1Helpers +{ +}"; + var selectedDestinationName = "Class1Helpers"; + var selectedMembers = ImmutableArray.Create("TestEvent"); + var fixedSourceMarkup = @" +using System; + +public class Class1 +{ +}"; + var fixedDestinationMarkup = @" +using System; + +public class Class1Helpers +{ + public static event EventHandler TestEvent; +}"; + + await TestMovementExistingFileAsync( + initialSourceMarkup, + initialDestinationMarkup, + fixedSourceMarkup, + fixedDestinationMarkup, + selectedMembers, + selectedDestinationName).ConfigureAwait(false); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsMoveStaticMembers)] + public async Task TestMoveMethodToExistingType() + { + var initialSourceMarkup = @" +public class Class1 +{ + public static int Test[||]Method() + { + return 0; + } +}"; + var initialDestinationMarkup = @" +public class Class1Helpers +{ +}"; + var selectedDestinationName = "Class1Helpers"; + var selectedMembers = ImmutableArray.Create("TestMethod"); + var fixedSourceMarkup = @" +public class Class1 +{ +}"; + var fixedDestinationMarkup = @" +public class Class1Helpers +{ + public static int TestMethod() + { + return 0; + } +}"; + + await TestMovementExistingFileAsync( + initialSourceMarkup, + initialDestinationMarkup, + fixedSourceMarkup, + fixedDestinationMarkup, + selectedMembers, + selectedDestinationName).ConfigureAwait(false); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsMoveStaticMembers)] + public async Task TestMoveExtensionMethodToExistingType() + { + var initialSourceMarkup = @" +public static class Class1 +{ + public static int Test[||]Method(this Other other) + { + return other.OtherInt + 2; + } +} + +public class Other +{ + public int OtherInt; + public Other() + { + OtherInt = 5; + } +}"; + var initialDestinationMarkup = @" +public static class Class1Helpers +{ +}"; + var selectedDestinationName = "Class1Helpers"; + var selectedMembers = ImmutableArray.Create("TestMethod"); + var fixedSourceMarkup = @" +public static class Class1 +{ +} + +public class Other +{ + public int OtherInt; + public Other() + { + OtherInt = 5; + } +}"; + var fixedDestinationMarkup = @" +public static class Class1Helpers +{ + public static int TestMethod(this Other other) + { + return other.OtherInt + 2; + } +}"; + + await TestMovementExistingFileAsync( + initialSourceMarkup, + initialDestinationMarkup, + fixedSourceMarkup, + fixedDestinationMarkup, + selectedMembers, + selectedDestinationName).ConfigureAwait(false); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsMoveStaticMembers)] + public async Task TestMoveConstFieldToExistingType() + { + var initialSourceMarkup = @" +public class Class1 +{ + public const int Test[||]Field = 1; +}"; + var initialDestinationMarkup = @" +public class Class1Helpers +{ +}"; + var selectedDestinationName = "Class1Helpers"; + var selectedMembers = ImmutableArray.Create("TestField"); + var fixedSourceMarkup = @" +public class Class1 +{ +}"; + var fixedDestinationMarkup = @" +public class Class1Helpers +{ + public const int TestField = 1; +}"; + + await TestMovementExistingFileAsync( + initialSourceMarkup, + initialDestinationMarkup, + fixedSourceMarkup, + fixedDestinationMarkup, + selectedMembers, + selectedDestinationName).ConfigureAwait(false); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsMoveStaticMembers)] + public async Task TestMoveMethodToExistingTypeWithNamespace() + { + var initialSourceMarkup = @" +namespace TestNs +{ + public class Class1 + { + public static int Test[||]Method() + { + return 0; + } + } +}"; + var initialDestinationMarkup = @" +namespace TestNs +{ + public class Class1Helpers + { + } +}"; + var selectedDestinationName = "TestNs.Class1Helpers"; + var selectedMembers = ImmutableArray.Create("TestMethod"); + var fixedSourceMarkup = @" +namespace TestNs +{ + public class Class1 + { + } +}"; + var fixedDestinationMarkup = @" +namespace TestNs +{ + public class Class1Helpers + { + public static int TestMethod() + { + return 0; + } + } +}"; + + await TestMovementExistingFileAsync( + initialSourceMarkup, + initialDestinationMarkup, + fixedSourceMarkup, + fixedDestinationMarkup, + selectedMembers, + selectedDestinationName).ConfigureAwait(false); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsMoveStaticMembers)] + public async Task TestMoveMethodToExistingTypeWithNewNamespace() + { + var initialSourceMarkup = @" +public class Class1 +{ + public static int Test[||]Method() + { + return 0; + } +}"; + var initialDestinationMarkup = @" +namespace TestNs +{ + public class Class1Helpers + { + } +}"; + var selectedDestinationName = "TestNs.Class1Helpers"; + var selectedMembers = ImmutableArray.Create("TestMethod"); + var fixedSourceMarkup = @" +public class Class1 +{ +}"; + var fixedDestinationMarkup = @" +namespace TestNs +{ + public class Class1Helpers + { + public static int TestMethod() + { + return 0; + } + } +}"; + + await TestMovementExistingFileAsync( + initialSourceMarkup, + initialDestinationMarkup, + fixedSourceMarkup, + fixedDestinationMarkup, + selectedMembers, + selectedDestinationName).ConfigureAwait(false); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsMoveStaticMembers)] + public async Task TestMoveMethodToExistingTypeRefactorSourceUsage() + { + var initialSourceMarkup = @" +public class Class1 +{ + public static int Test[||]Method() + { + return 0; + } + + public static int TestMethod2() + { + return TestMethod(); + } +}"; + var initialDestinationMarkup = @" +public class Class1Helpers +{ +}"; + var selectedDestinationName = "Class1Helpers"; + var selectedMembers = ImmutableArray.Create("TestMethod"); + var fixedSourceMarkup = @" +public class Class1 +{ + public static int TestMethod2() + { + return Class1Helpers.TestMethod(); + } +}"; + var fixedDestinationMarkup = @" +public class Class1Helpers +{ + public static int TestMethod() + { + return 0; + } +}"; + + await TestMovementExistingFileAsync( + initialSourceMarkup, + initialDestinationMarkup, + fixedSourceMarkup, + fixedDestinationMarkup, + selectedMembers, + selectedDestinationName).ConfigureAwait(false); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsMoveStaticMembers)] + public async Task TestMoveMethodToExistingTypeRefactorDestinationUsage() + { + var initialSourceMarkup = @" +public class Class1 +{ + public static int Test[||]Method() + { + return 0; + } +}"; + var initialDestinationMarkup = @" +public class Class1Helpers +{ + public static int TestMethod2() + { + return Class1.TestMethod(); + } +}"; + var selectedDestinationName = "Class1Helpers"; + var selectedMembers = ImmutableArray.Create("TestMethod"); + var fixedSourceMarkup = @" +public class Class1 +{ +}"; + var fixedDestinationMarkup = @" +public class Class1Helpers +{ + public static int TestMethod() + { + return 0; + } + public static int TestMethod2() + { + return Class1Helpers.TestMethod(); + } +}"; + + await TestMovementExistingFileAsync( + initialSourceMarkup, + initialDestinationMarkup, + fixedSourceMarkup, + fixedDestinationMarkup, + selectedMembers, + selectedDestinationName).ConfigureAwait(false); + } + #endregion + #region Selections and caret position [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsMoveStaticMembers)] - public async Task TestSelectInMethodParens() + public async Task TestSelectInMethodParens() + { + var initialMarkup = @" +namespace TestNs1 +{ + public class Class1 + { + public static int TestMethod([||]) + { + return 0; + } + } +}"; + var selectedDestinationName = "Class1Helpers"; + var newFileName = "Class1Helpers.cs"; + var selectedMembers = ImmutableArray.Create("TestMethod"); + var expectedResult1 = @" +namespace TestNs1 +{ + public class Class1 + { + } +}"; + var expectedResult2 = @"namespace TestNs1 +{ + internal static class Class1Helpers + { + public static int TestMethod() + { + return 0; + } + } +}"; + await TestMovementNewFileAsync(initialMarkup, expectedResult1, expectedResult2, newFileName, selectedMembers, selectedDestinationName).ConfigureAwait(false); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsMoveStaticMembers)] + public async Task TestSelectWholeFieldDeclaration() + { + var initialMarkup = @" +namespace TestNs1 +{ + public class Class1 + { + [|public static int TestField = 1;|] + } +}"; + var selectedDestinationName = "Class1Helpers"; + var newFileName = "Class1Helpers.cs"; + var selectedMembers = ImmutableArray.Create("TestField"); + var expectedResult1 = @" +namespace TestNs1 +{ + public class Class1 + { + } +}"; + var expectedResult2 = @"namespace TestNs1 +{ + internal static class Class1Helpers + { + public static int TestField = 1; + } +}"; + await TestMovementNewFileAsync(initialMarkup, expectedResult1, expectedResult2, newFileName, selectedMembers, selectedDestinationName).ConfigureAwait(false); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsMoveStaticMembers)] + public async Task TestSelectBeforeKeywordOfDeclaration() + { + var initialMarkup = @" +namespace TestNs1 +{ + public class Class1 + { + [||]public static int TestField = 1; + } +}"; + var selectedDestinationName = "Class1Helpers"; + var newFileName = "Class1Helpers.cs"; + var selectedMembers = ImmutableArray.Create("TestField"); + var expectedResult1 = @" +namespace TestNs1 +{ + public class Class1 + { + } +}"; + var expectedResult2 = @"namespace TestNs1 +{ + internal static class Class1Helpers + { + public static int TestField = 1; + } +}"; + await TestMovementNewFileAsync(initialMarkup, expectedResult1, expectedResult2, newFileName, selectedMembers, selectedDestinationName).ConfigureAwait(false); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsMoveStaticMembers)] + public async Task TestSelectInKeyWordOfDeclaration1() + { + var initialMarkup = @" +namespace TestNs1 +{ + public class Class1 + { + pub[||]lic static int TestField = 1; + } +}"; + var selectedDestinationName = "Class1Helpers"; + var newFileName = "Class1Helpers.cs"; + var selectedMembers = ImmutableArray.Create("TestField"); + var expectedResult1 = @" +namespace TestNs1 +{ + public class Class1 + { + } +}"; + var expectedResult2 = @"namespace TestNs1 +{ + internal static class Class1Helpers + { + public static int TestField = 1; + } +}"; + await TestMovementNewFileAsync(initialMarkup, expectedResult1, expectedResult2, newFileName, selectedMembers, selectedDestinationName).ConfigureAwait(false); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsMoveStaticMembers)] + public async Task TestSelectInKeyWordOfDeclaration2() + { + var initialMarkup = @" +namespace TestNs1 +{ + public class Class1 + { + public st[||]atic int TestField = 1; + } +}"; + var selectedDestinationName = "Class1Helpers"; + var newFileName = "Class1Helpers.cs"; + var selectedMembers = ImmutableArray.Create("TestField"); + var expectedResult1 = @" +namespace TestNs1 +{ + public class Class1 + { + } +}"; + var expectedResult2 = @"namespace TestNs1 +{ + internal static class Class1Helpers + { + public static int TestField = 1; + } +}"; + await TestMovementNewFileAsync(initialMarkup, expectedResult1, expectedResult2, newFileName, selectedMembers, selectedDestinationName).ConfigureAwait(false); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsMoveStaticMembers)] + public async Task TestSelectInTypeIdentifierMethodDeclaration() { var initialMarkup = @" namespace TestNs1 { public class Class1 { - public static int TestMethod([||]) + public static i[||]nt TestMethod() { return 0; } @@ -2233,14 +2822,15 @@ public static int TestMethod() } [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsMoveStaticMembers)] - public async Task TestSelectWholeFieldDeclaration() + public async Task TestSelectInFieldInitializerAfterSemicolon() { + // However, a semicolon after the initializer is still considered a declaration var initialMarkup = @" namespace TestNs1 { public class Class1 { - [|public static int TestField = 1;|] + public static int TestField = 1;[||] } }"; var selectedDestinationName = "Class1Helpers"; @@ -2260,23 +2850,24 @@ internal static class Class1Helpers public static int TestField = 1; } }"; + await TestMovementNewFileAsync(initialMarkup, expectedResult1, expectedResult2, newFileName, selectedMembers, selectedDestinationName).ConfigureAwait(false); } [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsMoveStaticMembers)] - public async Task TestSelectBeforeKeywordOfDeclaration() + public async Task TestSelectInMultipleFieldIdentifiers() { var initialMarkup = @" namespace TestNs1 { public class Class1 { - [||]public static int TestField = 1; + [|public static int Goo = 10, Foo = 9;|] } }"; var selectedDestinationName = "Class1Helpers"; var newFileName = "Class1Helpers.cs"; - var selectedMembers = ImmutableArray.Create("TestField"); + var selectedMembers = ImmutableArray.Create("Goo", "Foo"); var expectedResult1 = @" namespace TestNs1 { @@ -2288,26 +2879,33 @@ public class Class1 { internal static class Class1Helpers { - public static int TestField = 1; + public static int Goo = 10; + public static int Foo = 9; } }"; - await TestMovementNewFileAsync(initialMarkup, expectedResult1, expectedResult2, newFileName, selectedMembers, selectedDestinationName).ConfigureAwait(false); + + await TestMovementNewFileWithSelectionAsync(initialMarkup, expectedResult1, expectedResult2, newFileName, selectedMembers, selectedDestinationName).ConfigureAwait(false); } [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsMoveStaticMembers)] - public async Task TestSelectInKeyWordOfDeclaration1() + public async Task TestSelectMultipleMembers1() { var initialMarkup = @" namespace TestNs1 { public class Class1 { - pub[||]lic static int TestField = 1; + [|public static int Goo = 10, Foo = 9; + + public static int DoSomething() + { + return 5; + }|] } }"; var selectedDestinationName = "Class1Helpers"; var newFileName = "Class1Helpers.cs"; - var selectedMembers = ImmutableArray.Create("TestField"); + var selectedMembers = ImmutableArray.Create("Goo", "Foo", "DoSomething"); var expectedResult1 = @" namespace TestNs1 { @@ -2319,60 +2917,81 @@ public class Class1 { internal static class Class1Helpers { - public static int TestField = 1; + public static int Goo = 10; + public static int Foo = 9; + + public static int DoSomething() + { + return 5; + } } }"; - await TestMovementNewFileAsync(initialMarkup, expectedResult1, expectedResult2, newFileName, selectedMembers, selectedDestinationName).ConfigureAwait(false); + + await TestMovementNewFileWithSelectionAsync(initialMarkup, expectedResult1, expectedResult2, newFileName, selectedMembers, selectedDestinationName).ConfigureAwait(false); } [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsMoveStaticMembers)] - public async Task TestSelectInKeyWordOfDeclaration2() + public async Task TestSelectMultipleMembers2() { var initialMarkup = @" namespace TestNs1 { public class Class1 { - public st[||]atic int TestField = 1; + + public static int DoSomething() + { + return [|5; + } + public static int Goo = 10, Foo = 9;|] } }"; var selectedDestinationName = "Class1Helpers"; var newFileName = "Class1Helpers.cs"; - var selectedMembers = ImmutableArray.Create("TestField"); + var selectedMembers = ImmutableArray.Create("Goo", "Foo"); var expectedResult1 = @" namespace TestNs1 { public class Class1 { + + public static int DoSomething() + { + return 5; + } } }"; var expectedResult2 = @"namespace TestNs1 { internal static class Class1Helpers { - public static int TestField = 1; + public static int Goo = 10; + public static int Foo = 9; } }"; - await TestMovementNewFileAsync(initialMarkup, expectedResult1, expectedResult2, newFileName, selectedMembers, selectedDestinationName).ConfigureAwait(false); + + await TestMovementNewFileWithSelectionAsync(initialMarkup, expectedResult1, expectedResult2, newFileName, selectedMembers, selectedDestinationName).ConfigureAwait(false); } [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsMoveStaticMembers)] - public async Task TestSelectInTypeIdentifierMethodDeclaration() + public async Task TestSelectMultipleMembers3() { var initialMarkup = @" namespace TestNs1 { public class Class1 { - public static i[||]nt TestMethod() + public static int Go[|o = 10, Foo = 9; + + public static int DoSometh|]ing() { - return 0; + return 5; } } }"; var selectedDestinationName = "Class1Helpers"; var newFileName = "Class1Helpers.cs"; - var selectedMembers = ImmutableArray.Create("TestMethod"); + var selectedMembers = ImmutableArray.Create("Goo", "Foo", "DoSomething"); var expectedResult1 = @" namespace TestNs1 { @@ -2384,17 +3003,64 @@ public class Class1 { internal static class Class1Helpers { - public static int TestMethod() + public static int Goo = 10; + public static int Foo = 9; + + public static int DoSomething() { - return 0; + return 5; } } }"; - await TestMovementNewFileAsync(initialMarkup, expectedResult1, expectedResult2, newFileName, selectedMembers, selectedDestinationName).ConfigureAwait(false); + + await TestMovementNewFileWithSelectionAsync(initialMarkup, expectedResult1, expectedResult2, newFileName, selectedMembers, selectedDestinationName).ConfigureAwait(false); } [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsMoveStaticMembers)] - public async Task TestSelectInFieldInitializerAfterSemicolon() + public async Task TestSelectMultipleMembers4() + { + var initialMarkup = @" +namespace TestNs1 +{ + public class Class1 + { + public static int Goo = 10, F[|oo = 9; + + public static in|]t DoSomething() + { + return 5; + } + } +}"; + var selectedDestinationName = "Class1Helpers"; + var newFileName = "Class1Helpers.cs"; + var selectedMembers = ImmutableArray.Create("Foo"); + var expectedResult1 = @" +namespace TestNs1 +{ + public class Class1 + { + public static int Goo = 10; + + public static int DoSomething() + { + return 5; + } + } +}"; + var expectedResult2 = @"namespace TestNs1 +{ + internal static class Class1Helpers + { + public static int Foo = 9; + } +}"; + + await TestMovementNewFileWithSelectionAsync(initialMarkup, expectedResult1, expectedResult2, newFileName, selectedMembers, selectedDestinationName).ConfigureAwait(false); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsMoveStaticMembers)] + public async Task TestSelectOneOfMultipleFieldIdentifiers() { // However, a semicolon after the initializer is still considered a declaration var initialMarkup = @" @@ -2402,28 +3068,29 @@ namespace TestNs1 { public class Class1 { - public static int TestField = 1;[||] + public static int G[||]oo = 10, Foo = 9; } }"; var selectedDestinationName = "Class1Helpers"; var newFileName = "Class1Helpers.cs"; - var selectedMembers = ImmutableArray.Create("TestField"); + var selectedMembers = ImmutableArray.Create("Goo"); var expectedResult1 = @" namespace TestNs1 { public class Class1 { + public static int Foo = 9; } }"; var expectedResult2 = @"namespace TestNs1 { internal static class Class1Helpers { - public static int TestField = 1; + public static int Goo = 10; } }"; - await TestMovementNewFileAsync(initialMarkup, expectedResult1, expectedResult2, newFileName, selectedMembers, selectedDestinationName).ConfigureAwait(false); + await TestMovementNewFileWithSelectionAsync(initialMarkup, expectedResult1, expectedResult2, newFileName, selectedMembers, selectedDestinationName).ConfigureAwait(false); } [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsMoveStaticMembers)] @@ -2489,6 +3156,99 @@ public static int TestMethod() await TestNoRefactoringAsync(initialMarkup).ConfigureAwait(false); } + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsMoveStaticMembers)] + public async Task TestSelectMalformedMethod_NoAction() + { + var initialMarkup = @" +namespace TestNs1 +{ + public class Class1 + { + public st[||] {|CS1519:int|} TestMethod() + { + return 0; + } + } +}"; + await new Test("", ImmutableArray.Empty, "") + { + TestCode = initialMarkup, + FixedCode = initialMarkup, + }.RunAsync().ConfigureAwait(false); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsMoveStaticMembers)] + public async Task TestSelectMalformedField_NoAction1() + { + var initialMarkup = @" +namespace TestNs1 +{ + public class Class1 + { + public st[||] {|CS1519:int|} TestField = 0; + } +}"; + await new Test("", ImmutableArray.Empty, "") + { + TestCode = initialMarkup, + FixedCode = initialMarkup, + }.RunAsync().ConfigureAwait(false); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsMoveStaticMembers)] + public async Task TestSelectMalformedField_NoAction2() + { + var initialMarkup = @" +namespace TestNs1 +{ + public class Class1 + { + public st [|{|CS1519:int|} Test|]Field = 0; + } +}"; + await new Test("", ImmutableArray.Empty, "") + { + TestCode = initialMarkup, + FixedCode = initialMarkup, + }.RunAsync().ConfigureAwait(false); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsMoveStaticMembers)] + public async Task TestSelectMalformedField_NoAction3() + { + var initialMarkup = @" +namespace TestNs1 +{ + public class Class1 + { + [|public st {|CS1519:int|} TestField = 0;|] + } +}"; + await new Test("", ImmutableArray.Empty, "") + { + TestCode = initialMarkup, + FixedCode = initialMarkup, + }.RunAsync().ConfigureAwait(false); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsMoveStaticMembers)] + public async Task TestSelectMalformedField_NoAction4() + { + var initialMarkup = @" +namespace TestNs1 +{ + public class Class1 + { + [|publicc {|CS1585:static|} int TestField = 0;|] + } +}"; + await new Test("", ImmutableArray.Empty, "") + { + TestCode = initialMarkup, + FixedCode = initialMarkup, + }.RunAsync().ConfigureAwait(false); + } + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsMoveStaticMembers)] public async Task TestSelectPropertyBody_NoAction() { @@ -2565,56 +3325,111 @@ public class Class1 }"; await TestNoRefactoringAsync(initialMarkup).ConfigureAwait(false); } - #endregion [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsMoveStaticMembers)] - public async Task NoOptionsService_NoAction() + public async Task TestSelectTopLevelStatement_NoAction1() { var initialMarkup = @" -namespace TestNs1 +using System; + +[||]Console.WriteLine(5); +"; + + await new Test("", ImmutableArray.Empty, "") + { + TestCode = initialMarkup, + FixedCode = initialMarkup, + LanguageVersion = CodeAnalysis.CSharp.LanguageVersion.CSharp10, + TestState = + { + OutputKind = OutputKind.ConsoleApplication + }, + }.RunAsync().ConfigureAwait(false); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsMoveStaticMembers)] + public async Task TestSelectTopLevelStatement_NoAction2() + { + var initialMarkup = @" +using System; + +[|Console.WriteLine(5);|] +"; + + await new Test("", ImmutableArray.Empty, "") + { + TestCode = initialMarkup, + FixedCode = initialMarkup, + LanguageVersion = CodeAnalysis.CSharp.LanguageVersion.CSharp10, + TestState = + { + OutputKind = OutputKind.ConsoleApplication + }, + }.RunAsync().ConfigureAwait(false); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsMoveStaticMembers)] + public async Task TestSelectTopLevelLocalFunction_NoAction() + { + var initialMarkup = @" +DoSomething(); + +static int Do[||]Something() { - public class Class1 - { - public static int TestField = 1;[||] - } -}"; - await TestNoRefactoringAsync(initialMarkup, hostServices: FeaturesTestCompositions.Features.GetHostServices()).ConfigureAwait(false); + return 5; +} +"; + + await new Test("", ImmutableArray.Empty, "") + { + TestCode = initialMarkup, + FixedCode = initialMarkup, + LanguageVersion = CodeAnalysis.CSharp.LanguageVersion.CSharp10, + TestState = + { + OutputKind = OutputKind.ConsoleApplication + }, + }.RunAsync().ConfigureAwait(false); } + #endregion private class Test : VerifyCS.Test { public Test( string destinationType, ImmutableArray selection, - string destinationName = "a.cs", - HostServices? hostServices = null) + string? destinationName, + bool testPreselection = false, + bool createNew = true) { _destinationType = destinationType; _selection = selection; _destinationName = destinationName; - _hostServices = hostServices; + _testPreselection = testPreselection; + _createNew = createNew; } private readonly string _destinationType; private readonly ImmutableArray _selection; - private readonly string _destinationName; + private readonly string? _destinationName; - private readonly HostServices? _hostServices; + private readonly bool _createNew; + + private readonly bool _testPreselection; protected override Workspace CreateWorkspaceImpl() { - var hostServices = _hostServices ?? s_testServices.GetHostServices(); + var hostServices = s_testServices.GetHostServices(); var workspace = new AdhocWorkspace(hostServices); - var testOptionsService = workspace.Services.GetService() as TestMoveStaticMembersService; - if (testOptionsService is not null) - { - testOptionsService.DestinationType = _destinationType; - testOptionsService.SelectedMembers = _selection; - testOptionsService.Filename = _destinationName; - } + var testOptionsService = (TestMoveStaticMembersService)workspace.Services.GetRequiredService(); + testOptionsService.DestinationName = _destinationType; + testOptionsService.SelectedMembers = _selection; + testOptionsService.Filename = _destinationName; + testOptionsService.CreateNew = _createNew; + testOptionsService.ExpectedPrecheckedMembers = _testPreselection ? _selection : ImmutableArray.Empty; return workspace; } @@ -2640,9 +3455,55 @@ private static async Task TestMovementNewFileAsync( }, }.RunAsync().ConfigureAwait(false); - private static async Task TestNoRefactoringAsync(string initialMarkup, HostServices? hostServices = null) + private static async Task TestMovementNewFileWithSelectionAsync( + string initialMarkup, + string expectedSource, + string expectedNewFile, + string newFileName, + ImmutableArray selectedMembers, + string newTypeName) + => await new Test(newTypeName, selectedMembers, newFileName, testPreselection: true) + { + TestCode = initialMarkup, + FixedState = + { + Sources = + { + expectedSource, + (newFileName, expectedNewFile) + } + }, + }.RunAsync().ConfigureAwait(false); + + private static async Task TestMovementExistingFileAsync( + string intialSourceMarkup, + string initialDestinationMarkup, + string fixedSourceMarkup, + string fixedDestinationMarkup, + ImmutableArray selectedMembers, + string selectedDestinationType, + string? selectedDestinationFile = null) + { + var test = new Test(selectedDestinationType, selectedMembers, selectedDestinationFile, createNew: false); + test.TestState.Sources.Add(intialSourceMarkup); + test.FixedState.Sources.Add(fixedSourceMarkup); + if (selectedDestinationFile != null) + { + test.TestState.Sources.Add((selectedDestinationFile, initialDestinationMarkup)); + test.FixedState.Sources.Add((selectedDestinationFile, fixedDestinationMarkup)); + } + else + { + test.TestState.Sources.Add(initialDestinationMarkup); + test.FixedState.Sources.Add(fixedDestinationMarkup); + } + + await test.RunAsync().ConfigureAwait(false); + } + + private static async Task TestNoRefactoringAsync(string initialMarkup) { - await new Test("", ImmutableArray.Empty, hostServices: hostServices) + await new Test("", ImmutableArray.Empty, "") { TestCode = initialMarkup, FixedCode = initialMarkup, diff --git a/src/EditorFeatures/CSharpTest/NavigateTo/NavigateToTests.cs b/src/EditorFeatures/CSharpTest/NavigateTo/NavigateToTests.cs index 208f6ac7d673c..a664360f4eedf 100644 --- a/src/EditorFeatures/CSharpTest/NavigateTo/NavigateToTests.cs +++ b/src/EditorFeatures/CSharpTest/NavigateTo/NavigateToTests.cs @@ -667,6 +667,113 @@ await TestAsync( }); } + [Theory] + [CombinatorialData] + public async Task FindTopLevelLocalFunction(TestHost testHost, Composition composition) + { + await TestAsync( +testHost, composition, @"void Goo() +{ +}", async w => +{ + var item = (await _aggregator.GetItemsAsync("Goo")).Single(); + VerifyNavigateToResultItem(item, "Goo", "[|Goo|]()", PatternMatchKind.Exact, NavigateToItemKind.Method, Glyph.MethodPrivate); +}); + } + + [Theory] + [CombinatorialData] + public async Task FindTopLevelLocalFunction_WithParameters(TestHost testHost, Composition composition) + { + await TestAsync( +testHost, composition, @"void Goo(int i) +{ +}", async w => +{ + var item = (await _aggregator.GetItemsAsync("Goo")).Single(); + VerifyNavigateToResultItem(item, "Goo", "[|Goo|](int)", PatternMatchKind.Exact, NavigateToItemKind.Method, Glyph.MethodPrivate); +}); + } + + [Theory] + [CombinatorialData] + public async Task FindTopLevelLocalFunction_WithTypeArgumentsAndParameters(TestHost testHost, Composition composition) + { + await TestAsync( +testHost, composition, @"void Goo(int i) +{ +}", async w => +{ + var item = (await _aggregator.GetItemsAsync("Goo")).Single(); + VerifyNavigateToResultItem(item, "Goo", "[|Goo|](int)", PatternMatchKind.Exact, NavigateToItemKind.Method, Glyph.MethodPrivate); +}); + } + + [Theory] + [CombinatorialData] + public async Task FindNestedLocalFunctionTopLevelStatements(TestHost testHost, Composition composition) + { + await TestAsync( +testHost, composition, @"void Goo() +{ + void Bar() + { + } +}", async w => +{ + var item = (await _aggregator.GetItemsAsync("Bar")).Single(); + VerifyNavigateToResultItem(item, "Bar", "[|Bar|]()", PatternMatchKind.Exact, NavigateToItemKind.Method, Glyph.MethodPrivate); +}); + } + + [Theory] + [CombinatorialData] + public async Task FindLocalFunctionInMethod(TestHost testHost, Composition composition) + { + await TestAsync( +testHost, composition, @" +class C +{ + void M() + { + void Goo() + { + void Bar() + { + } + } + } +}", async w => +{ + var item = (await _aggregator.GetItemsAsync("Goo")).Single(); + VerifyNavigateToResultItem(item, "Goo", "[|Goo|]()", PatternMatchKind.Exact, NavigateToItemKind.Method, Glyph.MethodPrivate); +}); + } + + [Theory] + [CombinatorialData] + public async Task FindNestedLocalFunctionInMethod(TestHost testHost, Composition composition) + { + await TestAsync( +testHost, composition, @" +class C +{ + void M() + { + void Goo() + { + void Bar() + { + } + } + } +}", async w => +{ + var item = (await _aggregator.GetItemsAsync("Bar")).Single(); + VerifyNavigateToResultItem(item, "Bar", "[|Bar|]()", PatternMatchKind.Exact, NavigateToItemKind.Method, Glyph.MethodPrivate); +}); + } + [Theory] [CombinatorialData] public async Task FindDelegateInNamespace(TestHost testHost, Composition composition) diff --git a/src/EditorFeatures/CSharpTest/PdbSourceDocument/AbstractPdbSourceDocumentTests.cs b/src/EditorFeatures/CSharpTest/PdbSourceDocument/AbstractPdbSourceDocumentTests.cs index 8b05e0ca1e324..439bd53db35c2 100644 --- a/src/EditorFeatures/CSharpTest/PdbSourceDocument/AbstractPdbSourceDocumentTests.cs +++ b/src/EditorFeatures/CSharpTest/PdbSourceDocument/AbstractPdbSourceDocumentTests.cs @@ -132,7 +132,7 @@ protected static async Task GenerateFileAndVerifyAsync( try { // Using default settings here because none of the tests exercise any of the settings - var file = await service.GetGeneratedFileAsync(project, symbol, signaturesOnly: false, MetadataAsSourceOptions.GetDefault(project.LanguageServices), CancellationToken.None).ConfigureAwait(false); + var file = await service.GetGeneratedFileAsync(project, symbol, signaturesOnly: false, MetadataAsSourceOptions.GetDefault(project.Services), CancellationToken.None).ConfigureAwait(false); if (expectNullResult) { @@ -252,8 +252,7 @@ protected static void CompileTestSource(string path, SourceText source, Project protected static void CompileTestSource(string dllFilePath, string sourceCodePath, string? pdbFilePath, string assemblyName, SourceText source, Project project, Location pdbLocation, Location sourceLocation, bool buildReferenceAssembly, bool windowsPdb, Encoding? fallbackEncoding = null) { - var languageServices = project.Solution.Workspace.Services.GetLanguageServices(LanguageNames.CSharp); - var compilationFactory = languageServices.GetRequiredService(); + var compilationFactory = project.Solution.Services.GetRequiredLanguageService(LanguageNames.CSharp); var options = compilationFactory.GetDefaultCompilationOptions().WithOutputKind(OutputKind.DynamicallyLinkedLibrary); var parseOptions = project.ParseOptions; diff --git a/src/EditorFeatures/CSharpTest/PdbSourceDocument/ImplementationAssemblyLookupServiceTests.cs b/src/EditorFeatures/CSharpTest/PdbSourceDocument/ImplementationAssemblyLookupServiceTests.cs index 80bd80ba40c7f..52e8f4a35a791 100644 --- a/src/EditorFeatures/CSharpTest/PdbSourceDocument/ImplementationAssemblyLookupServiceTests.cs +++ b/src/EditorFeatures/CSharpTest/PdbSourceDocument/ImplementationAssemblyLookupServiceTests.cs @@ -188,6 +188,126 @@ await RunTestAsync(async path => }); } + [Fact] + public async Task FollowTypeForwards_Namespace() + { + var source = @" +namespace A +{ + namespace B + { + public class C + { + public class D + { + // A change + public event System.EventHandler [|E|] { add { } remove { } } + } + } + } +}"; + var typeForwardSource = @" +[assembly: System.Runtime.CompilerServices.TypeForwardedTo(typeof(A.B.C))] +"; + + await RunTestAsync(async path => + { + MarkupTestFile.GetSpan(source, out var metadataSource, out var expectedSpan); + + // Compile reference assembly + var sourceText = SourceText.From(metadataSource, encoding: Encoding.UTF8); + var (project, symbol) = await CompileAndFindSymbolAsync(path, Location.Embedded, Location.Embedded, sourceText, c => c.GetMember("A.B.C.D.E"), buildReferenceAssembly: true); + + // Compile implementation assembly to a different DLL + var dllFilePath = Path.Combine(path, "implementation.dll"); + var sourceCodePath = Path.Combine(path, "implementation.cs"); + var pdbFilePath = Path.Combine(path, "implementation.pdb"); + var assemblyName = "implementation"; + + var workspace = TestWorkspace.Create(@$" + + + +", composition: GetTestComposition()); + + var implProject = workspace.CurrentSolution.Projects.First(); + CompileTestSource(dllFilePath, sourceCodePath, pdbFilePath, assemblyName, sourceText, implProject, Location.Embedded, Location.Embedded, buildReferenceAssembly: false, windowsPdb: false); + + // Compile type forwarding implementation DLL + var typeForwardDllFilePath = Path.Combine(path, "typeforward.dll"); + assemblyName = "typeforward"; + + implProject = implProject.AddMetadataReference(MetadataReference.CreateFromFile(dllFilePath)); + sourceText = SourceText.From(typeForwardSource, Encoding.UTF8); + CompileTestSource(typeForwardDllFilePath, sourceCodePath, pdbFilePath, assemblyName, sourceText, implProject, Location.Embedded, Location.Embedded, buildReferenceAssembly: false, windowsPdb: false); + + var service = workspace.GetService(); + + var foundImplementationFilePath = service.FollowTypeForwards(symbol, typeForwardDllFilePath, new NoDuplicatesLogger()); + Assert.Equal(dllFilePath, foundImplementationFilePath); + }); + } + + [Fact] + public async Task FollowTypeForwards_Generics() + { + var source = @" +namespace A +{ + namespace B + { + public class C + { + public class D + { + // A change + public event System.EventHandler [|E|] { add { } remove { } } + } + } + } +}"; + var typeForwardSource = @" +[assembly: System.Runtime.CompilerServices.TypeForwardedTo(typeof(A.B.C<>))] +"; + + await RunTestAsync(async path => + { + MarkupTestFile.GetSpan(source, out var metadataSource, out var expectedSpan); + + // Compile reference assembly + var sourceText = SourceText.From(metadataSource, encoding: Encoding.UTF8); + var (project, symbol) = await CompileAndFindSymbolAsync(path, Location.Embedded, Location.Embedded, sourceText, c => c.GetMember("A.B.C.D.E"), buildReferenceAssembly: true); + + // Compile implementation assembly to a different DLL + var dllFilePath = Path.Combine(path, "implementation.dll"); + var sourceCodePath = Path.Combine(path, "implementation.cs"); + var pdbFilePath = Path.Combine(path, "implementation.pdb"); + var assemblyName = "implementation"; + + var workspace = TestWorkspace.Create(@$" + + + +", composition: GetTestComposition()); + + var implProject = workspace.CurrentSolution.Projects.First(); + CompileTestSource(dllFilePath, sourceCodePath, pdbFilePath, assemblyName, sourceText, implProject, Location.Embedded, Location.Embedded, buildReferenceAssembly: false, windowsPdb: false); + + // Compile type forwarding implementation DLL + var typeForwardDllFilePath = Path.Combine(path, "typeforward.dll"); + assemblyName = "typeforward"; + + implProject = implProject.AddMetadataReference(MetadataReference.CreateFromFile(dllFilePath)); + sourceText = SourceText.From(typeForwardSource, Encoding.UTF8); + CompileTestSource(typeForwardDllFilePath, sourceCodePath, pdbFilePath, assemblyName, sourceText, implProject, Location.Embedded, Location.Embedded, buildReferenceAssembly: false, windowsPdb: false); + + var service = workspace.GetService(); + + var foundImplementationFilePath = service.FollowTypeForwards(symbol, typeForwardDllFilePath, new NoDuplicatesLogger()); + Assert.Equal(dllFilePath, foundImplementationFilePath); + }); + } + [Fact] public async Task FollowTypeForwards_NestedType() { @@ -402,28 +522,36 @@ await RunTestAsync(async path => var typeForwardDllFilePath = Path.Combine(path, "typeforward.dll"); assemblyName = "typeforward"; - implProject = implProject.AddMetadataReference(MetadataReference.CreateFromFile(dllFilePath)); - sourceText = SourceText.From(typeForwardSource, Encoding.UTF8); - CompileTestSource(typeForwardDllFilePath, sourceCodePath, pdbFilePath, assemblyName, sourceText, implProject, Location.Embedded, Location.Embedded, buildReferenceAssembly: false, windowsPdb: false); + implProject = workspace.CurrentSolution.Projects.First().AddMetadataReference(MetadataReference.CreateFromFile(dllFilePath)); + var typeForwardSourceText = SourceText.From(typeForwardSource, Encoding.UTF8); + CompileTestSource(typeForwardDllFilePath, sourceCodePath, pdbFilePath, assemblyName, typeForwardSourceText, implProject, Location.Embedded, Location.Embedded, buildReferenceAssembly: false, windowsPdb: false); - var typeForward2DllFilePath = Path.Combine(path, "typeforward2.dll"); - assemblyName = "typeforward2"; + // Now compile a new implementation in realimplementation.dll + var realImplementationDllFilePath = Path.Combine(path, "realimplementation.dll"); + assemblyName = "realimplementation"; - implProject = implProject.AddMetadataReference(MetadataReference.CreateFromFile(typeForwardDllFilePath)); - sourceText = SourceText.From(typeForwardSource, Encoding.UTF8); - CompileTestSource(typeForward2DllFilePath, sourceCodePath, pdbFilePath, assemblyName, sourceText, implProject, Location.Embedded, Location.Embedded, buildReferenceAssembly: false, windowsPdb: false); + implProject = workspace.CurrentSolution.Projects.First(); + CompileTestSource(realImplementationDllFilePath, sourceCodePath, pdbFilePath, assemblyName, sourceText, implProject, Location.Embedded, Location.Embedded, buildReferenceAssembly: false, windowsPdb: false); + + // Now compile a new implementation.dll that typeforwards to realimplementation.dll + assemblyName = "implementation"; + + implProject = workspace.CurrentSolution.Projects.First().AddMetadataReference(MetadataReference.CreateFromFile(realImplementationDllFilePath)); + CompileTestSource(dllFilePath, sourceCodePath, pdbFilePath, assemblyName, typeForwardSourceText, implProject, Location.Embedded, Location.Embedded, buildReferenceAssembly: false, windowsPdb: false); var service = workspace.GetService(); - Assert.Equal(dllFilePath, service.FollowTypeForwards(symbol, typeForward2DllFilePath, new NoDuplicatesLogger())); + var foundImplementationFilePath = service.FollowTypeForwards(symbol, typeForwardDllFilePath, new NoDuplicatesLogger()); + Assert.Equal(realImplementationDllFilePath, foundImplementationFilePath); // We need the DLLs to exist, in order for some checks to pass correct, but to ensure // that the file isn't read, we just zero it out. File.WriteAllBytes(typeForwardDllFilePath, Array.Empty()); - File.WriteAllBytes(typeForward2DllFilePath, Array.Empty()); + File.WriteAllBytes(realImplementationDllFilePath, Array.Empty()); File.WriteAllBytes(dllFilePath, Array.Empty()); - Assert.Equal(dllFilePath, service.FollowTypeForwards(symbol, typeForward2DllFilePath, new NoDuplicatesLogger())); + foundImplementationFilePath = service.FollowTypeForwards(symbol, typeForwardDllFilePath, new NoDuplicatesLogger()); + Assert.Equal(realImplementationDllFilePath, foundImplementationFilePath); }); } diff --git a/src/EditorFeatures/CSharpTest/PdbSourceDocument/PdbSourceDocumentTests.cs b/src/EditorFeatures/CSharpTest/PdbSourceDocument/PdbSourceDocumentTests.cs index 59fc5c3a401ca..41eec40869823 100644 --- a/src/EditorFeatures/CSharpTest/PdbSourceDocument/PdbSourceDocumentTests.cs +++ b/src/EditorFeatures/CSharpTest/PdbSourceDocument/PdbSourceDocumentTests.cs @@ -5,9 +5,11 @@ using System.IO; using System.Linq; using System.Text; +using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.CSharp.UnitTests; using Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces; +using Microsoft.CodeAnalysis.MetadataAsSource; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Text; using Roslyn.Test.Utilities; @@ -457,6 +459,50 @@ public class C { } } +"; + + await RunTestAsync(async path => + { + MarkupTestFile.GetSpan(source, out var metadataSource, out var expectedSpan); + + var packDir = Directory.CreateDirectory(Path.Combine(path, "packs", "MyPack.Ref", "1.0", "ref", "net6.0")).FullName; + var dataDir = Directory.CreateDirectory(Path.Combine(path, "packs", "MyPack.Ref", "1.0", "data")).FullName; + var sharedDir = Directory.CreateDirectory(Path.Combine(path, "shared", "MyPack", "1.0")).FullName; + + var sourceText = SourceText.From(metadataSource, Encoding.UTF8); + var (project, symbol) = await CompileAndFindSymbolAsync(packDir, Location.Embedded, Location.Embedded, sourceText, c => c.GetMember("C.M"), buildReferenceAssembly: true); + + var workspace = TestWorkspace.Create(@$" + + + +", composition: GetTestComposition()); + + var implProject = workspace.CurrentSolution.Projects.First(); + + // Compile implementation assembly + CompileTestSource(sharedDir, sourceText, project, Location.Embedded, Location.Embedded, buildReferenceAssembly: false, windowsPdb: false); + + // Create FrameworkList.xml + File.WriteAllText(Path.Combine(dataDir, "FrameworkList.xml"), """ + + + """); + + await GenerateFileAndVerifyAsync(project, symbol, Location.Embedded, metadataSource.ToString(), expectedSpan, expectNullResult: false); + }); + } + + [Fact] + public async Task Net6SdkLayout_TypeForward() + { + var source = @" +public class [|C|] +{ + public void M(string d) + { + } +} "; var typeForwardSource = @" [assembly: System.Runtime.CompilerServices.TypeForwardedTo(typeof(C))] @@ -471,7 +517,7 @@ await RunTestAsync(async path => var sharedDir = Directory.CreateDirectory(Path.Combine(path, "shared", "MyPack", "1.0")).FullName; var sourceText = SourceText.From(metadataSource, Encoding.UTF8); - var (project, symbol) = await CompileAndFindSymbolAsync(packDir, Location.Embedded, Location.Embedded, sourceText, c => c.GetMember("C.M"), buildReferenceAssembly: true); + var (project, symbol) = await CompileAndFindSymbolAsync(packDir, Location.Embedded, Location.Embedded, sourceText, c => c.GetMember("C"), buildReferenceAssembly: true); var workspace = TestWorkspace.Create(@$" @@ -482,15 +528,20 @@ await RunTestAsync(async path => var implProject = workspace.CurrentSolution.Projects.First(); // Compile implementation assembly - CompileTestSource(sharedDir, sourceText, project, Location.Embedded, Location.Embedded, buildReferenceAssembly: false, windowsPdb: false); + var implementationDllFilePath = Path.Combine(sharedDir, "implementation.dll"); + var sourceCodePath = Path.Combine(sharedDir, "implementation.cs"); + var pdbFilePath = Path.Combine(sharedDir, "implementation.pdb"); + var assemblyName = "implementation"; - // Compile type forwarding implementation DLL - var typeForwardDllFilePath = Path.Combine(sharedDir, "typeforward.dll"); - var sourceCodePath = Path.Combine(sharedDir, "typeforward.cs"); - var pdbFilePath = Path.Combine(sharedDir, "typeforward.pdb"); - var assemblyName = "typeforward"; + CompileTestSource(implementationDllFilePath, sourceCodePath, pdbFilePath, assemblyName, sourceText, project, Location.Embedded, Location.Embedded, buildReferenceAssembly: false, windowsPdb: false); - implProject = implProject.AddMetadataReference(MetadataReference.CreateFromFile(GetDllPath(sharedDir))); + // Compile type forwarding implementation DLL, that looks like reference.dll + var typeForwardDllFilePath = Path.Combine(sharedDir, "reference.dll"); + sourceCodePath = Path.Combine(sharedDir, "reference.cs"); + pdbFilePath = Path.Combine(sharedDir, "reference.pdb"); + assemblyName = "reference"; + + implProject = implProject.AddMetadataReference(MetadataReference.CreateFromFile(implementationDllFilePath)); sourceText = SourceText.From(typeForwardSource, Encoding.UTF8); CompileTestSource(typeForwardDllFilePath, sourceCodePath, pdbFilePath, assemblyName, sourceText, implProject, Location.Embedded, Location.Embedded, buildReferenceAssembly: false, windowsPdb: false); @@ -796,5 +847,40 @@ await RunTestAsync(async path => AssertEx.EqualOrDiff(source, actualText.ToString()); }); } + + [Fact] + public async Task OptionTurnedOff_NullResult() + { + var source = @" +public class C +{ + public event System.EventHandler E { add { } remove { } } +}"; + + await RunTestAsync(async path => + { + var sourceText = SourceText.From(source, Encoding.UTF8); + var (project, symbol) = await CompileAndFindSymbolAsync(path, Location.Embedded, Location.Embedded, sourceText, c => c.GetMember("C.E")); + + using var workspace = (TestWorkspace)project.Solution.Workspace; + + var service = workspace.GetService(); + try + { + var options = MetadataAsSourceOptions.GetDefault(project.Services) with + { + NavigateToSourceLinkAndEmbeddedSources = false + }; + var file = await service.GetGeneratedFileAsync(project, symbol, signaturesOnly: false, options, CancellationToken.None).ConfigureAwait(false); + + Assert.Same(NullResultMetadataAsSourceFileProvider.NullResult, file); + } + finally + { + service.CleanupGeneratedFiles(); + service.TryGetWorkspace()?.Dispose(); + } + }); + } } } diff --git a/src/EditorFeatures/CSharpTest/PullMemberUp/CSharpPullMemberUpTests.cs b/src/EditorFeatures/CSharpTest/PullMemberUp/CSharpPullMemberUpTests.cs index 9e299784c158f..142af5bedede5 100644 --- a/src/EditorFeatures/CSharpTest/PullMemberUp/CSharpPullMemberUpTests.cs +++ b/src/EditorFeatures/CSharpTest/PullMemberUp/CSharpPullMemberUpTests.cs @@ -5897,6 +5897,368 @@ public class B : A await TestWithPullMemberDialogAsync(testText, expected); } + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsPullMemberUp)] + public async Task TestRefactoringSelectionFieldKeyword1_NoAction() + { + var text = @" +public class BaseClass +{ +} + +public class Bar : BaseClass +{ + pub[|l|]ic int Goo = 10; +}"; + await TestQuickActionNotProvidedAsync(text); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsPullMemberUp)] + public async Task TestRefactoringSelectionFieldKeyword2() + { + var text = @" +public class BaseClass +{ +} + +public class Bar : BaseClass +{ + pub[||]lic int Goo = 10; +}"; + var expected = @" +public class BaseClass +{ + public int Goo = 10; +} + +public class Bar : BaseClass +{ +}"; + await TestWithPullMemberDialogAsync(text, expected); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsPullMemberUp)] + public async Task TestRefactoringSelectionFieldAfterSemicolon() + { + var text = @" +public class BaseClass +{ +} + +public class Bar : BaseClass +{ + public int Goo = 10;[||] +}"; + var expected = @" +public class BaseClass +{ + public int Goo = 10; +} + +public class Bar : BaseClass +{ +}"; + await TestWithPullMemberDialogAsync(text, expected); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsPullMemberUp)] + public async Task TestRefactoringSelectionFieldEntireDeclaration() + { + var text = @" +public class BaseClass +{ +} + +public class Bar : BaseClass +{ + [|public int Goo = 10;|] +}"; + var expected = @" +public class BaseClass +{ + public int Goo = 10; +} + +public class Bar : BaseClass +{ +}"; + await TestWithPullMemberDialogAsync(text, expected); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsPullMemberUp)] + public async Task TestRefactoringSelectionMultipleFieldsInDeclaration1() + { + var text = @" +public class BaseClass +{ +} + +public class Bar : BaseClass +{ + [|public int Goo = 10, Foo = 9;|] +}"; + var expected = @" +public class BaseClass +{ + public int Goo = 10; + public int Foo = 9; +} + +public class Bar : BaseClass +{ +}"; + await TestWithPullMemberDialogAsync(text, expected); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsPullMemberUp)] + public async Task TestRefactoringSelectionMultipleFieldsInDeclaration2() + { + var text = @" +public class BaseClass +{ +} + +public class Bar : BaseClass +{ + public int Go[||]o = 10, Foo = 9; +}"; + var expected = @" +public class BaseClass +{ + public int Goo = 10; +} + +public class Bar : BaseClass +{ + public int Foo = 9; +}"; + await TestWithPullMemberDialogAsync(text, expected); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsPullMemberUp)] + public async Task TestRefactoringSelectionMultipleFieldsInDeclaration3() + { + var text = @" +public class BaseClass +{ +} + +public class Bar : BaseClass +{ + public int Goo = 10, [||]Foo = 9; +}"; + var expected = @" +public class BaseClass +{ + public int Foo = 9; +} + +public class Bar : BaseClass +{ + public int Goo = 10; +}"; + await TestWithPullMemberDialogAsync(text, expected); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsPullMemberUp)] + public async Task TestRefactoringSelectionMultipleMembers1() + { + var text = @" +public class BaseClass +{ +} + +public class Bar : BaseClass +{ + [|public int Goo = 10, Foo = 9; + + public int DoSomething() + { + return 5; + }|] +}"; + var expected = @" +public class BaseClass +{ + public int Goo = 10; + public int Foo = 9; + + public int DoSomething() + { + return 5; + } +} + +public class Bar : BaseClass +{ +}"; + await TestWithPullMemberDialogAsync(text, expected); + } + + // Some of these have weird whitespace spacing that might suggest a bug + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsPullMemberUp)] + public async Task TestRefactoringSelectionMultipleMembers2() + { + var text = @" +public class BaseClass +{ +} + +public class Bar : BaseClass +{ + public int DoSomething() + { + [|return 5; + } + + + public int Goo = 10, Foo = 9;|] +}"; + var expected = @" +public class BaseClass +{ + + + public int Goo = 10; + + + public int Foo = 9; +} + +public class Bar : BaseClass +{ + public int DoSomething() + { + return 5; + } +}"; + await TestWithPullMemberDialogAsync(text, expected); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsPullMemberUp)] + public async Task TestRefactoringSelectionMultipleMembers3() + { + var text = @" +public class BaseClass +{ +} + +public class Bar : BaseClass +{ + public int DoSom[|ething() + { + return 5; + } + + + public int Go|]o = 10, Foo = 9; +}"; + var expected = @" +public class BaseClass +{ + + + public int Goo = 10; + public int DoSomething() + { + return 5; + } +} + +public class Bar : BaseClass +{ + public int Foo = 9; +}"; + await TestWithPullMemberDialogAsync(text, expected); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsPullMemberUp)] + public async Task TestRefactoringSelectionMultipleMembers4() + { + var text = @" +public class BaseClass +{ +} + +public class Bar : BaseClass +{ + public int DoSomething()[| + { + return 5; + } + + + public int Goo = 10, F|]oo = 9; +}"; + var expected = @" +public class BaseClass +{ + + + public int Goo = 10; + + + public int Foo = 9; +} + +public class Bar : BaseClass +{ + public int DoSomething() + { + return 5; + } +}"; + await TestWithPullMemberDialogAsync(text, expected); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsPullMemberUp)] + public async Task TestRefactoringSelectionIncompleteField_NoAction1() + { + var text = @" +public class BaseClass +{ +} + +public class Bar : BaseClass +{ + publ[||] int Goo = 10; +}"; + // we expect a diagnostic/error, but also we shouldn't provide the refactoring + await TestQuickActionNotProvidedAsync(text); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsPullMemberUp)] + public async Task TestRefactoringSelectionIncompleteField_NoAction2() + { + var text = @" +public class BaseClass +{ +} + +public class Bar : BaseClass +{ + [|publicc int Goo = 10;|] +}"; + // we expect a diagnostic/error, but also we shouldn't provide the refactoring + await TestQuickActionNotProvidedAsync(text); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsPullMemberUp)] + public async Task TestRefactoringSelectionIncompleteMethod_NoAction() + { + var text = @" +public class BaseClass +{ +} + +public class Bar : BaseClass +{ + publ[||] int DoSomething() { + return 5; + } +}"; + // we expect a diagnostic/error, but also we shouldn't provide the refactoring + await TestQuickActionNotProvidedAsync(text); + } #endregion } } diff --git a/src/EditorFeatures/CSharpTest/QuickInfo/DiagnosticAnalyzerQuickInfoSourceTests.cs b/src/EditorFeatures/CSharpTest/QuickInfo/DiagnosticAnalyzerQuickInfoSourceTests.cs index 59ee0d46f5c76..158ab75461b65 100644 --- a/src/EditorFeatures/CSharpTest/QuickInfo/DiagnosticAnalyzerQuickInfoSourceTests.cs +++ b/src/EditorFeatures/CSharpTest/QuickInfo/DiagnosticAnalyzerQuickInfoSourceTests.cs @@ -15,7 +15,7 @@ using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.Diagnostics.CSharp; using Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.QuickInfo; using Microsoft.CodeAnalysis.SolutionCrawler; using Microsoft.CodeAnalysis.Test.Utilities; @@ -191,8 +191,8 @@ protected static async Task AssertContentIsAsync(TestWorkspace workspace, Docume private static async Task GetQuickinfo(TestWorkspace workspace, Document document, int position) { - var diagnosticAnalyzerService = workspace.ExportProvider.GetExportedValue(); - var provider = new CSharpDiagnosticAnalyzerQuickInfoProvider(diagnosticAnalyzerService); + var sharedGlobalCache = workspace.ExportProvider.GetExportedValue(); + var provider = new CSharpDiagnosticAnalyzerQuickInfoProvider(sharedGlobalCache); var info = await provider.GetQuickInfoAsync(new QuickInfoContext(document, position, SymbolDescriptionOptions.Default, CancellationToken.None)); return info; } diff --git a/src/EditorFeatures/CSharpTest/QuickInfo/SemanticQuickInfoSourceTests.cs b/src/EditorFeatures/CSharpTest/QuickInfo/SemanticQuickInfoSourceTests.cs index 7467a48a312b6..17c3c0c2bc561 100644 --- a/src/EditorFeatures/CSharpTest/QuickInfo/SemanticQuickInfoSourceTests.cs +++ b/src/EditorFeatures/CSharpTest/QuickInfo/SemanticQuickInfoSourceTests.cs @@ -14,7 +14,7 @@ using Microsoft.CodeAnalysis.CSharp.Test.Utilities; using Microsoft.CodeAnalysis.Editor.UnitTests.QuickInfo; using Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.QuickInfo; using Microsoft.CodeAnalysis.Test.Utilities; using Roslyn.Test.Utilities; @@ -6366,7 +6366,7 @@ void M(int x = 1) { } "; using var workspace = TestWorkspace.Create(XElement.Parse(workspaceDefinition), workspaceKind: WorkspaceKind.Interactive); - await TestWithOptionsAsync(workspace, MainDescription($"({ FeaturesResources.parameter }) int x = 1")); + await TestWithOptionsAsync(workspace, MainDescription($"({FeaturesResources.parameter}) int x = 1")); } [Fact, Trait(Traits.Feature, Traits.Features.QuickInfo)] @@ -6410,7 +6410,7 @@ void M() } } ", - MainDescription($"({ FeaturesResources.local_variable }) ValueTuple y")); + MainDescription($"({FeaturesResources.local_variable}) ValueTuple y")); } [WorkItem(18311, "https://github.com/dotnet/roslyn/issues/18311")] @@ -6446,7 +6446,7 @@ void M() } } ", - MainDescription($"({ FeaturesResources.local_variable }) ValueTuple y")); + MainDescription($"({FeaturesResources.local_variable}) ValueTuple y")); } [WorkItem(18311, "https://github.com/dotnet/roslyn/issues/18311")] @@ -6482,7 +6482,7 @@ void M() } } ", - MainDescription($"({ FeaturesResources.local_variable }) (int, int) y")); + MainDescription($"({FeaturesResources.local_variable}) (int, int) y")); } [WorkItem(18311, "https://github.com/dotnet/roslyn/issues/18311")] @@ -6756,7 +6756,7 @@ void method1() } } ", - MainDescription($"({ FeaturesResources.parameter }) ? b")); + MainDescription($"({FeaturesResources.parameter}) ? b")); } [Fact, Trait(Traits.Feature, Traits.Features.QuickInfo)] @@ -8570,7 +8570,7 @@ class Program void M(string s) { } } "; - await TestWithOptionsAsync(Options.Regular.WithLanguageVersion(LanguageVersionFacts.CSharpNext), source, + await TestWithOptionsAsync(Options.Regular.WithLanguageVersion(LanguageVersion.CSharp11), source, MainDescription($"({FeaturesResources.parameter}) string s")); } @@ -8583,7 +8583,7 @@ class Program void M([My(nameof($$s))] string s) { } } "; - await TestWithOptionsAsync(Options.Regular.WithLanguageVersion(LanguageVersionFacts.CSharpNext), source, + await TestWithOptionsAsync(Options.Regular.WithLanguageVersion(LanguageVersion.CSharp11), source, MainDescription($"({FeaturesResources.parameter}) string s")); } @@ -8600,7 +8600,7 @@ void local(string s) { } } } "; - await TestWithOptionsAsync(Options.Regular.WithLanguageVersion(LanguageVersionFacts.CSharpNext), source, + await TestWithOptionsAsync(Options.Regular.WithLanguageVersion(LanguageVersion.CSharp11), source, MainDescription($"({FeaturesResources.parameter}) string s")); } } diff --git a/src/EditorFeatures/CSharpTest/QuickInfo/SyntacticQuickInfoSourceTests.cs b/src/EditorFeatures/CSharpTest/QuickInfo/SyntacticQuickInfoSourceTests.cs index 0bb441b549c46..092a492de26fb 100644 --- a/src/EditorFeatures/CSharpTest/QuickInfo/SyntacticQuickInfoSourceTests.cs +++ b/src/EditorFeatures/CSharpTest/QuickInfo/SyntacticQuickInfoSourceTests.cs @@ -15,7 +15,7 @@ using Microsoft.CodeAnalysis.Editor.Shared.Utilities; using Microsoft.CodeAnalysis.Editor.UnitTests.QuickInfo; using Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.QuickInfo; using Microsoft.CodeAnalysis.Shared.TestHooks; using Microsoft.CodeAnalysis.Test.Utilities; diff --git a/src/EditorFeatures/CSharpTest/SplitStringLiteral/SplitStringLiteralCommandHandlerTests.cs b/src/EditorFeatures/CSharpTest/SplitStringLiteral/SplitStringLiteralCommandHandlerTests.cs index 79a8f167985e2..1f7cde12dcfe7 100644 --- a/src/EditorFeatures/CSharpTest/SplitStringLiteral/SplitStringLiteralCommandHandlerTests.cs +++ b/src/EditorFeatures/CSharpTest/SplitStringLiteral/SplitStringLiteralCommandHandlerTests.cs @@ -49,21 +49,26 @@ private static void TestWorker( { using var workspace = TestWorkspace.CreateCSharp(inputMarkup); - // TODO: set SmartIndent to textView.Options (https://devdiv.visualstudio.com/DevDiv/_workitems/edit/1412138) - workspace.GlobalOptions.SetGlobalOption(new OptionKey(IndentationOptionsStorage.SmartIndent, LanguageNames.CSharp), indentStyle); - if (useTabs && expectedOutputMarkup != null) { Assert.Contains("\t", expectedOutputMarkup); } + var editorOptionsFactory = workspace.GetService(); + var document = workspace.Documents.Single(); var view = document.GetTextView(); + var textBuffer = view.TextBuffer; + var options = editorOptionsFactory.GetOptions(textBuffer); + + options.SetOptionValue(DefaultOptions.ConvertTabsToSpacesOptionId, !useTabs); + options.SetOptionValue(DefaultOptions.TabSizeOptionId, 4); + options.SetOptionValue(DefaultOptions.IndentStyleId, indentStyle.ToEditorIndentStyle()); - view.Options.SetOptionValue(DefaultOptions.ConvertTabsToSpacesOptionId, !useTabs); - view.Options.SetOptionValue(DefaultOptions.TabSizeOptionId, 4); + // Remove once https://github.com/dotnet/roslyn/issues/62204 is fixed: + workspace.GlobalOptions.SetGlobalOption(new OptionKey(IndentationOptionsStorage.SmartIndent, document.Project.Language), indentStyle); - var originalSnapshot = view.TextBuffer.CurrentSnapshot; + var originalSnapshot = textBuffer.CurrentSnapshot; var originalSelections = document.SelectedSpans; var snapshotSpans = new List(); @@ -77,7 +82,7 @@ private static void TestWorker( var undoHistoryRegistry = workspace.GetService(); var commandHandler = workspace.ExportProvider.GetCommandHandler(nameof(SplitStringLiteralCommandHandler)); - if (!commandHandler.ExecuteCommand(new ReturnKeyCommandArgs(view, view.TextBuffer), TestCommandExecutionContext.Create())) + if (!commandHandler.ExecuteCommand(new ReturnKeyCommandArgs(view, textBuffer), TestCommandExecutionContext.Create())) { callback(); } @@ -87,7 +92,7 @@ private static void TestWorker( MarkupTestFile.GetSpans(expectedOutputMarkup, out var expectedOutput, out ImmutableArray expectedSpans); - Assert.Equal(expectedOutput, view.TextBuffer.CurrentSnapshot.AsText().ToString()); + Assert.Equal(expectedOutput, textBuffer.CurrentSnapshot.AsText().ToString()); Assert.Equal(expectedSpans.First().Start, view.Caret.Position.BufferPosition.Position); if (verifyUndo) diff --git a/src/EditorFeatures/CSharpTest/Squiggles/ErrorSquiggleProducerTests.cs b/src/EditorFeatures/CSharpTest/Squiggles/ErrorSquiggleProducerTests.cs index 15e89613a0593..eeb74f466874a 100644 --- a/src/EditorFeatures/CSharpTest/Squiggles/ErrorSquiggleProducerTests.cs +++ b/src/EditorFeatures/CSharpTest/Squiggles/ErrorSquiggleProducerTests.cs @@ -15,6 +15,7 @@ using Microsoft.CodeAnalysis.CSharp.RemoveUnnecessaryImports; using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.Editor.Implementation.IntelliSense.QuickInfo; +using Microsoft.CodeAnalysis.Editor.UnitTests.CodeActions; using Microsoft.CodeAnalysis.Editor.UnitTests.Diagnostics; using Microsoft.CodeAnalysis.Editor.UnitTests.Extensions; using Microsoft.CodeAnalysis.Editor.UnitTests.Squiggles; @@ -111,13 +112,11 @@ void Test() "; using var workspace = TestWorkspace.Create(workspaceXml, composition: SquiggleUtilities.CompositionWithSolutionCrawler); - var options = new Dictionary(); var language = workspace.Projects.Single().Language; - var preferIntrinsicPredefinedTypeOption = new OptionKey2(CodeStyleOptions2.PreferIntrinsicPredefinedTypeKeywordInDeclaration, language); - var preferIntrinsicPredefinedTypeOptionValue = new CodeStyleOption2(value: true, notification: NotificationOption2.Error); - options.Add(preferIntrinsicPredefinedTypeOption, preferIntrinsicPredefinedTypeOptionValue); - workspace.ApplyOptions(options); + workspace.GlobalOptions.SetGlobalOption( + new OptionKey(CodeStyleOptions2.PreferIntrinsicPredefinedTypeKeywordInDeclaration, language), + new CodeStyleOption2(value: true, notification: NotificationOption2.Error)); var analyzerMap = new Dictionary> { @@ -188,7 +187,7 @@ void Test() new ClassifiedTextRun(ClassificationTypeNames.Text, "IDE0049", QuickInfoHyperLink.TestAccessor.CreateNavigationAction(new Uri("https://docs.microsoft.com/dotnet/fundamentals/code-analysis/style-rules/ide0049", UriKind.Absolute)), "https://docs.microsoft.com/dotnet/fundamentals/code-analysis/style-rules/ide0049"), new ClassifiedTextRun(ClassificationTypeNames.Punctuation, ":"), new ClassifiedTextRun(ClassificationTypeNames.WhiteSpace, " "), - new ClassifiedTextRun(ClassificationTypeNames.Text, WorkspacesResources.Name_can_be_simplified))); + new ClassifiedTextRun(ClassificationTypeNames.Text, AnalyzersResources.Name_can_be_simplified))); Assert.Equal(PredefinedErrorTypeNames.SyntaxError, fourth.Tag.ErrorType); ToolTipAssert.EqualContent(expectedToolTip, fourth.Tag.ToolTipContent); diff --git a/src/EditorFeatures/CSharpTest/StringCopyPaste/PasteUnknownSourceIntoVerbatimStringTests.cs b/src/EditorFeatures/CSharpTest/StringCopyPaste/PasteUnknownSourceIntoVerbatimStringTests.cs index 2f9d6888d4d2c..ef5e2f9b230e3 100644 --- a/src/EditorFeatures/CSharpTest/StringCopyPaste/PasteUnknownSourceIntoVerbatimStringTests.cs +++ b/src/EditorFeatures/CSharpTest/StringCopyPaste/PasteUnknownSourceIntoVerbatimStringTests.cs @@ -121,5 +121,32 @@ public void TestNormalTextIntoVerbatimString() var x = @"[||]" """); } + + [WpfFact, WorkItem(62969, "https://github.com/dotnet/roslyn/issues/62969")] + public void TestNormalTextWithSomeQuotesToEscapeAndSomeToNotEscapeIntoVerbatimString() + { + // Because we're escaping the quotes in "CA2013", we should also escape teh `""`, even though `""` is legal + // to have in a verbatim string. + TestPasteUnknownSource( + pasteText: """ + var lambda = [SuppressMessage("", "CA2013")] () => Object.ReferenceEquals(1, 2); + """, + """ + string x = @"using System.Diagnostics.CodeAnalysis; + + [||]"; + """, + """""" + string x = @"using System.Diagnostics.CodeAnalysis; + + var lambda = [SuppressMessage("""", ""CA2013"")] () => Object.ReferenceEquals(1, 2);[||]"; + """""", + afterUndo: + """ + string x = @"using System.Diagnostics.CodeAnalysis; + + var lambda = [SuppressMessage("", "CA2013")] () => Object.ReferenceEquals(1, 2);[||]"; + """); + } } } diff --git a/src/EditorFeatures/CSharpTest/StringIndentation/StringIndentationTests.cs b/src/EditorFeatures/CSharpTest/StringIndentation/StringIndentationTests.cs index 7c5ced4254e32..fe0660853804f 100644 --- a/src/EditorFeatures/CSharpTest/StringIndentation/StringIndentationTests.cs +++ b/src/EditorFeatures/CSharpTest/StringIndentation/StringIndentationTests.cs @@ -66,226 +66,256 @@ private static string ApplyRegions(string val, ImmutableArray await TestAsync(string.Empty); - [Fact, Trait(Traits.Feature, Traits.Features.StringIndentation)] - public async Task TestLiteralError1() + [Theory, Trait(Traits.Feature, Traits.Features.StringIndentation)] + [InlineData("")] + [InlineData("u8")] + public async Task TestLiteralError1(string suffix) { - await TestAsync(@"class C -{ + await TestAsync($@"class C +{{ void M() - { + {{ // not enough lines in literal var v = """""" - """"""; - } -}"); + """"""{suffix}; + }} +}}"); } - [Fact, Trait(Traits.Feature, Traits.Features.StringIndentation)] - public async Task TestLiteralError2() + [Theory, Trait(Traits.Feature, Traits.Features.StringIndentation)] + [InlineData("")] + [InlineData("u8")] + public async Task TestLiteralError2(string suffix) { - await TestAsync(@"class C -{ + await TestAsync($@"class C +{{ void M() - { + {{ // invalid literal var v = """""" text too early - """"""; - } -}"); + """"""{suffix}; + }} +}}"); } - [Fact, Trait(Traits.Feature, Traits.Features.StringIndentation)] - public async Task TestZeroColumn1() + [Theory, Trait(Traits.Feature, Traits.Features.StringIndentation)] + [InlineData("")] + [InlineData("u8")] + public async Task TestZeroColumn1(string suffix) { - await TestAsync(@"class C -{ + await TestAsync($@"class C +{{ void M() - { + {{ var v = """""" goo -""""""; - } -}"); +""""""{suffix}; + }} +}}"); } - [Fact, Trait(Traits.Feature, Traits.Features.StringIndentation)] - public async Task TestZeroColumn2() + [Theory, Trait(Traits.Feature, Traits.Features.StringIndentation)] + [InlineData("")] + [InlineData("u8")] + public async Task TestZeroColumn2(string suffix) { - await TestAsync(@"class C -{ + await TestAsync($@"class C +{{ void M() - { + {{ var v = """""" goo -""""""; - } -}"); +""""""{suffix}; + }} +}}"); } - [Fact, Trait(Traits.Feature, Traits.Features.StringIndentation)] - public async Task TestOneColumn1() + [Theory, Trait(Traits.Feature, Traits.Features.StringIndentation)] + [InlineData("")] + [InlineData("u8")] + public async Task TestOneColumn1(string suffix) { - await TestAsync(@"class C -{ + await TestAsync($@"class C +{{ void M() - { + {{ var v = """""" |goo - """"""; - } -}"); + """"""{suffix}; + }} +}}"); } - [Fact, Trait(Traits.Feature, Traits.Features.StringIndentation)] - public async Task TestOneColumn2() + [Theory, Trait(Traits.Feature, Traits.Features.StringIndentation)] + [InlineData("")] + [InlineData("u8")] + public async Task TestOneColumn2(string suffix) { - await TestAsync(@"class C -{ + await TestAsync($@"class C +{{ void M() - { + {{ var v = """""" | goo - """"""; - } -}"); + """"""{suffix}; + }} +}}"); } - [Fact, Trait(Traits.Feature, Traits.Features.StringIndentation)] - public async Task TestCase1() + [Theory, Trait(Traits.Feature, Traits.Features.StringIndentation)] + [InlineData("")] + [InlineData("u8")] + public async Task TestCase1(string suffix) { - await TestAsync(@"class C -{ + await TestAsync($@"class C +{{ void M() - { + {{ var v = """""" |goo - """"""; - } -}"); + """"""{suffix}; + }} +}}"); } - [Fact, Trait(Traits.Feature, Traits.Features.StringIndentation)] - public async Task TestCase2() + [Theory, Trait(Traits.Feature, Traits.Features.StringIndentation)] + [InlineData("")] + [InlineData("u8")] + public async Task TestCase2(string suffix) { - await TestAsync(@"class C -{ + await TestAsync($@"class C +{{ void M() - { + {{ var v = """""" |goo |bar - """"""; - } -}"); + """"""{suffix}; + }} +}}"); } - [Fact, Trait(Traits.Feature, Traits.Features.StringIndentation)] - public async Task TestCase3() + [Theory, Trait(Traits.Feature, Traits.Features.StringIndentation)] + [InlineData("")] + [InlineData("u8")] + public async Task TestCase3(string suffix) { - await TestAsync(@"class C -{ + await TestAsync($@"class C +{{ void M() - { + {{ var v = """""" |goo |bar |baz - """"""; - } -}"); + """"""{suffix}; + }} +}}"); } - [Fact, Trait(Traits.Feature, Traits.Features.StringIndentation)] - public async Task TestCase4() + [Theory, Trait(Traits.Feature, Traits.Features.StringIndentation)] + [InlineData("")] + [InlineData("u8")] + public async Task TestCase4(string suffix) { - await TestAsync(@"class C -{ + await TestAsync($@"class C +{{ void M() - { + {{ var v = """""" |goo | |baz - """"""; - } -}"); + """"""{suffix}; + }} +}}"); } - [Fact, Trait(Traits.Feature, Traits.Features.StringIndentation)] - public async Task TestCase5() + [Theory, Trait(Traits.Feature, Traits.Features.StringIndentation)] + [InlineData("")] + [InlineData("u8")] + public async Task TestCase5(string suffix) { - await TestAsync(@"class C -{ + await TestAsync($@"class C +{{ void M() - { + {{ var v = """""" | goo | | baz - """"""; - } -}"); + """"""{suffix}; + }} +}}"); } - [Fact, Trait(Traits.Feature, Traits.Features.StringIndentation)] - public async Task TestCase6() + [Theory, Trait(Traits.Feature, Traits.Features.StringIndentation)] + [InlineData("")] + [InlineData("u8")] + public async Task TestCase6(string suffix) { - await TestAsync(@"class C -{ + await TestAsync($@"class C +{{ void M() - { + {{ var v = $"""""" |goo - """"""; - } -}"); + """"""{suffix}; + }} +}}"); } - [Fact, Trait(Traits.Feature, Traits.Features.StringIndentation)] - public async Task TestCase7() + [Theory, Trait(Traits.Feature, Traits.Features.StringIndentation)] + [InlineData("")] + [InlineData("u8")] + public async Task TestCase7(string suffix) { - await TestAsync(@"class C -{ + await TestAsync($@"class C +{{ void M() - { + {{ var v = $"""""" |goo - """"""; - } -}"); + """"""{suffix}; + }} +}}"); } - [Fact, Trait(Traits.Feature, Traits.Features.StringIndentation)] - public async Task TestCase8() + [Theory, Trait(Traits.Feature, Traits.Features.StringIndentation)] + [InlineData("")] + [InlineData("u8")] + public async Task TestCase8(string suffix) { - await TestAsync(@"class C -{ + await TestAsync($@"class C +{{ void M() - { + {{ var v = $"""""""" |goo - """"""""; - } -}"); + """"""""{suffix}; + }} +}}"); } - [Fact, Trait(Traits.Feature, Traits.Features.StringIndentation)] - public async Task TestCase9() + [Theory, Trait(Traits.Feature, Traits.Features.StringIndentation)] + [InlineData("")] + [InlineData("u8")] + public async Task TestCase9(string suffix) { - await TestAsync(@"class C -{ + await TestAsync($@"class C +{{ void M() - { + {{ var v = """""""" |goo - """"""""; - } -}"); + """"""""{suffix}; + }} +}}"); } [Fact, Trait(Traits.Feature, Traits.Features.StringIndentation)] diff --git a/src/EditorFeatures/CSharpTest/SymbolKey/SymbolKeyCompilationsTests.cs b/src/EditorFeatures/CSharpTest/SymbolKey/SymbolKeyCompilationsTests.cs index 036aecc1b8656..b3fcbbf29434d 100644 --- a/src/EditorFeatures/CSharpTest/SymbolKey/SymbolKeyCompilationsTests.cs +++ b/src/EditorFeatures/CSharpTest/SymbolKey/SymbolKeyCompilationsTests.cs @@ -239,6 +239,98 @@ public void M(List list) ResolveAndVerifySymbolList(members1, members2, comp1); } + [Fact] + public void FileType1() + { + var src1 = @"using System; + +namespace N1.N2 +{ + file class C { } +} +"; + var originalComp = CreateCompilation(src1, assemblyName: "Test"); + var newComp = CreateCompilation(src1, assemblyName: "Test"); + + var originalSymbols = GetSourceSymbols(originalComp, SymbolCategory.DeclaredType | SymbolCategory.DeclaredNamespace).OrderBy(s => s.Name).ToArray(); + var newSymbols = GetSourceSymbols(newComp, SymbolCategory.DeclaredType | SymbolCategory.DeclaredNamespace).OrderBy(s => s.Name).ToArray(); + + Assert.Equal(3, originalSymbols.Length); + ResolveAndVerifySymbolList(newSymbols, originalSymbols, originalComp); + } + + [Fact] + public void FileType2() + { + var src1 = @"using System; + +namespace N1.N2 +{ + file class C { } +} +"; + var originalComp = CreateCompilation(src1, assemblyName: "Test"); + var newComp = CreateCompilation(src1, assemblyName: "Test"); + + var originalSymbols = GetSourceSymbols(originalComp, SymbolCategory.DeclaredType | SymbolCategory.DeclaredNamespace).OrderBy(s => s.Name).ToArray(); + var newSymbols = GetSourceSymbols(newComp, SymbolCategory.DeclaredType | SymbolCategory.DeclaredNamespace).OrderBy(s => s.Name).ToArray(); + + Assert.Equal(3, originalSymbols.Length); + ResolveAndVerifySymbolList(newSymbols, originalSymbols, originalComp); + } + + [Fact] + public void FileType3() + { + var src1 = @"using System; + +namespace N1.N2 +{ + file class C { } +} +"; + // this should result in two entirely separate file symbols. + // note that the IDE can only distinguish file-local type symbols with the same name when they have distinct file paths. + // We are OK with this as we will require file types with identical names to have distinct file paths later in the preview. + // See https://github.com/dotnet/roslyn/issues/61999 + var originalComp = CreateCompilation(new[] { SyntaxFactory.ParseSyntaxTree(src1, path: "file1.cs"), SyntaxFactory.ParseSyntaxTree(src1, path: "file2.cs") }, assemblyName: "Test"); + var newComp = CreateCompilation(new[] { SyntaxFactory.ParseSyntaxTree(src1, path: "file1.cs"), SyntaxFactory.ParseSyntaxTree(src1, path: "file2.cs") }, assemblyName: "Test"); + + var originalSymbols = GetSourceSymbols(originalComp, SymbolCategory.DeclaredType | SymbolCategory.DeclaredNamespace).OrderBy(s => s.Name).ToArray(); + var newSymbols = GetSourceSymbols(newComp, SymbolCategory.DeclaredType | SymbolCategory.DeclaredNamespace).OrderBy(s => s.Name).ToArray(); + + Assert.Equal(4, originalSymbols.Length); + ResolveAndVerifySymbolList(newSymbols, originalSymbols, originalComp); + } + + [Fact] + public void FileType4() + { + // we should be able to distinguish a file-local type and non-file-local type when they have the same source name. + var src1 = SyntaxFactory.ParseSyntaxTree(@"using System; + +namespace N1.N2 +{ + file class C { } +} +", path: "File1.cs"); + + var src2 = SyntaxFactory.ParseSyntaxTree(@" +namespace N1.N2 +{ + class C { } +} +", path: "File2.cs"); + var originalComp = CreateCompilation(new[] { src1, src2 }, assemblyName: "Test"); + var newComp = CreateCompilation(new[] { src1, src2 }, assemblyName: "Test"); + + var originalSymbols = GetSourceSymbols(originalComp, SymbolCategory.DeclaredType | SymbolCategory.DeclaredNamespace).OrderBy(s => s.Name).ToArray(); + var newSymbols = GetSourceSymbols(newComp, SymbolCategory.DeclaredType | SymbolCategory.DeclaredNamespace).OrderBy(s => s.Name).ToArray(); + + Assert.Equal(4, originalSymbols.Length); + ResolveAndVerifySymbolList(newSymbols, originalSymbols, originalComp); + } + #endregion #region "Change to symbol" diff --git a/src/EditorFeatures/CSharpTest/SymbolKey/SymbolKeyErrorTypeTests.cs b/src/EditorFeatures/CSharpTest/SymbolKey/SymbolKeyErrorTypeTests.cs new file mode 100644 index 0000000000000..d73a2ec442969 --- /dev/null +++ b/src/EditorFeatures/CSharpTest/SymbolKey/SymbolKeyErrorTypeTests.cs @@ -0,0 +1,408 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Collections; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.CSharp.UnitTests; +using Microsoft.CodeAnalysis.Shared.Utilities; +using Microsoft.CodeAnalysis.Test.Utilities; +using Microsoft.Win32.SafeHandles; +using Xunit; + +namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.SymbolId +{ + public class SymbolKeyErrorTypeTests : SymbolKeyTestBase + { + [Fact] + public void GenericType_NotMissingWithMissingTypeArgument() + { + var source = """ + namespace N + { + public class C + { + public void M(D x) + { + } + } + + public class D + { + } + } + """; + + VerifyResolution(source, c => c.GetMember("N.C.M")); + } + + [Fact] + public void GenericType_MissingWithNonMissingTypeArgument() + { + var source = """ + using System.Collections.Generic; + + namespace N + { + public class C + { + public void M(List x) + { + } + } + + public class D + { + } + } + """; + + VerifyResolution(source, c => c.GetMember("N.C.M")); + } + + [Fact] + public void GenericType_MissingWithMissingTypeArgument() + { + var source = """ + using System.Collections.Generic; + + namespace N + { + public class C + { + public void M(List x) + { + } + } + } + """; + + VerifyResolution(source, c => c.GetMember("N.C.M")); + } + + [Fact] + public void Tuple_MissingTypes() + { + var source = """ + namespace N + { + public class C + { + public void M((string, int) x) + { + } + } + } + """; + + VerifyResolution(source, c => c.GetMember("N.C.M")); + } + + [Fact] + public void Tuple_NonMissingTypes() + { + var source = """ + namespace N + { + public class C + { + public void M((C, D) x) + { + } + } + + public class D + { + } + } + """; + + VerifyResolution(source, c => c.GetMember("N.C.M")); + } + + [Fact] + public void Array_MissingElementType() + { + var source = """ + namespace N + { + public class C + { + public void M(string[] x) + { + } + } + } + """; + + VerifyResolution(source, c => c.GetMember("N.C.M")); + } + + [Fact] + public void Array_NonMissingElementType() + { + var source = """ + namespace N + { + public class C + { + public void M(D[] x) + { + } + } + + public class D + { + } + } + """; + + VerifyResolution(source, c => c.GetMember("N.C.M")); + } + + [Fact] + public void Pointer_MissingType() + { + var source = """ + namespace N + { + public class C + { + public unsafe void M(int *x) + { + } + } + } + """; + + VerifyResolution(source, c => c.GetMember("N.C.M")); + } + + [Fact] + public void Pointer_NonMissingType() + { + var source = """ + namespace N + { + public class C + { + public unsafe void M(S *x) + { + } + } + + public struct S + { + } + } + """; + + VerifyResolution(source, c => c.GetMember("N.C.M")); + } + + [Fact] + public void NestedType_MissingInGenericContainer() + { + var source = """ + using System.Collections.Generic; + + namespace N + { + public class C + { + public void M(List.Enumerator x) + { + } + } + } + """; + + VerifyResolution(source, c => c.GetMember("N.C.M")); + } + + [Fact] + public void NestedType_MissingInNonGenericContainer() + { + var source = """ + using System.Diagnostics; + + namespace N + { + public class C + { + public void M(DebuggableAttribute.DebuggingModes x) + { + } + } + } + """; + + VerifyResolution(source, c => c.GetMember("N.C.M")); + } + + [Fact] + public void Method_MissingReturnType() + { + var source = """ + namespace N + { + public class C + { + public string Create() + { + return new string('c', 1); + } + } + } + """; + + VerifyResolution(source, c => c.GetMember("N.C.Create")); + } + + [Fact] + public void Method_MissingParameterType() + { + var source = """ + namespace N + { + public class C + { + public C Create(string x) + { + return new C(); + } + } + } + """; + + VerifyResolution(source, c => c.GetMember("N.C.Create")); + } + + [Fact] + public void Constructor_MissingParameterType() + { + var source = """ + public class C + { + public C(string x) + { + } + } + """; + + VerifyResolution(source, c => c.GetMember("C..ctor")); + } + + [Fact] + public void Indexer_MissingParameterType() + { + var source = """ + namespace N + { + public class C + { + public C this[string x] + { + get { return null; } + set { } + } + } + } + """; + + VerifyResolution(source, c => c.GetMember("N.C.this[]")); + } + + [Fact] + public void Indexer_MissingReturnType() + { + var source = """ + namespace N + { + public class C + { + public string this[C x] + { + get { return null; } + set { } + } + } + } + """; + + VerifyResolution(source, c => c.GetMember("N.C.this[]")); + } + + [Fact] + public void Property_MissingReturnType() + { + var source = """ + namespace N + { + public class C + { + public string P + { + get { return null; } + set { } + } + } + } + """; + + VerifyResolution(source, c => c.GetMember("N.C.P")); + } + + [Fact] + public void EventField_MissingReturnType() + { + var source = """ + namespace N + { + public class C + { + public event System.EventHandler E; + } + } + """; + + VerifyResolution(source, c => c.GetMember("N.C.E")); + } + + private static void VerifyResolution(string source, Func symbolToResolve) + { + var sourceCompilation = (Compilation)CreateCompilation(source, options: new(OutputKind.DynamicallyLinkedLibrary, allowUnsafe: true)); + var symbol = symbolToResolve(sourceCompilation); + + Assert.NotNull(symbol); + + var symbolKey = SymbolKey.CreateString(symbol); + + // Create a compilation that references our library, but doesn't reference types needed by the library. + // This emulates the experience in Go To Definition when navigating to metadata from the .NET runtime when + // implementations are split over multiple assemblies with various type forwards in play. + // For example: + // System.Uri exists in System.Private.Uri.dll, but System.String exists in System.Private.CoreLib.dll + // and we want to allow a symbol for System.Uri.Create(System.String) to resolve correctly even when the + // System.Private.CoreLib reference is missing. + var emptyCompilation = CSharpCompilation.Create("empty", options: new(OutputKind.DynamicallyLinkedLibrary, concurrentBuild: false)) + .AddReferences(sourceCompilation.EmitToImageReference()); + + var resolution = SymbolKey.ResolveString(symbolKey, emptyCompilation, ignoreAssemblyKey: true, out var failureReason, CancellationToken.None); + + Assert.Null(failureReason); + Assert.NotNull(resolution.Symbol); + + // Since we expect some types to be error types, we just use display string to make sure we found the right + // symbol. + Assert.Equal(symbol.ToDisplayString(), resolution.Symbol!.ToDisplayString()); + } + } +} diff --git a/src/EditorFeatures/CSharpTest/SymbolKey/SymbolKeyMetadataVsSourceTests.cs b/src/EditorFeatures/CSharpTest/SymbolKey/SymbolKeyMetadataVsSourceTests.cs index 2e3e2ad9fe634..5401425c3e00d 100644 --- a/src/EditorFeatures/CSharpTest/SymbolKey/SymbolKeyMetadataVsSourceTests.cs +++ b/src/EditorFeatures/CSharpTest/SymbolKey/SymbolKeyMetadataVsSourceTests.cs @@ -5,6 +5,7 @@ #nullable disable using System.Linq; +using System.Threading; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Symbols; using Microsoft.CodeAnalysis.CSharp.Syntax; diff --git a/src/EditorFeatures/CSharpTest/SymbolKey/SymbolKeyTestBase.cs b/src/EditorFeatures/CSharpTest/SymbolKey/SymbolKeyTestBase.cs index 3c22b088c282f..deee173ac252a 100644 --- a/src/EditorFeatures/CSharpTest/SymbolKey/SymbolKeyTestBase.cs +++ b/src/EditorFeatures/CSharpTest/SymbolKey/SymbolKeyTestBase.cs @@ -234,17 +234,11 @@ private static void GetSourceMemberSymbols(INamespaceOrTypeSymbol symbol, List(), list); - } + localDumper?.GetLocalSymbols(memberSymbol.GetSymbol(), list); break; } diff --git a/src/EditorFeatures/CSharpTest/SymbolKey/SymbolKeyTests.cs b/src/EditorFeatures/CSharpTest/SymbolKey/SymbolKeyTests.cs index c14e7076089f5..0acc20355cab7 100644 --- a/src/EditorFeatures/CSharpTest/SymbolKey/SymbolKeyTests.cs +++ b/src/EditorFeatures/CSharpTest/SymbolKey/SymbolKeyTests.cs @@ -19,6 +19,111 @@ namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.SymbolId [UseExportProvider] public class SymbolKeyTests { + [Fact] + public async Task FileType_01() + { + var typeSource = @" +file class C1 +{ + public static void M() { } +} +"; + + var workspaceXml = @$" + + + + +{typeSource} + + + +"; + using var workspace = TestWorkspace.Create(workspaceXml); + + var solution = workspace.CurrentSolution; + var project = solution.Projects.Single(); + + var compilation = await project.GetCompilationAsync(); + var type = compilation.GetTypeByMetadataName("F0__C1"); + Assert.NotNull(type); + var symbolKey = SymbolKey.Create(type); + var resolved = symbolKey.Resolve(compilation).Symbol; + Assert.Same(type, resolved); + } + + [Fact] + public async Task FileType_02() + { + var workspaceXml = $$""" + + + + +file class C +{ + public static void M() { } +} + + +file class C +{ + public static void M() { } +} + + + +"""; + using var workspace = TestWorkspace.Create(workspaceXml); + + var solution = workspace.CurrentSolution; + var project = solution.Projects.Single(); + + var compilation = await project.GetCompilationAsync(); + + var type = compilation.GetTypeByMetadataName("F1__C"); + Assert.NotNull(type); + var symbolKey = SymbolKey.Create(type); + var resolved = symbolKey.Resolve(compilation).Symbol; + Assert.Same(type, resolved); + + type = compilation.GetTypeByMetadataName("F0__C"); + Assert.NotNull(type); + symbolKey = SymbolKey.Create(type); + resolved = symbolKey.Resolve(compilation).Symbol; + Assert.Same(type, resolved); + } + + [Fact] + public async Task FileType_03() + { + var workspaceXml = $$""" + + + + +file class C +{ + public class Inner { } +} + + + +"""; + using var workspace = TestWorkspace.Create(workspaceXml); + + var solution = workspace.CurrentSolution; + var project = solution.Projects.Single(); + + var compilation = await project.GetCompilationAsync(); + + var type = compilation.GetTypeByMetadataName("F0__C+Inner"); + Assert.NotNull(type); + var symbolKey = SymbolKey.Create(type); + var resolved = symbolKey.Resolve(compilation).Symbol; + Assert.Same(type, resolved); + } + [Fact, WorkItem(45437, "https://github.com/dotnet/roslyn/issues/45437")] public async Task TestGenericsAndNullability() { diff --git a/src/EditorFeatures/CSharpTest/TypeInferrer/TypeInferrerTests.Delegate.cs b/src/EditorFeatures/CSharpTest/TypeInferrer/TypeInferrerTests.Delegate.cs index e825d512ef671..124bb9fefa27f 100644 --- a/src/EditorFeatures/CSharpTest/TypeInferrer/TypeInferrerTests.Delegate.cs +++ b/src/EditorFeatures/CSharpTest/TypeInferrer/TypeInferrerTests.Delegate.cs @@ -6,7 +6,7 @@ using System.Threading; using System.Threading.Tasks; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Test.Utilities; using Roslyn.Test.Utilities; diff --git a/src/EditorFeatures/CSharpTest/TypeInferrer/TypeInferrerTests.cs b/src/EditorFeatures/CSharpTest/TypeInferrer/TypeInferrerTests.cs index 48a9498bb2836..db0514de73cfe 100644 --- a/src/EditorFeatures/CSharpTest/TypeInferrer/TypeInferrerTests.cs +++ b/src/EditorFeatures/CSharpTest/TypeInferrer/TypeInferrerTests.cs @@ -10,7 +10,7 @@ using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Editor.UnitTests.TypeInferrer; using Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Test.Utilities; using Microsoft.CodeAnalysis.Text; diff --git a/src/EditorFeatures/CSharpTest/Workspaces/WorkspaceTests_EditorFeatures.cs b/src/EditorFeatures/CSharpTest/Workspaces/WorkspaceTests_EditorFeatures.cs index 1c702ce23bc64..3d7d3cf6428c4 100644 --- a/src/EditorFeatures/CSharpTest/Workspaces/WorkspaceTests_EditorFeatures.cs +++ b/src/EditorFeatures/CSharpTest/Workspaces/WorkspaceTests_EditorFeatures.cs @@ -1328,7 +1328,7 @@ public async Task TestLinkedFilesStayInSync() var input = $@" - { originalText } + {originalText} diff --git a/src/EditorFeatures/CSharpTest/Wrapping/ParameterWrappingTests.cs b/src/EditorFeatures/CSharpTest/Wrapping/ParameterWrappingTests.cs index d20d0c72cdbe2..4385ecd3daf9b 100644 --- a/src/EditorFeatures/CSharpTest/Wrapping/ParameterWrappingTests.cs +++ b/src/EditorFeatures/CSharpTest/Wrapping/ParameterWrappingTests.cs @@ -977,5 +977,15 @@ await TestInRegularAndScript1Async( @"record struct R(int I, string S) { }", new TestParameters(TestOptions.RegularPreview)); } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsWrapping)] + [WorkItem(61362, "https://github.com/dotnet/roslyn/issues/61362")] + public async Task TestWithMissingParameterList() + { + await TestMissingAsync( +@"class C { + public void UpsertRecord[||] +}"); + } } } diff --git a/src/EditorFeatures/CSharpTest2/Recommendations/NullableKeywordRecommenderTests.cs b/src/EditorFeatures/CSharpTest2/Recommendations/NullableKeywordRecommenderTests.cs index f636cc048e559..c59b91f3b9eee 100644 --- a/src/EditorFeatures/CSharpTest2/Recommendations/NullableKeywordRecommenderTests.cs +++ b/src/EditorFeatures/CSharpTest2/Recommendations/NullableKeywordRecommenderTests.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. -#nullable disable - using System.Threading.Tasks; using Microsoft.CodeAnalysis.Test.Utilities; +using Roslyn.Test.Utilities; using Xunit; namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.Recommendations @@ -95,19 +94,22 @@ public async Task TestNotAfterPragmaWarning() => await VerifyAbsenceAsync(@"#pragma warning $$"); [Fact] - public async Task TestAfterPragmaWarningDisable() - => await VerifyKeywordAsync(@"#pragma warning disable $$"); + [WorkItem(63594, "https://github.com/dotnet/roslyn/issues/63594")] + public async Task TestNotAfterPragmaWarningDisable() + => await VerifyAbsenceAsync(@"#pragma warning disable $$"); [Fact] - public async Task TestAfterPragmaWarningEnable() - => await VerifyKeywordAsync(@"#pragma warning enable $$"); + [WorkItem(63594, "https://github.com/dotnet/roslyn/issues/63594")] + public async Task TestNotAfterPragmaWarningEnable() + => await VerifyAbsenceAsync(@"#pragma warning enable $$"); [Fact] - public async Task TestAfterPragmaWarningRestore() - => await VerifyKeywordAsync(@"#pragma warning restore $$"); + [WorkItem(63594, "https://github.com/dotnet/roslyn/issues/63594")] + public async Task TestNotAfterPragmaWarningRestore() + => await VerifyAbsenceAsync(@"#pragma warning restore $$"); [Fact] - public async Task TestAfterPragmaWarningSafeOnly() + public async Task TestNotAfterPragmaWarningSafeOnly() => await VerifyAbsenceAsync(@"#pragma warning safeonly $$"); [Fact] diff --git a/src/EditorFeatures/Core.Cocoa/CommandHandlers/GoToMatchingBraceCommandHandler.cs b/src/EditorFeatures/Core.Cocoa/CommandHandlers/GoToMatchingBraceCommandHandler.cs index 932120bcdb19f..09120547e905b 100644 --- a/src/EditorFeatures/Core.Cocoa/CommandHandlers/GoToMatchingBraceCommandHandler.cs +++ b/src/EditorFeatures/Core.Cocoa/CommandHandlers/GoToMatchingBraceCommandHandler.cs @@ -6,6 +6,7 @@ using System; using System.ComponentModel.Composition; +using Microsoft.CodeAnalysis.BraceMatching; using Microsoft.CodeAnalysis.Editor.Shared.Extensions; using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.Options; diff --git a/src/EditorFeatures/Core.Cocoa/Preview/PreviewFactoryService.cs b/src/EditorFeatures/Core.Cocoa/Preview/PreviewFactoryService.cs index eba52723824e3..7c9f59bacfbad 100644 --- a/src/EditorFeatures/Core.Cocoa/Preview/PreviewFactoryService.cs +++ b/src/EditorFeatures/Core.Cocoa/Preview/PreviewFactoryService.cs @@ -31,21 +31,19 @@ public PreviewFactoryService( IContentTypeRegistryService contentTypeRegistryService, IProjectionBufferFactoryService projectionBufferFactoryService, ICocoaTextEditorFactoryService textEditorFactoryService, - IEditorOptionsFactoryService editorOptionsFactoryService, + EditorOptionsService editorOptionsService, ITextDifferencingSelectorService differenceSelectorService, IDifferenceBufferFactoryService differenceBufferService, - ICocoaDifferenceViewerFactoryService differenceViewerService, - IGlobalOptionService globalOptions) + ICocoaDifferenceViewerFactoryService differenceViewerService) : base(threadingContext, textBufferFactoryService, contentTypeRegistryService, projectionBufferFactoryService, - editorOptionsFactoryService, + editorOptionsService, differenceSelectorService, differenceBufferService, textEditorFactoryService.CreateTextViewRoleSet( - TextViewRoles.PreviewRole, PredefinedTextViewRoles.Analyzable), - globalOptions) + TextViewRoles.PreviewRole, PredefinedTextViewRoles.Analyzable)) { _differenceViewerService = differenceViewerService; } diff --git a/src/EditorFeatures/Core.Cocoa/Snippets/AbstractSnippetCommandHandler.cs b/src/EditorFeatures/Core.Cocoa/Snippets/AbstractSnippetCommandHandler.cs index ca21831a27d28..2d881175aabce 100644 --- a/src/EditorFeatures/Core.Cocoa/Snippets/AbstractSnippetCommandHandler.cs +++ b/src/EditorFeatures/Core.Cocoa/Snippets/AbstractSnippetCommandHandler.cs @@ -7,7 +7,7 @@ using Microsoft.CodeAnalysis.Editor.Shared.Extensions; using Microsoft.CodeAnalysis.Editor.Shared.Options; using Microsoft.CodeAnalysis.Editor.Shared.Utilities; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Text; @@ -32,7 +32,7 @@ internal abstract class AbstractSnippetCommandHandler : protected readonly IThreadingContext ThreadingContext; protected readonly IExpansionServiceProvider ExpansionServiceProvider; protected readonly IExpansionManager ExpansionManager; - protected readonly IGlobalOptionService GlobalOptions; + protected readonly EditorOptionsService EditorOptionsService; public string DisplayName => FeaturesResources.Snippets; @@ -40,12 +40,12 @@ public AbstractSnippetCommandHandler( IThreadingContext threadingContext, IExpansionServiceProvider expansionServiceProvider, IExpansionManager expansionManager, - IGlobalOptionService globalOptions) + EditorOptionsService editorOptionsService) { ThreadingContext = threadingContext; ExpansionServiceProvider = expansionServiceProvider; ExpansionManager = expansionManager; - GlobalOptions = globalOptions; + EditorOptionsService = editorOptionsService; } protected abstract AbstractSnippetExpansionClient GetSnippetExpansionClient(ITextView textView, ITextBuffer subjectBuffer); @@ -290,7 +290,7 @@ protected bool TryHandleTypedSnippet(ITextView textView, ITextBuffer subjectBuff protected bool AreSnippetsEnabled(EditorCommandArgs args) { - return GlobalOptions.GetOption(InternalFeatureOnOffOptions.Snippets) && + return EditorOptionsService.GlobalOptions.GetOption(InternalFeatureOnOffOptions.Snippets) && // TODO (https://github.com/dotnet/roslyn/issues/5107): enable in interactive !(Workspace.TryGetWorkspace(args.SubjectBuffer.AsTextContainer(), out var workspace) && workspace.Kind == WorkspaceKind.Interactive); } diff --git a/src/EditorFeatures/Core.Cocoa/Snippets/AbstractSnippetExpansionClient.cs b/src/EditorFeatures/Core.Cocoa/Snippets/AbstractSnippetExpansionClient.cs index 49b11b7cca634..9a6a6ab08c92b 100644 --- a/src/EditorFeatures/Core.Cocoa/Snippets/AbstractSnippetExpansionClient.cs +++ b/src/EditorFeatures/Core.Cocoa/Snippets/AbstractSnippetExpansionClient.cs @@ -8,9 +8,11 @@ using System.Linq; using System.Threading; using System.Xml.Linq; +using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Editor.Shared.Extensions; using Microsoft.CodeAnalysis.Editor.Shared.Utilities; using Microsoft.CodeAnalysis.Formatting; +using Microsoft.CodeAnalysis.Formatting.Rules; using Microsoft.CodeAnalysis.Internal.Log; using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Shared.Extensions; @@ -30,8 +32,7 @@ internal abstract class AbstractSnippetExpansionClient : IExpansionClient protected readonly IContentType LanguageServiceGuid; protected readonly ITextView TextView; protected readonly ITextBuffer SubjectBuffer; - - public readonly IGlobalOptionService GlobalOptions; + public readonly EditorOptionsService EditorOptionsService; protected bool _indentCaretOnCommit; protected int _indentDepth; @@ -39,13 +40,18 @@ internal abstract class AbstractSnippetExpansionClient : IExpansionClient public IExpansionSession? ExpansionSession { get; private set; } - public AbstractSnippetExpansionClient(IContentType languageServiceGuid, ITextView textView, ITextBuffer subjectBuffer, IExpansionServiceProvider expansionServiceProvider, IGlobalOptionService globalOptions) + public AbstractSnippetExpansionClient( + IContentType languageServiceGuid, + ITextView textView, + ITextBuffer subjectBuffer, + IExpansionServiceProvider expansionServiceProvider, + EditorOptionsService editorOptionsService) { LanguageServiceGuid = languageServiceGuid; TextView = textView; SubjectBuffer = subjectBuffer; ExpansionServiceProvider = expansionServiceProvider; - GlobalOptions = globalOptions; + EditorOptionsService = editorOptionsService; } public abstract IExpansionFunction? GetExpansionFunction(XElement xmlFunctionNode, string fieldName); @@ -93,7 +99,7 @@ public void FormatSpan(SnapshotSpan span) var formattingSpan = CommonFormattingHelpers.GetFormattingSpan(SubjectBuffer.CurrentSnapshot, snippetTrackingSpan.GetSpan(SubjectBuffer.CurrentSnapshot)); - SubjectBuffer.CurrentSnapshot.FormatAndApplyToBuffer(formattingSpan, GlobalOptions, CancellationToken.None); + SubjectBuffer.FormatAndApplyToBuffer(formattingSpan, EditorOptionsService, CancellationToken.None); if (isFullSnippetFormat) { @@ -147,7 +153,7 @@ private void CleanUpEndLocation(ITrackingSpan? endTrackingSpan) var document = this.SubjectBuffer.CurrentSnapshot.GetOpenDocumentInCurrentContextWithChanges(); if (document != null) { - var lineFormattingOptions = document.GetLineFormattingOptionsAsync(GlobalOptions, CancellationToken.None).AsTask().WaitAndGetResult(CancellationToken.None); + var lineFormattingOptions = SubjectBuffer.GetLineFormattingOptions(EditorOptionsService, explicitFormat: false); _indentDepth = lineText.GetColumnFromLineOffset(lineText.Length, lineFormattingOptions.TabSize); } else diff --git a/src/EditorFeatures/Core.Cocoa/Snippets/CSharpSnippets/SnippetCommandHandler.cs b/src/EditorFeatures/Core.Cocoa/Snippets/CSharpSnippets/SnippetCommandHandler.cs index eee35719dac32..5841500fb2d03 100644 --- a/src/EditorFeatures/Core.Cocoa/Snippets/CSharpSnippets/SnippetCommandHandler.cs +++ b/src/EditorFeatures/Core.Cocoa/Snippets/CSharpSnippets/SnippetCommandHandler.cs @@ -41,8 +41,8 @@ public SnippetCommandHandler( IThreadingContext threadingContext, IExpansionServiceProvider expansionServiceProvider, IExpansionManager expansionManager, - IGlobalOptionService globalOptions) - : base(threadingContext, expansionServiceProvider, expansionManager, globalOptions) + EditorOptionsService editorOptionsService) + : base(threadingContext, expansionServiceProvider, expansionManager, editorOptionsService) { } @@ -84,7 +84,7 @@ protected override AbstractSnippetExpansionClient GetSnippetExpansionClient(ITex { if (!textView.Properties.TryGetProperty(typeof(AbstractSnippetExpansionClient), out AbstractSnippetExpansionClient expansionClient)) { - expansionClient = new SnippetExpansionClient(subjectBuffer.ContentType, textView, subjectBuffer, ExpansionServiceProvider, GlobalOptions); + expansionClient = new SnippetExpansionClient(subjectBuffer.ContentType, textView, subjectBuffer, ExpansionServiceProvider, EditorOptionsService); textView.Properties.AddProperty(typeof(AbstractSnippetExpansionClient), expansionClient); } diff --git a/src/EditorFeatures/Core.Cocoa/Snippets/CSharpSnippets/SnippetExpansionClient.cs b/src/EditorFeatures/Core.Cocoa/Snippets/CSharpSnippets/SnippetExpansionClient.cs index 6243391dd4f7c..267e1d65ae4b1 100644 --- a/src/EditorFeatures/Core.Cocoa/Snippets/CSharpSnippets/SnippetExpansionClient.cs +++ b/src/EditorFeatures/Core.Cocoa/Snippets/CSharpSnippets/SnippetExpansionClient.cs @@ -18,8 +18,13 @@ namespace Microsoft.VisualStudio.LanguageServices.CSharp.Snippets { internal sealed partial class SnippetExpansionClient : AbstractSnippetExpansionClient { - public SnippetExpansionClient(IContentType languageServiceGuid, ITextView textView, ITextBuffer subjectBuffer, IExpansionServiceProvider expansionServiceProvider, IGlobalOptionService globalOptions) - : base(languageServiceGuid, textView, subjectBuffer, expansionServiceProvider, globalOptions) + public SnippetExpansionClient( + IContentType languageServiceGuid, + ITextView textView, + ITextBuffer subjectBuffer, + IExpansionServiceProvider expansionServiceProvider, + EditorOptionsService editorOptionsService) + : base(languageServiceGuid, textView, subjectBuffer, expansionServiceProvider, editorOptionsService) { } diff --git a/src/EditorFeatures/Core.Cocoa/Snippets/CSharpSnippets/SnippetFunctions/SnippetFunctionGenerateSwitchCases.cs b/src/EditorFeatures/Core.Cocoa/Snippets/CSharpSnippets/SnippetFunctions/SnippetFunctionGenerateSwitchCases.cs index 957ae572478e0..ac303228d7fb4 100644 --- a/src/EditorFeatures/Core.Cocoa/Snippets/CSharpSnippets/SnippetFunctions/SnippetFunctionGenerateSwitchCases.cs +++ b/src/EditorFeatures/Core.Cocoa/Snippets/CSharpSnippets/SnippetFunctions/SnippetFunctionGenerateSwitchCases.cs @@ -96,7 +96,7 @@ protected override bool TryGetSimplifiedTypeNameInCaseContext(Document document, var updatedRoot = syntaxRoot.ReplaceNode(nodeToReplace, nodeToReplace.WithAdditionalAnnotations(typeAnnotation, Simplifier.Annotation)); var documentWithAnnotations = documentWithCaseAdded.WithSyntaxRoot(updatedRoot); - var simplifierOptions = document.GetSimplifierOptionsAsync(_snippetExpansionClient.GlobalOptions, cancellationToken).AsTask().WaitAndGetResult(cancellationToken); + var simplifierOptions = document.GetSimplifierOptionsAsync(_snippetExpansionClient.EditorOptionsService.GlobalOptions, cancellationToken).AsTask().WaitAndGetResult(cancellationToken); var simplifiedDocument = Simplifier.ReduceAsync(documentWithAnnotations, simplifierOptions, cancellationToken).WaitAndGetResult(cancellationToken); simplifiedTypeName = simplifiedDocument.GetRequiredSyntaxRootSynchronously(cancellationToken).GetAnnotatedNodesAndTokens(typeAnnotation).Single().ToString(); return true; diff --git a/src/EditorFeatures/Core.Cocoa/Snippets/CSharpSnippets/SnippetFunctions/SnippetFunctionSimpleTypeName.cs b/src/EditorFeatures/Core.Cocoa/Snippets/CSharpSnippets/SnippetFunctions/SnippetFunctionSimpleTypeName.cs index a9be002ddc488..9c415f000a93d 100644 --- a/src/EditorFeatures/Core.Cocoa/Snippets/CSharpSnippets/SnippetFunctions/SnippetFunctionSimpleTypeName.cs +++ b/src/EditorFeatures/Core.Cocoa/Snippets/CSharpSnippets/SnippetFunctions/SnippetFunctionSimpleTypeName.cs @@ -37,7 +37,7 @@ protected override bool TryGetSimplifiedTypeName(Document documentWithFullyQuali var updatedRoot = syntaxRoot.ReplaceNode(nodeToReplace, nodeToReplace.WithAdditionalAnnotations(typeAnnotation, Simplifier.Annotation)); var documentWithAnnotations = documentWithFullyQualifiedTypeName.WithSyntaxRoot(updatedRoot); - var simplifierOptions = documentWithAnnotations.GetSimplifierOptionsAsync(_snippetExpansionClient.GlobalOptions, cancellationToken).AsTask().WaitAndGetResult(cancellationToken); + var simplifierOptions = documentWithAnnotations.GetSimplifierOptionsAsync(_snippetExpansionClient.EditorOptionsService.GlobalOptions, cancellationToken).AsTask().WaitAndGetResult(cancellationToken); var simplifiedDocument = Simplifier.ReduceAsync(documentWithAnnotations, simplifierOptions, cancellationToken).WaitAndGetResult(cancellationToken); simplifiedTypeName = simplifiedDocument.GetRequiredSyntaxRootSynchronously(cancellationToken).GetAnnotatedNodesAndTokens(typeAnnotation).Single().ToString(); return true; diff --git a/src/EditorFeatures/Core.Cocoa/Structure/StructureTaggerProvider.cs b/src/EditorFeatures/Core.Cocoa/Structure/StructureTaggerProvider.cs index e52963de22fee..a460ca3b5fa04 100644 --- a/src/EditorFeatures/Core.Cocoa/Structure/StructureTaggerProvider.cs +++ b/src/EditorFeatures/Core.Cocoa/Structure/StructureTaggerProvider.cs @@ -26,12 +26,11 @@ internal partial class StructureTaggerProvider : [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] public StructureTaggerProvider( IThreadingContext threadingContext, - IEditorOptionsFactoryService editorOptionsFactoryService, + EditorOptionsService editorOptionsService, IProjectionBufferFactoryService projectionBufferFactoryService, - IGlobalOptionService globalOptions, [Import(AllowDefault = true)] ITextBufferVisibilityTracker? visibilityTracker, IAsynchronousOperationListenerProvider listenerProvider) - : base(threadingContext, editorOptionsFactoryService, projectionBufferFactoryService, globalOptions, visibilityTracker, listenerProvider) + : base(threadingContext, editorOptionsService, projectionBufferFactoryService, visibilityTracker, listenerProvider) { } diff --git a/src/EditorFeatures/Core.Wpf/AsyncCompletion/LanguageServerSnippetExpanderAdapter.cs b/src/EditorFeatures/Core.Wpf/AsyncCompletion/LanguageServerSnippetExpanderAdapter.cs new file mode 100644 index 0000000000000..b98a0d39d296c --- /dev/null +++ b/src/EditorFeatures/Core.Wpf/AsyncCompletion/LanguageServerSnippetExpanderAdapter.cs @@ -0,0 +1,30 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Composition; +using Microsoft.CodeAnalysis.Host.Mef; +using Microsoft.VisualStudio.LanguageServer.Client.Snippets; +using Microsoft.VisualStudio.Text; +using Microsoft.VisualStudio.Text.Editor; + +namespace Microsoft.CodeAnalysis.Editor.Implementation.IntelliSense.AsyncCompletion +{ + [Export(typeof(ILanguageServerSnippetExpander))] + [Shared] + internal sealed class LanguageServerSnippetExpanderAdapter : ILanguageServerSnippetExpander + { + private readonly LanguageServerSnippetExpander _languageServerSnippetExpander; + + [ImportingConstructor] + [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] + public LanguageServerSnippetExpanderAdapter(LanguageServerSnippetExpander languageServerSnippetExpander) + { + _languageServerSnippetExpander = languageServerSnippetExpander; + } + + public bool TryExpand(string lspSnippetText, SnapshotSpan snapshotSpan, ITextView textView) + => _languageServerSnippetExpander.TryExpand(lspSnippetText, snapshotSpan, textView); + } +} diff --git a/src/EditorFeatures/Core.Wpf/InlineDiagnostics/InlineDiagnosticsTaggerProvider.cs b/src/EditorFeatures/Core.Wpf/InlineDiagnostics/InlineDiagnosticsTaggerProvider.cs index 74882fc8252fa..cf26c23c2eed4 100644 --- a/src/EditorFeatures/Core.Wpf/InlineDiagnostics/InlineDiagnosticsTaggerProvider.cs +++ b/src/EditorFeatures/Core.Wpf/InlineDiagnostics/InlineDiagnosticsTaggerProvider.cs @@ -54,6 +54,12 @@ public InlineDiagnosticsTaggerProvider( _classificationTypeRegistryService = classificationTypeRegistryService; } + protected internal override bool SupportsDignosticMode(DiagnosticMode mode) + { + // We support inline diagnostics in both push and pull (since lsp doesn't support inline diagnostics yet). + return true; + } + // Need to override this from AbstractDiagnosticsTaggerProvider because the location option needs to be added // to the TaggerEventSource, otherwise it does not get updated until there is a change in the editor. protected override ITaggerEventSource CreateEventSource(ITextView? textView, ITextBuffer subjectBuffer) diff --git a/src/EditorFeatures/Core.Wpf/InlineRename/CommandHandlers/RenameCommandHandler.cs b/src/EditorFeatures/Core.Wpf/InlineRename/CommandHandlers/RenameCommandHandler.cs index 8e357e7501559..cd77837c6eba1 100644 --- a/src/EditorFeatures/Core.Wpf/InlineRename/CommandHandlers/RenameCommandHandler.cs +++ b/src/EditorFeatures/Core.Wpf/InlineRename/CommandHandlers/RenameCommandHandler.cs @@ -11,9 +11,8 @@ using Microsoft.VisualStudio.Utilities; using Microsoft.CodeAnalysis.Notification; using Microsoft.CodeAnalysis.ErrorReporting; -using Microsoft.CodeAnalysis.Extensions; using Microsoft.CodeAnalysis.Telemetry; -using System.Windows; +using Microsoft.CodeAnalysis.Shared.TestHooks; #if !COCOA using System.Linq; @@ -36,8 +35,11 @@ internal partial class RenameCommandHandler : AbstractRenameCommandHandler { [ImportingConstructor] [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] - public RenameCommandHandler(IThreadingContext threadingContext, InlineRenameService renameService) - : base(threadingContext, renameService) + public RenameCommandHandler( + IThreadingContext threadingContext, + InlineRenameService renameService, + IAsynchronousOperationListenerProvider asynchronousOperationListenerProvider) + : base(threadingContext, renameService, asynchronousOperationListenerProvider) { } diff --git a/src/EditorFeatures/Core.Wpf/InlineRename/InlineRenameExperimentationOptions.cs b/src/EditorFeatures/Core.Wpf/InlineRename/InlineRenameUIOptions.cs similarity index 72% rename from src/EditorFeatures/Core.Wpf/InlineRename/InlineRenameExperimentationOptions.cs rename to src/EditorFeatures/Core.Wpf/InlineRename/InlineRenameUIOptions.cs index 18437f5b6550d..245be3a81745b 100644 --- a/src/EditorFeatures/Core.Wpf/InlineRename/InlineRenameExperimentationOptions.cs +++ b/src/EditorFeatures/Core.Wpf/InlineRename/InlineRenameUIOptions.cs @@ -6,12 +6,12 @@ namespace Microsoft.CodeAnalysis.Editor.InlineRename { - internal sealed class InlineRenameExperimentationOptions + internal sealed class InlineRenameUIOptions { public static readonly Option2 UseInlineAdornment = new( - feature: "InlineRenameExperimentation", + feature: "InlineRename", name: "UseInlineAdornment", - defaultValue: false, - storageLocation: new FeatureFlagStorageLocation("Roslyn.UseInlineAdornmentForRename")); + defaultValue: true, + storageLocation: new FeatureFlagStorageLocation("Roslyn.Rename_UseInlineAdornment")); } } diff --git a/src/EditorFeatures/Core.Wpf/InlineRename/UI/Adornment/RenameFlyout.xaml b/src/EditorFeatures/Core.Wpf/InlineRename/UI/Adornment/RenameFlyout.xaml index a991bac80d70d..277ee8c331ec5 100644 --- a/src/EditorFeatures/Core.Wpf/InlineRename/UI/Adornment/RenameFlyout.xaml +++ b/src/EditorFeatures/Core.Wpf/InlineRename/UI/Adornment/RenameFlyout.xaml @@ -99,7 +99,7 @@ + Name="OverloadsCheckbox" Visibility="{Binding IsRenameOverloadsVisible, Converter={StaticResource BooleanToVisibilityConverter}, Mode=OneWay}" IsEnabled="{Binding IsRenameOverloadsEditable}" /> { - Focus(); - MoveFocus(new TraversalRequest(FocusNavigationDirection.First)); + IdentifierTextBox.Focus(); + IdentifierTextBox.Select(_viewModel.StartingSelection.Start, _viewModel.StartingSelection.Length); + + // Don't hook up our close events until we're done loading and have focused within the textbox + _textView.LostAggregateFocus += TextView_LostFocus; + LostFocus += RenameFlyout_LostFocus; }; InitializeComponent(); @@ -50,7 +52,7 @@ public RenameFlyout(RenameFlyoutViewModel viewModel, ITextView textView) public string SubmitText => EditorFeaturesWpfResources.Enter_to_rename_shift_enter_to_preview; #pragma warning restore CA1822 // Mark members as static - private void TextView_CursorChanged(object sender, CaretPositionChangedEventArgs e) + private void RenameFlyout_LostFocus(object sender, RoutedEventArgs e) => _viewModel.Cancel(); private void TextView_LostFocus(object sender, EventArgs e) @@ -79,7 +81,9 @@ public override void Dispose() _textView.ViewportHeightChanged -= TextView_ViewPortChanged; _textView.ViewportWidthChanged -= TextView_ViewPortChanged; _textView.LostAggregateFocus -= TextView_LostFocus; - _textView.Caret.PositionChanged -= TextView_CursorChanged; + + // Restore focus back to the textview + _textView.VisualElement.Focus(); } private void Submit_Click(object sender, RoutedEventArgs e) diff --git a/src/EditorFeatures/Core.Wpf/InlineRename/UI/Adornment/RenameFlyoutViewModel.cs b/src/EditorFeatures/Core.Wpf/InlineRename/UI/Adornment/RenameFlyoutViewModel.cs index 4a43312758b72..55c65a7adf97e 100644 --- a/src/EditorFeatures/Core.Wpf/InlineRename/UI/Adornment/RenameFlyoutViewModel.cs +++ b/src/EditorFeatures/Core.Wpf/InlineRename/UI/Adornment/RenameFlyoutViewModel.cs @@ -12,6 +12,7 @@ using Microsoft.CodeAnalysis.InlineRename; using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Rename; +using Microsoft.CodeAnalysis.Text; using Microsoft.VisualStudio.PlatformUI.OleComponentSupport; namespace Microsoft.CodeAnalysis.Editor.Implementation.InlineRename @@ -19,16 +20,20 @@ namespace Microsoft.CodeAnalysis.Editor.Implementation.InlineRename internal class RenameFlyoutViewModel : INotifyPropertyChanged, IDisposable { private readonly InlineRenameSession _session; + private readonly bool _registerOleComponent; private OleComponent? _oleComponent; private bool _disposedValue; private bool _isReplacementTextValid = true; public event PropertyChangedEventHandler? PropertyChanged; - public RenameFlyoutViewModel(InlineRenameSession session) + public RenameFlyoutViewModel(InlineRenameSession session, TextSpan selectionSpan, bool registerOleComponent) { _session = session; + _registerOleComponent = registerOleComponent; _session.ReplacementTextChanged += OnReplacementTextChanged; _session.ReplacementsComputed += OnReplacementsComputed; + StartingSelection = selectionSpan; + ComputeRenameFile(); RegisterOleComponent(); } @@ -46,6 +51,8 @@ public string IdentifierText } } + public InlineRenameSession Session => _session; + public bool AllowFileRename => _session.FileRenameInfo == InlineRenameFileRenameInfo.Allowed && _isReplacementTextValid; public bool ShowFileRename => _session.FileRenameInfo != InlineRenameFileRenameInfo.NotAllowed; @@ -128,15 +135,16 @@ public bool IsExpanded public bool IsRenameOverloadsEditable => !_session.MustRenameOverloads; + public bool IsRenameOverloadsVisible + => _session.HasRenameOverloads; + + public TextSpan StartingSelection { get; } + public void Submit() - { - _session.Commit(); - } + => _session.Commit(); public void Cancel() - { - _session.Cancel(); - } + => _session.Cancel(); public void Dispose() { @@ -152,6 +160,13 @@ public void Dispose() /// public void RegisterOleComponent() { + // In unit testing we won't have an OleComponentManager available, so + // calls to OleComponent.CreateHostedComponent will throw + if (!_registerOleComponent) + { + return; + } + Debug.Assert(_oleComponent is null); _oleComponent = OleComponent.CreateHostedComponent("Microsoft CodeAnalysis Inline Rename"); diff --git a/src/EditorFeatures/Core.Wpf/InlineRename/UI/InlineRenameAdornmentManager.cs b/src/EditorFeatures/Core.Wpf/InlineRename/UI/InlineRenameAdornmentManager.cs index 0d0b37c6bfa9c..4bdcfaa61bf3b 100644 --- a/src/EditorFeatures/Core.Wpf/InlineRename/UI/InlineRenameAdornmentManager.cs +++ b/src/EditorFeatures/Core.Wpf/InlineRename/UI/InlineRenameAdornmentManager.cs @@ -68,7 +68,7 @@ private void UpdateAdornments() { _dashboardColorUpdater?.UpdateColors(); - var useInlineAdornment = _globalOptionService.GetOption(InlineRenameExperimentationOptions.UseInlineAdornment); + var useInlineAdornment = _globalOptionService.GetOption(InlineRenameUIOptions.UseInlineAdornment); if (useInlineAdornment) { if (!_textView.HasAggregateFocus) @@ -78,8 +78,22 @@ private void UpdateAdornments() return; } + // Get the active selection to make sure the rename text is selected in the same way + var originalSpan = _renameService.ActiveSession.TriggerSpan; + var selectionSpan = _textView.Selection.SelectedSpans.First(); + + var start = selectionSpan.IsEmpty + ? 0 + : selectionSpan.Start - originalSpan.Start; // The length from the identifier to the start of selection + + var length = selectionSpan.IsEmpty + ? originalSpan.Length + : selectionSpan.Length; + + var identifierSelection = new TextSpan(start, length); + var adornment = new RenameFlyout( - (RenameFlyoutViewModel)s_createdViewModels.GetValue(_renameService.ActiveSession, session => new RenameFlyoutViewModel(session)), + (RenameFlyoutViewModel)s_createdViewModels.GetValue(_renameService.ActiveSession, session => new RenameFlyoutViewModel(session, identifierSelection, registerOleComponent: true)), _textView); _adornmentLayer.AddAdornment( diff --git a/src/EditorFeatures/Core.Wpf/Interactive/InteractiveCommandHandler.cs b/src/EditorFeatures/Core.Wpf/Interactive/InteractiveCommandHandler.cs index 950f687e7af53..0d9ff77432de6 100644 --- a/src/EditorFeatures/Core.Wpf/Interactive/InteractiveCommandHandler.cs +++ b/src/EditorFeatures/Core.Wpf/Interactive/InteractiveCommandHandler.cs @@ -17,6 +17,7 @@ using Microsoft.VisualStudio.Text.Editor.Commanding.Commands; using Microsoft.VisualStudio.Commanding; using Microsoft.VisualStudio.Text.Editor.Commanding; +using Microsoft.CodeAnalysis.Options; namespace Microsoft.CodeAnalysis.Interactive { @@ -25,16 +26,16 @@ internal abstract class InteractiveCommandHandler : ICommandHandler { private readonly IContentTypeRegistryService _contentTypeRegistryService; - private readonly IEditorOptionsFactoryService _editorOptionsFactoryService; + private readonly EditorOptionsService _editorOptionsService; private readonly IEditorOperationsFactoryService _editorOperationsFactoryService; protected InteractiveCommandHandler( IContentTypeRegistryService contentTypeRegistryService, - IEditorOptionsFactoryService editorOptionsFactoryService, + EditorOptionsService editorOptionsService, IEditorOperationsFactoryService editorOperationsFactoryService) { _contentTypeRegistryService = contentTypeRegistryService; - _editorOptionsFactoryService = editorOptionsFactoryService; + _editorOptionsService = editorOptionsService; _editorOperationsFactoryService = editorOperationsFactoryService; } @@ -48,7 +49,7 @@ protected InteractiveCommandHandler( private string GetSelectedText(EditorCommandArgs args, CancellationToken cancellationToken) { - var editorOptions = _editorOptionsFactoryService.GetOptions(args.SubjectBuffer); + var editorOptions = _editorOptionsService.Factory.GetOptions(args.SubjectBuffer); return SendToInteractiveSubmissionProvider.GetSelectedText(editorOptions, args, cancellationToken); } @@ -113,7 +114,7 @@ private void CopyToWindow(IInteractiveWindow window, CopyToInteractiveCommandArg var lastLine = buffer.CurrentSnapshot.GetLineFromLineNumber(buffer.CurrentSnapshot.LineCount - 1); if (lastLine.Extent.Length > 0) { - var editorOptions = _editorOptionsFactoryService.GetOptions(args.SubjectBuffer); + var editorOptions = _editorOptionsService.Factory.GetOptions(args.SubjectBuffer); text = editorOptions.GetNewLineCharacter() + text; } diff --git a/src/EditorFeatures/Core.Wpf/Interactive/InteractiveEvaluator.cs b/src/EditorFeatures/Core.Wpf/Interactive/InteractiveEvaluator.cs index 7e767904a1a2b..3e86f9f8a8523 100644 --- a/src/EditorFeatures/Core.Wpf/Interactive/InteractiveEvaluator.cs +++ b/src/EditorFeatures/Core.Wpf/Interactive/InteractiveEvaluator.cs @@ -26,6 +26,7 @@ namespace Microsoft.CodeAnalysis.Interactive { using InteractiveHost::Microsoft.CodeAnalysis.Interactive; + using Microsoft.VisualStudio.Text.Editor; // TODO: Rename to InteractiveEvaluator https://github.com/dotnet/roslyn/issues/6441 // The code is not specific to C#, but Interactive Window has hardcoded "CSharpInteractiveEvaluator" name. @@ -62,7 +63,6 @@ internal sealed class CSharpInteractiveEvaluator : IResettableInteractiveEvaluat = new InteractiveEvaluatorResetOptions(InteractiveHostPlatform.Desktop64); internal CSharpInteractiveEvaluator( - IGlobalOptionService globalOptions, IThreadingContext threadingContext, IAsynchronousOperationListener listener, IContentType contentType, @@ -71,6 +71,7 @@ internal CSharpInteractiveEvaluator( IInteractiveWindowCommandsFactory commandsFactory, ImmutableArray commands, ITextDocumentFactoryService textDocumentFactoryService, + EditorOptionsService editorOptionsService, InteractiveEvaluatorLanguageInfoProvider languageInfo, string initialWorkingDirectory) { @@ -83,9 +84,17 @@ internal CSharpInteractiveEvaluator( _commandsFactory = commandsFactory; _commands = commands; - _workspace = new InteractiveWindowWorkspace(hostServices, globalOptions); + _workspace = new InteractiveWindowWorkspace(hostServices, editorOptionsService.GlobalOptions); + + _session = new InteractiveSession( + _workspace, + threadingContext, + listener, + textDocumentFactoryService, + editorOptionsService, + languageInfo, + initialWorkingDirectory); - _session = new InteractiveSession(_workspace, threadingContext, listener, textDocumentFactoryService, languageInfo, initialWorkingDirectory); _session.Host.ProcessInitialized += ProcessInitialized; } diff --git a/src/EditorFeatures/Core.Wpf/Interactive/ResetInteractive.cs b/src/EditorFeatures/Core.Wpf/Interactive/ResetInteractive.cs index d298561b31a73..d674c005a943d 100644 --- a/src/EditorFeatures/Core.Wpf/Interactive/ResetInteractive.cs +++ b/src/EditorFeatures/Core.Wpf/Interactive/ResetInteractive.cs @@ -12,6 +12,7 @@ using System.Threading.Tasks; using InteractiveHost::Microsoft.CodeAnalysis.Interactive; using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.Options; using Microsoft.VisualStudio.InteractiveWindow; using Microsoft.VisualStudio.Text.Editor; using Microsoft.VisualStudio.Text.Editor.OptionsExtensionMethods; @@ -30,13 +31,13 @@ internal abstract class ResetInteractive private readonly Func _createImport; - private readonly IEditorOptionsFactoryService _editorOptionsFactoryService; + private readonly EditorOptionsService _editorOptionsService; internal event EventHandler ExecutionCompleted; - internal ResetInteractive(IEditorOptionsFactoryService editorOptionsFactoryService, Func createReference, Func createImport) + internal ResetInteractive(EditorOptionsService editorOptionsService, Func createReference, Func createImport) { - _editorOptionsFactoryService = editorOptionsFactoryService; + _editorOptionsService = editorOptionsService; _createReference = createReference; _createImport = createImport; } @@ -110,7 +111,7 @@ private async Task ResetInteractiveAsync( // Now send the reference paths we've collected to the repl. await evaluator.SetPathsAsync(referenceSearchPaths, sourceSearchPaths, projectDirectory).ConfigureAwait(true); - var editorOptions = _editorOptionsFactoryService.GetOptions(interactiveWindow.CurrentLanguageBuffer); + var editorOptions = _editorOptionsService.Factory.GetOptions(interactiveWindow.CurrentLanguageBuffer); var importReferencesCommand = referencePaths.Select(_createReference); await interactiveWindow.SubmitAsync(importReferencesCommand).ConfigureAwait(true); diff --git a/src/EditorFeatures/Core.Wpf/Notification/EditorNotificationServiceFactory.cs b/src/EditorFeatures/Core.Wpf/Notification/EditorNotificationServiceFactory.cs index b18d957c63a33..41071d58ae1fa 100644 --- a/src/EditorFeatures/Core.Wpf/Notification/EditorNotificationServiceFactory.cs +++ b/src/EditorFeatures/Core.Wpf/Notification/EditorNotificationServiceFactory.cs @@ -31,10 +31,7 @@ public IWorkspaceService CreateService(HostWorkspaceServices workspaceServices) { lock (s_gate) { - if (s_singleton == null) - { - s_singleton = new EditorDialogService(); - } + s_singleton ??= new EditorDialogService(); } return s_singleton; diff --git a/src/EditorFeatures/Core.Wpf/Peek/DefinitionPeekableItem.cs b/src/EditorFeatures/Core.Wpf/Peek/DefinitionPeekableItem.cs index ce968efc38081..baf73d8360fc4 100644 --- a/src/EditorFeatures/Core.Wpf/Peek/DefinitionPeekableItem.cs +++ b/src/EditorFeatures/Core.Wpf/Peek/DefinitionPeekableItem.cs @@ -77,7 +77,7 @@ public void FindResults(string relationshipName, IPeekResultCollection resultCol if (!sourceLocations.Any()) { // It's a symbol from metadata, so we want to go produce it from metadata - var options = _peekableItem._globalOptions.GetMetadataAsSourceOptions(project.LanguageServices); + var options = _peekableItem._globalOptions.GetMetadataAsSourceOptions(project.Services); var declarationFile = _peekableItem._metadataAsSourceFileService.GetGeneratedFileAsync(project, symbol, signaturesOnly: false, options, cancellationToken).WaitAndGetResult_CanCallOnBackground(cancellationToken); var peekDisplayInfo = new PeekResultDisplayInfo(declarationFile.DocumentTitle, declarationFile.DocumentTooltip, declarationFile.DocumentTitle, declarationFile.DocumentTooltip); var identifierSpan = declarationFile.IdentifierLocation.GetLineSpan().Span; diff --git a/src/EditorFeatures/Core.Wpf/Peek/PeekHelpers.cs b/src/EditorFeatures/Core.Wpf/Peek/PeekHelpers.cs index 0efa3aaeea75d..2135bbb8529cd 100644 --- a/src/EditorFeatures/Core.Wpf/Peek/PeekHelpers.cs +++ b/src/EditorFeatures/Core.Wpf/Peek/PeekHelpers.cs @@ -6,7 +6,7 @@ using System.IO; using System.Threading; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Text; using Microsoft.VisualStudio.Language.Intellisense; diff --git a/src/EditorFeatures/Core.Wpf/Peek/PeekableItemFactory.cs b/src/EditorFeatures/Core.Wpf/Peek/PeekableItemFactory.cs index 3ea94a11dfa90..d6d099b41d959 100644 --- a/src/EditorFeatures/Core.Wpf/Peek/PeekableItemFactory.cs +++ b/src/EditorFeatures/Core.Wpf/Peek/PeekableItemFactory.cs @@ -68,7 +68,7 @@ public async Task> GetPeekableItemsAsync( project = originatingProject ?? project; } - var symbolNavigationService = solution.Workspace.Services.GetService(); + var symbolNavigationService = solution.Services.GetService(); var definitionItem = symbol.ToNonClassifiedDefinitionItem(solution, includeHiddenLocations: true); var result = await symbolNavigationService.GetExternalNavigationSymbolLocationAsync(definitionItem, cancellationToken).ConfigureAwait(false); diff --git a/src/EditorFeatures/Core.Wpf/Peek/PeekableItemSource.cs b/src/EditorFeatures/Core.Wpf/Peek/PeekableItemSource.cs index 8d58c2480f039..933d0bb334382 100644 --- a/src/EditorFeatures/Core.Wpf/Peek/PeekableItemSource.cs +++ b/src/EditorFeatures/Core.Wpf/Peek/PeekableItemSource.cs @@ -73,7 +73,7 @@ private async Task AugumentPeekSessionAsync( IList peekableItems, IUIThreadOperationContext context, SnapshotPoint triggerPoint, Document document) { var cancellationToken = context.UserCancellationToken; - var services = document.Project.Solution.Workspace.Services; + var services = document.Project.Solution.Services; if (!document.SupportsSemanticModel) { diff --git a/src/EditorFeatures/Core.Wpf/Preview/PreviewFactoryService.cs b/src/EditorFeatures/Core.Wpf/Preview/PreviewFactoryService.cs index 65940f2ea8c80..79e8bd3346973 100644 --- a/src/EditorFeatures/Core.Wpf/Preview/PreviewFactoryService.cs +++ b/src/EditorFeatures/Core.Wpf/Preview/PreviewFactoryService.cs @@ -33,21 +33,19 @@ public PreviewFactoryService( IContentTypeRegistryService contentTypeRegistryService, IProjectionBufferFactoryService projectionBufferFactoryService, ITextEditorFactoryService textEditorFactoryService, - IEditorOptionsFactoryService editorOptionsFactoryService, + EditorOptionsService editorOptionsService, ITextDifferencingSelectorService differenceSelectorService, IDifferenceBufferFactoryService differenceBufferService, - IWpfDifferenceViewerFactoryService differenceViewerService, - IGlobalOptionService globalOptions) + IWpfDifferenceViewerFactoryService differenceViewerService) : base(threadingContext, textBufferFactoryService, contentTypeRegistryService, projectionBufferFactoryService, - editorOptionsFactoryService, + editorOptionsService, differenceSelectorService, differenceBufferService, textEditorFactoryService.CreateTextViewRoleSet( - TextViewRoles.PreviewRole, PredefinedTextViewRoles.Analyzable), - globalOptions) + TextViewRoles.PreviewRole, PredefinedTextViewRoles.Analyzable)) { _differenceViewerService = differenceViewerService; } diff --git a/src/EditorFeatures/Core.Wpf/QuickInfo/ContentControlService.cs b/src/EditorFeatures/Core.Wpf/QuickInfo/ContentControlService.cs index f72d641be89c9..ec89e90feaa12 100644 --- a/src/EditorFeatures/Core.Wpf/QuickInfo/ContentControlService.cs +++ b/src/EditorFeatures/Core.Wpf/QuickInfo/ContentControlService.cs @@ -14,6 +14,7 @@ using Microsoft.CodeAnalysis.Editor.Shared.Preview; using Microsoft.CodeAnalysis.Editor.Shared.Utilities; using Microsoft.CodeAnalysis.Host.Mef; +using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Text; using Microsoft.CodeAnalysis.Text.Shared.Extensions; using Microsoft.VisualStudio.Text; @@ -30,7 +31,7 @@ internal partial class ContentControlService : IContentControlService private readonly ITextEditorFactoryService _textEditorFactoryService; private readonly IContentTypeRegistryService _contentTypeRegistryService; private readonly IProjectionBufferFactoryService _projectionBufferFactoryService; - private readonly IEditorOptionsFactoryService _editorOptionsFactoryService; + private readonly EditorOptionsService _editorOptionsService; [ImportingConstructor] [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] @@ -39,13 +40,13 @@ public ContentControlService( ITextEditorFactoryService textEditorFactoryService, IContentTypeRegistryService contentTypeRegistryService, IProjectionBufferFactoryService projectionBufferFactoryService, - IEditorOptionsFactoryService editorOptionsFactoryService) + EditorOptionsService editorOptionsService) { _threadingContext = threadingContext; _textEditorFactoryService = textEditorFactoryService; _contentTypeRegistryService = contentTypeRegistryService; _projectionBufferFactoryService = projectionBufferFactoryService; - _editorOptionsFactoryService = editorOptionsFactoryService; + _editorOptionsService = editorOptionsService; } public void AttachToolTipToControl(FrameworkElement element, Func createToolTip) @@ -105,7 +106,7 @@ public ViewHostingControl CreateViewHostingControl(ITextBuffer textBuffer, Span _threadingContext, ImmutableArray.Create(snapshotSpan), _projectionBufferFactoryService, - _editorOptionsFactoryService, + _editorOptionsService, _textEditorFactoryService, contentType, roleSet); diff --git a/src/EditorFeatures/Core.Wpf/QuickInfo/Extensions.cs b/src/EditorFeatures/Core.Wpf/QuickInfo/Extensions.cs index 5ac75ce61af44..8345d39b3262f 100644 --- a/src/EditorFeatures/Core.Wpf/QuickInfo/Extensions.cs +++ b/src/EditorFeatures/Core.Wpf/QuickInfo/Extensions.cs @@ -29,10 +29,10 @@ public static ITextBuffer CreateTextBufferWithRoslynContentType(this SourceText /// public static ITextBuffer CloneTextBuffer(this Document document, SourceText sourceText) { - var contentTypeService = document.Project.LanguageServices.GetService(); + var contentTypeService = document.Project.Services.GetService(); var contentType = contentTypeService.GetDefaultContentType(); - var cloneService = document.Project.Solution.Workspace.Services.GetService(); + var cloneService = document.Project.Solution.Services.GetService(); return cloneService.Clone(sourceText, contentType); } diff --git a/src/EditorFeatures/Core.Wpf/QuickInfo/ProjectionBufferContent.cs b/src/EditorFeatures/Core.Wpf/QuickInfo/ProjectionBufferContent.cs index 2d55131c0d249..a0bed1d52547c 100644 --- a/src/EditorFeatures/Core.Wpf/QuickInfo/ProjectionBufferContent.cs +++ b/src/EditorFeatures/Core.Wpf/QuickInfo/ProjectionBufferContent.cs @@ -9,6 +9,7 @@ using System.Windows.Media; using Microsoft.CodeAnalysis.Editor.Shared.Extensions; using Microsoft.CodeAnalysis.Editor.Shared.Utilities; +using Microsoft.CodeAnalysis.Options; using Microsoft.VisualStudio.Text; using Microsoft.VisualStudio.Text.Editor; using Microsoft.VisualStudio.Text.Projection; @@ -25,7 +26,7 @@ internal class ProjectionBufferContent : ForegroundThreadAffinitizedObject { private readonly ImmutableArray _spans; private readonly IProjectionBufferFactoryService _projectionBufferFactoryService; - private readonly IEditorOptionsFactoryService _editorOptionsFactoryService; + private readonly EditorOptionsService _editorOptionsService; private readonly ITextEditorFactoryService _textEditorFactoryService; private readonly IContentType _contentType; private readonly ITextViewRoleSet _roleSet; @@ -34,7 +35,7 @@ private ProjectionBufferContent( IThreadingContext threadingContext, ImmutableArray spans, IProjectionBufferFactoryService projectionBufferFactoryService, - IEditorOptionsFactoryService editorOptionsFactoryService, + EditorOptionsService editorOptionsService, ITextEditorFactoryService textEditorFactoryService, IContentType contentType = null, ITextViewRoleSet roleSet = null) @@ -42,7 +43,7 @@ private ProjectionBufferContent( { _spans = spans; _projectionBufferFactoryService = projectionBufferFactoryService; - _editorOptionsFactoryService = editorOptionsFactoryService; + _editorOptionsService = editorOptionsService; _textEditorFactoryService = textEditorFactoryService; _contentType = contentType; _roleSet = roleSet ?? _textEditorFactoryService.NoRoles; @@ -52,7 +53,7 @@ public static ViewHostingControl Create( IThreadingContext threadingContext, ImmutableArray spans, IProjectionBufferFactoryService projectionBufferFactoryService, - IEditorOptionsFactoryService editorOptionsFactoryService, + EditorOptionsService editorOptionsService, ITextEditorFactoryService textEditorFactoryService, IContentType contentType = null, ITextViewRoleSet roleSet = null) @@ -61,7 +62,7 @@ public static ViewHostingControl Create( threadingContext, spans, projectionBufferFactoryService, - editorOptionsFactoryService, + editorOptionsService, textEditorFactoryService, contentType, roleSet); @@ -95,7 +96,7 @@ private IWpfTextView CreateView(ITextBuffer buffer) private IProjectionBuffer CreateBuffer() { return _projectionBufferFactoryService.CreateProjectionBufferWithoutIndentation( - _editorOptionsFactoryService.GlobalOptions, _contentType, _spans.ToArray()); + _editorOptionsService.Factory.GlobalOptions, _contentType, _spans.ToArray()); } } } diff --git a/src/EditorFeatures/Core.Wpf/SignatureHelp/AbstractSignatureHelpCommandHandler.cs b/src/EditorFeatures/Core.Wpf/SignatureHelp/AbstractSignatureHelpCommandHandler.cs index f854ed36aa280..8106e43c6597b 100644 --- a/src/EditorFeatures/Core.Wpf/SignatureHelp/AbstractSignatureHelpCommandHandler.cs +++ b/src/EditorFeatures/Core.Wpf/SignatureHelp/AbstractSignatureHelpCommandHandler.cs @@ -40,7 +40,7 @@ protected bool TryGetController(EditorCommandArgs args, out Controller controlle var languageName = args.SubjectBuffer.GetLanguageName(); if (args is not InvokeSignatureHelpCommandArgs && languageName != null && - !_globalOptions.GetOption(SignatureHelpViewOptions.ShowSignatureHelp, languageName)) + !_globalOptions.GetOption(SignatureHelpViewOptionsStorage.ShowSignatureHelp, languageName)) { controller = null; return false; diff --git a/src/EditorFeatures/Core.Wpf/SignatureHelp/Controller.Session_ComputeModel.cs b/src/EditorFeatures/Core.Wpf/SignatureHelp/Controller.Session_ComputeModel.cs index 3d9b05ad89458..93b6e9b990c46 100644 --- a/src/EditorFeatures/Core.Wpf/SignatureHelp/Controller.Session_ComputeModel.cs +++ b/src/EditorFeatures/Core.Wpf/SignatureHelp/Controller.Session_ComputeModel.cs @@ -12,7 +12,7 @@ using Microsoft.CodeAnalysis.Editor.Shared.Extensions; using Microsoft.CodeAnalysis.ErrorReporting; using Microsoft.CodeAnalysis.Internal.Log; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.SignatureHelp; @@ -163,11 +163,8 @@ private static SignatureHelpItem GetSelectedItem(Model currentModel, SignatureHe lastSelectionOrDefault = items.Items.FirstOrDefault(i => DisplayPartsMatch(i, currentModel.SelectedItem)); } - if (lastSelectionOrDefault == null) - { - // Otherwise, just pick the first item we have. - lastSelectionOrDefault = items.Items.First(); - } + // Otherwise, just pick the first item we have. + lastSelectionOrDefault ??= items.Items.First(); return lastSelectionOrDefault; } diff --git a/src/EditorFeatures/Core.Wpf/SignatureHelp/Controller.cs b/src/EditorFeatures/Core.Wpf/SignatureHelp/Controller.cs index dc30c27348316..c47daf7d94ede 100644 --- a/src/EditorFeatures/Core.Wpf/SignatureHelp/Controller.cs +++ b/src/EditorFeatures/Core.Wpf/SignatureHelp/Controller.cs @@ -131,7 +131,7 @@ private ImmutableArray GetProviders() var document = snapshot.GetOpenDocumentInCurrentContextWithChanges(); if (document != null) { - _providers = document.Project.LanguageServices.WorkspaceServices.SelectMatchingExtensionValues( + _providers = document.Project.Solution.Services.SelectMatchingExtensionValues( _allProviders, this.SubjectBuffer.ContentType).ToImmutableArray(); _lastSeenContentType = currentContentType; } diff --git a/src/EditorFeatures/Core.Wpf/SignatureHelp/Presentation/Parameter.cs b/src/EditorFeatures/Core.Wpf/SignatureHelp/Presentation/Parameter.cs index 7bb556d899e3e..fc5b91ce806b3 100644 --- a/src/EditorFeatures/Core.Wpf/SignatureHelp/Presentation/Parameter.cs +++ b/src/EditorFeatures/Core.Wpf/SignatureHelp/Presentation/Parameter.cs @@ -20,7 +20,7 @@ internal class Parameter : IParameter private readonly int _index; private readonly int _prettyPrintedIndex; - public string Documentation => _documentation ?? (_documentation = _parameter.DocumentationFactory(CancellationToken.None).GetFullText()); + public string Documentation => _documentation ??= _parameter.DocumentationFactory(CancellationToken.None).GetFullText(); public string Name => _parameter.Name; public Span Locus => new(_index, _contentLength); public Span PrettyPrintedLocus => new(_prettyPrintedIndex, _contentLength); diff --git a/src/EditorFeatures/Core.Wpf/Structure/StructureTaggerProvider.cs b/src/EditorFeatures/Core.Wpf/Structure/StructureTaggerProvider.cs index 5c629e8caa685..8d1cee5339a30 100644 --- a/src/EditorFeatures/Core.Wpf/Structure/StructureTaggerProvider.cs +++ b/src/EditorFeatures/Core.Wpf/Structure/StructureTaggerProvider.cs @@ -34,13 +34,13 @@ internal class StructureTaggerProvider : [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] public StructureTaggerProvider( IThreadingContext threadingContext, - IEditorOptionsFactoryService editorOptionsFactoryService, + EditorOptionsService editorOptionsService, IProjectionBufferFactoryService projectionBufferFactoryService, ITextEditorFactoryService textEditorFactoryService, IGlobalOptionService globalOptions, [Import(AllowDefault = true)] ITextBufferVisibilityTracker? visibilityTracker, IAsynchronousOperationListenerProvider listenerProvider) - : base(threadingContext, editorOptionsFactoryService, projectionBufferFactoryService, globalOptions, visibilityTracker, listenerProvider) + : base(threadingContext, editorOptionsService, projectionBufferFactoryService, visibilityTracker, listenerProvider) { _textEditorFactoryService = textEditorFactoryService; } diff --git a/src/EditorFeatures/Core.Wpf/Suggestions/PreviewChanges/PreviewChangesSuggestedAction.cs b/src/EditorFeatures/Core.Wpf/Suggestions/PreviewChanges/PreviewChangesSuggestedAction.cs index 084e72e3c4414..73254d07b4829 100644 --- a/src/EditorFeatures/Core.Wpf/Suggestions/PreviewChanges/PreviewChangesSuggestedAction.cs +++ b/src/EditorFeatures/Core.Wpf/Suggestions/PreviewChanges/PreviewChangesSuggestedAction.cs @@ -23,10 +23,11 @@ private PreviewChangesSuggestedAction( IThreadingContext threadingContext, SuggestedActionsSourceProvider sourceProvider, Workspace workspace, + Solution originalSolution, ITextBuffer subjectBuffer, object provider, PreviewChangesCodeAction codeAction) - : base(threadingContext, sourceProvider, workspace, subjectBuffer, provider, codeAction) + : base(threadingContext, sourceProvider, workspace, originalSolution, subjectBuffer, provider, codeAction) { } @@ -47,8 +48,11 @@ public static async Task CreateAsync( return new PreviewChangesSuggestedAction( suggestedAction.ThreadingContext, - suggestedAction.SourceProvider, suggestedAction.Workspace, - suggestedAction.SubjectBuffer, suggestedAction.Provider, + suggestedAction.SourceProvider, + suggestedAction.Workspace, + suggestedAction.OriginalSolution, + suggestedAction.SubjectBuffer, + suggestedAction.Provider, new PreviewChangesCodeAction( suggestedAction.Workspace, suggestedAction.CodeAction, changeSummary)); } diff --git a/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionWithNestedActions.cs b/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionWithNestedActions.cs index be030502e72cc..16a51d6c876e6 100644 --- a/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionWithNestedActions.cs +++ b/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionWithNestedActions.cs @@ -27,10 +27,14 @@ internal sealed class SuggestedActionWithNestedActions : SuggestedAction public SuggestedActionWithNestedActions( IThreadingContext threadingContext, - SuggestedActionsSourceProvider sourceProvider, Workspace workspace, - ITextBuffer subjectBuffer, object provider, - CodeAction codeAction, ImmutableArray nestedActionSets) - : base(threadingContext, sourceProvider, workspace, subjectBuffer, provider, codeAction) + SuggestedActionsSourceProvider sourceProvider, + Workspace workspace, + Solution originalSolution, + ITextBuffer subjectBuffer, + object provider, + CodeAction codeAction, + ImmutableArray nestedActionSets) + : base(threadingContext, sourceProvider, workspace, originalSolution, subjectBuffer, provider, codeAction) { Debug.Assert(!nestedActionSets.IsDefaultOrEmpty); NestedActionSets = nestedActionSets; @@ -38,10 +42,14 @@ public SuggestedActionWithNestedActions( public SuggestedActionWithNestedActions( IThreadingContext threadingContext, - SuggestedActionsSourceProvider sourceProvider, Workspace workspace, - ITextBuffer subjectBuffer, object provider, - CodeAction codeAction, SuggestedActionSet nestedActionSet) - : this(threadingContext, sourceProvider, workspace, subjectBuffer, provider, codeAction, ImmutableArray.Create(nestedActionSet)) + SuggestedActionsSourceProvider sourceProvider, + Workspace workspace, + Solution originalSolution, + ITextBuffer subjectBuffer, + object provider, + CodeAction codeAction, + SuggestedActionSet nestedActionSet) + : this(threadingContext, sourceProvider, workspace, originalSolution, subjectBuffer, provider, codeAction, ImmutableArray.Create(nestedActionSet)) { } diff --git a/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionWithNestedFlavors.cs b/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionWithNestedFlavors.cs index 51f5466d78777..9c24f9de28e09 100644 --- a/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionWithNestedFlavors.cs +++ b/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionWithNestedFlavors.cs @@ -38,11 +38,19 @@ internal abstract partial class SuggestedActionWithNestedFlavors : SuggestedActi public SuggestedActionWithNestedFlavors( IThreadingContext threadingContext, SuggestedActionsSourceProvider sourceProvider, - Workspace workspace, ITextBuffer subjectBuffer, - object provider, CodeAction codeAction, + Workspace workspace, + Solution originalSolution, + ITextBuffer subjectBuffer, + object provider, + CodeAction codeAction, SuggestedActionSet additionalFlavors) - : base(threadingContext, sourceProvider, workspace, subjectBuffer, - provider, codeAction) + : base(threadingContext, + sourceProvider, + workspace, + originalSolution, + subjectBuffer, + provider, + codeAction) { _additionalFlavors = additionalFlavors; } diff --git a/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActions/AbstractFixAllSuggestedAction.cs b/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActions/AbstractFixAllSuggestedAction.cs index d09b011255ac2..c3b68680e7f48 100644 --- a/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActions/AbstractFixAllSuggestedAction.cs +++ b/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActions/AbstractFixAllSuggestedAction.cs @@ -28,12 +28,18 @@ protected AbstractFixAllSuggestedAction( IThreadingContext threadingContext, SuggestedActionsSourceProvider sourceProvider, Workspace workspace, + Solution originalSolution, ITextBuffer subjectBuffer, IFixAllState fixAllState, CodeAction originalCodeAction, AbstractFixAllCodeAction fixAllCodeAction) - : base(threadingContext, sourceProvider, workspace, subjectBuffer, - fixAllState.FixAllProvider, fixAllCodeAction) + : base(threadingContext, + sourceProvider, + workspace, + originalSolution, + subjectBuffer, + fixAllState.FixAllProvider, + fixAllCodeAction) { OriginalCodeAction = originalCodeAction; FixAllState = fixAllState; diff --git a/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActions/CodeFixSuggestedAction.cs b/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActions/CodeFixSuggestedAction.cs index 1a56faba462d8..401a5b19750e7 100644 --- a/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActions/CodeFixSuggestedAction.cs +++ b/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActions/CodeFixSuggestedAction.cs @@ -26,13 +26,20 @@ public CodeFixSuggestedAction( IThreadingContext threadingContext, SuggestedActionsSourceProvider sourceProvider, Workspace workspace, + Solution originalSolution, ITextBuffer subjectBuffer, CodeFix fix, object provider, CodeAction action, SuggestedActionSet fixAllFlavors) - : base(threadingContext, sourceProvider, workspace, subjectBuffer, - provider, action, fixAllFlavors) + : base(threadingContext, + sourceProvider, + workspace, + originalSolution, + subjectBuffer, + provider, + action, + fixAllFlavors) { CodeFix = fix; } diff --git a/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActions/CodeRefactoringSuggestedAction.cs b/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActions/CodeRefactoringSuggestedAction.cs index ac14b9c18cd06..2b179ecd6e5e9 100644 --- a/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActions/CodeRefactoringSuggestedAction.cs +++ b/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActions/CodeRefactoringSuggestedAction.cs @@ -24,11 +24,12 @@ public CodeRefactoringSuggestedAction( IThreadingContext threadingContext, SuggestedActionsSourceProvider sourceProvider, Workspace workspace, + Solution originalSolution, ITextBuffer subjectBuffer, CodeRefactoringProvider provider, CodeAction codeAction, SuggestedActionSet fixAllFlavors) - : base(threadingContext, sourceProvider, workspace, subjectBuffer, provider, codeAction, fixAllFlavors) + : base(threadingContext, sourceProvider, workspace, originalSolution, subjectBuffer, provider, codeAction, fixAllFlavors) { CodeRefactoringProvider = provider; } diff --git a/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActions/FixAllCodeFixSuggestedAction.cs b/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActions/FixAllCodeFixSuggestedAction.cs index 9148893d8ab65..290609d9551c6 100644 --- a/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActions/FixAllCodeFixSuggestedAction.cs +++ b/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActions/FixAllCodeFixSuggestedAction.cs @@ -25,12 +25,19 @@ public FixAllCodeFixSuggestedAction( IThreadingContext threadingContext, SuggestedActionsSourceProvider sourceProvider, Workspace workspace, + Solution originalSolution, ITextBuffer subjectBuffer, IFixAllState fixAllState, Diagnostic diagnostic, CodeAction originalCodeAction) - : base(threadingContext, sourceProvider, workspace, subjectBuffer, fixAllState, - originalCodeAction, new FixAllCodeAction(fixAllState)) + : base(threadingContext, + sourceProvider, + workspace, + originalSolution, + subjectBuffer, + fixAllState, + originalCodeAction, + new FixAllCodeAction(fixAllState)) { Diagnostic = diagnostic; } diff --git a/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActions/FixAllCodeRefactoringSuggestedAction.cs b/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActions/FixAllCodeRefactoringSuggestedAction.cs index fa7b3a833dfa5..c4320a1f7bd12 100644 --- a/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActions/FixAllCodeRefactoringSuggestedAction.cs +++ b/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActions/FixAllCodeRefactoringSuggestedAction.cs @@ -21,11 +21,18 @@ public FixAllCodeRefactoringSuggestedAction( IThreadingContext threadingContext, SuggestedActionsSourceProvider sourceProvider, Workspace workspace, + Solution originalSolution, ITextBuffer subjectBuffer, IFixAllState fixAllState, CodeAction originalCodeAction) - : base(threadingContext, sourceProvider, workspace, subjectBuffer, fixAllState, - originalCodeAction, new FixAllCodeRefactoringCodeAction(fixAllState)) + : base(threadingContext, + sourceProvider, + workspace, + originalSolution, + subjectBuffer, + fixAllState, + originalCodeAction, + new FixAllCodeRefactoringCodeAction(fixAllState)) { } } diff --git a/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActions/SuggestedAction.cs b/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActions/SuggestedAction.cs index 1152683034ec6..8c5e3934cdce4 100644 --- a/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActions/SuggestedAction.cs +++ b/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActions/SuggestedAction.cs @@ -35,6 +35,7 @@ internal abstract partial class SuggestedAction : ForegroundThreadAffinitizedObj protected readonly SuggestedActionsSourceProvider SourceProvider; protected readonly Workspace Workspace; + protected readonly Solution OriginalSolution; protected readonly ITextBuffer SubjectBuffer; protected readonly object Provider; @@ -46,6 +47,7 @@ internal SuggestedAction( IThreadingContext threadingContext, SuggestedActionsSourceProvider sourceProvider, Workspace workspace, + Solution originalSolution, ITextBuffer subjectBuffer, object provider, CodeAction codeAction) @@ -56,6 +58,7 @@ internal SuggestedAction( SourceProvider = sourceProvider; Workspace = workspace; + OriginalSolution = originalSolution; SubjectBuffer = subjectBuffer; Provider = provider; CodeAction = codeAction; @@ -164,9 +167,13 @@ private async Task InvokeWorkerAsync(IProgressTracker progressTracker, Cancellat var document = this.SubjectBuffer.CurrentSnapshot.GetOpenDocumentInCurrentContextWithChanges(); await EditHandler.ApplyAsync( - Workspace, document, - operations.ToImmutableArray(), CodeAction.Title, - progressTracker, cancellationToken).ConfigureAwait(false); + Workspace, + OriginalSolution, + document, + operations.ToImmutableArray(), + CodeAction.Title, + progressTracker, + cancellationToken).ConfigureAwait(false); } } } diff --git a/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionsSource.State.cs b/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionsSource.State.cs index 591e08e8161de..84f880c93f75d 100644 --- a/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionsSource.State.cs +++ b/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionsSource.State.cs @@ -24,9 +24,7 @@ protected sealed class State : IDisposable public readonly ITextBuffer SubjectBuffer; public readonly WorkspaceRegistration Registration; - // mutable state - public Workspace? Workspace { get; set; } - public int LastSolutionVersionReported; + public Workspace? Workspace => Registration.Workspace; public State(SuggestedActionsSource source, SuggestedActionsSourceProvider owner, ITextView textView, ITextBuffer textBuffer) { @@ -36,21 +34,10 @@ public State(SuggestedActionsSource source, SuggestedActionsSourceProvider owner TextView = textView; SubjectBuffer = textBuffer; Registration = Workspace.GetWorkspaceRegistration(textBuffer.AsTextContainer()); - LastSolutionVersionReported = InvalidSolutionVersion; } void IDisposable.Dispose() { - if (Workspace != null) - { - Workspace.Services.GetRequiredService().StatusChanged -= _source.OnWorkspaceStatusChanged; - Workspace.DocumentActiveContextChanged -= _source.OnActiveContextChanged; - Workspace.WorkspaceChanged -= _source.OnWorkspaceChanged; - } - - if (Registration != null) - Registration.WorkspaceChanged -= _source.OnWorkspaceChanged; - if (TextView != null) TextView.Closed -= _source.OnTextViewClosed; } diff --git a/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionsSource.cs b/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionsSource.cs index a17775590827b..91b48d7373ada 100644 --- a/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionsSource.cs +++ b/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionsSource.cs @@ -40,7 +40,7 @@ private abstract partial class SuggestedActionsSource : ForegroundThreadAffiniti private readonly ReferenceCountedDisposable _state; - public event EventHandler? SuggestedActionsChanged; + public event EventHandler? SuggestedActionsChanged { add { } remove { } } public readonly IGlobalOptionService GlobalOptions; @@ -59,10 +59,6 @@ protected SuggestedActionsSource( _state = new ReferenceCountedDisposable(new State(this, owner, textView, textBuffer)); _state.Target.TextView.Closed += OnTextViewClosed; - - RegisterEventsToWorkspace(_state, _state.Target.Registration.Workspace); - - _state.Target.Registration.WorkspaceChanged += OnWorkspaceChanged; } public void Dispose() @@ -215,6 +211,8 @@ protected ImmutableArray ConvertToSuggestedActionSets( if (unifiedSuggestedActionSet == null) return null; + var originalSolution = unifiedSuggestedActionSet.OriginalSolution; + return new SuggestedActionSet( unifiedSuggestedActionSet.CategoryName, unifiedSuggestedActionSet.Actions.SelectAsArray(set => ConvertToSuggestedAction(set)), @@ -227,21 +225,21 @@ ISuggestedAction ConvertToSuggestedAction(IUnifiedSuggestedAction unifiedSuggest => unifiedSuggestedAction switch { UnifiedCodeFixSuggestedAction codeFixAction => new CodeFixSuggestedAction( - ThreadingContext, owner, codeFixAction.Workspace, subjectBuffer, + ThreadingContext, owner, codeFixAction.Workspace, originalSolution, subjectBuffer, codeFixAction.CodeFix, codeFixAction.Provider, codeFixAction.OriginalCodeAction, ConvertToSuggestedActionSet(codeFixAction.FixAllFlavors, owner, subjectBuffer)), UnifiedCodeRefactoringSuggestedAction codeRefactoringAction => new CodeRefactoringSuggestedAction( - ThreadingContext, owner, codeRefactoringAction.Workspace, subjectBuffer, + ThreadingContext, owner, codeRefactoringAction.Workspace, originalSolution, subjectBuffer, codeRefactoringAction.CodeRefactoringProvider, codeRefactoringAction.OriginalCodeAction, ConvertToSuggestedActionSet(codeRefactoringAction.FixAllFlavors, owner, subjectBuffer)), UnifiedFixAllCodeFixSuggestedAction fixAllAction => new FixAllCodeFixSuggestedAction( - ThreadingContext, owner, fixAllAction.Workspace, subjectBuffer, + ThreadingContext, owner, fixAllAction.Workspace, originalSolution, subjectBuffer, fixAllAction.FixAllState, fixAllAction.Diagnostic, fixAllAction.OriginalCodeAction), UnifiedFixAllCodeRefactoringSuggestedAction fixAllCodeRefactoringAction => new FixAllCodeRefactoringSuggestedAction( - ThreadingContext, owner, fixAllCodeRefactoringAction.Workspace, subjectBuffer, + ThreadingContext, owner, fixAllCodeRefactoringAction.Workspace, originalSolution, subjectBuffer, fixAllCodeRefactoringAction.FixAllState, fixAllCodeRefactoringAction.OriginalCodeAction), UnifiedSuggestedActionWithNestedActions nestedAction => new SuggestedActionWithNestedActions( - ThreadingContext, owner, nestedAction.Workspace, subjectBuffer, + ThreadingContext, owner, nestedAction.Workspace, originalSolution, subjectBuffer, nestedAction.Provider ?? this, nestedAction.OriginalCodeAction, nestedAction.NestedActionSets.SelectAsArray((s, arg) => ConvertToSuggestedActionSet(s, arg.owner, arg.subjectBuffer), (owner, subjectBuffer))), _ => throw ExceptionUtilities.Unreachable @@ -447,11 +445,7 @@ await InvokeBelowInputPriorityAsync(() => } if (!result.UpToDate) - { - // reset solution version number so that we can raise suggested action changed event - Volatile.Write(ref state.Target.LastSolutionVersionReported, InvalidSolutionVersion); return null; - } } return null; @@ -518,107 +512,6 @@ await InvokeBelowInputPriorityAsync(() => private void OnTextViewClosed(object sender, EventArgs e) => Dispose(); - private void OnWorkspaceChanged(object sender, EventArgs e) - { - using var state = _state.TryAddReference(); - if (state is null) - return; - - // REVIEW: this event should give both old and new workspace as argument so that - // one doesn't need to hold onto workspace in field. - - // remove existing event registration - if (state.Target.Workspace != null) - { - state.Target.Workspace.Services.GetRequiredService().StatusChanged -= OnWorkspaceStatusChanged; - state.Target.Workspace.DocumentActiveContextChanged -= OnActiveContextChanged; - } - - // REVIEW: why one need to get new workspace from registration? why not just pass in the new workspace? - // add new event registration - RegisterEventsToWorkspace(state, state.Target.Registration.Workspace); - } - - private void RegisterEventsToWorkspace(ReferenceCountedDisposable state, Workspace? workspace) - { - state.Target.Workspace = workspace; - - if (state.Target.Workspace == null) - { - return; - } - - state.Target.Workspace.DocumentActiveContextChanged += OnActiveContextChanged; - state.Target.Workspace.Services.GetRequiredService().StatusChanged += OnWorkspaceStatusChanged; - state.Target.Workspace.WorkspaceChanged += OnWorkspaceChanged; - } - - private void OnWorkspaceChanged(object? sender, WorkspaceChangeEventArgs e) - { - switch (e.Kind) - { - // Only care about document changes here, the call to OnSuggestedActionsChange - // will filter and make sure the event only gets sent if its relevant to this buffer. - case WorkspaceChangeKind.DocumentAdded: - case WorkspaceChangeKind.DocumentRemoved: - case WorkspaceChangeKind.DocumentReloaded: - case WorkspaceChangeKind.DocumentChanged: - OnSuggestedActionsChanged(e.NewSolution.Workspace, e.DocumentId, e.NewSolution.WorkspaceVersion); - break; - default: - break; - } - } - - private void OnActiveContextChanged(object sender, DocumentActiveContextChangedEventArgs e) - { - // REVIEW: it would be nice for changed event to pass in both old and new document. - OnSuggestedActionsChanged(e.Solution.Workspace, e.NewActiveContextDocumentId, e.Solution.WorkspaceVersion); - } - - private void OnWorkspaceStatusChanged(object sender, EventArgs args) - { - using var state = _state.TryAddReference(); - if (state is null) - return; - - var document = state.Target.SubjectBuffer.AsTextContainer().GetOpenDocumentInCurrentContext(); - if (document == null) - { - // document is already closed - return; - } - - // ask editor to refresh light-bulb when workspace solution status is changed - this.SuggestedActionsChanged?.Invoke(this, EventArgs.Empty); - } - - private void OnSuggestedActionsChanged(Workspace currentWorkspace, DocumentId? currentDocumentId, int solutionVersion) - { - using var state = _state.TryAddReference(); - if (state is null) - return; - - var buffer = state.Target.SubjectBuffer; - var workspace = buffer.GetWorkspace(); - - // workspace is not ready, nothing to do. - if (workspace == null || workspace != currentWorkspace) - { - return; - } - - if (currentDocumentId != workspace.GetDocumentIdInCurrentContext(buffer.AsTextContainer()) || - solutionVersion == Volatile.Read(ref state.Target.LastSolutionVersionReported)) - { - return; - } - - this.SuggestedActionsChanged?.Invoke(this, EventArgs.Empty); - - Volatile.Write(ref state.Target.LastSolutionVersionReported, solutionVersion); - } - public async Task GetSuggestedActionCategoriesAsync(ISuggestedActionCategorySet requestedActionCategories, SnapshotSpan range, CancellationToken cancellationToken) { using var state = _state.TryAddReference(); diff --git a/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionsSourceProvider.cs b/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionsSourceProvider.cs index 3299c00f8e22b..c19a0afe3b1d4 100644 --- a/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionsSourceProvider.cs +++ b/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionsSourceProvider.cs @@ -45,8 +45,6 @@ internal partial class SuggestedActionsSourceProvider : ISuggestedActionsSourceP private static readonly Guid s_visualBasicSourceGuid = new Guid("4de30e93-3e0c-40c2-a4ba-1124da4539f6"); private static readonly Guid s_xamlSourceGuid = new Guid("a0572245-2eab-4c39-9f61-06a6d8c5ddda"); - private const int InvalidSolutionVersion = -1; - private readonly IThreadingContext _threadingContext; private readonly ICodeRefactoringService _codeRefactoringService; private readonly ICodeFixService _codeFixService; diff --git a/src/EditorFeatures/Core.Wpf/ViewHostingControl.cs b/src/EditorFeatures/Core.Wpf/ViewHostingControl.cs index d56161ad6a8c6..7a5ab9acef507 100644 --- a/src/EditorFeatures/Core.Wpf/ViewHostingControl.cs +++ b/src/EditorFeatures/Core.Wpf/ViewHostingControl.cs @@ -35,10 +35,7 @@ public ViewHostingControl( private void EnsureBufferCreated() { - if (_createdTextBuffer == null) - { - _createdTextBuffer = _createBuffer(); - } + _createdTextBuffer ??= _createBuffer(); } private void EnsureContentCreated() diff --git a/src/EditorFeatures/Core/AddImports/AbstractAddImportsPasteCommandHandler.cs b/src/EditorFeatures/Core/AddImports/AbstractAddImportsPasteCommandHandler.cs index fd215741024cf..271cf6e61ab14 100644 --- a/src/EditorFeatures/Core/AddImports/AbstractAddImportsPasteCommandHandler.cs +++ b/src/EditorFeatures/Core/AddImports/AbstractAddImportsPasteCommandHandler.cs @@ -139,7 +139,7 @@ private async Task ExecuteAsync(Document document, SnapshotSpan snapshotSpan, IT { _threadingContext.ThrowIfNotOnUIThread(); - var indicatorFactory = document.Project.Solution.Workspace.Services.GetRequiredService(); + var indicatorFactory = document.Project.Solution.Services.GetRequiredService(); using var backgroundWorkContext = indicatorFactory.Create( textView, snapshotSpan, diff --git a/src/EditorFeatures/Core/AutomaticCompletion/AbstractAutomaticLineEnderCommandHandler.cs b/src/EditorFeatures/Core/AutomaticCompletion/AbstractAutomaticLineEnderCommandHandler.cs index a7b717b0dc534..5af0a94f398a2 100644 --- a/src/EditorFeatures/Core/AutomaticCompletion/AbstractAutomaticLineEnderCommandHandler.cs +++ b/src/EditorFeatures/Core/AutomaticCompletion/AbstractAutomaticLineEnderCommandHandler.cs @@ -25,18 +25,19 @@ internal abstract class AbstractAutomaticLineEnderCommandHandler : { private readonly ITextUndoHistoryRegistry _undoRegistry; private readonly IEditorOperationsFactoryService _editorOperationsFactoryService; - public readonly IGlobalOptionService GlobalOptions; + + public readonly EditorOptionsService EditorOptionsService; public string DisplayName => EditorFeaturesResources.Automatic_Line_Ender; protected AbstractAutomaticLineEnderCommandHandler( ITextUndoHistoryRegistry undoRegistry, IEditorOperationsFactoryService editorOperationsFactoryService, - IGlobalOptionService globalOptions) + EditorOptionsService editorOptionsService) { _undoRegistry = undoRegistry; _editorOperationsFactoryService = editorOperationsFactoryService; - GlobalOptions = globalOptions; + EditorOptionsService = editorOptionsService; } /// @@ -90,7 +91,7 @@ public void ExecuteCommand(AutomaticLineEnderCommandArgs args, Action nextHandle } // feature off - if (!GlobalOptions.GetOption(InternalFeatureOnOffOptions.AutomaticLineEnder)) + if (!EditorOptionsService.GlobalOptions.GetOption(InternalFeatureOnOffOptions.AutomaticLineEnder)) { NextAction(operations, nextHandler); return; @@ -142,7 +143,7 @@ public void ExecuteCommand(AutomaticLineEnderCommandArgs args, Action nextHandle if (endingInsertionPosition != null) { using var transaction = args.TextView.CreateEditTransaction(EditorFeaturesResources.Automatic_Line_Ender, _undoRegistry, _editorOperationsFactoryService); - var formattingOptions = document.GetSyntaxFormattingOptionsAsync(GlobalOptions, cancellationToken).AsTask().WaitAndGetResult(cancellationToken); + var formattingOptions = args.SubjectBuffer.GetSyntaxFormattingOptions(EditorOptionsService, document.Project.Services, explicitFormat: false); InsertEnding(args.TextView, document, endingInsertionPosition.Value, caretPosition, formattingOptions, cancellationToken); NextAction(operations, nextHandler); transaction.Complete(); diff --git a/src/EditorFeatures/Core/AutomaticCompletion/AbstractBraceCompletionServiceFactory.cs b/src/EditorFeatures/Core/AutomaticCompletion/AbstractBraceCompletionServiceFactory.cs index 0f3de0920809c..e3b9376318f60 100644 --- a/src/EditorFeatures/Core/AutomaticCompletion/AbstractBraceCompletionServiceFactory.cs +++ b/src/EditorFeatures/Core/AutomaticCompletion/AbstractBraceCompletionServiceFactory.cs @@ -20,11 +20,11 @@ protected AbstractBraceCompletionServiceFactory( _braceCompletionServices = braceCompletionServices.ToImmutableArray(); } - public async Task TryGetServiceAsync(Document document, int openingPosition, char openingBrace, CancellationToken cancellationToken) + public IBraceCompletionService? TryGetService(ParsedDocument document, int openingPosition, char openingBrace, CancellationToken cancellationToken) { foreach (var service in _braceCompletionServices) { - if (await service.CanProvideBraceCompletionAsync(openingBrace, openingPosition, document, cancellationToken).ConfigureAwait(false)) + if (service.CanProvideBraceCompletion(openingBrace, openingPosition, document, cancellationToken)) { return service; } diff --git a/src/EditorFeatures/Core/AutomaticCompletion/BraceCompletionSessionProvider.BraceCompletionSession.cs b/src/EditorFeatures/Core/AutomaticCompletion/BraceCompletionSessionProvider.BraceCompletionSession.cs index 86d5652e9896a..7cd8982080d0e 100644 --- a/src/EditorFeatures/Core/AutomaticCompletion/BraceCompletionSessionProvider.BraceCompletionSession.cs +++ b/src/EditorFeatures/Core/AutomaticCompletion/BraceCompletionSessionProvider.BraceCompletionSession.cs @@ -44,15 +44,15 @@ private class BraceCompletionSession : IBraceCompletionSession private readonly ITextUndoHistory _undoHistory; private readonly IEditorOperations _editorOperations; + private readonly EditorOptionsService _editorOptionsService; private readonly IBraceCompletionService _service; - private readonly IGlobalOptionService _globalOptions; private readonly IThreadingContext _threadingContext; public BraceCompletionSession( ITextView textView, ITextBuffer subjectBuffer, SnapshotPoint openingPoint, char openingBrace, char closingBrace, ITextUndoHistory undoHistory, - IEditorOperationsFactoryService editorOperationsFactoryService, IBraceCompletionService service, - IGlobalOptionService globalOptions, IThreadingContext threadingContext) + IEditorOperationsFactoryService editorOperationsFactoryService, + EditorOptionsService editorOptionsService, IBraceCompletionService service, IThreadingContext threadingContext) { TextView = textView; SubjectBuffer = subjectBuffer; @@ -61,9 +61,9 @@ public BraceCompletionSession( ClosingPoint = SubjectBuffer.CurrentSnapshot.CreateTrackingPoint(openingPoint.Position, PointTrackingMode.Positive); _undoHistory = undoHistory; _editorOperations = editorOperationsFactoryService.GetEditorOperations(textView); + _editorOptionsService = editorOptionsService; _service = service; _threadingContext = threadingContext; - _globalOptions = globalOptions; } #region IBraceCompletionSession Methods @@ -101,33 +101,35 @@ private bool TryStart(CancellationToken cancellationToken) OpeningPoint = SubjectBuffer.CurrentSnapshot.CreateTrackingPoint(openingSnapshotPoint, PointTrackingMode.Positive); - var context = GetBraceCompletionContext(); - if (context == null) + var document = SubjectBuffer.CurrentSnapshot.GetOpenDocumentInCurrentContextWithChanges(); + if (document == null) { return false; } - var braceResult = _service.GetBraceCompletionAsync(context.Value, cancellationToken).WaitAndGetResult(cancellationToken); - if (braceResult == null) + var parsedDocument = ParsedDocument.CreateSynchronously(document, cancellationToken); + var context = GetBraceCompletionContext(parsedDocument); + + // Note: completes synchronously unless Semantic Model is needed to determine the result: + if (!_service.HasBraceCompletionAsync(context, document, cancellationToken).WaitAndGetResult(cancellationToken)) { return false; } + var braceResult = _service.GetBraceCompletion(context); + using var caretPreservingTransaction = new CaretPreservingEditTransaction(EditorFeaturesResources.Brace_Completion, _undoHistory, _editorOperations); // Apply the change to complete the brace. - ApplyBraceCompletionResult(braceResult.Value); + ApplyBraceCompletionResult(braceResult); // switch the closing point from positive to negative tracking so that the closing point stays against the closing brace ClosingPoint = SubjectBuffer.CurrentSnapshot.CreateTrackingPoint(ClosingPoint.GetPoint(SubjectBuffer.CurrentSnapshot), PointTrackingMode.Negative); - var contextAfterStart = GetBraceCompletionContext(); - if (contextAfterStart != null) + if (TryGetBraceCompletionContext(out var contextAfterStart, cancellationToken)) { - var document = contextAfterStart.Value.Document; - var indentationOptions = document.GetIndentationOptionsAsync(_globalOptions, cancellationToken).WaitAndGetResult(cancellationToken); - - var changesAfterStart = _service.GetTextChangesAfterCompletionAsync(contextAfterStart.Value, indentationOptions, cancellationToken).WaitAndGetResult(cancellationToken); + var indentationOptions = SubjectBuffer.GetIndentationOptions(_editorOptionsService, contextAfterStart.Document.LanguageServices, explicitFormat: false); + var changesAfterStart = _service.GetTextChangesAfterCompletion(contextAfterStart, indentationOptions, cancellationToken); if (changesAfterStart != null) { ApplyBraceCompletionResult(changesAfterStart.Value); @@ -193,52 +195,52 @@ public void PreOverType(out bool handledCommand) var closingSnapshotPoint = ClosingPoint.GetPoint(snapshot); - if (!HasForwardTyping && AllowOverType()) + if (HasForwardTyping) { - var caretPos = this.GetCaretPosition(); + return; + } - Debug.Assert(caretPos.HasValue && caretPos.Value.Position < closingSnapshotPoint.Position); + if (!TryGetBraceCompletionContext(out var context, cancellationToken) || + !_service.AllowOverType(context, cancellationToken)) + { + return; + } - // ensure that we are within the session before clearing - if (caretPos.HasValue && caretPos.Value.Position < closingSnapshotPoint.Position && closingSnapshotPoint.Position > 0) - { - using var undo = CreateUndoTransaction(); + var caretPos = this.GetCaretPosition(); - _editorOperations.AddBeforeTextBufferChangePrimitive(); + Debug.Assert(caretPos.HasValue && caretPos.Value.Position < closingSnapshotPoint.Position); - var span = new SnapshotSpan(caretPos.Value, closingSnapshotPoint.Subtract(1)); + // ensure that we are within the session before clearing + if (caretPos.HasValue && caretPos.Value.Position < closingSnapshotPoint.Position && closingSnapshotPoint.Position > 0) + { + using var undo = CreateUndoTransaction(); - using var edit = SubjectBuffer.CreateEdit(); + _editorOperations.AddBeforeTextBufferChangePrimitive(); - edit.Delete(span); + var span = new SnapshotSpan(caretPos.Value, closingSnapshotPoint.Subtract(1)); - if (edit.HasFailedChanges) - { - Debug.Fail("Unable to clear closing brace"); - edit.Cancel(); - undo.Cancel(); - } - else - { - handledCommand = true; + using var edit = SubjectBuffer.CreateEdit(); - edit.ApplyAndLogExceptions(); + edit.Delete(span); - MoveCaretToClosingPoint(); + if (edit.HasFailedChanges) + { + Debug.Fail("Unable to clear closing brace"); + edit.Cancel(); + undo.Cancel(); + } + else + { + handledCommand = true; - _editorOperations.AddAfterTextBufferChangePrimitive(); + edit.ApplyAndLogExceptions(); - undo.Complete(); - } - } - } + MoveCaretToClosingPoint(); - return; + _editorOperations.AddAfterTextBufferChangePrimitive(); - bool AllowOverType() - { - var context = GetBraceCompletionContext(); - return context != null && _service.AllowOverTypeAsync(context.Value, cancellationToken).WaitAndGetResult(cancellationToken); + undo.Complete(); + } } } @@ -279,14 +281,13 @@ public void PostReturn() if (closingSnapshotPoint.Position > 0 && HasNoForwardTyping(this.GetCaretPosition().Value, closingSnapshotPoint.Subtract(1))) { - var context = GetBraceCompletionContext(); - if (context == null) + if (!TryGetBraceCompletionContext(out var context, CancellationToken.None)) { return; } - var indentationOptions = context.Value.Document.GetIndentationOptionsAsync(_globalOptions, CancellationToken.None).WaitAndGetResult(CancellationToken.None); - var changesAfterReturn = _service.GetTextChangeAfterReturnAsync(context.Value, indentationOptions, CancellationToken.None).WaitAndGetResult(CancellationToken.None); + var indentationOptions = SubjectBuffer.GetIndentationOptions(_editorOptionsService, context.Document.LanguageServices, explicitFormat: false); + var changesAfterReturn = _service.GetTextChangeAfterReturn(context, indentationOptions, CancellationToken.None); if (changesAfterReturn != null) { using var caretPreservingTransaction = new CaretPreservingEditTransaction(EditorFeaturesResources.Brace_Completion, _undoHistory, _editorOperations); @@ -390,19 +391,29 @@ private void MoveCaretToClosingPoint() } } - private BraceCompletionContext? GetBraceCompletionContext() + private bool TryGetBraceCompletionContext(out BraceCompletionContext context, CancellationToken cancellationToken) + { + var document = SubjectBuffer.CurrentSnapshot.GetOpenDocumentInCurrentContextWithChanges(); + if (document == null) + { + context = default; + return false; + } + + context = GetBraceCompletionContext(ParsedDocument.CreateSynchronously(document, cancellationToken)); + return true; + } + + private BraceCompletionContext GetBraceCompletionContext(ParsedDocument document) { _threadingContext.ThrowIfNotOnUIThread(); var snapshot = SubjectBuffer.CurrentSnapshot; - var document = snapshot.GetOpenDocumentInCurrentContextWithChanges(); - if (document == null) - return null; - var closingSnapshotPoint = ClosingPoint.GetPosition(snapshot); var openingSnapshotPoint = OpeningPoint.GetPosition(snapshot); // The user is actively typing so the caret position should not be null. var caretPosition = this.GetCaretPosition().Value.Position; + return new BraceCompletionContext(document, openingSnapshotPoint, closingSnapshotPoint, caretPosition); } diff --git a/src/EditorFeatures/Core/AutomaticCompletion/BraceCompletionSessionProvider.cs b/src/EditorFeatures/Core/AutomaticCompletion/BraceCompletionSessionProvider.cs index d1abdc5e9b424..7f9508b4bb1f5 100644 --- a/src/EditorFeatures/Core/AutomaticCompletion/BraceCompletionSessionProvider.cs +++ b/src/EditorFeatures/Core/AutomaticCompletion/BraceCompletionSessionProvider.cs @@ -37,7 +37,7 @@ internal partial class BraceCompletionSessionProvider : IBraceCompletionSessionP private readonly IThreadingContext _threadingContext; private readonly ITextBufferUndoManagerProvider _undoManager; private readonly IEditorOperationsFactoryService _editorOperationsFactoryService; - private readonly IGlobalOptionService _globalOptions; + private readonly EditorOptionsService _editorOptionsService; [ImportingConstructor] [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] @@ -45,12 +45,12 @@ public BraceCompletionSessionProvider( IThreadingContext threadingContext, ITextBufferUndoManagerProvider undoManager, IEditorOperationsFactoryService editorOperationsFactoryService, - IGlobalOptionService globalOptions) + EditorOptionsService editorOptionsService) { _threadingContext = threadingContext; _undoManager = undoManager; _editorOperationsFactoryService = editorOperationsFactoryService; - _globalOptions = globalOptions; + _editorOptionsService = editorOptionsService; } public bool TryCreateSession(ITextView textView, SnapshotPoint openingPoint, char openingBrace, char closingBrace, out IBraceCompletionSession session) @@ -66,14 +66,15 @@ public bool TryCreateSession(ITextView textView, SnapshotPoint openingPoint, cha // Brace completion is (currently) not cancellable. var cancellationToken = CancellationToken.None; - var editorSession = editorSessionFactory.TryGetServiceAsync(document, openingPoint, openingBrace, cancellationToken).WaitAndGetResult(cancellationToken); + var parsedDocument = ParsedDocument.CreateSynchronously(document, cancellationToken); + var editorSession = editorSessionFactory.TryGetService(parsedDocument, openingPoint, openingBrace, cancellationToken); if (editorSession != null) { var undoHistory = _undoManager.GetTextBufferUndoManager(textView.TextBuffer).TextBufferUndoHistory; session = new BraceCompletionSession( textView, openingPoint.Snapshot.TextBuffer, openingPoint, openingBrace, closingBrace, - undoHistory, _editorOperationsFactoryService, - editorSession, _globalOptions, _threadingContext); + undoHistory, _editorOperationsFactoryService, _editorOptionsService, + editorSession, _threadingContext); return true; } } diff --git a/src/EditorFeatures/Core/AutomaticCompletion/IBraceCompletionServiceFactory.cs b/src/EditorFeatures/Core/AutomaticCompletion/IBraceCompletionServiceFactory.cs index 4c5c03440d6c5..35ffe020ab447 100644 --- a/src/EditorFeatures/Core/AutomaticCompletion/IBraceCompletionServiceFactory.cs +++ b/src/EditorFeatures/Core/AutomaticCompletion/IBraceCompletionServiceFactory.cs @@ -11,6 +11,6 @@ namespace Microsoft.CodeAnalysis.AutomaticCompletion { internal interface IBraceCompletionServiceFactory : ILanguageService { - Task TryGetServiceAsync(Document document, int openingPosition, char openingBrace, CancellationToken cancellationToken); + IBraceCompletionService? TryGetService(ParsedDocument document, int openingPosition, char openingBrace, CancellationToken cancellationToken); } } diff --git a/src/EditorFeatures/Core/ChangeSignature/AbstractChangeSignatureCommandHandler.cs b/src/EditorFeatures/Core/ChangeSignature/AbstractChangeSignatureCommandHandler.cs index c4d13cb114611..407a22c414494 100644 --- a/src/EditorFeatures/Core/ChangeSignature/AbstractChangeSignatureCommandHandler.cs +++ b/src/EditorFeatures/Core/ChangeSignature/AbstractChangeSignatureCommandHandler.cs @@ -80,6 +80,9 @@ private bool ExecuteCommand(ITextView textView, ITextBuffer subjectBuffer, Comma var cancellationToken = context.OperationContext.UserCancellationToken; + // TODO: Make asynchronous and avoid expensive semantic operations on UI thread: + // https://github.com/dotnet/roslyn/issues/62135 + // Async operation to determine the change signature var changeSignatureContext = changeSignatureService.GetChangeSignatureContextAsync( document, diff --git a/src/EditorFeatures/Core/Classification/Semantic/AbstractSemanticOrEmbeddedClassificationViewTaggerProvider.cs b/src/EditorFeatures/Core/Classification/Semantic/AbstractSemanticOrEmbeddedClassificationViewTaggerProvider.cs index 3a5182a7814a9..3be71fece5c0d 100644 --- a/src/EditorFeatures/Core/Classification/Semantic/AbstractSemanticOrEmbeddedClassificationViewTaggerProvider.cs +++ b/src/EditorFeatures/Core/Classification/Semantic/AbstractSemanticOrEmbeddedClassificationViewTaggerProvider.cs @@ -111,7 +111,7 @@ protected sealed override Task ProduceTagsAsync( // The LSP client will handle producing tags when running under the LSP editor. // Our tagger implementation should return nothing to prevent conflicts. - var workspaceContextService = document.Project.Solution.Workspace.Services.GetRequiredService(); + var workspaceContextService = document.Project.Solution.Services.GetRequiredService(); if (workspaceContextService?.IsInLspEditorContext() == true) return Task.CompletedTask; diff --git a/src/EditorFeatures/Core/Classification/Semantic/ClassificationUtilities.cs b/src/EditorFeatures/Core/Classification/Semantic/ClassificationUtilities.cs index 7ff88e65af579..2e000f12e457d 100644 --- a/src/EditorFeatures/Core/Classification/Semantic/ClassificationUtilities.cs +++ b/src/EditorFeatures/Core/Classification/Semantic/ClassificationUtilities.cs @@ -15,7 +15,7 @@ using Microsoft.CodeAnalysis.ErrorReporting; using Microsoft.CodeAnalysis.Host; using Microsoft.CodeAnalysis.Internal.Log; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Text; diff --git a/src/EditorFeatures/Core/Classification/Syntactic/SyntacticClassificationTaggerProvider.TagComputer.cs b/src/EditorFeatures/Core/Classification/Syntactic/SyntacticClassificationTaggerProvider.TagComputer.cs index e2122f5cdd902..ef6a14174dfbb 100644 --- a/src/EditorFeatures/Core/Classification/Syntactic/SyntacticClassificationTaggerProvider.TagComputer.cs +++ b/src/EditorFeatures/Core/Classification/Syntactic/SyntacticClassificationTaggerProvider.TagComputer.cs @@ -110,7 +110,7 @@ public TagComputer( public event EventHandler? TagsChanged; private IClassificationService? TryGetClassificationService(ITextSnapshot snapshot) - => _workspace?.Services.GetLanguageServices(snapshot.ContentType)?.GetService(); + => _workspace?.Services.SolutionServices.GetProjectServices(snapshot.ContentType)?.GetService(); #region Workspace Hookup @@ -325,7 +325,7 @@ async ValueTask ComputeChangedSpanAsync() { // If we have syntax available fast path the change computation without async or blocking. if (previousRoot != null && currentRoot != null) - return new(classificationService.ComputeSyntacticChangeRange(currentDocument.Project.Solution.Workspace, previousRoot, currentRoot, _diffTimeout, cancellationToken)); + return new(classificationService.ComputeSyntacticChangeRange(currentDocument.Project.Solution.Services, previousRoot, currentRoot, _diffTimeout, cancellationToken)); // Otherwise, fall back to the language to compute the difference based on the document contents. if (previousDocument != null) @@ -427,7 +427,7 @@ private void AddSyntacticClassificationsForDocument( if (root == null) classificationService.AddSyntacticClassificationsAsync(document, span.Span.ToTextSpan(), tempList, cancellationToken).Wait(cancellationToken); else - classificationService.AddSyntacticClassifications(document.Project.Solution.Workspace, root, span.Span.ToTextSpan(), tempList, cancellationToken); + classificationService.AddSyntacticClassifications(document.Project.Solution.Services, root, span.Span.ToTextSpan(), tempList, cancellationToken); _lastLineCache.Update(span, tempList); classifiedSpans.AddRange(tempList); diff --git a/src/EditorFeatures/Core/CodeActions/CodeActionEditHandlerService.cs b/src/EditorFeatures/Core/CodeActions/CodeActionEditHandlerService.cs index adea3ae0fde1b..3aff8234b2547 100644 --- a/src/EditorFeatures/Core/CodeActions/CodeActionEditHandlerService.cs +++ b/src/EditorFeatures/Core/CodeActions/CodeActionEditHandlerService.cs @@ -100,9 +100,12 @@ public CodeActionEditHandlerService( } public async Task ApplyAsync( - Workspace workspace, Document? fromDocument, + Workspace workspace, + Solution originalSolution, + Document? fromDocument, ImmutableArray operations, - string title, IProgressTracker progressTracker, + string title, + IProgressTracker progressTracker, CancellationToken cancellationToken) { // Much of the work we're going to do will be on the UI thread, so switch there preemptively. @@ -148,7 +151,7 @@ public async Task ApplyAsync( _threadingContext.ThrowIfNotOnUIThread(); applied = await operations.Single().TryApplyAsync( - workspace, progressTracker, cancellationToken).ConfigureAwait(true); + workspace, originalSolution, progressTracker, cancellationToken).ConfigureAwait(true); } catch (Exception ex) when (FatalError.ReportAndPropagateUnlessCanceled(ex, cancellationToken)) { @@ -174,7 +177,7 @@ public async Task ApplyAsync( { // Come back to the UI thread after processing the operations so we can commit the transaction applied = await ProcessOperationsAsync( - workspace, operations, progressTracker, cancellationToken).ConfigureAwait(true); + workspace, originalSolution, operations, progressTracker, cancellationToken).ConfigureAwait(true); } catch (Exception ex) when (FatalError.ReportAndPropagateUnlessCanceled(ex, cancellationToken)) { @@ -265,8 +268,11 @@ await TryNavigateToLocationOrStartRenameSessionAsync( /// if all expected are applied successfully; /// otherwise, . private async Task ProcessOperationsAsync( - Workspace workspace, ImmutableArray operations, - IProgressTracker progressTracker, CancellationToken cancellationToken) + Workspace workspace, + Solution originalSolution, + ImmutableArray operations, + IProgressTracker progressTracker, + CancellationToken cancellationToken) { await this._threadingContext.JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken); @@ -284,7 +290,7 @@ private async Task ProcessOperationsAsync( } _threadingContext.ThrowIfNotOnUIThread(); - applied &= await operation.TryApplyAsync(workspace, progressTracker, cancellationToken).ConfigureAwait(true); + applied &= await operation.TryApplyAsync(workspace, originalSolution, progressTracker, cancellationToken).ConfigureAwait(true); } return applied; diff --git a/src/EditorFeatures/Core/CodeActions/ICodeActionEditHandlerService.cs b/src/EditorFeatures/Core/CodeActions/ICodeActionEditHandlerService.cs index ff34e723b9ed3..846715efef1fa 100644 --- a/src/EditorFeatures/Core/CodeActions/ICodeActionEditHandlerService.cs +++ b/src/EditorFeatures/Core/CodeActions/ICodeActionEditHandlerService.cs @@ -18,9 +18,12 @@ internal interface ICodeActionEditHandlerService Workspace workspace, ImmutableArray operations, CancellationToken cancellationToken); Task ApplyAsync( - Workspace workspace, Document? fromDocument, + Workspace workspace, + Solution originalSolution, + Document? fromDocument, ImmutableArray operations, - string title, IProgressTracker progressTracker, + string title, + IProgressTracker progressTracker, CancellationToken cancellationToken); } } diff --git a/src/EditorFeatures/Core/CodeDefinitionWindow/DefinitionContextTracker.cs b/src/EditorFeatures/Core/CodeDefinitionWindow/DefinitionContextTracker.cs index d5861917efa69..b908ddfb64a85 100644 --- a/src/EditorFeatures/Core/CodeDefinitionWindow/DefinitionContextTracker.cs +++ b/src/EditorFeatures/Core/CodeDefinitionWindow/DefinitionContextTracker.cs @@ -210,7 +210,7 @@ internal async Task> GetContextFrom } else if (_metadataAsSourceFileService.IsNavigableMetadataSymbol(symbol)) { - var options = _globalOptions.GetMetadataAsSourceOptions(document.Project.LanguageServices); + var options = _globalOptions.GetMetadataAsSourceOptions(document.Project.Services); var declarationFile = await _metadataAsSourceFileService.GetGeneratedFileAsync(document.Project, symbol, signaturesOnly: false, options, cancellationToken).ConfigureAwait(false); var identifierSpan = declarationFile.IdentifierLocation.GetLineSpan().Span; return ImmutableArray.Create(new CodeDefinitionWindowLocation(symbol.ToDisplayString(), declarationFile.FilePath, identifierSpan.Start)); diff --git a/src/EditorFeatures/Core/CommentSelection/AbstractCommentSelectionBase.cs b/src/EditorFeatures/Core/CommentSelection/AbstractCommentSelectionBase.cs index 2bbcc7e933097..b0d0434fa6521 100644 --- a/src/EditorFeatures/Core/CommentSelection/AbstractCommentSelectionBase.cs +++ b/src/EditorFeatures/Core/CommentSelection/AbstractCommentSelectionBase.cs @@ -6,6 +6,7 @@ using System; using System.Collections.Generic; +using System.Collections.Immutable; using System.Linq; using System.Threading; using System.Threading.Tasks; @@ -45,19 +46,19 @@ internal abstract class AbstractCommentSelectionBase private readonly ITextUndoHistoryRegistry _undoHistoryRegistry; private readonly IEditorOperationsFactoryService _editorOperationsFactoryService; - private readonly IGlobalOptionService _globalOptions; + private readonly EditorOptionsService _editorOptionsService; internal AbstractCommentSelectionBase( ITextUndoHistoryRegistry undoHistoryRegistry, IEditorOperationsFactoryService editorOperationsFactoryService, - IGlobalOptionService globalOptions) + EditorOptionsService editorOptionsService) { Contract.ThrowIfNull(undoHistoryRegistry); Contract.ThrowIfNull(editorOperationsFactoryService); _undoHistoryRegistry = undoHistoryRegistry; _editorOperationsFactoryService = editorOperationsFactoryService; - _globalOptions = globalOptions; + _editorOptionsService = editorOptionsService; } public abstract string DisplayName { get; } @@ -67,7 +68,7 @@ internal AbstractCommentSelectionBase( protected abstract string GetMessage(TCommand command); // Internal as tests currently rely on this method. - internal abstract Task CollectEditsAsync( + internal abstract CommentSelectionResult CollectEdits( Document document, ICommentSelectionService service, ITextBuffer textBuffer, NormalizedSnapshotSpanCollection selectedSpans, TCommand command, CancellationToken cancellationToken); @@ -111,9 +112,8 @@ internal bool ExecuteCommand(ITextView textView, ITextBuffer subjectBuffer, TCom return true; } - var edits = CollectEditsAsync(document, service, subjectBuffer, selectedSpans, command, cancellationToken).WaitAndGetResult(cancellationToken); - - ApplyEdits(document, textView, subjectBuffer, service, title, edits); + var edits = CollectEdits(document, service, subjectBuffer, selectedSpans, command, cancellationToken); + ApplyEdits(document, textView, subjectBuffer, title, edits, cancellationToken); } return true; @@ -123,37 +123,42 @@ internal bool ExecuteCommand(ITextView textView, ITextBuffer subjectBuffer, TCom /// Applies the requested edits and sets the selection. /// This operation is not cancellable. /// - private void ApplyEdits(Document document, ITextView textView, ITextBuffer subjectBuffer, - ICommentSelectionService service, string title, CommentSelectionResult edits) + private void ApplyEdits(Document document, ITextView textView, ITextBuffer subjectBuffer, string title, CommentSelectionResult edits, CancellationToken cancellationToken) { - // Create tracking spans to track the text changes. - var currentSnapshot = subjectBuffer.CurrentSnapshot; - var trackingSpans = edits.TrackingSpans - .SelectAsArray(textSpan => (originalSpan: textSpan, trackingSpan: CreateTrackingSpan(edits.ResultOperation, currentSnapshot, textSpan.TrackingTextSpan))); + var originalSnapshot = subjectBuffer.CurrentSnapshot; // Apply the text changes. using (var transaction = new CaretPreservingEditTransaction(title, textView, _undoHistoryRegistry, _editorOperationsFactoryService)) { - document.Project.Solution.Workspace.ApplyTextChanges(document.Id, edits.TextChanges.Distinct(), CancellationToken.None); + subjectBuffer.ApplyChanges(edits.TextChanges); transaction.Complete(); } - // Convert the tracking spans into snapshot spans for formatting and selection. - var trackingSnapshotSpans = trackingSpans.Select(s => CreateSnapshotSpan(subjectBuffer.CurrentSnapshot, s.trackingSpan, s.originalSpan)); - - if (trackingSnapshotSpans.Any()) + if (edits.TrackingSpans.Any()) { - if (edits.ResultOperation == Operation.Uncomment) + // Create tracking spans to track the text changes. + var trackingSpans = edits.TrackingSpans + .SelectAsArray(textSpan => (originalSpan: textSpan, trackingSpan: CreateTrackingSpan(edits.ResultOperation, originalSnapshot, textSpan.TrackingTextSpan))); + + // Convert the tracking spans into snapshot spans for formatting and selection. + var trackingSnapshotSpans = trackingSpans.Select(s => CreateSnapshotSpan(subjectBuffer.CurrentSnapshot, s.trackingSpan, s.originalSpan)); + + if (edits.ResultOperation == Operation.Uncomment && document.SupportsSyntaxTree) { // Format the document only during uncomment operations. Use second transaction so it can be undone. using var transaction = new CaretPreservingEditTransaction(title, textView, _undoHistoryRegistry, _editorOperationsFactoryService); - var formattedDocument = Format(service, subjectBuffer.CurrentSnapshot, trackingSnapshotSpans, CancellationToken.None); - if (formattedDocument != null) - { - formattedDocument.Project.Solution.Workspace.ApplyDocumentChanges(formattedDocument, CancellationToken.None); - transaction.Complete(); - } + var newText = subjectBuffer.CurrentSnapshot.AsText(); + var oldSyntaxTree = document.GetSyntaxTreeSynchronously(cancellationToken); + var newRoot = oldSyntaxTree.WithChangedText(newText).GetRoot(cancellationToken); + + var formattingOptions = subjectBuffer.GetSyntaxFormattingOptions(_editorOptionsService, document.Project.Services, explicitFormat: false); + var formattingSpans = trackingSnapshotSpans.Select(change => CommonFormattingHelpers.GetFormattingSpan(newRoot, change.Span.ToTextSpan())); + var formattedChanges = Formatter.GetFormattedTextChanges(newRoot, formattingSpans, document.Project.Solution.Services, formattingOptions, rules: null, cancellationToken); + + subjectBuffer.ApplyChanges(formattedChanges); + + transaction.Complete(); } // Set the multi selection after edits have been applied. @@ -194,19 +199,6 @@ private static SnapshotSpan CreateSnapshotSpan(ITextSnapshot snapshot, ITracking return snapshotSpan; } - private Document Format(ICommentSelectionService service, ITextSnapshot snapshot, IEnumerable changes, CancellationToken cancellationToken) - { - var document = snapshot.GetOpenDocumentInCurrentContextWithChanges(); - if (document == null) - { - return null; - } - - var formattingOptions = document.GetSyntaxFormattingOptionsAsync(_globalOptions, cancellationToken).AsTask().WaitAndGetResult(cancellationToken); - var textSpans = changes.SelectAsArray(change => change.Span.ToTextSpan()); - return service.FormatAsync(document, textSpans, formattingOptions, cancellationToken).WaitAndGetResult(cancellationToken); - } - /// /// Given a set of lines, find the minimum indent of all of the non-blank, non-whitespace lines. /// diff --git a/src/EditorFeatures/Core/CommentSelection/AbstractToggleBlockCommentBase.cs b/src/EditorFeatures/Core/CommentSelection/AbstractToggleBlockCommentBase.cs index 69a30d2d3954c..e88a5991b5afc 100644 --- a/src/EditorFeatures/Core/CommentSelection/AbstractToggleBlockCommentBase.cs +++ b/src/EditorFeatures/Core/CommentSelection/AbstractToggleBlockCommentBase.cs @@ -19,6 +19,7 @@ using Microsoft.CodeAnalysis.Text.Shared.Extensions; using Microsoft.VisualStudio.Commanding; using Microsoft.VisualStudio.Text; +using Microsoft.VisualStudio.Text.Editor; using Microsoft.VisualStudio.Text.Editor.Commanding.Commands; using Microsoft.VisualStudio.Text.Operations; using Roslyn.Utilities; @@ -39,8 +40,8 @@ internal AbstractToggleBlockCommentBase( ITextUndoHistoryRegistry undoHistoryRegistry, IEditorOperationsFactoryService editorOperationsFactoryService, ITextStructureNavigatorSelectorService navigatorSelectorService, - IGlobalOptionService globalOptions) - : base(undoHistoryRegistry, editorOperationsFactoryService, globalOptions) + EditorOptionsService editorOptionsService) + : base(undoHistoryRegistry, editorOperationsFactoryService, editorOptionsService) { _navigatorSelectorService = navigatorSelectorService; } @@ -55,9 +56,8 @@ internal AbstractToggleBlockCommentBase( /// until the last character of the last line in the selection(s) /// /// the comment information for the document. - /// a cancellation token. /// any commented spans relevant to the selection in the document. - protected abstract Task> GetBlockCommentsInDocumentAsync(Document document, ITextSnapshot snapshot, + protected abstract ImmutableArray GetBlockCommentsInDocument(Document document, ITextSnapshot snapshot, TextSpan linesContainingSelections, CommentSelectionInfo commentInfo, CancellationToken cancellationToken); public CommandState GetCommandState(ToggleBlockCommentCommandArgs args) @@ -72,7 +72,7 @@ public bool ExecuteCommand(ToggleBlockCommentCommandArgs args, CommandExecutionC protected override string GetMessage(ValueTuple command) => EditorFeaturesResources.Toggling_block_comment; - internal override async Task CollectEditsAsync(Document document, ICommentSelectionService service, + internal override CommentSelectionResult CollectEdits(Document document, ICommentSelectionService service, ITextBuffer subjectBuffer, NormalizedSnapshotSpanCollection selectedSpans, ValueTuple command, CancellationToken cancellationToken) { using (Logger.LogBlock(FunctionId.CommandHandler_ToggleBlockComment, KeyValueLogMessage.Create(LogType.UserAction, m => @@ -83,24 +83,24 @@ internal override async Task CollectEditsAsync(Document { var navigator = _navigatorSelectorService.GetTextStructureNavigator(subjectBuffer); - var commentInfo = await service.GetInfoAsync(document, selectedSpans.First().Span.ToTextSpan(), cancellationToken).ConfigureAwait(false); + var commentInfo = service.GetInfo(); if (commentInfo.SupportsBlockComment) { - return await ToggleBlockCommentsAsync(document, commentInfo, navigator, selectedSpans, cancellationToken).ConfigureAwait(false); + return ToggleBlockComments(document, commentInfo, navigator, selectedSpans, cancellationToken); } return s_emptyCommentSelectionResult; } } - private async Task ToggleBlockCommentsAsync(Document document, CommentSelectionInfo commentInfo, + private CommentSelectionResult ToggleBlockComments(Document document, CommentSelectionInfo commentInfo, ITextStructureNavigator navigator, NormalizedSnapshotSpanCollection selectedSpans, CancellationToken cancellationToken) { var firstLineAroundSelection = selectedSpans.First().Start.GetContainingLine().Start; var lastLineAroundSelection = selectedSpans.Last().End.GetContainingLine().End; var linesContainingSelection = TextSpan.FromBounds(firstLineAroundSelection, lastLineAroundSelection); - var blockCommentedSpans = await GetBlockCommentsInDocumentAsync( - document, selectedSpans.First().Snapshot, linesContainingSelection, commentInfo, cancellationToken).ConfigureAwait(false); + var blockCommentedSpans = GetBlockCommentsInDocument( + document, selectedSpans.First().Snapshot, linesContainingSelection, commentInfo, cancellationToken); var blockCommentSelections = selectedSpans.SelectAsArray(span => new BlockCommentSelectionHelper(blockCommentedSpans, span)); diff --git a/src/EditorFeatures/Core/CommentSelection/CommentUncommentSelectionCommandHandler.cs b/src/EditorFeatures/Core/CommentSelection/CommentUncommentSelectionCommandHandler.cs index f032bd2ad35c8..8f037f025f73a 100644 --- a/src/EditorFeatures/Core/CommentSelection/CommentUncommentSelectionCommandHandler.cs +++ b/src/EditorFeatures/Core/CommentSelection/CommentUncommentSelectionCommandHandler.cs @@ -19,6 +19,7 @@ using Microsoft.CodeAnalysis.Text.Shared.Extensions; using Microsoft.VisualStudio.Commanding; using Microsoft.VisualStudio.Text; +using Microsoft.VisualStudio.Text.Editor; using Microsoft.VisualStudio.Text.Editor.Commanding.Commands; using Microsoft.VisualStudio.Text.Operations; using Roslyn.Utilities; @@ -38,8 +39,8 @@ internal class CommentUncommentSelectionCommandHandler : public CommentUncommentSelectionCommandHandler( ITextUndoHistoryRegistry undoHistoryRegistry, IEditorOperationsFactoryService editorOperationsFactoryService, - IGlobalOptionService globalOptions) - : base(undoHistoryRegistry, editorOperationsFactoryService, globalOptions) + EditorOptionsService editorOptionsService) + : base(undoHistoryRegistry, editorOperationsFactoryService, editorOptionsService) { } @@ -78,7 +79,7 @@ protected override string GetMessage(Operation operation) => /// /// Internal so that it can be called by unit tests. /// - internal override Task CollectEditsAsync( + internal override CommentSelectionResult CollectEdits( Document document, ICommentSelectionService service, ITextBuffer subjectBuffer, NormalizedSnapshotSpanCollection selectedSpans, Operation operation, CancellationToken cancellationToken) { @@ -88,23 +89,23 @@ internal override Task CollectEditsAsync( { if (operation == Operation.Comment) { - CommentSpan(document, service, span, textChanges, spanTrackingList, cancellationToken); + CommentSpan(service, span, textChanges, spanTrackingList); } else { - UncommentSpan(document, service, span, textChanges, spanTrackingList, cancellationToken); + UncommentSpan(service, span, textChanges, spanTrackingList); } } - return Task.FromResult(new CommentSelectionResult(textChanges.ToArrayAndFree(), spanTrackingList.ToArrayAndFree(), operation)); + return new CommentSelectionResult(textChanges.ToArrayAndFree(), spanTrackingList.ToArrayAndFree(), operation); } /// /// Add the necessary edits to comment out a single span. /// private static void CommentSpan( - Document document, ICommentSelectionService service, SnapshotSpan span, - ArrayBuilder textChanges, ArrayBuilder trackingSpans, CancellationToken cancellationToken) + ICommentSelectionService service, SnapshotSpan span, + ArrayBuilder textChanges, ArrayBuilder trackingSpans) { var (firstLine, lastLine) = DetermineFirstAndLastLine(span); @@ -121,7 +122,7 @@ private static void CommentSpan( } // Get the information from the language as to how they'd like to comment this region. - var commentInfo = service.GetInfoAsync(document, span.Span.ToTextSpan(), cancellationToken).WaitAndGetResult(cancellationToken); + var commentInfo = service.GetInfo(); if (!commentInfo.SupportsBlockComment && !commentInfo.SupportsSingleLineComment) { // Neither type of comment supported. @@ -186,10 +187,10 @@ private static void AddBlockComment(SnapshotSpan span, ArrayBuilder /// Add the necessary edits to uncomment out a single span. /// private static void UncommentSpan( - Document document, ICommentSelectionService service, SnapshotSpan span, - ArrayBuilder textChanges, ArrayBuilder spansToSelect, CancellationToken cancellationToken) + ICommentSelectionService service, SnapshotSpan span, + ArrayBuilder textChanges, ArrayBuilder spansToSelect) { - var info = service.GetInfoAsync(document, span.Span.ToTextSpan(), cancellationToken).WaitAndGetResult(cancellationToken); + var info = service.GetInfo(); // If the selection is exactly a block comment, use it as priority over single line comments. if (info.SupportsBlockComment && TryUncommentExactlyBlockComment(info, span, textChanges, spansToSelect)) diff --git a/src/EditorFeatures/Core/CommentSelection/ToggleBlockCommentCommandHandler.cs b/src/EditorFeatures/Core/CommentSelection/ToggleBlockCommentCommandHandler.cs index d545ad8c0655d..080615dda86ef 100644 --- a/src/EditorFeatures/Core/CommentSelection/ToggleBlockCommentCommandHandler.cs +++ b/src/EditorFeatures/Core/CommentSelection/ToggleBlockCommentCommandHandler.cs @@ -17,6 +17,7 @@ using Microsoft.CodeAnalysis.Text; using Microsoft.VisualStudio.Commanding; using Microsoft.VisualStudio.Text; +using Microsoft.VisualStudio.Text.Editor; using Microsoft.VisualStudio.Text.Operations; namespace Microsoft.CodeAnalysis.CommentSelection @@ -32,15 +33,15 @@ public ToggleBlockCommentCommandHandler( ITextUndoHistoryRegistry undoHistoryRegistry, IEditorOperationsFactoryService editorOperationsFactoryService, ITextStructureNavigatorSelectorService navigatorSelectorService, - IGlobalOptionService globalOptions) - : base(undoHistoryRegistry, editorOperationsFactoryService, navigatorSelectorService, globalOptions) + EditorOptionsService editorOptionsService) + : base(undoHistoryRegistry, editorOperationsFactoryService, navigatorSelectorService, editorOptionsService) { } /// /// Gets block comments by parsing the text for comment markers. /// - protected override Task> GetBlockCommentsInDocumentAsync(Document document, ITextSnapshot snapshot, + protected override ImmutableArray GetBlockCommentsInDocument(Document document, ITextSnapshot snapshot, TextSpan linesContainingSelections, CommentSelectionInfo commentInfo, CancellationToken cancellationToken) { var allText = snapshot.AsText(); @@ -62,7 +63,7 @@ protected override Task> GetBlockCommentsInDocumentAsyn openIdx = closeIdx; } - return Task.FromResult(commentedSpans.ToImmutableAndFree()); + return commentedSpans.ToImmutableAndFree(); } } } diff --git a/src/EditorFeatures/Core/CommentSelection/ToggleLineCommentCommandHandler.cs b/src/EditorFeatures/Core/CommentSelection/ToggleLineCommentCommandHandler.cs index 950b314a00776..5b5a8d60201e6 100644 --- a/src/EditorFeatures/Core/CommentSelection/ToggleLineCommentCommandHandler.cs +++ b/src/EditorFeatures/Core/CommentSelection/ToggleLineCommentCommandHandler.cs @@ -45,8 +45,8 @@ internal class ToggleLineCommentCommandHandler : public ToggleLineCommentCommandHandler( ITextUndoHistoryRegistry undoHistoryRegistry, IEditorOperationsFactoryService editorOperationsFactoryService, - IGlobalOptionService globalOptions) - : base(undoHistoryRegistry, editorOperationsFactoryService, globalOptions) + EditorOptionsService editorOptionsService) + : base(undoHistoryRegistry, editorOperationsFactoryService, editorOptionsService) { } @@ -62,7 +62,7 @@ public bool ExecuteCommand(ToggleLineCommentCommandArgs args, CommandExecutionCo protected override string GetMessage(ValueTuple command) => EditorFeaturesResources.Toggling_line_comment; - internal override async Task CollectEditsAsync(Document document, ICommentSelectionService service, + internal override CommentSelectionResult CollectEdits(Document document, ICommentSelectionService service, ITextBuffer subjectBuffer, NormalizedSnapshotSpanCollection selectedSpans, ValueTuple command, CancellationToken cancellationToken) { using (Logger.LogBlock(FunctionId.CommandHandler_ToggleLineComment, KeyValueLogMessage.Create(LogType.UserAction, m => @@ -71,7 +71,7 @@ internal override async Task CollectEditsAsync(Document m[LengthString] = subjectBuffer.CurrentSnapshot.Length; }), cancellationToken)) { - var commentInfo = await service.GetInfoAsync(document, selectedSpans.First().Span.ToTextSpan(), cancellationToken).ConfigureAwait(false); + var commentInfo = service.GetInfo(); if (commentInfo.SupportsSingleLineComment) { return ToggleLineComment(commentInfo, selectedSpans); diff --git a/src/EditorFeatures/Core/Diagnostics/AbstractDiagnosticsTaggerProvider.cs b/src/EditorFeatures/Core/Diagnostics/AbstractDiagnosticsTaggerProvider.cs index 15050f2abbb9f..8957bc99b76ca 100644 --- a/src/EditorFeatures/Core/Diagnostics/AbstractDiagnosticsTaggerProvider.cs +++ b/src/EditorFeatures/Core/Diagnostics/AbstractDiagnosticsTaggerProvider.cs @@ -24,6 +24,7 @@ using Microsoft.VisualStudio.Text; using Microsoft.VisualStudio.Text.Editor; using Microsoft.VisualStudio.Text.Tagging; +using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Diagnostics { @@ -51,8 +52,7 @@ internal abstract partial class AbstractDiagnosticsTaggerProvider : Asynch /// diagnostics, we don't know how to map the span of the diagnostic to the current snapshot /// we're tagging. /// - private static readonly ConditionalWeakTable _diagnosticIdToTextSnapshot = - new(); + private static readonly ConditionalWeakTable _diagnosticIdToTextSnapshot = new(); protected AbstractDiagnosticsTaggerProvider( IThreadingContext threadingContext, @@ -66,6 +66,11 @@ protected AbstractDiagnosticsTaggerProvider( _diagnosticService.DiagnosticsUpdated += OnDiagnosticsUpdated; } + protected internal abstract bool IsEnabled { get; } + protected internal abstract bool SupportsDignosticMode(DiagnosticMode mode); + protected internal abstract bool IncludeDiagnostic(DiagnosticData data); + protected internal abstract ITagSpan? CreateTagSpan(Workspace workspace, bool isLiveUpdate, SnapshotSpan span, DiagnosticData data); + private void OnDiagnosticsUpdated(object? sender, DiagnosticsUpdatedArgs e) { if (e.Solution == null || e.DocumentId == null) @@ -125,10 +130,6 @@ protected override ITaggerEventSource CreateEventSource(ITextView? textView, ITe TaggerEventSources.OnTextChanged(subjectBuffer)); } - protected internal abstract bool IsEnabled { get; } - protected internal abstract bool IncludeDiagnostic(DiagnosticData data); - protected internal abstract ITagSpan? CreateTagSpan(Workspace workspace, bool isLiveUpdate, SnapshotSpan span, DiagnosticData data); - /// /// Get the that should have the tag applied to it. /// In most cases, this is the but overrides can change it (e.g. unnecessary classifications). @@ -148,15 +149,15 @@ private async Task ProduceTagsAsync( TaggerContext context, DocumentSnapshotSpan spanToTag, CancellationToken cancellationToken) { if (!this.IsEnabled) - { return; - } + + var diagnosticMode = GlobalOptions.GetDiagnosticMode(InternalDiagnosticsOptions.NormalDiagnosticMode); + if (!SupportsDignosticMode(diagnosticMode)) + return; var document = spanToTag.Document; if (document == null) - { return; - } var editorSnapshot = spanToTag.SnapshotSpan.Snapshot; @@ -169,10 +170,12 @@ private async Task ProduceTagsAsync( var suppressedDiagnosticsSpans = (NormalizedSnapshotSpanCollection?)null; buffer?.Properties.TryGetProperty(PredefinedPreviewTaggerKeys.SuppressDiagnosticsSpansKey, out suppressedDiagnosticsSpans); - var diagnosticMode = GlobalOptions.GetDiagnosticMode(InternalDiagnosticsOptions.NormalDiagnosticMode); - - var buckets = _diagnosticService.GetPushDiagnosticBuckets( - workspace, document.Project.Id, document.Id, diagnosticMode, cancellationToken); + var buckets = diagnosticMode switch + { + DiagnosticMode.Pull => _diagnosticService.GetPullDiagnosticBuckets(workspace, document.Project.Id, document.Id, diagnosticMode, cancellationToken), + DiagnosticMode.Push => _diagnosticService.GetPushDiagnosticBuckets(workspace, document.Project.Id, document.Id, diagnosticMode, cancellationToken), + _ => throw ExceptionUtilities.UnexpectedValue(diagnosticMode), + }; foreach (var bucket in buckets) { @@ -257,7 +260,7 @@ private async Task ProduceTagsAsync( { // https://devdiv.visualstudio.com/DefaultCollection/DevDiv/_workitems?id=428328&_a=edit&triage=false // explicitly report NFW to find out what is causing us for out of range. - // stop crashing on such occations + // stop crashing on such occasions return; } diff --git a/src/EditorFeatures/Core/Diagnostics/DiagnosticsClassificationTaggerProvider.cs b/src/EditorFeatures/Core/Diagnostics/DiagnosticsClassificationTaggerProvider.cs index 147ab01f6e250..6ad73f3dfec0d 100644 --- a/src/EditorFeatures/Core/Diagnostics/DiagnosticsClassificationTaggerProvider.cs +++ b/src/EditorFeatures/Core/Diagnostics/DiagnosticsClassificationTaggerProvider.cs @@ -6,8 +6,9 @@ using System.Collections.Generic; using System.Collections.Immutable; using System.ComponentModel.Composition; +using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.IO; -using System.Linq; using System.Runtime.Serialization.Json; using System.Text; using Microsoft.CodeAnalysis.Editor; @@ -15,6 +16,7 @@ using Microsoft.CodeAnalysis.Editor.Shared.Utilities; using Microsoft.CodeAnalysis.ErrorReporting; using Microsoft.CodeAnalysis.Host.Mef; +using Microsoft.CodeAnalysis.LanguageServer.Features.Diagnostics; using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Shared.TestHooks; using Microsoft.CodeAnalysis.Workspaces; @@ -22,7 +24,6 @@ using Microsoft.VisualStudio.Text.Editor; using Microsoft.VisualStudio.Text.Tagging; using Microsoft.VisualStudio.Utilities; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Diagnostics { @@ -36,7 +37,7 @@ internal partial class DiagnosticsClassificationTaggerProvider : AbstractDiagnos private readonly ClassificationTypeMap _typeMap; private readonly ClassificationTag _classificationTag; - private readonly IEditorOptionsFactoryService _editorOptionsFactoryService; + private readonly EditorOptionsService _editorOptionsService; protected override IEnumerable> Options => s_tagSourceOptions; @@ -46,61 +47,63 @@ public DiagnosticsClassificationTaggerProvider( IThreadingContext threadingContext, IDiagnosticService diagnosticService, ClassificationTypeMap typeMap, - IEditorOptionsFactoryService editorOptionsFactoryService, - IGlobalOptionService globalOptions, + EditorOptionsService editorOptionsService, [Import(AllowDefault = true)] ITextBufferVisibilityTracker? visibilityTracker, IAsynchronousOperationListenerProvider listenerProvider) - : base(threadingContext, diagnosticService, globalOptions, visibilityTracker, listenerProvider.GetListener(FeatureAttribute.Classification)) + : base(threadingContext, diagnosticService, editorOptionsService.GlobalOptions, visibilityTracker, listenerProvider.GetListener(FeatureAttribute.Classification)) { _typeMap = typeMap; _classificationTag = new ClassificationTag(_typeMap.GetClassificationType(ClassificationTypeDefinitions.UnnecessaryCode)); - _editorOptionsFactoryService = editorOptionsFactoryService; + _editorOptionsService = editorOptionsService; } // If we are under high contrast mode, the editor ignores classification tags that fade things out, // because that reduces contrast. Since the editor will ignore them, there's no reason to produce them. protected internal override bool IsEnabled - => !_editorOptionsFactoryService.GlobalOptions.GetOptionValue(DefaultTextViewHostOptions.IsInContrastModeId); + => !_editorOptionsService.Factory.GlobalOptions.GetOptionValue(DefaultTextViewHostOptions.IsInContrastModeId); + + protected internal override bool SupportsDignosticMode(DiagnosticMode mode) + { + // We only support push diagnostics. When pull diagnostics are on, diagnostic fading is handled by the lsp client. + return mode == DiagnosticMode.Push; + } protected internal override bool IncludeDiagnostic(DiagnosticData data) - => data.CustomTags.Contains(WellKnownDiagnosticTags.Unnecessary); + { + if (!data.CustomTags.Contains(WellKnownDiagnosticTags.Unnecessary)) + { + // All unnecessary code diagnostics should have the 'Unnecessary' custom tag. + // Below assert ensures that we do no report unnecessary code diagnostics that + // want to fade out multiple locations which are encoded as + // additional location indices in the diagnostic's property bag + // without the 'Unnecessary' custom tag. + Debug.Assert(!data.TryGetUnnecessaryLocationIndices(out _)); + + return false; + } + + // Do not fade if user has disabled the fading option corresponding to this diagnostic. + if (IDEDiagnosticIdToOptionMappingHelper.TryGetMappedFadingOption(data.Id, out var fadingOption)) + { + return data.Language != null + && _editorOptionsService.GlobalOptions.GetOption(fadingOption, data.Language); + } + + return true; + } protected internal override ITagSpan CreateTagSpan(Workspace workspace, bool isLiveUpdate, SnapshotSpan span, DiagnosticData data) => new TagSpan(span, _classificationTag); protected internal override ImmutableArray GetLocationsToTag(DiagnosticData diagnosticData) { - // If there are 'unnecessary' locations specified in the property bag, use those instead of the main diagnostic location. - if (diagnosticData.AdditionalLocations.Length > 0 - && diagnosticData.Properties != null - && diagnosticData.Properties.TryGetValue(WellKnownDiagnosticTags.Unnecessary, out var unnecessaryIndices) - && unnecessaryIndices is object) + if (diagnosticData.TryGetUnnecessaryDataLocations(out var locationsToTag)) { - using var _ = PooledObjects.ArrayBuilder.GetInstance(out var locationsToTag); - - foreach (var index in GetLocationIndices(unnecessaryIndices)) - locationsToTag.Add(diagnosticData.AdditionalLocations[index]); - - return locationsToTag.ToImmutable(); + return locationsToTag.Value; } // Default to the base implementation for the diagnostic data return base.GetLocationsToTag(diagnosticData); - - static IEnumerable GetLocationIndices(string indicesProperty) - { - try - { - using var stream = new MemoryStream(Encoding.UTF8.GetBytes(indicesProperty)); - var serializer = new DataContractJsonSerializer(typeof(IEnumerable)); - var result = serializer.ReadObject(stream) as IEnumerable; - return result ?? Array.Empty(); - } - catch (Exception e) when (FatalError.ReportAndCatch(e)) - { - return ImmutableArray.Empty; - } - } } } } diff --git a/src/EditorFeatures/Core/Diagnostics/DiagnosticsSquiggleTaggerProvider.cs b/src/EditorFeatures/Core/Diagnostics/DiagnosticsSquiggleTaggerProvider.cs index 01d7cfe7d7237..02b28ad345eb0 100644 --- a/src/EditorFeatures/Core/Diagnostics/DiagnosticsSquiggleTaggerProvider.cs +++ b/src/EditorFeatures/Core/Diagnostics/DiagnosticsSquiggleTaggerProvider.cs @@ -44,6 +44,12 @@ public DiagnosticsSquiggleTaggerProvider( { } + protected internal override bool SupportsDignosticMode(DiagnosticMode mode) + { + // We only support push diagnostics. When pull diagnostics are on, squiggles are handled by the lsp client. + return mode == DiagnosticMode.Push; + } + protected internal override bool IncludeDiagnostic(DiagnosticData diagnostic) { var isUnnecessary = diagnostic.Severity == DiagnosticSeverity.Hidden && diagnostic.CustomTags.Contains(WellKnownDiagnosticTags.Unnecessary); diff --git a/src/EditorFeatures/Core/Diagnostics/DiagnosticsSuggestionTaggerProvider.cs b/src/EditorFeatures/Core/Diagnostics/DiagnosticsSuggestionTaggerProvider.cs index 597101c20fffb..0779cb93ff45f 100644 --- a/src/EditorFeatures/Core/Diagnostics/DiagnosticsSuggestionTaggerProvider.cs +++ b/src/EditorFeatures/Core/Diagnostics/DiagnosticsSuggestionTaggerProvider.cs @@ -24,7 +24,7 @@ namespace Microsoft.CodeAnalysis.Diagnostics [ContentType(ContentTypeNames.RoslynContentType)] [ContentType(ContentTypeNames.XamlContentType)] [TagType(typeof(IErrorTag))] - internal partial class DiagnosticsSuggestionTaggerProvider : + internal sealed partial class DiagnosticsSuggestionTaggerProvider : AbstractDiagnosticsAdornmentTaggerProvider { private static readonly IEnumerable> s_tagSourceOptions = @@ -47,6 +47,13 @@ public DiagnosticsSuggestionTaggerProvider( protected internal override bool IncludeDiagnostic(DiagnosticData diagnostic) => diagnostic.Severity == DiagnosticSeverity.Info; + protected internal override bool SupportsDignosticMode(DiagnosticMode mode) + { + // We only support push diagnostics. When pull diagnostics are on, ellipses suggestions are handled by the + // lsp client. + return mode == DiagnosticMode.Push; + } + protected override IErrorTag CreateTag(Workspace workspace, DiagnosticData diagnostic) => new ErrorTag( PredefinedErrorTypeNames.HintedSuggestion, diff --git a/src/EditorFeatures/Core/DocumentationComments/AbstractDocumentationCommentCommandHandler.cs b/src/EditorFeatures/Core/DocumentationComments/AbstractDocumentationCommentCommandHandler.cs index 1f4e7eb6da94d..2aa4bacfe494d 100644 --- a/src/EditorFeatures/Core/DocumentationComments/AbstractDocumentationCommentCommandHandler.cs +++ b/src/EditorFeatures/Core/DocumentationComments/AbstractDocumentationCommentCommandHandler.cs @@ -30,13 +30,13 @@ internal abstract class AbstractDocumentationCommentCommandHandler : private readonly IUIThreadOperationExecutor _uiThreadOperationExecutor; private readonly ITextUndoHistoryRegistry _undoHistoryRegistry; private readonly IEditorOperationsFactoryService _editorOperationsFactoryService; - private readonly IGlobalOptionService _globalOptions; + private readonly EditorOptionsService _editorOptionsService; protected AbstractDocumentationCommentCommandHandler( IUIThreadOperationExecutor uiThreadOperationExecutor, ITextUndoHistoryRegistry undoHistoryRegistry, IEditorOperationsFactoryService editorOperationsFactoryService, - IGlobalOptionService globalOptions) + EditorOptionsService editorOptionsService) { Contract.ThrowIfNull(uiThreadOperationExecutor); Contract.ThrowIfNull(undoHistoryRegistry); @@ -45,7 +45,7 @@ protected AbstractDocumentationCommentCommandHandler( _uiThreadOperationExecutor = uiThreadOperationExecutor; _undoHistoryRegistry = undoHistoryRegistry; _editorOperationsFactoryService = editorOperationsFactoryService; - _globalOptions = globalOptions; + _editorOptionsService = editorOptionsService; } protected abstract string ExteriorTriviaText { get; } @@ -92,16 +92,15 @@ private bool CompleteComment( } var service = document.GetRequiredLanguageService(); - var syntaxTree = document.GetRequiredSyntaxTreeSynchronously(cancellationToken); - var text = syntaxTree.GetText(cancellationToken); - var options = document.GetDocumentationCommentOptionsAsync(_globalOptions, cancellationToken).AsTask().WaitAndGetResult(cancellationToken); + var parsedDocument = ParsedDocument.CreateSynchronously(document, cancellationToken); + var options = subjectBuffer.GetDocumentationCommentOptions(_editorOptionsService, document.Project.Services); // Apply snippet in reverse order so that the first applied snippet doesn't affect span of next snippets. var snapshots = textView.Selection.GetSnapshotSpansOnBuffer(subjectBuffer).OrderByDescending(s => s.Span.Start); var returnValue = false; foreach (var snapshot in snapshots) { - var snippet = getSnippetAction(service, syntaxTree, text, snapshot.Span.Start, options, cancellationToken); + var snippet = getSnippetAction(service, parsedDocument.SyntaxTree, parsedDocument.Text, snapshot.Span.Start, options, cancellationToken); if (snippet != null) { ApplySnippet(snippet, subjectBuffer, textView); @@ -170,7 +169,7 @@ public bool ExecuteCommand(ReturnKeyCommandArgs args, CommandExecutionContext co return false; } - if (!CurrentLineStartsWithExteriorTrivia(args.SubjectBuffer, originalPosition)) + if (!CurrentLineStartsWithExteriorTrivia(args.SubjectBuffer, originalPosition, context.OperationContext.UserCancellationToken)) { return false; } @@ -246,7 +245,7 @@ public void ExecuteCommand(OpenLineAboveCommandArgs args, Action nextHandler, Co return; } - if (!CurrentLineStartsWithExteriorTrivia(subjectBuffer, caretPosition)) + if (!CurrentLineStartsWithExteriorTrivia(subjectBuffer, caretPosition, context.OperationContext.UserCancellationToken)) { nextHandler(); return; @@ -263,7 +262,7 @@ public void ExecuteCommand(OpenLineAboveCommandArgs args, Action nextHandler, Co var service = document.GetRequiredLanguageService(); - InsertExteriorTriviaIfNeeded(service, args.TextView, subjectBuffer); + InsertExteriorTriviaIfNeeded(service, args.TextView, subjectBuffer, context.OperationContext.UserCancellationToken); } public CommandState GetCommandState(OpenLineBelowCommandArgs args, Func nextHandler) @@ -282,7 +281,7 @@ public void ExecuteCommand(OpenLineBelowCommandArgs args, Action nextHandler, Co return; } - if (!CurrentLineStartsWithExteriorTrivia(subjectBuffer, caretPosition)) + if (!CurrentLineStartsWithExteriorTrivia(subjectBuffer, caretPosition, context.OperationContext.UserCancellationToken)) { nextHandler(); return; @@ -299,10 +298,10 @@ public void ExecuteCommand(OpenLineBelowCommandArgs args, Action nextHandler, Co // Allow nextHandler() to run and the insert exterior trivia if necessary. nextHandler(); - InsertExteriorTriviaIfNeeded(service, args.TextView, subjectBuffer); + InsertExteriorTriviaIfNeeded(service, args.TextView, subjectBuffer, context.OperationContext.UserCancellationToken); } - private void InsertExteriorTriviaIfNeeded(IDocumentationCommentSnippetService service, ITextView textView, ITextBuffer subjectBuffer) + private void InsertExteriorTriviaIfNeeded(IDocumentationCommentSnippetService service, ITextView textView, ITextBuffer subjectBuffer, CancellationToken cancellationToken) { var caretPosition = textView.GetCaretPoint(subjectBuffer) ?? -1; if (caretPosition < 0) @@ -316,27 +315,25 @@ private void InsertExteriorTriviaIfNeeded(IDocumentationCommentSnippetService se return; } - var text = document - .GetTextAsync(CancellationToken.None) - .WaitAndGetResult(CancellationToken.None); + var parsedDocument = ParsedDocument.CreateSynchronously(document, cancellationToken); // We only insert exterior trivia if the current line does not start with exterior trivia // and the previous line does. - var currentLine = text.Lines.GetLineFromPosition(caretPosition); + var currentLine = parsedDocument.Text.Lines.GetLineFromPosition(caretPosition); if (currentLine.LineNumber <= 0) { return; } - var previousLine = text.Lines[currentLine.LineNumber - 1]; + var previousLine = parsedDocument.Text.Lines[currentLine.LineNumber - 1]; if (LineStartsWithExteriorTrivia(currentLine) || !LineStartsWithExteriorTrivia(previousLine)) { return; } - var options = document.GetDocumentationCommentOptionsAsync(_globalOptions, CancellationToken.None).AsTask().WaitAndGetResult(CancellationToken.None); + var options = subjectBuffer.GetDocumentationCommentOptions(_editorOptionsService, document.Project.Services); var snippet = service.GetDocumentationCommentSnippetFromPreviousLine(options, currentLine, previousLine); if (snippet != null) @@ -345,7 +342,7 @@ private void InsertExteriorTriviaIfNeeded(IDocumentationCommentSnippetService se } } - private bool CurrentLineStartsWithExteriorTrivia(ITextBuffer subjectBuffer, int position) + private bool CurrentLineStartsWithExteriorTrivia(ITextBuffer subjectBuffer, int position, CancellationToken cancellationToken) { var document = subjectBuffer.CurrentSnapshot.GetOpenDocumentInCurrentContextWithChanges(); if (document == null) @@ -353,11 +350,8 @@ private bool CurrentLineStartsWithExteriorTrivia(ITextBuffer subjectBuffer, int return false; } - var text = document - .GetTextAsync(CancellationToken.None) - .WaitAndGetResult(CancellationToken.None); - - var currentLine = text.Lines.GetLineFromPosition(position); + var parsedDocument = ParsedDocument.CreateSynchronously(document, cancellationToken); + var currentLine = parsedDocument.Text.Lines.GetLineFromPosition(position); return LineStartsWithExteriorTrivia(currentLine); } diff --git a/src/EditorFeatures/Core/EditAndContinue/ActiveStatementTaggerProvider.cs b/src/EditorFeatures/Core/EditAndContinue/ActiveStatementTaggerProvider.cs index 6e243b1a36b85..5b2844f20aa6a 100644 --- a/src/EditorFeatures/Core/EditAndContinue/ActiveStatementTaggerProvider.cs +++ b/src/EditorFeatures/Core/EditAndContinue/ActiveStatementTaggerProvider.cs @@ -75,7 +75,7 @@ protected override async Task ProduceTagsAsync( return; } - var activeStatementTrackingService = document.Project.Solution.Workspace.Services.GetService(); + var activeStatementTrackingService = document.Project.Solution.Services.GetService(); if (activeStatementTrackingService == null) { return; diff --git a/src/EditorFeatures/Core/EditAndContinue/Contracts/ContractWrappers.cs b/src/EditorFeatures/Core/EditAndContinue/Contracts/ContractWrappers.cs index 0c2090809e4e2..061377ca9e06b 100644 --- a/src/EditorFeatures/Core/EditAndContinue/Contracts/ContractWrappers.cs +++ b/src/EditorFeatures/Core/EditAndContinue/Contracts/ContractWrappers.cs @@ -25,20 +25,21 @@ public static Contracts.SourceSpan ToContract(this SourceSpan id) public static Contracts.ManagedHotReloadAvailability ToContract(this ManagedHotReloadAvailability value) => new((Contracts.ManagedHotReloadAvailabilityStatus)value.Status, value.LocalizedMessage); - public static ManagedModuleUpdates FromContract(this Contracts.ManagedModuleUpdates updates) - => new((ManagedModuleUpdateStatus)updates.Status, updates.Updates.SelectAsArray(FromContract)); - - public static ManagedModuleUpdate FromContract(this Contracts.ManagedModuleUpdate update) + public static ManagedHotReloadUpdate FromContract(this ModuleUpdate update) => new( - update.Module, - update.ILDelta, - update.MetadataDelta, - update.PdbDelta, - update.SequencePoints.SelectAsArray(FromContract), - update.UpdatedMethods, - update.UpdatedTypes, - update.ActiveStatements.SelectAsArray(FromContract), - update.ExceptionRegions.SelectAsArray(FromContract)); + module: update.Module, + ilDelta: update.ILDelta, + metadataDelta: update.MetadataDelta, + pdbDelta: update.PdbDelta, + updatedTypes: update.UpdatedTypes, + requiredCapabilities: update.RequiredCapabilities.ToStringArray(), + updatedMethods: update.UpdatedMethods, + sequencePoints: update.SequencePoints.SelectAsArray(FromContract), + activeStatements: update.ActiveStatements.SelectAsArray(FromContract), + exceptionRegions: update.ExceptionRegions.SelectAsArray(FromContract)); + + public static ImmutableArray FromContract(this ImmutableArray diagnostics) + => diagnostics.SelectAsArray(FromContract); public static SequencePointUpdates FromContract(this Contracts.SequencePointUpdates updates) => new(updates.FileName, updates.LineUpdates.SelectAsArray(FromContract)); diff --git a/src/EditorFeatures/Core/EditAndContinue/DebuggerContractVersionCheck.cs b/src/EditorFeatures/Core/EditAndContinue/DebuggerContractVersionCheck.cs index 93b8c909d9ae1..7a2af33e64f6c 100644 --- a/src/EditorFeatures/Core/EditAndContinue/DebuggerContractVersionCheck.cs +++ b/src/EditorFeatures/Core/EditAndContinue/DebuggerContractVersionCheck.cs @@ -9,8 +9,7 @@ namespace Microsoft.CodeAnalysis.EditAndContinue { /// - /// Temporaroly needed to allow us to run integration tests on older VS than build that has the required version of Microsoft.VisualStudio.Debugger.Contracts. - /// TODO: Remove (https://github.com/dotnet/roslyn/issues/56742) + /// Allow us to run integration tests on older VS than build that has the required version of Microsoft.VisualStudio.Debugger.Contracts. /// internal static class DebuggerContractVersionCheck { @@ -29,6 +28,6 @@ public static bool IsRequiredDebuggerContractVersionAvailable() [MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.NoOptimization)] private static Type LoadContracts() - => typeof(ManagedHotReloadAvailability); + => typeof(ManagedActiveStatementUpdate); } } diff --git a/src/EditorFeatures/Core/EditAndContinue/EditAndContinueLanguageService.cs b/src/EditorFeatures/Core/EditAndContinue/EditAndContinueLanguageService.cs index ec49f53b391be..70d90cecc94f9 100644 --- a/src/EditorFeatures/Core/EditAndContinue/EditAndContinueLanguageService.cs +++ b/src/EditorFeatures/Core/EditAndContinue/EditAndContinueLanguageService.cs @@ -26,9 +26,6 @@ namespace Microsoft.CodeAnalysis.EditAndContinue [ExportMetadata("UIContext", EditAndContinueUIContext.EncCapableProjectExistsInWorkspaceUIContextString)] internal sealed class EditAndContinueLanguageService : IManagedHotReloadLanguageService, IEditAndContinueSolutionProvider { - private static readonly ActiveStatementSpanProvider s_noActiveStatementSpanProvider = - (_, _, _) => ValueTaskFactory.FromResult(ImmutableArray.Empty); - private readonly Lazy _debuggerService; private readonly IDiagnosticAnalyzerService _diagnosticService; private readonly EditAndContinueDiagnosticUpdateSource _diagnosticUpdateSource; @@ -293,29 +290,7 @@ await EditSession.HasChangesAsync(oldSolution, newSolution, sourceFilePath, canc } } - public async ValueTask GetEditAndContinueUpdatesAsync(CancellationToken cancellationToken) - { - if (_disabled) - { - return new ManagedModuleUpdates(ManagedModuleUpdateStatus.None, ImmutableArray.Empty); - } - - var workspace = WorkspaceProvider.Value.Workspace; - var designTimeSolution = workspace.CurrentSolution; - var solution = GetCurrentCompileTimeSolution(designTimeSolution); - var activeStatementSpanProvider = GetActiveStatementSpanProvider(solution); - var (updates, _, _, _) = await GetDebuggingSession().EmitSolutionUpdateAsync(solution, activeStatementSpanProvider, _diagnosticService, _diagnosticUpdateSource, cancellationToken).ConfigureAwait(false); - - // Only store the solution if we have any changes to apply, otherwise CommitUpdatesAsync/DiscardUpdatesAsync won't be called. - if (updates.Status == Contracts.ManagedModuleUpdateStatus.Ready) - { - _pendingUpdatedDesignTimeSolution = designTimeSolution; - } - - return updates.FromContract(); - } - - public async ValueTask GetHotReloadUpdatesAsync(CancellationToken cancellationToken) + public async ValueTask GetUpdatesAsync(CancellationToken cancellationToken) { if (_disabled) { @@ -325,20 +300,17 @@ public async ValueTask GetHotReloadUpdatesAsync(Cancell var workspace = WorkspaceProvider.Value.Workspace; var designTimeSolution = workspace.CurrentSolution; var solution = GetCurrentCompileTimeSolution(designTimeSolution); - var (moduleUpdates, diagnosticData, rudeEdits, syntaxError) = await GetDebuggingSession().EmitSolutionUpdateAsync(solution, s_noActiveStatementSpanProvider, _diagnosticService, _diagnosticUpdateSource, cancellationToken).ConfigureAwait(false); + var activeStatementSpanProvider = GetActiveStatementSpanProvider(solution); + var (moduleUpdates, diagnosticData, rudeEdits, syntaxError) = await GetDebuggingSession().EmitSolutionUpdateAsync(solution, activeStatementSpanProvider, _diagnosticService, _diagnosticUpdateSource, cancellationToken).ConfigureAwait(false); // Only store the solution if we have any changes to apply, otherwise CommitUpdatesAsync/DiscardUpdatesAsync won't be called. - if (moduleUpdates.Status == Contracts.ManagedModuleUpdateStatus.Ready) + if (moduleUpdates.Status == ModuleUpdateStatus.Ready) { _pendingUpdatedDesignTimeSolution = designTimeSolution; } - var updates = moduleUpdates.Updates.SelectAsArray( - update => new ManagedHotReloadUpdate(update.Module, update.ILDelta, update.MetadataDelta, update.PdbDelta, update.UpdatedTypes)); - - var diagnostics = await EmitSolutionUpdateResults.GetHotReloadDiagnosticsAsync(solution, diagnosticData, rudeEdits, syntaxError, cancellationToken).ConfigureAwait(false); - - return new ManagedHotReloadUpdates(updates, diagnostics.FromContract()); + var diagnostics = await EmitSolutionUpdateResults.GetHotReloadDiagnosticsAsync(solution, diagnosticData, rudeEdits, syntaxError, moduleUpdates.Status, cancellationToken).ConfigureAwait(false); + return new ManagedHotReloadUpdates(moduleUpdates.Updates.FromContract(), diagnostics.FromContract()); } public async ValueTask GetCurrentActiveStatementPositionAsync(ManagedInstructionId instruction, CancellationToken cancellationToken) diff --git a/src/EditorFeatures/Core/Editor/GoToAdjacentMemberCommandHandler.cs b/src/EditorFeatures/Core/Editor/GoToAdjacentMemberCommandHandler.cs index 5022e9b1a1ecb..96c87f1bfb141 100644 --- a/src/EditorFeatures/Core/Editor/GoToAdjacentMemberCommandHandler.cs +++ b/src/EditorFeatures/Core/Editor/GoToAdjacentMemberCommandHandler.cs @@ -11,7 +11,7 @@ using System.Threading.Tasks; using Microsoft.CodeAnalysis.Editor.Shared.Extensions; using Microsoft.CodeAnalysis.Host.Mef; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Text; using Microsoft.VisualStudio.Commanding; @@ -80,17 +80,17 @@ private bool ExecuteCommandImpl(EditorCommandArgs args, bool gotoNextMember, Com } var document = subjectBuffer.CurrentSnapshot.GetOpenDocumentInCurrentContextWithChanges(); - if (document?.SupportsSyntaxTree != true) + var syntaxFactsService = document?.GetLanguageService(); + if (syntaxFactsService == null) { return false; } int? targetPosition = null; - using (context.OperationContext.AddScope(allowCancellation: true, description: EditorFeaturesResources.Navigating)) { - var task = GetTargetPositionAsync(document, caretPoint.Value.Position, gotoNextMember, context.OperationContext.UserCancellationToken); - targetPosition = task.WaitAndGetResult(context.OperationContext.UserCancellationToken); + var root = document.GetSyntaxRootSynchronously(context.OperationContext.UserCancellationToken); + targetPosition = GetTargetPosition(syntaxFactsService, root, caretPoint.Value.Position, gotoNextMember); } if (targetPosition != null) @@ -104,16 +104,9 @@ private bool ExecuteCommandImpl(EditorCommandArgs args, bool gotoNextMember, Com /// /// Internal for testing purposes. /// - internal static async Task GetTargetPositionAsync(Document document, int caretPosition, bool next, CancellationToken cancellationToken) + internal static int? GetTargetPosition(ISyntaxFactsService service, SyntaxNode root, int caretPosition, bool next) { - var syntaxFactsService = document.GetLanguageService(); - if (syntaxFactsService == null) - { - return null; - } - - var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(true); - var members = syntaxFactsService.GetMethodLevelMembers(root); + var members = service.GetMethodLevelMembers(root); if (members.Count == 0) { return null; diff --git a/src/EditorFeatures/Core/Editor/IContainedDocument.cs b/src/EditorFeatures/Core/Editor/IContainedDocument.cs new file mode 100644 index 0000000000000..04e76db9e5894 --- /dev/null +++ b/src/EditorFeatures/Core/Editor/IContainedDocument.cs @@ -0,0 +1,17 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Collections.Generic; +using System.Text; +using Microsoft.CodeAnalysis.Host; +using Microsoft.CodeAnalysis.Text; +using Microsoft.VisualStudio.Text; + +namespace Microsoft.CodeAnalysis.Editor; + +internal interface IContainedDocument +{ + public ITextSnapshot ApplyChanges(IEnumerable changes); +} diff --git a/src/EditorFeatures/Core/EditorConfigSettings/Data/Whitespace/PerLanguageWhitespaceSetting.cs b/src/EditorFeatures/Core/EditorConfigSettings/Data/Whitespace/PerLanguageWhitespaceSetting.cs index 3079c44230617..77d0452a7f447 100644 --- a/src/EditorFeatures/Core/EditorConfigSettings/Data/Whitespace/PerLanguageWhitespaceSetting.cs +++ b/src/EditorFeatures/Core/EditorConfigSettings/Data/Whitespace/PerLanguageWhitespaceSetting.cs @@ -62,7 +62,7 @@ public PerLanguageWhitespaceSetting(PerLanguageOption2 option, public override string Category => _option.Group.Description; public override Type Type => typeof(T); - public override OptionKey2 Key => new(_option, _option.OptionDefinition.IsPerLanguage ? Language ?? LanguageNames.CSharp : null); + public override OptionKey2 Key => new(_option, Language ?? LanguageNames.CSharp); public override bool IsDefinedInEditorConfig => _editorConfigOptions.TryGetEditorConfigOption(_option, out _); diff --git a/src/EditorFeatures/Core/EditorConfigSettings/Data/Whitespace/WhitespaceSetting`1.cs b/src/EditorFeatures/Core/EditorConfigSettings/Data/Whitespace/WhitespaceSetting`1.cs index c5e0cb7d2c5ac..5d1e30bf2aee0 100644 --- a/src/EditorFeatures/Core/EditorConfigSettings/Data/Whitespace/WhitespaceSetting`1.cs +++ b/src/EditorFeatures/Core/EditorConfigSettings/Data/Whitespace/WhitespaceSetting`1.cs @@ -47,7 +47,7 @@ private set public override Type Type => typeof(T); public override string Category => _option.Group.Description; - public override OptionKey2 Key => new(_option, _option.OptionDefinition.IsPerLanguage ? Language ?? LanguageNames.CSharp : null); + public override OptionKey2 Key => new(_option); private readonly Option2 _option; private readonly AnalyzerConfigOptions _options; diff --git a/src/EditorFeatures/Core/EditorConfigSettings/Updater/SettingsUpdateHelper.cs b/src/EditorFeatures/Core/EditorConfigSettings/Updater/SettingsUpdateHelper.cs index a0e19b5577dd7..79669b1405d87 100644 --- a/src/EditorFeatures/Core/EditorConfigSettings/Updater/SettingsUpdateHelper.cs +++ b/src/EditorFeatures/Core/EditorConfigSettings/Updater/SettingsUpdateHelper.cs @@ -87,7 +87,26 @@ internal static partial class SettingsUpdateHelper optionValue = $"{optionValue}:{severity}"; } - var language = option.IsPerLanguage ? Language.CSharp | Language.VisualBasic : Language.CSharp; + Language language; + if (option is ISingleValuedOption singleValuedOption) + { + language = singleValuedOption.LanguageName switch + { + LanguageNames.CSharp => Language.CSharp, + LanguageNames.VisualBasic => Language.VisualBasic, + null => Language.CSharp | Language.VisualBasic, + _ => throw ExceptionUtilities.UnexpectedValue(singleValuedOption.LanguageName), + }; + } + else if (option is IPerLanguageValuedOption perLanguageValuedOption) + { + language = Language.CSharp | Language.VisualBasic; + } + else + { + throw ExceptionUtilities.UnexpectedValue(option); + } + return (true, optionName, optionValue, language); } } diff --git a/src/EditorFeatures/Core/Extensibility/BraceMatching/BraceMatchingOptionsStorage.cs b/src/EditorFeatures/Core/Extensibility/BraceMatching/BraceMatchingOptionsStorage.cs index 401ad0c30d4ec..2c4f2738714f1 100644 --- a/src/EditorFeatures/Core/Extensibility/BraceMatching/BraceMatchingOptionsStorage.cs +++ b/src/EditorFeatures/Core/Extensibility/BraceMatching/BraceMatchingOptionsStorage.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +using Microsoft.CodeAnalysis.BraceMatching; using Microsoft.CodeAnalysis.DocumentHighlighting; using Microsoft.CodeAnalysis.Options; diff --git a/src/EditorFeatures/Core/Extensibility/NavigationBar/AbstractEditorNavigationBarItemService.cs b/src/EditorFeatures/Core/Extensibility/NavigationBar/AbstractEditorNavigationBarItemService.cs index 5aa4cc1f8600e..ab34ba9e49605 100644 --- a/src/EditorFeatures/Core/Extensibility/NavigationBar/AbstractEditorNavigationBarItemService.cs +++ b/src/EditorFeatures/Core/Extensibility/NavigationBar/AbstractEditorNavigationBarItemService.cs @@ -27,10 +27,14 @@ protected AbstractEditorNavigationBarItemService(IThreadingContext threadingCont protected abstract Task TryNavigateToItemAsync(Document document, WrappedNavigationBarItem item, ITextView textView, ITextVersion textVersion, CancellationToken cancellationToken); - public async Task> GetItemsAsync(Document document, bool forceFrozenPartialSemanticsForCrossProcessOperations, ITextVersion textVersion, CancellationToken cancellationToken) + public async Task> GetItemsAsync( + Document document, + bool workspaceSupportsDocumentChanges, + bool forceFrozenPartialSemanticsForCrossProcessOperations, + ITextVersion textVersion, + CancellationToken cancellationToken) { var service = document.GetRequiredLanguageService(); - var workspaceSupportsDocumentChanges = document.Project.Solution.Workspace.CanApplyChange(ApplyChangesKind.ChangeDocument); var items = await service.GetItemsAsync(document, workspaceSupportsDocumentChanges, forceFrozenPartialSemanticsForCrossProcessOperations, cancellationToken).ConfigureAwait(false); return items.SelectAsArray(v => (NavigationBarItem)new WrappedNavigationBarItem(textVersion, v)); } diff --git a/src/EditorFeatures/Core/Extensibility/NavigationBar/INavigationBarItemService.cs b/src/EditorFeatures/Core/Extensibility/NavigationBar/INavigationBarItemService.cs index e5db68b5e70f9..bdcf0ed3c19b9 100644 --- a/src/EditorFeatures/Core/Extensibility/NavigationBar/INavigationBarItemService.cs +++ b/src/EditorFeatures/Core/Extensibility/NavigationBar/INavigationBarItemService.cs @@ -13,7 +13,12 @@ namespace Microsoft.CodeAnalysis.Editor { internal interface INavigationBarItemService : ILanguageService { - Task> GetItemsAsync(Document document, bool forceFrozenPartialSemanticsForCrossProcessOperations, ITextVersion textVersion, CancellationToken cancellationToken); + Task> GetItemsAsync( + Document document, + bool workspaceSupportsDocumentChanges, + bool forceFrozenPartialSemanticsForCrossProcessOperations, + ITextVersion textVersion, + CancellationToken cancellationToken); bool ShowItemGrayedIfNear(NavigationBarItem item); /// diff --git a/src/EditorFeatures/Core/ExternalAccess/IntelliCode/IntentProcessor.cs b/src/EditorFeatures/Core/ExternalAccess/IntelliCode/IntentProcessor.cs index 179fd30c48f0e..eb967d7eca186 100644 --- a/src/EditorFeatures/Core/ExternalAccess/IntelliCode/IntentProcessor.cs +++ b/src/EditorFeatures/Core/ExternalAccess/IntelliCode/IntentProcessor.cs @@ -130,7 +130,7 @@ public async Task> ComputeIntentsAsync(IntentReques var changedDocument = changedSolution.GetRequiredDocument(changedDocumentId); var currentDocument = currentSolution.GetRequiredDocument(changedDocumentId); - var textDiffService = changedSolution.Workspace.Services.GetRequiredService(); + var textDiffService = changedSolution.Services.GetRequiredService(); // Compute changes against the current version of the document. var textDiffs = await textDiffService.GetTextChangesAsync(currentDocument, changedDocument, cancellationToken).ConfigureAwait(false); if (textDiffs.IsEmpty) diff --git a/src/EditorFeatures/Core/ExternalAccess/UnitTestGenerator/Api/UnitTestGeneratorAddMissingImportsFeatureServiceAccessor.cs b/src/EditorFeatures/Core/ExternalAccess/UnitTestGenerator/Api/UnitTestGeneratorAddMissingImportsFeatureServiceAccessor.cs new file mode 100644 index 0000000000000..68d8063ed1998 --- /dev/null +++ b/src/EditorFeatures/Core/ExternalAccess/UnitTestGenerator/Api/UnitTestGeneratorAddMissingImportsFeatureServiceAccessor.cs @@ -0,0 +1,66 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Collections.Immutable; +using System.Composition; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.AddMissingImports; +using Microsoft.CodeAnalysis.CodeCleanup; +using Microsoft.CodeAnalysis.Completion; +using Microsoft.CodeAnalysis.Host.Mef; +using Microsoft.CodeAnalysis.Options; +using Microsoft.CodeAnalysis.Shared.Extensions; +using Microsoft.CodeAnalysis.Text; + +namespace Microsoft.CodeAnalysis.ExternalAccess.UnitTestGenerator.Api; + +[Export] +[Shared] +internal class UnitTestGeneratorAddMissingImportsFeatureServiceAccessor +{ + private readonly IGlobalOptionService _globalOptions; + + [ImportingConstructor] + [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] + public UnitTestGeneratorAddMissingImportsFeatureServiceAccessor(IGlobalOptionService globalOptions) + { + _globalOptions = globalOptions; + } + + internal async Task AddMissingImportsAsync(Document document, TextSpan textSpan, CancellationToken cancellationToken) + { + var options = await GetOptionsAsync(document, cancellationToken).ConfigureAwait(false); + var service = document.Project.GetRequiredLanguageService(); + return await service.AddMissingImportsAsync(document, textSpan, options, cancellationToken).ConfigureAwait(false); + } + + internal async Task AnalyzeAsync(Document document, TextSpan textSpan, CancellationToken cancellationToken) + { + var options = await GetOptionsAsync(document, cancellationToken).ConfigureAwait(false); + var service = document.Project.GetRequiredLanguageService(); + var result = await service.AnalyzeAsync(document, textSpan, options, cancellationToken).ConfigureAwait(false); + return new WrappedMissingImportsAnalysisResult(result.AddImportFixData.SelectAsArray(data => new WrappedAddImportFixData(data))); + } + + internal async Task AddMissingImportsAsync(Document document, WrappedMissingImportsAnalysisResult analysisResult, CancellationToken cancellationToken) + { + var options = await GetOptionsAsync(document, cancellationToken).ConfigureAwait(false); + var service = document.Project.GetRequiredLanguageService(); + var unwrappedResult = new AddMissingImportsAnalysisResult(analysisResult.AddImportFixDatas.SelectAsArray(result => result.Underlying)); + return await service.AddMissingImportsAsync(document, unwrappedResult, options.CleanupOptions.FormattingOptions, cancellationToken).ConfigureAwait(false); + } + + private async Task GetOptionsAsync(Document document, CancellationToken cancellationToken) + { + var cleanupOptions = await document.GetCodeCleanupOptionsAsync(_globalOptions, cancellationToken).ConfigureAwait(false); + + var options = new AddMissingImportsOptions( + CleanupOptions: cleanupOptions, + HideAdvancedMembers: _globalOptions.GetOption(CompletionOptionsStorage.HideAdvancedMembers, document.Project.Language)); + + return options; + } +} diff --git a/src/EditorFeatures/Core/ExternalAccess/UnitTestGenerator/Api/UnitTestGeneratorOrganizeImportsAccessor.cs b/src/EditorFeatures/Core/ExternalAccess/UnitTestGenerator/Api/UnitTestGeneratorOrganizeImportsAccessor.cs new file mode 100644 index 0000000000000..736c4e1123b6e --- /dev/null +++ b/src/EditorFeatures/Core/ExternalAccess/UnitTestGenerator/Api/UnitTestGeneratorOrganizeImportsAccessor.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 System.Collections.Generic; +using System.Composition; +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; + +namespace Microsoft.CodeAnalysis.ExternalAccess.UnitTestGenerator.Api; + +[Export] +[Shared] +internal class UnitTestGeneratorOrganizeImportsAccessor +{ + private readonly IGlobalOptionService _globalOptions; + + [ImportingConstructor] + [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] + public UnitTestGeneratorOrganizeImportsAccessor(IGlobalOptionService globalOptions) + { + _globalOptions = globalOptions; + } + + public async Task OrganizeImportsAsync(Document document, CancellationToken cancellationToken) + { + var organizeImportsService = document.GetRequiredLanguageService(); + var options = await document.GetOrganizeImportsOptionsAsync(_globalOptions, cancellationToken).ConfigureAwait(false); + return await organizeImportsService.OrganizeImportsAsync(document, options, cancellationToken).ConfigureAwait(false); + } +} diff --git a/src/EditorFeatures/Core/ExternalAccess/UnitTestGenerator/Api/WrappedAddImportFixData.cs b/src/EditorFeatures/Core/ExternalAccess/UnitTestGenerator/Api/WrappedAddImportFixData.cs new file mode 100644 index 0000000000000..327fc9d38048a --- /dev/null +++ b/src/EditorFeatures/Core/ExternalAccess/UnitTestGenerator/Api/WrappedAddImportFixData.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.Collections.Immutable; +using Microsoft.CodeAnalysis.AddImport; +using Microsoft.CodeAnalysis.Text; +using Roslyn.Utilities; + +namespace Microsoft.CodeAnalysis.ExternalAccess.UnitTestGenerator.Api; + +internal sealed class WrappedAddImportFixData +{ + internal readonly AddImportFixData Underlying; + + public WrappedAddImportFixKind Kind => Underlying.Kind switch + { + AddImportFixKind.ProjectSymbol => WrappedAddImportFixKind.ProjectSymbol, + AddImportFixKind.PackageSymbol => WrappedAddImportFixKind.PackageSymbol, + AddImportFixKind.MetadataSymbol => WrappedAddImportFixKind.MetadataSymbol, + AddImportFixKind.ReferenceAssemblySymbol => WrappedAddImportFixKind.ReferenceAssemblySymbol, + _ => throw ExceptionUtilities.UnexpectedValue(Underlying.Kind), + }; + + public ImmutableArray TextChanges => Underlying.TextChanges; + + public string Title => Underlying.Title; + + public ImmutableArray Tags => Underlying.Tags; + + #region When adding P2P references. + + public ProjectId ProjectReferenceToAdd => Underlying.ProjectReferenceToAdd; + + #endregion + + #region When adding a metadata reference + + public ProjectId PortableExecutableReferenceProjectId => Underlying.PortableExecutableReferenceProjectId; + + public string PortableExecutableReferenceFilePathToAdd => Underlying.PortableExecutableReferenceFilePathToAdd; + + #endregion + + #region When adding an assembly reference + + public string AssemblyReferenceAssemblyName => Underlying.AssemblyReferenceAssemblyName; + + public string AssemblyReferenceFullyQualifiedTypeName => Underlying.AssemblyReferenceFullyQualifiedTypeName; + + #endregion + + #region When adding a package reference + + public string PackageSource => Underlying.PackageSource; + + public string PackageName => Underlying.PackageName; + + public string PackageVersionOpt => Underlying.PackageVersionOpt; + + #endregion + + internal WrappedAddImportFixData(AddImportFixData underlying) + { + Underlying = underlying; + } +} diff --git a/src/EditorFeatures/Core/ExternalAccess/UnitTestGenerator/Api/WrappedAddImportFixKind.cs b/src/EditorFeatures/Core/ExternalAccess/UnitTestGenerator/Api/WrappedAddImportFixKind.cs new file mode 100644 index 0000000000000..bdea6ff47cfca --- /dev/null +++ b/src/EditorFeatures/Core/ExternalAccess/UnitTestGenerator/Api/WrappedAddImportFixKind.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. + +namespace Microsoft.CodeAnalysis.ExternalAccess.UnitTestGenerator.Api; + +internal enum WrappedAddImportFixKind +{ + ProjectSymbol, + MetadataSymbol, + PackageSymbol, + ReferenceAssemblySymbol, +} diff --git a/src/EditorFeatures/Core/ExternalAccess/UnitTestGenerator/Api/WrappedMissingImportsAnalysisResult.cs b/src/EditorFeatures/Core/ExternalAccess/UnitTestGenerator/Api/WrappedMissingImportsAnalysisResult.cs new file mode 100644 index 0000000000000..207beb88402e5 --- /dev/null +++ b/src/EditorFeatures/Core/ExternalAccess/UnitTestGenerator/Api/WrappedMissingImportsAnalysisResult.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.Collections.Immutable; +using Microsoft.CodeAnalysis.AddMissingImports; + +namespace Microsoft.CodeAnalysis.ExternalAccess.UnitTestGenerator.Api; + +internal sealed class WrappedMissingImportsAnalysisResult +{ + public ImmutableArray AddImportFixDatas; + + public WrappedMissingImportsAnalysisResult(ImmutableArray addImportFixDatas) + { + AddImportFixDatas = addImportFixDatas; + } +} diff --git a/src/EditorFeatures/Core/ExternalAccess/VSTypeScript/Api/VSTypeScriptInlineRenameInfo.cs b/src/EditorFeatures/Core/ExternalAccess/VSTypeScript/Api/VSTypeScriptInlineRenameInfo.cs index 1e6ca0a8e1a4f..4aaa1b227d345 100644 --- a/src/EditorFeatures/Core/ExternalAccess/VSTypeScript/Api/VSTypeScriptInlineRenameInfo.cs +++ b/src/EditorFeatures/Core/ExternalAccess/VSTypeScript/Api/VSTypeScriptInlineRenameInfo.cs @@ -57,5 +57,8 @@ bool IInlineRenameInfo.TryOnAfterGlobalSymbolRenamed(Workspace workspace, IEnume bool IInlineRenameInfo.TryOnBeforeGlobalSymbolRenamed(Workspace workspace, IEnumerable changedDocumentIDs, string replacementText) => true; + + public InlineRenameFileRenameInfo GetFileRenameInfo() + => InlineRenameFileRenameInfo.NotAllowed; } } diff --git a/src/EditorFeatures/Core/ExternalAccess/VSTypeScript/VSTypeScriptBraceMatcher.cs b/src/EditorFeatures/Core/ExternalAccess/VSTypeScript/VSTypeScriptBraceMatcher.cs index fb9f3ef7dedd7..24f67b527572f 100644 --- a/src/EditorFeatures/Core/ExternalAccess/VSTypeScript/VSTypeScriptBraceMatcher.cs +++ b/src/EditorFeatures/Core/ExternalAccess/VSTypeScript/VSTypeScriptBraceMatcher.cs @@ -3,16 +3,17 @@ // See the LICENSE file in the project root for more information. using System; -using System.ComponentModel.Composition; +using System.Composition; using System.Threading; using System.Threading.Tasks; +using Microsoft.CodeAnalysis.BraceMatching; using Microsoft.CodeAnalysis.Editor; using Microsoft.CodeAnalysis.ExternalAccess.VSTypeScript.Api; using Microsoft.CodeAnalysis.Host.Mef; namespace Microsoft.CodeAnalysis.ExternalAccess.VSTypeScript { - [ExportBraceMatcher(InternalLanguageNames.TypeScript)] + [ExportBraceMatcher(InternalLanguageNames.TypeScript), Shared] internal sealed class VSTypeScriptBraceMatcher : IBraceMatcher { private readonly IVSTypeScriptBraceMatcherImplementation _impl; diff --git a/src/EditorFeatures/Core/ExternalAccess/VSTypeScript/VSTypeScriptNavigationBarItemService.cs b/src/EditorFeatures/Core/ExternalAccess/VSTypeScript/VSTypeScriptNavigationBarItemService.cs index 8bd7fe75c8f9a..b8864629dc139 100644 --- a/src/EditorFeatures/Core/ExternalAccess/VSTypeScript/VSTypeScriptNavigationBarItemService.cs +++ b/src/EditorFeatures/Core/ExternalAccess/VSTypeScript/VSTypeScriptNavigationBarItemService.cs @@ -38,11 +38,16 @@ public VSTypeScriptNavigationBarItemService( public Task> GetItemsAsync( Document document, ITextVersion textVersion, CancellationToken cancellationToken) { - return ((INavigationBarItemService)this).GetItemsAsync(document, forceFrozenPartialSemanticsForCrossProcessOperations: false, textVersion, cancellationToken); + return ((INavigationBarItemService)this).GetItemsAsync( + document, workspaceSupportsDocumentChanges: true, forceFrozenPartialSemanticsForCrossProcessOperations: false, textVersion, cancellationToken); } async Task> INavigationBarItemService.GetItemsAsync( - Document document, bool forceFrozenPartialSemanticsForCrossProcessOperations, ITextVersion textVersion, CancellationToken cancellationToken) + Document document, + bool workspaceSupportsDocumentChanges, + bool forceFrozenPartialSemanticsForCrossProcessOperations, + ITextVersion textVersion, + CancellationToken cancellationToken) { var items = await _service.GetItemsAsync(document, cancellationToken).ConfigureAwait(false); return ConvertItems(items, textVersion); diff --git a/src/EditorFeatures/Core/ExtractMethod/ExtractMethodCommandHandler.cs b/src/EditorFeatures/Core/ExtractMethod/ExtractMethodCommandHandler.cs index 57e0733c499e1..65e32f123563a 100644 --- a/src/EditorFeatures/Core/ExtractMethod/ExtractMethodCommandHandler.cs +++ b/src/EditorFeatures/Core/ExtractMethod/ExtractMethodCommandHandler.cs @@ -3,6 +3,8 @@ // See the LICENSE file in the project root for more information. using System; +using System.Collections; +using System.Collections.Generic; using System.ComponentModel.Composition; using System.Linq; using System.Reflection.Metadata; @@ -22,6 +24,7 @@ using Microsoft.CodeAnalysis.Text; using Microsoft.CodeAnalysis.Text.Shared.Extensions; using Microsoft.VisualStudio.Commanding; +using Microsoft.VisualStudio.OLE.Interop; using Microsoft.VisualStudio.Shell.Interop; using Microsoft.VisualStudio.Text; using Microsoft.VisualStudio.Text.Editor; @@ -121,7 +124,7 @@ private async Task ExecuteAsync( SnapshotSpan span) { _threadingContext.ThrowIfNotOnUIThread(); - var indicatorFactory = document.Project.Solution.Workspace.Services.GetRequiredService(); + var indicatorFactory = document.Project.Solution.Services.GetRequiredService(); using var indicatorContext = indicatorFactory.Create( view, span, EditorFeaturesResources.Applying_Extract_Method_refactoring, cancelOnEdit: true, cancelOnFocusLost: true); @@ -155,7 +158,7 @@ private async Task ExecuteWorkerAsync( document, span, result, options, cancellationToken).ConfigureAwait(false); if (newResult != null) { - var notificationService = document.Project.Solution.Workspace.Services.GetService(); + var notificationService = document.Project.Solution.Services.GetService(); if (notificationService != null) { // We are about to show a modal UI dialog so we should take over the command execution @@ -189,10 +192,11 @@ private async Task ExecuteWorkerAsync( var cleanupOptions = await document.GetCodeCleanupOptionsAsync(_globalOptions, cancellationToken).ConfigureAwait(false); var (formattedDocument, methodNameAtInvocation) = await result.GetFormattedDocumentAsync(cleanupOptions, cancellationToken).ConfigureAwait(false); + var changes = await formattedDocument.GetTextChangesAsync(document, cancellationToken).ConfigureAwait(false); await _threadingContext.JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken); - ApplyChange_OnUIThread(formattedDocument, textBuffer, waitContext); + ApplyChange_OnUIThread(textBuffer, changes, waitContext); // start inline rename to allow the user to change the name if they want. var textSnapshot = textBuffer.CurrentSnapshot; @@ -206,17 +210,15 @@ private async Task ExecuteWorkerAsync( } private void ApplyChange_OnUIThread( - Document formattedDocument, ITextBuffer textBuffer, IBackgroundWorkIndicatorContext waitContext) + ITextBuffer textBuffer, IEnumerable changes, IBackgroundWorkIndicatorContext waitContext) { _threadingContext.ThrowIfNotOnUIThread(); - var cancellationToken = waitContext.UserCancellationToken; - using var undoTransaction = _undoManager.GetTextBufferUndoManager(textBuffer).TextBufferUndoHistory.CreateTransaction("Extract Method"); // We're about to make an edit ourselves. so disable the cancellation that happens on editing. waitContext.CancelOnEdit = false; - formattedDocument.Project.Solution.Workspace.ApplyDocumentChanges(formattedDocument, cancellationToken); + textBuffer.ApplyChanges(changes); // apply changes undoTransaction.Complete(); @@ -235,7 +237,7 @@ private async Task TryNotifyFailureToUserAsync( // and also will take it into consideration when measuring command handling duration. var project = document.Project; var solution = project.Solution; - var notificationService = solution.Workspace.Services.GetService(); + var notificationService = solution.Services.GetService(); // see whether we will allow best effort extraction and if it is possible. if (!_globalOptions.GetOption(ExtractMethodPresentationOptionsStorage.AllowBestEffort, document.Project.Language) || diff --git a/src/EditorFeatures/Core/Formatting/FormatCommandHandler.Paste.cs b/src/EditorFeatures/Core/Formatting/FormatCommandHandler.Paste.cs index 088612034526f..6cf6e63a4698b 100644 --- a/src/EditorFeatures/Core/Formatting/FormatCommandHandler.Paste.cs +++ b/src/EditorFeatures/Core/Formatting/FormatCommandHandler.Paste.cs @@ -51,50 +51,41 @@ public void ExecuteCommand(PasteCommandArgs args, Action nextHandler, CommandExe private void ExecuteCommandWorker(PasteCommandArgs args, SnapshotPoint? caretPosition, CancellationToken cancellationToken) { if (!caretPosition.HasValue) + return; + + var subjectBuffer = args.SubjectBuffer; + if (!subjectBuffer.TryGetWorkspace(out var workspace) || + !workspace.CanApplyChange(ApplyChangesKind.ChangeDocument)) { return; } - var document = args.SubjectBuffer.CurrentSnapshot.GetOpenDocumentInCurrentContextWithChanges(); + var document = subjectBuffer.CurrentSnapshot.GetOpenDocumentInCurrentContextWithChanges(); if (document == null) - { return; - } if (!_globalOptions.GetOption(FormattingOptionsMetadata.FormatOnPaste, document.Project.Language)) - { return; - } var solution = document.Project.Solution; - if (!solution.Workspace.CanApplyChange(ApplyChangesKind.ChangeDocument)) - { - return; - } - - var services = solution.Workspace.Services; + var services = solution.Services; var formattingRuleService = services.GetService(); if (formattingRuleService != null && formattingRuleService.ShouldNotFormatOrCommitOnPaste(document.Id)) - { return; - } var formattingService = document.GetLanguageService(); if (formattingService == null || !formattingService.SupportsFormatOnPaste) - { return; - } var trackingSpan = caretPosition.Value.Snapshot.CreateTrackingSpan(caretPosition.Value.Position, 0, SpanTrackingMode.EdgeInclusive); - var span = trackingSpan.GetSpan(args.SubjectBuffer.CurrentSnapshot).Span.ToTextSpan(); + var span = trackingSpan.GetSpan(subjectBuffer.CurrentSnapshot).Span.ToTextSpan(); - var changes = formattingService.GetFormattingChangesOnPasteAsync(document, args.SubjectBuffer, span, cancellationToken).WaitAndGetResult(cancellationToken); + // Note: C# always completes synchronously, TypeScript is async + var changes = formattingService.GetFormattingChangesOnPasteAsync(document, subjectBuffer, span, cancellationToken).WaitAndGetResult(cancellationToken); if (changes.IsEmpty) - { return; - } - solution.Workspace.ApplyTextChanges(document.Id, changes, cancellationToken); + subjectBuffer.ApplyChanges(changes); } } } diff --git a/src/EditorFeatures/Core/Formatting/FormatCommandHandler.cs b/src/EditorFeatures/Core/Formatting/FormatCommandHandler.cs index 9405b0b68e399..c71e2384819e8 100644 --- a/src/EditorFeatures/Core/Formatting/FormatCommandHandler.cs +++ b/src/EditorFeatures/Core/Formatting/FormatCommandHandler.cs @@ -4,6 +4,7 @@ using System; using System.Collections.Generic; +using System.Collections.Immutable; using System.ComponentModel.Composition; using System.Linq; using System.Threading; @@ -67,33 +68,28 @@ private void Format(ITextView textView, ITextBuffer textBuffer, Document documen using (Logger.LogBlock(FunctionId.CommandHandler_FormatCommand, KeyValueLogMessage.Create(LogType.UserAction, m => m["Span"] = selectionOpt?.Length ?? -1), cancellationToken)) using (var transaction = CreateEditTransaction(textView, EditorFeaturesResources.Formatting)) { + // Note: C# always completes synchronously, TypeScript is async var changes = formattingService.GetFormattingChangesAsync(document, textBuffer, selectionOpt, cancellationToken).WaitAndGetResult(cancellationToken); if (changes.IsEmpty) { return; } - ApplyChanges(document, changes, selectionOpt, cancellationToken); - transaction.Complete(); - } - } - - private static void ApplyChanges(Document document, IList changes, TextSpan? selectionOpt, CancellationToken cancellationToken) - { - if (selectionOpt.HasValue) - { - var ruleFactory = document.Project.Solution.Workspace.Services.GetRequiredService(); + if (selectionOpt.HasValue) + { + var ruleFactory = document.Project.Solution.Services.GetRequiredService(); + changes = ruleFactory.FilterFormattedChanges(document.Id, selectionOpt.Value, changes).ToImmutableArray(); + } - changes = ruleFactory.FilterFormattedChanges(document.Id, selectionOpt.Value, changes).ToList(); - if (changes.Count == 0) + if (!changes.IsEmpty) { - return; + using (Logger.LogBlock(FunctionId.Formatting_ApplyResultToBuffer, cancellationToken)) + { + textBuffer.ApplyChanges(changes); + } } - } - using (Logger.LogBlock(FunctionId.Formatting_ApplyResultToBuffer, cancellationToken)) - { - document.Project.Solution.Workspace.ApplyTextChanges(document.Id, changes, cancellationToken); + transaction.Complete(); } } @@ -161,6 +157,7 @@ private void ExecuteReturnOrTypeCommandWorker(EditorCommandArgs args, Cancellati return; } + // Note: C# always completes synchronously, TypeScript is async textChanges = service.GetFormattingChangesOnReturnAsync(document, caretPosition.Value, cancellationToken).WaitAndGetResult(cancellationToken); } else if (args is TypeCharCommandArgs typeCharArgs) @@ -170,6 +167,7 @@ private void ExecuteReturnOrTypeCommandWorker(EditorCommandArgs args, Cancellati return; } + // Note: C# always completes synchronously, TypeScript is async textChanges = service.GetFormattingChangesAsync( document, typeCharArgs.SubjectBuffer, typeCharArgs.TypedChar, caretPosition.Value, cancellationToken).WaitAndGetResult(cancellationToken); } @@ -186,7 +184,7 @@ private void ExecuteReturnOrTypeCommandWorker(EditorCommandArgs args, Cancellati using (var transaction = CreateEditTransaction(textView, EditorFeaturesResources.Automatic_Formatting)) { transaction.MergePolicy = AutomaticCodeChangeMergePolicy.Instance; - document.Project.Solution.Workspace.ApplyTextChanges(document.Id, textChanges, cancellationToken); + subjectBuffer.ApplyChanges(textChanges); transaction.Complete(); } @@ -197,7 +195,7 @@ private void ExecuteReturnOrTypeCommandWorker(EditorCommandArgs args, Cancellati return; } - var snapshotAfterFormatting = args.SubjectBuffer.CurrentSnapshot; + var snapshotAfterFormatting = subjectBuffer.CurrentSnapshot; var oldCaretPosition = caretPosition.Value.TranslateTo(snapshotAfterFormatting, PointTrackingMode.Negative); var newCaretPosition = newCaretPositionMarker.Value.TranslateTo(snapshotAfterFormatting, PointTrackingMode.Negative); diff --git a/src/EditorFeatures/Core/Formatting/IndentationManagerExtensions.cs b/src/EditorFeatures/Core/Formatting/IndentationManagerExtensions.cs deleted file mode 100644 index 35f97053a2ff6..0000000000000 --- a/src/EditorFeatures/Core/Formatting/IndentationManagerExtensions.cs +++ /dev/null @@ -1,41 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using System.Threading; -using System.Threading.Tasks; -using Microsoft.CodeAnalysis.CodeActions; -using Microsoft.CodeAnalysis.Diagnostics; -using Microsoft.CodeAnalysis.Host; -using Microsoft.CodeAnalysis.Options; -using Microsoft.CodeAnalysis.Text; -using Microsoft.VisualStudio.Text; -using Microsoft.VisualStudio.Text.Editor; - -namespace Microsoft.CodeAnalysis.Formatting -{ - internal static class IndentationManagerExtensions - { - public static SyntaxFormattingOptions GetInferredFormattingOptions( - this IIndentationManagerService indentationManager, - ITextBuffer textBuffer, - IEditorOptionsFactoryService editorOptionsFactory, - HostLanguageServices languageServices, - SyntaxFormattingOptions fallbackOptions, - bool explicitFormat) - { - var configOptions = new EditorAnalyzerConfigOptions(editorOptionsFactory.GetOptions(textBuffer)); - var options = configOptions.GetSyntaxFormattingOptions(fallbackOptions, languageServices); - - indentationManager.GetIndentation(textBuffer, explicitFormat, out var convertTabsToSpaces, out var tabSize, out var indentSize); - - return options.With(new LineFormattingOptions() - { - UseTabs = !convertTabsToSpaces, - IndentationSize = indentSize, - TabSize = tabSize, - NewLine = options.NewLine - }); - } - } -} diff --git a/src/EditorFeatures/Core/GoToDefinition/AbstractGoToCommandHandler`2.cs b/src/EditorFeatures/Core/GoToDefinition/AbstractGoToCommandHandler`2.cs index 7f149dd8f3b06..5bb648b414aac 100644 --- a/src/EditorFeatures/Core/GoToDefinition/AbstractGoToCommandHandler`2.cs +++ b/src/EditorFeatures/Core/GoToDefinition/AbstractGoToCommandHandler`2.cs @@ -259,7 +259,7 @@ private async Task FindResultsAsync( // Let the user know in the FAR window if results may be inaccurate because this is running prior to the // solution being fully loaded. - var service = document.Project.Solution.Workspace.Services.GetRequiredService(); + var service = document.Project.Solution.Services.GetRequiredService(); var isFullyLoaded = await service.IsFullyLoadedAsync(cancellationToken).ConfigureAwait(false); if (!isFullyLoaded) { diff --git a/src/EditorFeatures/Core/GoToDefinition/AbstractGoToDefinitionService.cs b/src/EditorFeatures/Core/GoToDefinition/AbstractGoToDefinitionService.cs index 8bc75b94f633d..16cd5062eebd2 100644 --- a/src/EditorFeatures/Core/GoToDefinition/AbstractGoToDefinitionService.cs +++ b/src/EditorFeatures/Core/GoToDefinition/AbstractGoToDefinitionService.cs @@ -11,7 +11,7 @@ using Microsoft.CodeAnalysis.Editor.Host; using Microsoft.CodeAnalysis.Editor.Shared.Utilities; using Microsoft.CodeAnalysis.FindUsages; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Navigation; using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Shared.Extensions; @@ -54,7 +54,7 @@ protected AbstractAsyncGoToDefinitionService( } // Try to compute the referenced symbol and attempt to go to definition for the symbol. - var (symbol, _) = await symbolService.GetSymbolAndBoundSpanAsync( + var (symbol, project, _) = await symbolService.GetSymbolProjectAndBoundSpanAsync( document, position, includeType: true, cancellationToken).ConfigureAwait(false); if (symbol is null) return null; @@ -62,7 +62,7 @@ protected AbstractAsyncGoToDefinitionService( // if the symbol only has a single source location, and we're already on it, // try to see if there's a better symbol we could navigate to. var remappedLocation = await GetAlternativeLocationIfAlreadyOnDefinitionAsync( - document, position, symbol, cancellationToken).ConfigureAwait(false); + project, position, symbol, originalDocument: document, cancellationToken).ConfigureAwait(false); if (remappedLocation != null) return remappedLocation; @@ -71,17 +71,21 @@ protected AbstractAsyncGoToDefinitionService( return await GoToDefinitionHelpers.GetDefinitionLocationAsync( symbol, - document.Project.Solution, + project.Solution, _threadingContext, _streamingPresenter, thirdPartyNavigationAllowed: isThirdPartyNavigationAllowed, cancellationToken: cancellationToken).ConfigureAwait(false); } + /// + /// Attempts to find a better definition for the symbol, if the user is already on the definition of it. + /// + /// The project context to use for finding symbols + /// The document the user is navigating from. This may not be part of the project supplied. private async Task GetAlternativeLocationIfAlreadyOnDefinitionAsync( - Document document, int position, ISymbol symbol, CancellationToken cancellationToken) + Project project, int position, ISymbol symbol, Document originalDocument, CancellationToken cancellationToken) { - var project = document.Project; var solution = project.Solution; var sourceLocations = symbol.Locations.WhereAsArray(loc => loc.IsInSource); @@ -94,7 +98,7 @@ protected AbstractAsyncGoToDefinitionService( var definitionTree = definitionLocation.SourceTree; var definitionDocument = solution.GetDocument(definitionTree); - if (definitionDocument != document) + if (definitionDocument != originalDocument) return null; // Ok, we were already on the definition. Look for better symbols we could show results diff --git a/src/EditorFeatures/Core/GoToDefinition/AbstractGoToSymbolService.cs b/src/EditorFeatures/Core/GoToDefinition/AbstractGoToSymbolService.cs index 1bbc820c4cb23..6e436f50f5fdd 100644 --- a/src/EditorFeatures/Core/GoToDefinition/AbstractGoToSymbolService.cs +++ b/src/EditorFeatures/Core/GoToDefinition/AbstractGoToSymbolService.cs @@ -22,14 +22,14 @@ public async Task GetSymbolsAsync(GoToSymbolContext context) // [includeType: false] // Enable Ctrl+Click on tokens with aliased, referenced or declared symbol. // If the token has none of those but does have a type (mostly literals), we're not interested - var (symbol, span) = await service.GetSymbolAndBoundSpanAsync(document, position, includeType: false, cancellationToken).ConfigureAwait(false); + var (symbol, project, span) = await service.GetSymbolProjectAndBoundSpanAsync(document, position, includeType: false, cancellationToken).ConfigureAwait(false); if (symbol == null) { return; } - var solution = document.Project.Solution; + var solution = project.Solution; var definitions = await GoToDefinitionHelpers.GetDefinitionsAsync(symbol, solution, thirdPartyNavigationAllowed: true, cancellationToken).ConfigureAwait(false); foreach (var definition in definitions) diff --git a/src/EditorFeatures/Core/GoToDefinition/GoToDefinitionCommandHandler.cs b/src/EditorFeatures/Core/GoToDefinition/GoToDefinitionCommandHandler.cs index b7a462a81be21..27cdc2286b0db 100644 --- a/src/EditorFeatures/Core/GoToDefinition/GoToDefinitionCommandHandler.cs +++ b/src/EditorFeatures/Core/GoToDefinition/GoToDefinitionCommandHandler.cs @@ -145,7 +145,7 @@ private bool ExecuteSynchronously( private static void ReportFailure(Document document) { - var notificationService = document.Project.Solution.Workspace.Services.GetRequiredService(); + var notificationService = document.Project.Solution.Services.GetRequiredService(); notificationService.SendNotification( FeaturesResources.Cannot_navigate_to_the_symbol_under_the_caret, EditorFeaturesResources.Go_to_Definition, NotificationSeverity.Information); } @@ -155,7 +155,7 @@ private async Task ExecuteAsynchronouslyAsync( { bool succeeded; - var indicatorFactory = document.Project.Solution.Workspace.Services.GetRequiredService(); + var indicatorFactory = document.Project.Solution.Services.GetRequiredService(); using (var backgroundIndicator = indicatorFactory.Create( args.TextView, new SnapshotSpan(args.SubjectBuffer.CurrentSnapshot, position, 1), EditorFeaturesResources.Navigating_to_definition)) diff --git a/src/EditorFeatures/Core/GoToDefinition/GoToDefinitionHelpers.cs b/src/EditorFeatures/Core/GoToDefinition/GoToDefinitionHelpers.cs index 9e29eb95e500f..271a7b4e49958 100644 --- a/src/EditorFeatures/Core/GoToDefinition/GoToDefinitionHelpers.cs +++ b/src/EditorFeatures/Core/GoToDefinition/GoToDefinitionHelpers.cs @@ -89,7 +89,7 @@ public static async Task> GetDefinitionsAsync( if (thirdPartyNavigationAllowed) { - var factory = solution.Workspace.Services.GetService(); + var factory = solution.Services.GetService(); if (factory != null) { var thirdPartyItem = await factory.GetThirdPartyDefinitionItemAsync(solution, definitionItem, cancellationToken).ConfigureAwait(false); diff --git a/src/EditorFeatures/Core/InlineHints/InlineHintsOptionsStorage.cs b/src/EditorFeatures/Core/InlineHints/InlineHintsOptionsStorage.cs index 94c5a1b3a12e2..476b8e307639d 100644 --- a/src/EditorFeatures/Core/InlineHints/InlineHintsOptionsStorage.cs +++ b/src/EditorFeatures/Core/InlineHints/InlineHintsOptionsStorage.cs @@ -2,7 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Options; namespace Microsoft.CodeAnalysis.InlineHints diff --git a/src/EditorFeatures/Core/InlineRename/AbstractEditorInlineRenameService.FailureInlineRenameInfo.cs b/src/EditorFeatures/Core/InlineRename/AbstractEditorInlineRenameService.FailureInlineRenameInfo.cs index fad7ccdab55e3..d694700280902 100644 --- a/src/EditorFeatures/Core/InlineRename/AbstractEditorInlineRenameService.FailureInlineRenameInfo.cs +++ b/src/EditorFeatures/Core/InlineRename/AbstractEditorInlineRenameService.FailureInlineRenameInfo.cs @@ -52,6 +52,8 @@ public FailureInlineRenameInfo(string localizedErrorMessage) public bool TryOnAfterGlobalSymbolRenamed(Workspace workspace, IEnumerable changedDocumentIDs, string replacementText) => false; public bool TryOnBeforeGlobalSymbolRenamed(Workspace workspace, IEnumerable changedDocumentIDs, string replacementText) => false; + + public InlineRenameFileRenameInfo GetFileRenameInfo() => InlineRenameFileRenameInfo.NotAllowed; } } } diff --git a/src/EditorFeatures/Core/InlineRename/AbstractEditorInlineRenameService.InlineRenameLocationSet.cs b/src/EditorFeatures/Core/InlineRename/AbstractEditorInlineRenameService.InlineRenameLocationSet.cs index 45b1faf47c43f..fc13b583fc7b3 100644 --- a/src/EditorFeatures/Core/InlineRename/AbstractEditorInlineRenameService.InlineRenameLocationSet.cs +++ b/src/EditorFeatures/Core/InlineRename/AbstractEditorInlineRenameService.InlineRenameLocationSet.cs @@ -7,9 +7,8 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; -using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Rename; -using Roslyn.Utilities; +using Microsoft.CodeAnalysis.Rename.ConflictEngine; namespace Microsoft.CodeAnalysis.Editor.Implementation.InlineRename { @@ -17,12 +16,12 @@ internal abstract partial class AbstractEditorInlineRenameService { private class InlineRenameLocationSet : IInlineRenameLocationSet { - private readonly RenameLocations _renameLocationSet; + private readonly LightweightRenameLocations _renameLocationSet; private readonly SymbolInlineRenameInfo _renameInfo; public IList Locations { get; } - public InlineRenameLocationSet(SymbolInlineRenameInfo renameInfo, RenameLocations renameLocationSet) + public InlineRenameLocationSet(SymbolInlineRenameInfo renameInfo, LightweightRenameLocations renameLocationSet) { _renameInfo = renameInfo; _renameLocationSet = renameLocationSet; @@ -40,9 +39,7 @@ private InlineRenameLocation ConvertLocation(RenameLocation location) public async Task GetReplacementsAsync(string replacementText, SymbolRenameOptions options, CancellationToken cancellationToken) { var conflicts = await _renameLocationSet.ResolveConflictsAsync( - _renameInfo.GetFinalSymbolName(replacementText), nonConflictSymbols: null, cancellationToken: cancellationToken).ConfigureAwait(false); - - Contract.ThrowIfTrue(conflicts.ErrorMessage != null); + _renameInfo.RenameSymbol, _renameInfo.GetFinalSymbolName(replacementText), nonConflictSymbolKeys: default, cancellationToken).ConfigureAwait(false); return new InlineRenameReplacementInfo(conflicts); } diff --git a/src/EditorFeatures/Core/InlineRename/AbstractEditorInlineRenameService.InlineRenameReplacementInfo.cs b/src/EditorFeatures/Core/InlineRename/AbstractEditorInlineRenameService.InlineRenameReplacementInfo.cs index 5a1a07a7d7b72..75c806681a643 100644 --- a/src/EditorFeatures/Core/InlineRename/AbstractEditorInlineRenameService.InlineRenameReplacementInfo.cs +++ b/src/EditorFeatures/Core/InlineRename/AbstractEditorInlineRenameService.InlineRenameReplacementInfo.cs @@ -16,13 +16,16 @@ private class InlineRenameReplacementInfo : IInlineRenameReplacementInfo private readonly ConflictResolution _conflicts; public InlineRenameReplacementInfo(ConflictResolution conflicts) - => _conflicts = conflicts; + { + Contract.ThrowIfFalse(conflicts.IsSuccessful); + _conflicts = conflicts; + } public IEnumerable DocumentIds => _conflicts.DocumentIds; - public Solution NewSolution => _conflicts.NewSolution; + public Solution NewSolution => _conflicts.NewSolution!; - public bool ReplacementTextValid => _conflicts.ReplacementTextValid; + public bool ReplacementTextValid => _conflicts.ReplacementTextValid!.Value; public IEnumerable GetReplacements(DocumentId documentId) { diff --git a/src/EditorFeatures/Core/InlineRename/AbstractEditorInlineRenameService.SymbolRenameInfo.cs b/src/EditorFeatures/Core/InlineRename/AbstractEditorInlineRenameService.SymbolRenameInfo.cs index 841d5bc7eee76..44e7574d92516 100644 --- a/src/EditorFeatures/Core/InlineRename/AbstractEditorInlineRenameService.SymbolRenameInfo.cs +++ b/src/EditorFeatures/Core/InlineRename/AbstractEditorInlineRenameService.SymbolRenameInfo.cs @@ -11,7 +11,7 @@ using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CodeCleanup; using Microsoft.CodeAnalysis.Editor.Shared.Extensions; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Rename; using Microsoft.CodeAnalysis.Shared.Extensions; @@ -26,7 +26,7 @@ internal abstract partial class AbstractEditorInlineRenameService /// /// Represents information about the ability to rename a particular location. /// - private partial class SymbolInlineRenameInfo : IInlineRenameInfoWithFileRename + private partial class SymbolInlineRenameInfo : IInlineRenameInfo { private const string AttributeSuffix = "Attribute"; @@ -71,7 +71,7 @@ public SymbolInlineRenameInfo( _fallbackOptions = fallbackOptions; this.RenameSymbol = renameSymbol; - this.HasOverloads = RenameLocations.GetOverloadedSymbols(this.RenameSymbol).Any(); + this.HasOverloads = RenameUtilities.GetOverloadedSymbols(this.RenameSymbol).Any(); this.MustRenameOverloads = forceRenameOverloads; _isRenamingAttributePrefix = CanRenameAttributePrefix(triggerText); @@ -211,7 +211,7 @@ public bool TryOnAfterGlobalSymbolRenamed(Workspace workspace, IEnumerable 1) { diff --git a/src/EditorFeatures/Core/InlineRename/AbstractEditorInlineRenameService.cs b/src/EditorFeatures/Core/InlineRename/AbstractEditorInlineRenameService.cs index a89dc3270fcf8..f7074529cfd0b 100644 --- a/src/EditorFeatures/Core/InlineRename/AbstractEditorInlineRenameService.cs +++ b/src/EditorFeatures/Core/InlineRename/AbstractEditorInlineRenameService.cs @@ -10,7 +10,7 @@ using System.Threading.Tasks; using Microsoft.CodeAnalysis.CodeCleanup; using Microsoft.CodeAnalysis.FindSymbols; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Rename; @@ -55,7 +55,7 @@ private async Task GetRenameInfoAsync( return new FailureInlineRenameInfo(EditorFeaturesResources.You_must_rename_an_identifier); var semanticModel = await document.GetRequiredSemanticModelAsync(cancellationToken).ConfigureAwait(false); - var semanticFacts = document.GetLanguageService(); + var semanticFacts = document.GetRequiredLanguageService(); var tokenRenameInfo = RenameUtilities.GetTokenRenameInfo(semanticFacts, semanticModel, triggerToken, cancellationToken); @@ -76,7 +76,7 @@ private async Task GetRenameInfoAsync( // If rename is invoked on a member group reference in a nameof expression, then the // RenameOverloads option should be forced on. var forceRenameOverloads = tokenRenameInfo.IsMemberGroup; - var symbol = await RenameLocations.ReferenceProcessing.TryGetRenamableSymbolAsync(document, triggerToken.SpanStart, cancellationToken: cancellationToken).ConfigureAwait(false); + var symbol = await RenameUtilities.TryGetRenamableSymbolAsync(document, triggerToken.SpanStart, cancellationToken: cancellationToken).ConfigureAwait(false); if (symbol == null) return new FailureInlineRenameInfo(EditorFeaturesResources.You_cannot_rename_this_element); @@ -84,13 +84,12 @@ private async Task GetRenameInfoAsync( return new FailureInlineRenameInfo(EditorFeaturesResources.You_cannot_rename_this_element); // Cannot rename constructors in VB. TODO: this logic should be in the VB subclass of this type. - var workspace = document.Project.Solution.Workspace; if (symbol.Kind == SymbolKind.NamedType && symbol.Language == LanguageNames.VisualBasic && triggerToken.ToString().Equals("New", StringComparison.OrdinalIgnoreCase)) { var originalSymbol = await SymbolFinder.FindSymbolAtPositionAsync( - semanticModel, triggerToken.SpanStart, workspace, cancellationToken: cancellationToken).ConfigureAwait(false); + semanticModel, triggerToken.SpanStart, document.Project.Solution.Services, cancellationToken: cancellationToken).ConfigureAwait(false); if (originalSymbol != null && originalSymbol.IsConstructor()) return new FailureInlineRenameInfo(EditorFeaturesResources.You_cannot_rename_this_element); diff --git a/src/EditorFeatures/Core/InlineRename/CommandHandlers/AbstractRenameCommandHandler.cs b/src/EditorFeatures/Core/InlineRename/CommandHandlers/AbstractRenameCommandHandler.cs index 908ed357152ff..d8f1718d7fe18 100644 --- a/src/EditorFeatures/Core/InlineRename/CommandHandlers/AbstractRenameCommandHandler.cs +++ b/src/EditorFeatures/Core/InlineRename/CommandHandlers/AbstractRenameCommandHandler.cs @@ -4,8 +4,10 @@ using System; using System.Linq; +using Microsoft.CodeAnalysis.Editor.BackgroundWorkIndicator; using Microsoft.CodeAnalysis.Editor.Shared.Extensions; using Microsoft.CodeAnalysis.Editor.Shared.Utilities; +using Microsoft.CodeAnalysis.Shared.TestHooks; using Microsoft.VisualStudio.Commanding; using Microsoft.VisualStudio.Text; using Microsoft.VisualStudio.Text.Editor; @@ -17,13 +19,16 @@ internal abstract partial class AbstractRenameCommandHandler { private readonly IThreadingContext _threadingContext; private readonly InlineRenameService _renameService; + private readonly IAsynchronousOperationListener _listener; protected AbstractRenameCommandHandler( IThreadingContext threadingContext, - InlineRenameService renameService) + InlineRenameService renameService, + IAsynchronousOperationListenerProvider asynchronousOperationListenerProvider) { _threadingContext = threadingContext; _renameService = renameService; + _listener = asynchronousOperationListenerProvider.GetListener(FeatureAttribute.Rename); } public string DisplayName => EditorFeaturesResources.Rename; diff --git a/src/EditorFeatures/Core/InlineRename/CommandHandlers/AbstractRenameCommandHandler_RenameHandler.cs b/src/EditorFeatures/Core/InlineRename/CommandHandlers/AbstractRenameCommandHandler_RenameHandler.cs index d762156c45e02..64ec599ba670f 100644 --- a/src/EditorFeatures/Core/InlineRename/CommandHandlers/AbstractRenameCommandHandler_RenameHandler.cs +++ b/src/EditorFeatures/Core/InlineRename/CommandHandlers/AbstractRenameCommandHandler_RenameHandler.cs @@ -4,12 +4,19 @@ #nullable disable +using System; using System.Linq; +using System.Runtime.CompilerServices; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.Editor.BackgroundWorkIndicator; using Microsoft.CodeAnalysis.Editor.Shared.Extensions; +using Microsoft.CodeAnalysis.Editor.Shared.Utilities; using Microsoft.CodeAnalysis.Notification; using Microsoft.CodeAnalysis.Rename; +using Microsoft.CodeAnalysis.Shared.TestHooks; using Microsoft.VisualStudio.Commanding; using Microsoft.VisualStudio.Text.Editor.Commanding.Commands; +using Microsoft.VisualStudio.Utilities; namespace Microsoft.CodeAnalysis.Editor.Implementation.InlineRename { @@ -38,16 +45,15 @@ public bool ExecuteCommand(RenameCommandArgs args, CommandExecutionContext conte return false; } - using (context.OperationContext.AddScope(allowCancellation: true, EditorFeaturesResources.Finding_token_to_rename)) - { - ExecuteRenameWorker(args, context); - } - + var token = _listener.BeginAsyncOperation(nameof(ExecuteCommand)); + _ = ExecuteCommandAsync(args).CompletesAsyncOperation(token); return true; } - private void ExecuteRenameWorker(RenameCommandArgs args, CommandExecutionContext context) + private async Task ExecuteCommandAsync(RenameCommandArgs args) { + _threadingContext.ThrowIfNotOnUIThread(); + if (!args.SubjectBuffer.TryGetWorkspace(out var workspace)) { return; @@ -56,10 +62,16 @@ private void ExecuteRenameWorker(RenameCommandArgs args, CommandExecutionContext var caretPoint = args.TextView.GetCaretPoint(args.SubjectBuffer); if (!caretPoint.HasValue) { - ShowErrorDialog(workspace, EditorFeaturesResources.You_must_rename_an_identifier); + await ShowErrorDialogAsync(workspace, EditorFeaturesResources.You_must_rename_an_identifier).ConfigureAwait(false); return; } + var backgroundWorkIndicatorFactory = workspace.Services.GetRequiredService(); + using var context = backgroundWorkIndicatorFactory.Create( + args.TextView, + args.TextView.GetTextElementSpan(caretPoint.Value), + EditorFeaturesResources.Finding_token_to_rename); + // If there is already an active session, commit it first if (_renameService.ActiveSession != null) { @@ -77,12 +89,17 @@ private void ExecuteRenameWorker(RenameCommandArgs args, CommandExecutionContext } } - var cancellationToken = context.OperationContext.UserCancellationToken; - var document = args.SubjectBuffer.CurrentSnapshot.GetFullyLoadedOpenDocumentInCurrentContextWithChanges( - context.OperationContext, _threadingContext); + var cancellationToken = context.UserCancellationToken; + + var document = await args + .SubjectBuffer + .CurrentSnapshot + .GetFullyLoadedOpenDocumentInCurrentContextWithChangesAsync(context) + .ConfigureAwait(false); + if (document == null) { - ShowErrorDialog(workspace, EditorFeaturesResources.You_must_rename_an_identifier); + await ShowErrorDialogAsync(workspace, EditorFeaturesResources.You_must_rename_an_identifier).ConfigureAwait(false); return; } @@ -92,14 +109,15 @@ private void ExecuteRenameWorker(RenameCommandArgs args, CommandExecutionContext // There can be zero selectedSpans in projection scenarios. if (selectedSpans.Count != 1) { - ShowErrorDialog(workspace, EditorFeaturesResources.You_must_rename_an_identifier); + await ShowErrorDialogAsync(workspace, EditorFeaturesResources.You_must_rename_an_identifier).ConfigureAwait(false); return; } - var sessionInfo = _renameService.StartInlineSession(document, selectedSpans.Single().Span.ToTextSpan(), cancellationToken); + var sessionInfo = await _renameService.StartInlineSessionAsync(document, selectedSpans.Single().Span.ToTextSpan(), cancellationToken).ConfigureAwait(false); if (!sessionInfo.CanRename) { - ShowErrorDialog(workspace, sessionInfo.LocalizedErrorMessage); + await ShowErrorDialogAsync(workspace, sessionInfo.LocalizedErrorMessage).ConfigureAwait(false); + return; } } @@ -110,8 +128,9 @@ private static bool CanRename(RenameCommandArgs args) args.SubjectBuffer.SupportsRename() && !args.SubjectBuffer.IsInLspEditorContext(); } - private static void ShowErrorDialog(Workspace workspace, string message) + private async Task ShowErrorDialogAsync(Workspace workspace, string message) { + await _threadingContext.JoinableTaskFactory.SwitchToMainThreadAsync(); var notificationService = workspace.Services.GetService(); notificationService.SendNotification(message, title: EditorFeaturesResources.Rename, severity: NotificationSeverity.Error); } diff --git a/src/EditorFeatures/Core/InlineRename/CommandHandlers/AbstractRenameCommandHandler_TypeCharHandler.cs b/src/EditorFeatures/Core/InlineRename/CommandHandlers/AbstractRenameCommandHandler_TypeCharHandler.cs index 7c401edc775f4..12eddc3e75e0c 100644 --- a/src/EditorFeatures/Core/InlineRename/CommandHandlers/AbstractRenameCommandHandler_TypeCharHandler.cs +++ b/src/EditorFeatures/Core/InlineRename/CommandHandlers/AbstractRenameCommandHandler_TypeCharHandler.cs @@ -3,7 +3,7 @@ // See the LICENSE file in the project root for more information. using System; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Text; using Microsoft.VisualStudio.Commanding; diff --git a/src/EditorFeatures/Core/InlineRename/IEditorInlineRenameService.cs b/src/EditorFeatures/Core/InlineRename/IEditorInlineRenameService.cs index 9975fffe79d83..d245010a9d0d8 100644 --- a/src/EditorFeatures/Core/InlineRename/IEditorInlineRenameService.cs +++ b/src/EditorFeatures/Core/InlineRename/IEditorInlineRenameService.cs @@ -239,10 +239,7 @@ internal interface IInlineRenameInfo /// if this operation succeeded, or if it failed. /// bool TryOnAfterGlobalSymbolRenamed(Workspace workspace, IEnumerable changedDocumentIDs, string replacementText); - } - internal interface IInlineRenameInfoWithFileRename : IInlineRenameInfo - { /// /// Returns information about the file rename capabilities of /// an inline rename diff --git a/src/EditorFeatures/Core/InlineRename/InlineRenameService.cs b/src/EditorFeatures/Core/InlineRename/InlineRenameService.cs index ada565c309834..9d9eedac77b42 100644 --- a/src/EditorFeatures/Core/InlineRename/InlineRenameService.cs +++ b/src/EditorFeatures/Core/InlineRename/InlineRenameService.cs @@ -7,6 +7,7 @@ using System.ComponentModel.Composition; using System.Threading; using System.Threading.Tasks; +using Microsoft.CodeAnalysis.Editor.Shared.Extensions; using Microsoft.CodeAnalysis.Editor.Shared.Utilities; using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.InlineRename; @@ -68,7 +69,7 @@ public InlineRenameSessionInfo StartInlineSession( return _threadingContext.JoinableTaskFactory.Run(() => StartInlineSessionAsync(document, textSpan, cancellationToken)); } - private async Task StartInlineSessionAsync( + public async Task StartInlineSessionAsync( Document document, TextSpan textSpan, CancellationToken cancellationToken) @@ -172,11 +173,19 @@ internal InlineRenameSession? ActiveSession { get { + _threadingContext.ThrowIfNotOnUIThread(); + return _activeRenameSession; } set { + _threadingContext.ThrowIfNotOnUIThread(); + + // This is also checked in InlineRenameSession (which should be the only thing that ever sets this). + // However, this just adds an extra level of safety to make sure nothing bad is about to happen. + Contract.ThrowIfTrue(_activeRenameSession != null && value != null, "Cannot assign an active rename session when one is already in progress."); + var previousSession = _activeRenameSession; _activeRenameSession = value; ActiveSessionChanged?.Invoke(this, new ActiveSessionChangedEventArgs(previousSession!)); diff --git a/src/EditorFeatures/Core/InlineRename/InlineRenameSession.OpenTextBufferManager.cs b/src/EditorFeatures/Core/InlineRename/InlineRenameSession.OpenTextBufferManager.cs index 19d516cc00c15..69a3fafeba936 100644 --- a/src/EditorFeatures/Core/InlineRename/InlineRenameSession.OpenTextBufferManager.cs +++ b/src/EditorFeatures/Core/InlineRename/InlineRenameSession.OpenTextBufferManager.cs @@ -144,10 +144,7 @@ private void OnTextViewClosed(object sender, EventArgs e) var view = sender as ITextView; view.Closed -= OnTextViewClosed; _textViews.Remove(view); - if (!_session._dismissed) - { - _session.Cancel(); - } + _session.Cancel(); } internal void ConnectToView(ITextView textView) @@ -475,7 +472,7 @@ internal void ApplyConflictResolutionEdits(IInlineRenameReplacementInfo conflict var linkedRenameSpan = _session._renameInfo.GetConflictEditSpan( new InlineRenameLocation(newDocument, replacement.NewSpan), GetTriggerText(newDocument, replacement.NewSpan), GetWithoutAttributeSuffix(_session.ReplacementText, - document.GetLanguageService().IsCaseSensitive), cancellationToken); + document.GetLanguageService().IsCaseSensitive), cancellationToken); if (linkedRenameSpan.HasValue) { @@ -570,7 +567,7 @@ private static async Task> GetTextChangesFromTextDiffere return textChanges; } - var textDiffService = oldDocument.Project.Solution.Workspace.Services.GetService(); + var textDiffService = oldDocument.Project.Solution.Services.GetService(); return await textDiffService.GetTextChangesAsync(oldDocument, newDocument, cancellationToken).ConfigureAwait(false); } } @@ -588,8 +585,8 @@ private IEnumerable GetMergedReplacementInfos( { _session._threadingContext.ThrowIfNotOnUIThread(); - var textDiffService = preMergeDocument.Project.Solution.Workspace.Services.GetService(); - var contentType = preMergeDocument.Project.LanguageServices.GetService().GetDefaultContentType(); + var textDiffService = preMergeDocument.Project.Solution.Services.GetService(); + var contentType = preMergeDocument.Project.Services.GetService().GetDefaultContentType(); // TODO: Track all spans at once @@ -601,7 +598,7 @@ private IEnumerable GetMergedReplacementInfos( var snapshot = preMergeDocumentText.FindCorrespondingEditorTextSnapshot(); if (snapshot != null) { - textBufferCloneService = preMergeDocument.Project.Solution.Workspace.Services.GetService(); + textBufferCloneService = preMergeDocument.Project.Solution.Services.GetService(); if (textBufferCloneService != null) { snapshotSpanToClone = snapshot.GetFullSpan(); diff --git a/src/EditorFeatures/Core/InlineRename/InlineRenameSession.cs b/src/EditorFeatures/Core/InlineRename/InlineRenameSession.cs index b37cb1cedc165..e89dd8efd015d 100644 --- a/src/EditorFeatures/Core/InlineRename/InlineRenameSession.cs +++ b/src/EditorFeatures/Core/InlineRename/InlineRenameSession.cs @@ -46,7 +46,6 @@ internal partial class InlineRenameSession : IInlineRenameSession, IFeatureContr private readonly IAsynchronousOperationListener _asyncListener; private readonly Solution _baseSolution; private readonly Document _triggerDocument; - private readonly SnapshotSpan _triggerSpan; private readonly ITextView _triggerView; private readonly IDisposable _inlineRenameSessionDurationLogBlock; private readonly IThreadingContext _threadingContext; @@ -59,6 +58,11 @@ internal partial class InlineRenameSession : IInlineRenameSession, IFeatureContr private bool _previewChanges; private readonly Dictionary _openTextBuffers = new Dictionary(); + /// + /// The original for the identifier that rename was triggered on + /// + public SnapshotSpan TriggerSpan { get; } + /// /// If non-null, the current text of the replacement. Linked spans added will automatically be updated with this /// text. @@ -82,6 +86,13 @@ private set /// public InlineRenameFileRenameInfo FileRenameInfo { get; } + /// + /// Rename session held alive with the OOP server. This allows us to pin the initial solution snapshot over on + /// the oop side, which is valuable for preventing it from constantly being dropped/synced on every conflict + /// resolution step. + /// + private readonly IRemoteRenameKeepAliveSession _keepAliveSession; + /// /// The task which computes the main rename locations against the original workspace /// snapshot. @@ -92,7 +103,7 @@ private set /// The cancellation token for most work being done by the inline rename session. This /// includes the tasks. /// - private readonly CancellationTokenSource _cancellationTokenSource = new CancellationTokenSource(); + private readonly CancellationTokenSource _cancellationTokenSource = new(); /// /// This task is a continuation of the that is the result of computing @@ -131,7 +142,7 @@ public InlineRenameSession( _threadingContext = threadingContext; _renameInfo = renameInfo; - _triggerSpan = triggerSpan; + TriggerSpan = triggerSpan; _triggerDocument = triggerSpan.Snapshot.GetOpenDocumentInCurrentContextWithChanges(); if (_triggerDocument == null) { @@ -166,15 +177,11 @@ public InlineRenameSession( _baseSolution = _triggerDocument.Project.Solution; this.UndoManager = workspace.Services.GetService(); - if (_renameInfo is IInlineRenameInfoWithFileRename renameInfoWithFileRename) - { - FileRenameInfo = renameInfoWithFileRename.GetFileRenameInfo(); - } - else - { - FileRenameInfo = InlineRenameFileRenameInfo.NotAllowed; - } + FileRenameInfo = _renameInfo.GetFileRenameInfo(); + // Open a session to oop, syncing our solution to it and pinning it there. The connection will close once + // _cancellationTokenSource is canceled (which we always do when the session is finally ended). + _keepAliveSession = Renamer.CreateRemoteKeepAliveSession(_baseSolution, asyncListener); InitializeOpenBuffers(triggerSpan); } @@ -244,8 +251,7 @@ private void InitializeOpenBuffers(SnapshotSpan triggerSpan) this.UndoManager.CreateInitialState(this.ReplacementText, _triggerView.Selection, new SnapshotSpan(triggerSpan.Snapshot, startingSpan)); _openTextBuffers[triggerSpan.Snapshot.TextBuffer].SetReferenceSpans(SpecializedCollections.SingletonEnumerable(startingSpan.ToTextSpan())); - UpdateReferenceLocationsTask(_threadingContext.JoinableTaskFactory.RunAsync( - () => _renameInfo.FindRenameLocationsAsync(_options, _cancellationTokenSource.Token))); + UpdateReferenceLocationsTask(); RenameTrackingDismisser.DismissRenameTracking(_workspace, _workspace.GetOpenDocumentIds()); } @@ -289,20 +295,31 @@ private void OnSubjectBuffersConnected(object sender, SubjectBuffersConnectedEve } } - private void UpdateReferenceLocationsTask(JoinableTask findRenameLocationsTask) + private void UpdateReferenceLocationsTask() { _threadingContext.ThrowIfNotOnUIThread(); var asyncToken = _asyncListener.BeginAsyncOperation("UpdateReferencesTask"); + + var currentOptions = _options; + var currentRenameLocationsTask = _allRenameLocationsTask; + var cancellationToken = _cancellationTokenSource.Token; + _allRenameLocationsTask = _threadingContext.JoinableTaskFactory.RunAsync(async () => { - var inlineRenameLocations = await findRenameLocationsTask.JoinAsync().ConfigureAwaitRunInline(); + // Join prior work before proceeding, since it performs a required state update. + // https://github.com/dotnet/roslyn/pull/34254#discussion_r267024593 + if (currentRenameLocationsTask != null) + await _allRenameLocationsTask.JoinAsync(cancellationToken).ConfigureAwait(false); + + await TaskScheduler.Default; + var inlineRenameLocations = await _renameInfo.FindRenameLocationsAsync(currentOptions, cancellationToken).ConfigureAwait(false); // It's unfortunate that _allRenameLocationsTask has a UI thread dependency (prevents continuations // from running prior to the completion of the UI operation), but the implementation does not currently // follow the originally-intended design. // https://github.com/dotnet/roslyn/issues/40890 - await _threadingContext.JoinableTaskFactory.SwitchToMainThreadAsync(alwaysYield: true, _cancellationTokenSource.Token); + await _threadingContext.JoinableTaskFactory.SwitchToMainThreadAsync(alwaysYield: true, cancellationToken); RaiseSessionSpansUpdated(inlineRenameLocations.Locations.ToImmutableArray()); @@ -344,21 +361,7 @@ public void RefreshRenameSessionWithOptionsChanged(SymbolRenameOptions newOption VerifyNotDismissed(); _options = newOptions; - - var cancellationToken = _cancellationTokenSource.Token; - - UpdateReferenceLocationsTask(_threadingContext.JoinableTaskFactory.RunAsync(async () => - { - // Join prior work before proceeding, since it performs a required state update. - // https://github.com/dotnet/roslyn/pull/34254#discussion_r267024593 - // - // The cancellation token is passed to the prior work when it starts, not when it's joined. This is - // the equivalent of TaskContinuationOptions.LazyCancellation. - await _allRenameLocationsTask.JoinAsync(CancellationToken.None).ConfigureAwait(false); - await TaskScheduler.Default; - - return await _renameInfo.FindRenameLocationsAsync(_options, cancellationToken).ConfigureAwait(false); - })); + UpdateReferenceLocationsTask(); } public void SetPreviewChanges(bool value) @@ -381,10 +384,7 @@ private void OnWorkspaceChanged(object sender, WorkspaceChangeEventArgs args) { if (args.Kind != WorkspaceChangeKind.DocumentChanged) { - if (!_dismissed) - { - this.Cancel(); - } + Cancel(); } } @@ -636,7 +636,6 @@ private void LogRenameSession(RenameLogMessage.UserActionOutcome outcome, bool p public void Cancel() { _threadingContext.ThrowIfNotOnUIThread(); - VerifyNotDismissed(); // This wait is safe. We are not passing the async callback to DismissUIAndRollbackEditsAndEndRenameSessionAsync. // So everything in that method will happen synchronously. @@ -649,6 +648,13 @@ private async Task DismissUIAndRollbackEditsAndEndRenameSessionAsync( bool previewChanges, Func finalCommitAction = null) { + if (_dismissed) + { + return; + } + + _dismissed = true; + // Note: this entire sequence of steps is not cancellable. We must perform it all to get back to a correct // state for all the editors the user is interacting with. var cancellationToken = CancellationToken.None; @@ -661,6 +667,9 @@ private async Task DismissUIAndRollbackEditsAndEndRenameSessionAsync( _cancellationTokenSource.Cancel(); _conflictResolutionTaskCancellationSource.Cancel(); + // Close the keep alive session we have open with OOP, allowing it to release the solution it is holding onto. + _keepAliveSession.Dispose(); + // Perform the actual commit step if we've been asked to. if (finalCommitAction != null) { @@ -681,7 +690,6 @@ private async Task DismissUIAndRollbackEditsAndEndRenameSessionAsync( void DismissUIAndRollbackEdits() { - _dismissed = true; _workspace.WorkspaceChanged -= OnWorkspaceChanged; _textBufferAssociatedViewService.SubjectBuffersConnected -= OnSubjectBuffersConnected; @@ -762,7 +770,7 @@ private async Task CommitWorkerAsync(bool previewChanges, bool canUseBackg // and applying the desired edits ourselves. var factory = _workspace.Services.GetRequiredService(); using var context = factory.Create( - _triggerView, _triggerSpan, EditorFeaturesResources.Computing_Rename_information, + _triggerView, TriggerSpan, EditorFeaturesResources.Computing_Rename_information, cancelOnEdit: false, cancelOnFocusLost: false); await CommitCoreAsync(context, previewChanges).ConfigureAwait(true); @@ -804,6 +812,8 @@ private async Task CommitCoreAsync(IUIThreadOperationContext operationContext, b { var previewService = _workspace.Services.GetService(); + // The preview service needs to be called from the UI thread, since it's doing COM calls underneath. + await _threadingContext.JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken); newSolution = previewService.PreviewChanges( string.Format(EditorFeaturesResources.Preview_Changes_0, EditorFeaturesResources.Rename), "vs.csharp.refactoring.rename", diff --git a/src/EditorFeatures/Core/IntelliSense/AsyncCompletion/AsyncCompletionLogger.cs b/src/EditorFeatures/Core/IntelliSense/AsyncCompletion/AsyncCompletionLogger.cs index bcd12a505f7cc..c2e63be98ac14 100644 --- a/src/EditorFeatures/Core/IntelliSense/AsyncCompletion/AsyncCompletionLogger.cs +++ b/src/EditorFeatures/Core/IntelliSense/AsyncCompletion/AsyncCompletionLogger.cs @@ -2,15 +2,16 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +using System; using Microsoft.CodeAnalysis.Internal.Log; namespace Microsoft.CodeAnalysis.Editor.Implementation.IntelliSense.AsyncCompletion { internal static class AsyncCompletionLogger { - private static readonly LogAggregator s_logAggregator = new(); - private static readonly StatisticLogAggregator s_statisticLogAggregator = new(); - private static readonly HistogramLogAggregator s_histogramLogAggregator = new(25, 500); + private static readonly CountLogAggregator s_countLogAggregator = new(); + private static readonly StatisticLogAggregator s_statisticLogAggregator = new(); + private static readonly HistogramLogAggregator s_histogramLogAggregator = new(25, 500); private enum ActionInfo { @@ -44,60 +45,60 @@ private enum ActionInfo internal static void LogImportCompletionGetContext(bool isBlocking, bool delayed) { - s_logAggregator.IncreaseCount((int)ActionInfo.SessionWithTypeImportCompletionEnabled); + s_countLogAggregator.IncreaseCount(ActionInfo.SessionWithTypeImportCompletionEnabled); if (isBlocking) - s_logAggregator.IncreaseCount((int)ActionInfo.SessionWithImportCompletionBlocking); + s_countLogAggregator.IncreaseCount(ActionInfo.SessionWithImportCompletionBlocking); if (delayed) - s_logAggregator.IncreaseCount((int)ActionInfo.SessionWithImportCompletionDelayed); + s_countLogAggregator.IncreaseCount(ActionInfo.SessionWithImportCompletionDelayed); } internal static void LogSessionWithDelayedImportCompletionIncludedInUpdate() => - s_logAggregator.IncreaseCount((int)ActionInfo.SessionWithDelayedImportCompletionIncludedInUpdate); + s_countLogAggregator.IncreaseCount(ActionInfo.SessionWithDelayedImportCompletionIncludedInUpdate); - internal static void LogAdditionalTicksToCompleteDelayedImportCompletionDataPoint(int count) => - s_histogramLogAggregator.IncreaseCount((int)ActionInfo.AdditionalTicksToCompleteDelayedImportCompletion, count); + internal static void LogAdditionalTicksToCompleteDelayedImportCompletionDataPoint(TimeSpan timeSpan) => + s_histogramLogAggregator.LogTime(ActionInfo.AdditionalTicksToCompleteDelayedImportCompletion, timeSpan); internal static void LogDelayedImportCompletionIncluded() => - s_logAggregator.IncreaseCount((int)ActionInfo.SessionWithTypeImportCompletionEnabled); + s_countLogAggregator.IncreaseCount(ActionInfo.SessionWithTypeImportCompletionEnabled); internal static void LogExpanderUsage() => - s_logAggregator.IncreaseCount((int)ActionInfo.ExpanderUsageCount); + s_countLogAggregator.IncreaseCount(ActionInfo.ExpanderUsageCount); internal static void LogGetDefaultsMatchTicksDataPoint(int count) => - s_statisticLogAggregator.AddDataPoint((int)ActionInfo.GetDefaultsMatchTicks, count); + s_statisticLogAggregator.AddDataPoint(ActionInfo.GetDefaultsMatchTicks, count); - internal static void LogSourceInitializationTicksDataPoint(int count) + internal static void LogSourceInitializationTicksDataPoint(TimeSpan elapsed) { - s_statisticLogAggregator.AddDataPoint((int)ActionInfo.SourceInitializationTicks, count); - s_histogramLogAggregator.IncreaseCount((int)ActionInfo.SourceInitializationTicks, count); + s_statisticLogAggregator.AddDataPoint(ActionInfo.SourceInitializationTicks, elapsed); + s_histogramLogAggregator.LogTime(ActionInfo.SourceInitializationTicks, elapsed); } - internal static void LogSourceGetContextTicksDataPoint(int count, bool isCanceled) + internal static void LogSourceGetContextTicksDataPoint(TimeSpan elapsed, bool isCanceled) { var key = isCanceled ? ActionInfo.SourceGetContextCanceledTicks : ActionInfo.SourceGetContextCompletedTicks; - s_statisticLogAggregator.AddDataPoint((int)key, count); - s_histogramLogAggregator.IncreaseCount((int)key, count); + s_statisticLogAggregator.AddDataPoint(key, elapsed); + s_histogramLogAggregator.LogTime(key, elapsed); } - internal static void LogItemManagerSortTicksDataPoint(int count) + internal static void LogItemManagerSortTicksDataPoint(TimeSpan elapsed) { - s_statisticLogAggregator.AddDataPoint((int)ActionInfo.ItemManagerSortTicks, count); - s_histogramLogAggregator.IncreaseCount((int)ActionInfo.ItemManagerSortTicks, count); + s_statisticLogAggregator.AddDataPoint(ActionInfo.ItemManagerSortTicks, elapsed); + s_histogramLogAggregator.LogTime(ActionInfo.ItemManagerSortTicks, elapsed); } - internal static void LogItemManagerUpdateDataPoint(int count, bool isCanceled) + internal static void LogItemManagerUpdateDataPoint(TimeSpan elapsed, bool isCanceled) { var key = isCanceled ? ActionInfo.ItemManagerUpdateCanceledTicks : ActionInfo.ItemManagerUpdateCompletedTicks; - s_statisticLogAggregator.AddDataPoint((int)key, count); - s_histogramLogAggregator.IncreaseCount((int)key, count); + s_statisticLogAggregator.AddDataPoint(key, elapsed); + s_histogramLogAggregator.LogTime(key, elapsed); } internal static void ReportTelemetry() @@ -106,33 +107,20 @@ internal static void ReportTelemetry() { foreach (var kv in s_statisticLogAggregator) { - var info = ((ActionInfo)kv.Key).ToString("f"); var statistics = kv.Value.GetStatisticResult(); - - m[CreateProperty(info, nameof(StatisticResult.Maximum))] = statistics.Maximum; - m[CreateProperty(info, nameof(StatisticResult.Minimum))] = statistics.Minimum; - m[CreateProperty(info, nameof(StatisticResult.Mean))] = statistics.Mean; - m[CreateProperty(info, nameof(StatisticResult.Range))] = statistics.Range; - m[CreateProperty(info, nameof(StatisticResult.Count))] = statistics.Count; + statistics.WriteTelemetryPropertiesTo(m, prefix: kv.Key.ToString()); } - foreach (var kv in s_logAggregator) + foreach (var kv in s_countLogAggregator) { - var mergeInfo = ((ActionInfo)kv.Key).ToString("f"); - m[mergeInfo] = kv.Value.GetCount(); + m[kv.Key.ToString()] = kv.Value.GetCount(); } foreach (var kv in s_histogramLogAggregator) { - var info = ((ActionInfo)kv.Key).ToString("f"); - m[$"{info}.BucketSize"] = kv.Value.BucketSize; - m[$"{info}.MaxBucketValue"] = kv.Value.MaxBucketValue; - m[$"{info}.Buckets"] = kv.Value.GetBucketsAsString(); + kv.Value.WriteTelemetryPropertiesTo(m, prefix: kv.Key.ToString()); } })); } - - private static string CreateProperty(string parent, string child) - => parent + "." + child; } } diff --git a/src/EditorFeatures/Core/IntelliSense/AsyncCompletion/CommitManager.cs b/src/EditorFeatures/Core/IntelliSense/AsyncCompletion/CommitManager.cs index 824b5edd7bfc4..1aea549900f79 100644 --- a/src/EditorFeatures/Core/IntelliSense/AsyncCompletion/CommitManager.cs +++ b/src/EditorFeatures/Core/IntelliSense/AsyncCompletion/CommitManager.cs @@ -9,12 +9,12 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.Completion; +using Microsoft.CodeAnalysis.Completion.Providers.Snippets; using Microsoft.CodeAnalysis.Editor.Shared.Extensions; using Microsoft.CodeAnalysis.Editor.Shared.Utilities; using Microsoft.CodeAnalysis.ErrorReporting; -using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Formatting; -using Microsoft.CodeAnalysis.Indentation; +using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Text; using Microsoft.CodeAnalysis.Text.Shared.Extensions; @@ -38,6 +38,7 @@ internal sealed class CommitManager : IAsyncCompletionCommitManager private readonly ITextView _textView; private readonly IGlobalOptionService _globalOptions; private readonly IThreadingContext _threadingContext; + private readonly ILanguageServerSnippetExpander? _languageServerSnippetExpander; public IEnumerable PotentialCommitCharacters { @@ -59,12 +60,14 @@ internal CommitManager( ITextView textView, RecentItemsManager recentItemsManager, IGlobalOptionService globalOptions, - IThreadingContext threadingContext) + IThreadingContext threadingContext, + ILanguageServerSnippetExpander? languageServerSnippetExpander) { _globalOptions = globalOptions; _threadingContext = threadingContext; _recentItemsManager = recentItemsManager; _textView = textView; + _languageServerSnippetExpander = languageServerSnippetExpander; } /// @@ -218,7 +221,7 @@ private AsyncCompletionData.CommitResult Commit( var view = session.TextView; - var provider = completionService.GetProvider(roslynItem); + var provider = completionService.GetProvider(roslynItem, document.Project); if (provider is ICustomCommitCompletionProvider customCommitProvider) { customCommitProvider.Commit(roslynItem, view, subjectBuffer, triggerSnapshot, commitCharacter); @@ -229,61 +232,80 @@ private AsyncCompletionData.CommitResult Commit( var triggerSnapshotSpan = new SnapshotSpan(triggerSnapshot, textChange.Span.ToSpan()); var mappedSpan = triggerSnapshotSpan.TranslateTo(subjectBuffer.CurrentSnapshot, SpanTrackingMode.EdgeInclusive); + // Specifically for snippets, we check to see if the associated completion item is a snippet, + // and if so, we call upon the LanguageServerSnippetExpander's TryExpand to insert the snippet. + if (SnippetCompletionItem.IsSnippet(roslynItem)) + { + Contract.ThrowIfNull(_languageServerSnippetExpander); + + var lspSnippetText = change.Properties[SnippetCompletionItem.LSPSnippetKey]; + + Contract.ThrowIfNull(lspSnippetText); + if (!_languageServerSnippetExpander.TryExpand(lspSnippetText, mappedSpan, _textView)) + { + FatalError.ReportAndCatch(new InvalidOperationException("The invoked LSP snippet expander came back as false."), ErrorSeverity.Critical); + } + + return new AsyncCompletionData.CommitResult(isHandled: true, AsyncCompletionData.CommitBehavior.None); + } + + ITextSnapshot updatedCurrentSnapshot; using (var edit = subjectBuffer.CreateEdit(EditOptions.DefaultMinimalChange, reiteratedVersionNumber: null, editTag: null)) { edit.Replace(mappedSpan.Span, change.TextChange.NewText); // edit.Apply() may trigger changes made by extensions. // updatedCurrentSnapshot will contain changes made by Roslyn but not by other extensions. - var updatedCurrentSnapshot = edit.Apply(); + updatedCurrentSnapshot = edit.Apply(); + } - if (change.NewPosition.HasValue) + if (change.NewPosition.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)); + } + else + { + // Or, If we're doing a minimal change, then the edit that we make to the + // buffer may not make the total text change that places the caret where we + // would expect it to go based on the requested change. In this case, + // determine where the item should go and set the care manually. + + // Note: we only want to move the caret if the caret would have been moved + // by the edit. i.e. if the caret was actually in the mapped span that + // we're replacing. + var caretPositionInBuffer = view.GetCaretPoint(subjectBuffer); + if (caretPositionInBuffer.HasValue && mappedSpan.IntersectsWith(caretPositionInBuffer.Value)) { - // 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)); + view.TryMoveCaretToAndEnsureVisible(new SnapshotPoint(subjectBuffer.CurrentSnapshot, mappedSpan.Start.Position + textChange.NewText?.Length ?? 0)); } else { - // Or, If we're doing a minimal change, then the edit that we make to the - // buffer may not make the total text change that places the caret where we - // would expect it to go based on the requested change. In this case, - // determine where the item should go and set the care manually. - - // Note: we only want to move the caret if the caret would have been moved - // by the edit. i.e. if the caret was actually in the mapped span that - // we're replacing. - var caretPositionInBuffer = view.GetCaretPoint(subjectBuffer); - if (caretPositionInBuffer.HasValue && mappedSpan.IntersectsWith(caretPositionInBuffer.Value)) - { - view.TryMoveCaretToAndEnsureVisible(new SnapshotPoint(subjectBuffer.CurrentSnapshot, mappedSpan.Start.Position + textChange.NewText?.Length ?? 0)); - } - else - { - view.Caret.EnsureVisible(); - } + view.Caret.EnsureVisible(); } + } + + includesCommitCharacter = change.IncludesCommitCharacter; - includesCommitCharacter = change.IncludesCommitCharacter; + if (roslynItem.Rules.FormatOnCommit) + { + // The edit updates the snapshot however other extensions may make changes there. + // Therefore, it is required to use subjectBuffer.CurrentSnapshot for further calculations rather than the updated current snapshot defined above. + var currentDocument = subjectBuffer.CurrentSnapshot.GetOpenDocumentInCurrentContextWithChanges(); + var formattingService = currentDocument?.GetRequiredLanguageService(); - if (roslynItem.Rules.FormatOnCommit) + if (currentDocument != null && formattingService != null) { - // The edit updates the snapshot however other extensions may make changes there. - // Therefore, it is required to use subjectBuffer.CurrentSnapshot for further calculations rather than the updated current snapshot defined above. - var currentDocument = subjectBuffer.CurrentSnapshot.GetOpenDocumentInCurrentContextWithChanges(); - var formattingService = currentDocument?.GetRequiredLanguageService(); + var spanToFormat = triggerSnapshotSpan.TranslateTo(subjectBuffer.CurrentSnapshot, SpanTrackingMode.EdgeInclusive); - if (currentDocument != null && formattingService != null) - { - var spanToFormat = triggerSnapshotSpan.TranslateTo(subjectBuffer.CurrentSnapshot, SpanTrackingMode.EdgeInclusive); - var changes = formattingService.GetFormattingChangesAsync( - currentDocument, subjectBuffer, spanToFormat.Span.ToTextSpan(), cancellationToken).WaitAndGetResult(cancellationToken); - currentDocument.Project.Solution.Workspace.ApplyTextChanges(currentDocument.Id, changes, cancellationToken); - } + // Note: C# always completes synchronously, TypeScript is async + var changes = formattingService.GetFormattingChangesAsync(currentDocument, subjectBuffer, spanToFormat.Span.ToTextSpan(), cancellationToken).WaitAndGetResult(cancellationToken); + subjectBuffer.ApplyChanges(changes); } } - _recentItemsManager.MakeMostRecentItem(roslynItem.FilterText); + _recentItemsManager.MakeMostRecentItem(roslynItem); if (provider is INotifyCommittingItemCompletionProvider notifyProvider) { diff --git a/src/EditorFeatures/Core/IntelliSense/AsyncCompletion/CommitManagerProvider.cs b/src/EditorFeatures/Core/IntelliSense/AsyncCompletion/CommitManagerProvider.cs index 0e26037c4397d..61d259cd93922 100644 --- a/src/EditorFeatures/Core/IntelliSense/AsyncCompletion/CommitManagerProvider.cs +++ b/src/EditorFeatures/Core/IntelliSense/AsyncCompletion/CommitManagerProvider.cs @@ -22,17 +22,20 @@ internal class CommitManagerProvider : IAsyncCompletionCommitManagerProvider private readonly IThreadingContext _threadingContext; private readonly RecentItemsManager _recentItemsManager; private readonly IGlobalOptionService _globalOptions; + private readonly ILanguageServerSnippetExpander? _languageServerSnippetExpander; [ImportingConstructor] [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] public CommitManagerProvider( IThreadingContext threadingContext, RecentItemsManager recentItemsManager, - IGlobalOptionService globalOptions) + IGlobalOptionService globalOptions, + [Import(AllowDefault = true)] ILanguageServerSnippetExpander? languageServerSnippetExpander) { _threadingContext = threadingContext; _recentItemsManager = recentItemsManager; _globalOptions = globalOptions; + _languageServerSnippetExpander = languageServerSnippetExpander; } IAsyncCompletionCommitManager? IAsyncCompletionCommitManagerProvider.GetOrCreate(ITextView textView) @@ -42,7 +45,7 @@ public CommitManagerProvider( return null; } - return new CommitManager(textView, _recentItemsManager, _globalOptions, _threadingContext); + return new CommitManager(textView, _recentItemsManager, _globalOptions, _threadingContext, _languageServerSnippetExpander); } } } diff --git a/src/EditorFeatures/Core/IntelliSense/AsyncCompletion/CompletionSessionData.cs b/src/EditorFeatures/Core/IntelliSense/AsyncCompletion/CompletionSessionData.cs index 7f2aa62b984f1..e193e489267ca 100644 --- a/src/EditorFeatures/Core/IntelliSense/AsyncCompletion/CompletionSessionData.cs +++ b/src/EditorFeatures/Core/IntelliSense/AsyncCompletion/CompletionSessionData.cs @@ -26,6 +26,7 @@ internal sealed class CompletionSessionData public TextSpan? CompletionListSpan { get; set; } public CompletionList? CombinedSortedList { get; set; } public Task<(CompletionContext, RoslynCompletionList)>? ExpandedItemsTask { get; set; } + public bool IsExclusive { get; set; } private CompletionSessionData() { diff --git a/src/EditorFeatures/Core/IntelliSense/AsyncCompletion/CompletionSource.cs b/src/EditorFeatures/Core/IntelliSense/AsyncCompletion/CompletionSource.cs index c4519c3057b3b..522cec2a253ea 100644 --- a/src/EditorFeatures/Core/IntelliSense/AsyncCompletion/CompletionSource.cs +++ b/src/EditorFeatures/Core/IntelliSense/AsyncCompletion/CompletionSource.cs @@ -17,9 +17,9 @@ using Microsoft.CodeAnalysis.Editor.Implementation.IntelliSense.QuickInfo; using Microsoft.CodeAnalysis.Editor.Shared.Extensions; using Microsoft.CodeAnalysis.Editor.Shared.Utilities; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.Host; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Options; -using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Shared.TestHooks; using Microsoft.CodeAnalysis.Text; @@ -55,6 +55,9 @@ internal sealed class CompletionSource : IAsyncExpandingCompletionSource private static readonly ConditionalWeakTable> s_roslynItemToVsItemData = new(); + // Cancellation series we use to stop background task for expanded items when exclusive items are returned by core providers. + private readonly CancellationSeries _expandeditemsTaskCancellationSeries = new(); + private readonly ITextView _textView; private readonly bool _isDebuggerTextView; private readonly ImmutableHashSet _roles; @@ -143,7 +146,7 @@ public AsyncCompletionData.CompletionStartData InitializeCompletion( } finally { - AsyncCompletionLogger.LogSourceInitializationTicksDataPoint((int)stopwatch.Elapsed.TotalMilliseconds); + AsyncCompletionLogger.LogSourceInitializationTicksDataPoint(stopwatch.Elapsed); } } @@ -153,7 +156,7 @@ private bool ShouldTriggerCompletion( SourceText sourceText, Document document, CompletionService completionService, - in CompletionOptions options) + CompletionOptions options) { // The trigger reason guarantees that user wants a completion. if (trigger.Reason is AsyncCompletionData.CompletionTriggerReason.Invoke or @@ -173,27 +176,26 @@ private bool ShouldTriggerCompletion( // Otherwise, tab should not be a completion trigger. if (trigger.Reason == AsyncCompletionData.CompletionTriggerReason.Insertion && trigger.Character == '\t') { - return TryInvokeSnippetCompletion(completionService, document, sourceText, triggerLocation.Position, options); + return TryInvokeSnippetCompletion(triggerLocation.Snapshot.TextBuffer, triggerLocation.Position, sourceText, document.Project.Services, completionService.GetRules(options)); } var roslynTrigger = Helpers.GetRoslynTrigger(trigger, triggerLocation); // The completion service decides that user may want a completion. return completionService.ShouldTriggerCompletion( - document.Project, document.Project.LanguageServices, sourceText, triggerLocation.Position, roslynTrigger, options, document.Project.Solution.Options, _roles); + document.Project, document.Project.Services, sourceText, triggerLocation.Position, roslynTrigger, options, document.Project.Solution.Options, _roles); } private bool TryInvokeSnippetCompletion( - CompletionService completionService, Document document, SourceText text, int caretPoint, in CompletionOptions options) + ITextBuffer buffer, int caretPoint, SourceText text, LanguageServices services, CompletionRules rules) { - var rules = completionService.GetRules(options); // Do not invoke snippet if the corresponding rule is not set in options. if (rules.SnippetsRule != SnippetsRule.IncludeAfterTypingIdentifierQuestionTab) { return false; } - var syntaxFacts = document.GetLanguageService(); + var syntaxFacts = services.GetService(); // Snippets are included if the user types: // If at least one condition for snippets do not hold, bail out. if (syntaxFacts == null || @@ -206,8 +208,7 @@ private bool TryInvokeSnippetCompletion( // Because is actually a command to bring up snippets, // we delete the last that was typed. - var textChange = new TextChange(TextSpan.FromBounds(caretPoint - 2, caretPoint), string.Empty); - document.Project.Solution.Workspace.ApplyTextChanges(document.Id, textChange, CancellationToken.None); + buffer.ApplyChange(new TextChange(TextSpan.FromBounds(caretPoint - 2, caretPoint), string.Empty)); _snippetCompletionTriggeredIndirectly = true; return true; @@ -271,7 +272,7 @@ public async Task GetCompletionContextAsync( var sessionData = CompletionSessionData.GetOrCreateSessionData(session); - if (!options.ShouldShowItemsFromUnimportNamspaces()) + if (!options.ShouldShowItemsFromUnimportedNamespaces()) { // No need to trigger expanded providers at all if the feature is disabled, just trigger core providers and return; var (context, list) = await GetCompletionContextWorkerAsync(session, document, trigger, triggerLocation, @@ -296,10 +297,12 @@ public async Task GetCompletionContextAsync( // OK, expand item is enabled but we shouldn't block completion on its results. // Kick off expand item calculation first in background. Stopwatch stopwatch = new(); + + var expandeditemsTaskCancellationToken = _expandeditemsTaskCancellationSeries.CreateNext(cancellationToken); var expandedItemsTask = Task.Run(async () => { var result = await GetCompletionContextWorkerAsync(session, document, trigger, triggerLocation, - options with { ExpandedCompletionBehavior = ExpandedCompletionMode.ExpandedItemsOnly }, cancellationToken).ConfigureAwait(false); + options with { ExpandedCompletionBehavior = ExpandedCompletionMode.ExpandedItemsOnly }, expandeditemsTaskCancellationToken).ConfigureAwait(false); // Record how long it takes for the background task to complete *after* core providers returned. // If telemetry shows that a short wait is all it takes for ExpandedItemsTask to complete in @@ -307,16 +310,24 @@ public async Task GetCompletionContextAsync( // There could be a race around the usage of this stopwatch, I ignored it since we just need a rough idea: // we always log the time even if the stopwatch's not started regardless of whether expand items are included intially // (that number can be obtained via another property.) - AsyncCompletionLogger.LogAdditionalTicksToCompleteDelayedImportCompletionDataPoint((int)stopwatch.ElapsedMilliseconds); + AsyncCompletionLogger.LogAdditionalTicksToCompleteDelayedImportCompletionDataPoint(stopwatch.Elapsed); return result; - }, cancellationToken); + }, expandeditemsTaskCancellationToken); // Now trigger and wait for core providers to return; var (nonExpandedContext, nonExpandedCompletionList) = await GetCompletionContextWorkerAsync(session, document, trigger, triggerLocation, options with { ExpandedCompletionBehavior = ExpandedCompletionMode.NonExpandedItemsOnly }, cancellationToken).ConfigureAwait(false); UpdateSessionData(session, sessionData, nonExpandedCompletionList, triggerLocation); + // If the core items are exclusive, we don't include expanded items. + if (sessionData.IsExclusive) + { + // This would cancel expandedItemsTask. + _ = _expandeditemsTaskCancellationSeries.CreateNext(CancellationToken.None); + return nonExpandedContext; + } + if (expandedItemsTask.IsCompleted) { // the task of expanded item is completed, get the result and combine it with result of non-expanded items. @@ -342,7 +353,7 @@ public async Task GetCompletionContextAsync( } finally { - AsyncCompletionLogger.LogSourceGetContextTicksDataPoint((int)totalStopWatch.Elapsed.TotalMilliseconds, isCanceled: cancellationToken.IsCancellationRequested); + AsyncCompletionLogger.LogSourceGetContextTicksDataPoint(totalStopWatch.Elapsed, isCanceled: cancellationToken.IsCancellationRequested); } static VSCompletionContext CombineCompletionContext(IAsyncCompletionSession session, VSCompletionContext context1, VSCompletionContext context2) @@ -372,8 +383,8 @@ public async Task GetExpandedCompletionContextAsync( { var sessionData = CompletionSessionData.GetOrCreateSessionData(session); - // We only want to provide expanded items for Roslyn's expander. - if (expander == FilterSet.Expander && sessionData.ExpandedItemTriggerLocation.HasValue) + // We only want to provide expanded items for Roslyn's expander + if (!sessionData.IsExclusive && expander == FilterSet.Expander && sessionData.ExpandedItemTriggerLocation.HasValue) { var initialTriggerLocation = sessionData.ExpandedItemTriggerLocation.Value; AsyncCompletionLogger.LogExpanderUsage(); @@ -458,6 +469,8 @@ public async Task GetExpandedCompletionContextAsync( private static void UpdateSessionData(IAsyncCompletionSession session, CompletionSessionData sessionData, CompletionList completionList, SnapshotPoint triggerLocation) { + sessionData.IsExclusive |= completionList.IsExclusive; + // Store around the span this completion list applies to. We'll use this later // to pass this value in when we're committing a completion list item. // It's OK to overwrite this value when expanded items are requested. diff --git a/src/EditorFeatures/Core/IntelliSense/AsyncCompletion/Helpers.cs b/src/EditorFeatures/Core/IntelliSense/AsyncCompletion/Helpers.cs index a811fbb8d2376..585bc42783d47 100644 --- a/src/EditorFeatures/Core/IntelliSense/AsyncCompletion/Helpers.cs +++ b/src/EditorFeatures/Core/IntelliSense/AsyncCompletion/Helpers.cs @@ -4,6 +4,7 @@ using System; using System.Collections.Immutable; +using System.Linq; using Microsoft.CodeAnalysis.Completion; using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.VisualStudio.Text; @@ -121,9 +122,12 @@ public static bool TextTypedSoFarMatchesItem(RoslynCompletionItem item, string t { if (textTypedSoFar.Length > 0) { + using var _ = PooledDelegates.GetPooledFunction(static (filterText, pattern) => filterText.StartsWith(pattern, StringComparison.CurrentCultureIgnoreCase), textTypedSoFar, out Func isPrefixMatch); + // Note that StartsWith ignores \0 at the end of textTypedSoFar on VS Mac and Mono. return item.DisplayText.StartsWith(textTypedSoFar, StringComparison.CurrentCultureIgnoreCase) || - item.FilterText.StartsWith(textTypedSoFar, StringComparison.CurrentCultureIgnoreCase); + item.HasDifferentFilterText && item.FilterText.StartsWith(textTypedSoFar, StringComparison.CurrentCultureIgnoreCase) || + item.HasAdditionalFilterTexts && item.AdditionalFilterTexts.Any(isPrefixMatch); } return false; diff --git a/src/EditorFeatures/Core/IntelliSense/AsyncCompletion/ILanguageServerSnippetExpander.cs b/src/EditorFeatures/Core/IntelliSense/AsyncCompletion/ILanguageServerSnippetExpander.cs new file mode 100644 index 0000000000000..bdfe02aa3816b --- /dev/null +++ b/src/EditorFeatures/Core/IntelliSense/AsyncCompletion/ILanguageServerSnippetExpander.cs @@ -0,0 +1,14 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using Microsoft.VisualStudio.Text; +using Microsoft.VisualStudio.Text.Editor; + +namespace Microsoft.CodeAnalysis.Editor.Implementation.IntelliSense.AsyncCompletion +{ + internal interface ILanguageServerSnippetExpander + { + bool TryExpand(string lspSnippetText, SnapshotSpan snapshotSpan, ITextView textView); + } +} diff --git a/src/EditorFeatures/Core/IntelliSense/AsyncCompletion/ItemManager.CompletionListUpdater.cs b/src/EditorFeatures/Core/IntelliSense/AsyncCompletion/ItemManager.CompletionListUpdater.cs index 9f006a011f984..8fb827780bb7a 100644 --- a/src/EditorFeatures/Core/IntelliSense/AsyncCompletion/ItemManager.CompletionListUpdater.cs +++ b/src/EditorFeatures/Core/IntelliSense/AsyncCompletion/ItemManager.CompletionListUpdater.cs @@ -33,6 +33,9 @@ internal partial class ItemManager /// private sealed class CompletionListUpdater { + // Index used for selecting suggestion item when in suggestion mode. + private const int SuggestionItemIndex = -1; + private readonly CompletionSessionData _sessionData; private readonly AsyncCompletionSessionDataSnapshot _snapshotData; private readonly RecentItemsManager _recentItemsManager; @@ -49,6 +52,9 @@ private sealed class CompletionListUpdater private readonly Action, string, IList> _filterMethod; + private bool ShouldSelectSuggestionItemWhenNoItemMatchesFilterText + => _snapshotData.DisplaySuggestionItem && _filterText.Length > 0; + private CompletionTriggerReason InitialTriggerReason => _snapshotData.InitialTrigger.Reason; private CompletionTriggerReason UpdateTriggerReason => _snapshotData.Trigger.Reason; @@ -232,7 +238,7 @@ private void AddCompletionItems(List> list, Cancel if (CompletionItemData.TryGetData(item, out var itemData)) { if (CompletionHelper.TryCreateMatchResult(_completionHelper, itemData.RoslynItem, item, _filterText, - roslynInitialTriggerKind, roslynFilterReason, _recentItemsManager.RecentItems, _highlightMatchingPortions, currentIndex, + roslynInitialTriggerKind, roslynFilterReason, _recentItemsManager.GetRecentItemIndex(itemData.RoslynItem) >= 0, _highlightMatchingPortions, currentIndex, out var matchResult)) { list.Add(matchResult); @@ -258,7 +264,7 @@ private void AddCompletionItems(List> list, Cancel { // Not deletion. Defer to the language to decide which item it thinks best // matches the text typed so far. - itemMatchPairBuilder.AddRange(items.Where(r => r.MatchedFilterText).Select(t => (t.RoslynCompletionItem, t.PatternMatch))); + itemMatchPairBuilder.AddRange(items.Where(r => r.ShouldBeConsideredMatchingFilterText).Select(t => (t.RoslynCompletionItem, t.PatternMatch))); _filterMethod(itemMatchPairBuilder, _filterText, filteredItemsBuilder); // Ask the language to determine which of the *matched* items it wants to select. @@ -267,17 +273,22 @@ private void AddCompletionItems(List> list, Cancel MatchResult bestOrFirstMatchResult; if (filteredItemsBuilder.Count == 0) { + // When we are in suggestion mode and there's nothing in the list matches what user has typed in any ways, + // we should select the SuggestionItem instead. + if (ShouldSelectSuggestionItemWhenNoItemMatchesFilterText) + return new ItemSelection(SelectedItemIndex: SuggestionItemIndex, SelectionHint: UpdateSelectionHint.SoftSelected, UniqueItem: null); + // We do not have matches: pick the one with longest common prefix. // If we can't find such an item, just return the first item from the list. selectedItemIndex = 0; bestOrFirstMatchResult = items[0]; - var longestCommonPrefixLength = bestOrFirstMatchResult.RoslynCompletionItem.FilterText.GetCaseInsensitivePrefixLength(_filterText); + var longestCommonPrefixLength = bestOrFirstMatchResult.FilterTextUsed.GetCaseInsensitivePrefixLength(_filterText); for (var i = 1; i < items.Count; ++i) { var item = items[i]; - var commonPrefixLength = item.RoslynCompletionItem.FilterText.GetCaseInsensitivePrefixLength(_filterText); + var commonPrefixLength = item.FilterTextUsed.GetCaseInsensitivePrefixLength(_filterText); if (commonPrefixLength > longestCommonPrefixLength) { @@ -334,7 +345,7 @@ private void AddCompletionItems(List> list, Cancel return null; } - var isHardSelection = IsHardSelection(bestOrFirstMatchResult.RoslynCompletionItem, bestOrFirstMatchResult.MatchedFilterText); + var isHardSelection = IsHardSelection(bestOrFirstMatchResult.RoslynCompletionItem, bestOrFirstMatchResult.ShouldBeConsideredMatchingFilterText); var updateSelectionHint = isHardSelection ? UpdateSelectionHint.Selected : UpdateSelectionHint.SoftSelected; return new(selectedItemIndex, updateSelectionHint, uniqueItem); @@ -365,7 +376,7 @@ private void AddCompletionItems(List> list, Cancel { var currentMatchResult = items[i]; - if (!currentMatchResult.MatchedFilterText) + if (!currentMatchResult.ShouldBeConsideredMatchingFilterText) continue; if (bestMatchResult == null) @@ -390,7 +401,7 @@ private void AddCompletionItems(List> list, Cancel } } - if (UpdateTriggerReason == CompletionTriggerReason.Insertion && bestMatchResult is null) + if (bestMatchResult is null) { // The user has typed something, but nothing in the actual list matched what // they were typing. In this case, we want to dismiss completion entirely. @@ -398,10 +409,14 @@ private void AddCompletionItems(List> list, Cancel // to help them when they typed delete (in case they wanted to pick another // item). However, they're typing something that doesn't seem to match at all // The completion list is just distracting at this point. - return null; - } + if (UpdateTriggerReason == CompletionTriggerReason.Insertion) + return null; - if (bestMatchResult is not null) + // If we are in suggestion mode and nothing matches filter text, we should soft select SuggestionItem. + if (ShouldSelectSuggestionItemWhenNoItemMatchesFilterText) + indexToSelect = SuggestionItemIndex; + } + else { // Only hard select this result if it's a prefix match // We need to do this so that @@ -409,13 +424,13 @@ private void AddCompletionItems(List> list, Cancel // text that originally appeared before the dot // * deleting through a word from the end keeps that word selected // This also preserves the behavior the VB had through Dev12. - hardSelect = !_hasSuggestedItemOptions && bestMatchResult.Value.EditorCompletionItem.FilterText.StartsWith(_filterText, StringComparison.CurrentCultureIgnoreCase); + hardSelect = !_hasSuggestedItemOptions && bestMatchResult.Value.FilterTextUsed.StartsWith(_filterText, StringComparison.CurrentCultureIgnoreCase); } // The best match we have selected is unique if `moreThanOneMatch` is false. return new(SelectedItemIndex: indexToSelect, SelectionHint: hardSelect ? UpdateSelectionHint.Selected : UpdateSelectionHint.SoftSelected, - UniqueItem: moreThanOneMatch ? null : bestMatchResult.GetValueOrDefault().EditorCompletionItem); + UniqueItem: moreThanOneMatch || !bestMatchResult.HasValue ? null : bestMatchResult.Value.EditorCompletionItem); } private CompletionList GetHighlightedList( @@ -438,14 +453,15 @@ static ImmutableArray GetHighlightedSpans( CompletionHelper completionHelper, string filterText) { - if (matchResult.RoslynCompletionItem.HasDifferentFilterText) + if (matchResult.RoslynCompletionItem.HasDifferentFilterText || matchResult.RoslynCompletionItem.HasAdditionalFilterTexts) { - // The PatternMatch in MatchResult is calculated based on Roslyn item's FilterText, - // which can be used to calculate highlighted span for VSCompletion item's DisplayText w/o doing the matching again. - // However, if the Roslyn item's FilterText is different from its DisplayText, - // we need to do the match against the display text of the VS item directly to get the highlighted spans. + // The PatternMatch in MatchResult is calculated based on Roslyn item's FilterText, which can be used to calculate + // highlighted span for VSCompletion item's DisplayText w/o doing the matching again. + // However, if the Roslyn item's FilterText is different from its DisplayText, we need to do the match against the + // display text of the VS item directly to get the highlighted spans. This is done in a best effort fashion and there + // is no guarantee a proper match would be found for highlighting. return completionHelper.GetHighlightedSpans( - matchResult.EditorCompletionItem.DisplayText, filterText, CultureInfo.CurrentCulture).SelectAsArray(s => s.ToSpan()); + matchResult.RoslynCompletionItem, filterText, CultureInfo.CurrentCulture).SelectAsArray(s => s.ToSpan()); } var patternMatch = matchResult.PatternMatch; @@ -479,6 +495,9 @@ static Span GetOffsetSpan(TextSpan span, RoslynCompletionItem item) } } + // If we are in suggestion mode then we should select the SuggestionItem instead. + var selectedItemIndex = ShouldSelectSuggestionItemWhenNoItemMatchesFilterText ? SuggestionItemIndex : 0; + // If the user has turned on some filtering states, and we filtered down to // nothing, then we do want the UI to show that to them. That way the user // can turn off filters they don't want and get the right set of items. @@ -487,7 +506,7 @@ static Span GetOffsetSpan(TextSpan span, RoslynCompletionItem item) // model (and all the previously filtered items), but switch over to soft // selection. return new FilteredCompletionModel( - items: ImmutableArray.Empty, selectedItemIndex: 0, + items: ImmutableArray.Empty, selectedItemIndex, filters: _snapshotData.SelectedFilters, selectionHint: UpdateSelectionHint.SoftSelected, centerSelection: true, uniqueItem: null); } @@ -517,26 +536,24 @@ private RoslynCompletionItem GetBestCompletionItemBasedOnMRUFirstOtherwiseOnPrio { Debug.Assert(chosenItems.Count > 0); - var recentItems = _recentItemsManager.RecentItems; - // Try to find the chosen item has been most recently used. var bestItem = chosenItems[0]; - var mruIndex1 = GetRecentItemIndex(recentItems, bestItem); + var bestItemMruIndex = _recentItemsManager.GetRecentItemIndex(bestItem); for (int i = 1, n = chosenItems.Count; i < n; i++) { - var chosenItem = chosenItems[i]; - var mruIndex2 = GetRecentItemIndex(recentItems, chosenItem); + var currentItem = chosenItems[i]; + var currentItemMruIndex = _recentItemsManager.GetRecentItemIndex(currentItem); - if ((mruIndex2 < mruIndex1) || - (mruIndex2 == mruIndex1 && !bestItem.IsPreferredItem() && chosenItem.IsPreferredItem())) + if (currentItemMruIndex > bestItemMruIndex || + (currentItemMruIndex == bestItemMruIndex && !bestItem.IsPreferredItem() && currentItem.IsPreferredItem())) { - bestItem = chosenItem; - mruIndex1 = GetRecentItemIndex(recentItems, bestItem); + bestItem = currentItem; + bestItemMruIndex = currentItemMruIndex; } } // If our best item appeared in the MRU list, use it - if (GetRecentItemIndex(recentItems, bestItem) <= 0) + if (_recentItemsManager.GetRecentItemIndex(bestItem) >= 0) { return bestItem; } @@ -556,12 +573,6 @@ private RoslynCompletionItem GetBestCompletionItemBasedOnMRUFirstOtherwiseOnPrio } return bestItem; - - static int GetRecentItemIndex(ImmutableArray recentItems, RoslynCompletionItem item) - { - var index = recentItems.IndexOf(item.FilterText); - return -index; - } } private static bool TryGetInitialTriggerLocation(AsyncCompletionSessionDataSnapshot data, out SnapshotPoint intialTriggerLocation) @@ -671,8 +682,8 @@ private static bool IsPotentialFilterCharacter(char c) private ItemSelection UpdateSelectionBasedOnSuggestedDefaults(IReadOnlyList> items, ItemSelection itemSelection, CancellationToken cancellationToken) { - // Editor doesn't provide us a list of "default" items. - if (_snapshotData.Defaults.IsDefaultOrEmpty) + // Editor doesn't provide us a list of "default" items, or we select SuggestionItem (because we are in suggestion mode and have no match in the list) + if (_snapshotData.Defaults.IsDefaultOrEmpty || itemSelection.SelectedItemIndex == SuggestionItemIndex) return itemSelection; // "Preselect" is only used when we have high confidence with the selection, so don't override it. diff --git a/src/EditorFeatures/Core/IntelliSense/AsyncCompletion/ItemManager.cs b/src/EditorFeatures/Core/IntelliSense/AsyncCompletion/ItemManager.cs index 923ccaf47ce15..1af161ff26fbb 100644 --- a/src/EditorFeatures/Core/IntelliSense/AsyncCompletion/ItemManager.cs +++ b/src/EditorFeatures/Core/IntelliSense/AsyncCompletion/ItemManager.cs @@ -39,7 +39,7 @@ public Task> SortCompletionListAsync( var stopwatch = SharedStopwatch.StartNew(); var items = SortCompletionitems(data, cancellationToken).ToImmutableArray(); - AsyncCompletionLogger.LogItemManagerSortTicksDataPoint((int)stopwatch.Elapsed.TotalMilliseconds); + AsyncCompletionLogger.LogItemManagerSortTicksDataPoint(stopwatch.Elapsed); return Task.FromResult(items); } @@ -51,16 +51,21 @@ public Task> SortCompletionItemListAsync( var stopwatch = SharedStopwatch.StartNew(); var itemList = session.CreateCompletionList(SortCompletionitems(data, cancellationToken)); - AsyncCompletionLogger.LogItemManagerSortTicksDataPoint((int)stopwatch.Elapsed.TotalMilliseconds); + AsyncCompletionLogger.LogItemManagerSortTicksDataPoint(stopwatch.Elapsed); return Task.FromResult(itemList); } private static SegmentedList SortCompletionitems(AsyncCompletionSessionInitialDataSnapshot data, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); - var items = new SegmentedList(data.InitialItemList); - items.Sort(VSItemComparer.Instance); + var items = new SegmentedList(data.InitialItemList.Count); + foreach (var item in data.InitialItemList) + { + CompletionItemData.GetOrAddDummyRoslynItem(item); + items.Add(item); + } + items.Sort(VSItemComparer.Instance); return items; } @@ -122,7 +127,7 @@ private static SegmentedList SortCompletionitems(AsyncCompleti } finally { - AsyncCompletionLogger.LogItemManagerUpdateDataPoint((int)stopwatch.Elapsed.TotalMilliseconds, isCanceled: cancellationToken.IsCancellationRequested); + AsyncCompletionLogger.LogItemManagerUpdateDataPoint(stopwatch.Elapsed, isCanceled: cancellationToken.IsCancellationRequested); } } diff --git a/src/EditorFeatures/Core/IntelliSense/AsyncCompletion/RecentItemsManager.cs b/src/EditorFeatures/Core/IntelliSense/AsyncCompletion/RecentItemsManager.cs index c648d4f008c60..ad15a678477d2 100644 --- a/src/EditorFeatures/Core/IntelliSense/AsyncCompletion/RecentItemsManager.cs +++ b/src/EditorFeatures/Core/IntelliSense/AsyncCompletion/RecentItemsManager.cs @@ -5,6 +5,7 @@ using System; using System.Collections.Immutable; using System.ComponentModel.Composition; +using Microsoft.CodeAnalysis.Completion; using Microsoft.CodeAnalysis.Host.Mef; namespace Microsoft.CodeAnalysis.Editor.Implementation.IntelliSense.AsyncCompletion @@ -25,14 +26,14 @@ public RecentItemsManager() { } - public ImmutableArray RecentItems { get; private set; } = ImmutableArray.Empty; + private ImmutableArray RecentItems { get; set; } = ImmutableArray.Empty; - public void MakeMostRecentItem(string item) + public void MakeMostRecentItem(CompletionItem item) { lock (_mruUpdateLock) { var items = RecentItems; - items = items.Remove(item); + items = items.Remove(item.FilterText); if (items.Length == MaxMRUSize) { @@ -40,8 +41,13 @@ public void MakeMostRecentItem(string item) items = items.RemoveAt(0); } - RecentItems = items.Add(item); + RecentItems = items.Add(item.FilterText); } } + + public int GetRecentItemIndex(CompletionItem item) + { + return RecentItems.IndexOf(item.FilterText); + } } } diff --git a/src/EditorFeatures/Core/IntelliSense/ModelComputation.cs b/src/EditorFeatures/Core/IntelliSense/ModelComputation.cs index 8a0048d55543e..34ad60a6c31cd 100644 --- a/src/EditorFeatures/Core/IntelliSense/ModelComputation.cs +++ b/src/EditorFeatures/Core/IntelliSense/ModelComputation.cs @@ -182,10 +182,7 @@ private void OnModelUpdated(TModel result, bool updateController) this.ThreadingContext.ThrowIfNotOnUIThread(); // Store the first result so that anyone who cares knows we've computed something - if (_initialUnfilteredModel == null) - { - _initialUnfilteredModel = result; - } + _initialUnfilteredModel ??= result; _controller.OnModelUpdated(result, updateController); } diff --git a/src/EditorFeatures/Core/IntelliSense/QuickInfo/QuickInfoSourceProvider.QuickInfoSource.cs b/src/EditorFeatures/Core/IntelliSense/QuickInfo/QuickInfoSourceProvider.QuickInfoSource.cs index acad4c42dbb00..e45ee3288845a 100644 --- a/src/EditorFeatures/Core/IntelliSense/QuickInfo/QuickInfoSourceProvider.QuickInfoSource.cs +++ b/src/EditorFeatures/Core/IntelliSense/QuickInfo/QuickInfoSourceProvider.QuickInfoSource.cs @@ -12,7 +12,7 @@ using Microsoft.CodeAnalysis.Editor.Shared.Utilities; using Microsoft.CodeAnalysis.ErrorReporting; using Microsoft.CodeAnalysis.Internal.Log; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.QuickInfo; using Microsoft.CodeAnalysis.Shared.TestHooks; using Microsoft.CodeAnalysis.Options; diff --git a/src/EditorFeatures/Core/Interactive/Completion/InteractiveCommandCompletionService.cs b/src/EditorFeatures/Core/Interactive/Completion/InteractiveCommandCompletionService.cs index 0c3d0d97fc7e6..6d816eb59abc4 100644 --- a/src/EditorFeatures/Core/Interactive/Completion/InteractiveCommandCompletionService.cs +++ b/src/EditorFeatures/Core/Interactive/Completion/InteractiveCommandCompletionService.cs @@ -22,11 +22,11 @@ public Factory() } public ILanguageService CreateLanguageService(HostLanguageServices languageServices) - => new InteractiveCommandCompletionService(languageServices.WorkspaceServices.Workspace); + => new InteractiveCommandCompletionService(languageServices.LanguageServices.SolutionServices); } - private InteractiveCommandCompletionService(Workspace workspace) - : base(workspace) + private InteractiveCommandCompletionService(SolutionServices services) + : base(services) { } diff --git a/src/EditorFeatures/Core/Interactive/InteractiveSession.cs b/src/EditorFeatures/Core/Interactive/InteractiveSession.cs index d457f271f1e32..26cad7274c8fa 100644 --- a/src/EditorFeatures/Core/Interactive/InteractiveSession.cs +++ b/src/EditorFeatures/Core/Interactive/InteractiveSession.cs @@ -4,7 +4,6 @@ extern alias InteractiveHost; extern alias Scripting; - using System; using System.Collections.Generic; using System.Collections.Immutable; @@ -17,11 +16,13 @@ using Microsoft.CodeAnalysis.Editor.Shared.Utilities; using Microsoft.CodeAnalysis.ErrorReporting; using Microsoft.CodeAnalysis.Host; +using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Scripting.Hosting; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Shared.TestHooks; using Microsoft.CodeAnalysis.Text; using Microsoft.VisualStudio.Text; +using Microsoft.VisualStudio.Text.Editor; using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Interactive @@ -37,6 +38,7 @@ internal sealed class InteractiveSession : IDisposable private readonly InteractiveEvaluatorLanguageInfoProvider _languageInfo; private readonly InteractiveWorkspace _workspace; private readonly ITextDocumentFactoryService _textDocumentFactoryService; + private readonly EditorOptionsService _editorOptionsService; private readonly CancellationTokenSource _shutdownCancellationSource; @@ -77,14 +79,16 @@ public InteractiveSession( InteractiveWorkspace workspace, IThreadingContext threadingContext, IAsynchronousOperationListener listener, - ITextDocumentFactoryService factoryService, + ITextDocumentFactoryService documentFactory, + EditorOptionsService editorOptionsService, InteractiveEvaluatorLanguageInfoProvider languageInfo, string initialWorkingDirectory) { _workspace = workspace; _threadingContext = threadingContext; _languageInfo = languageInfo; - _textDocumentFactoryService = factoryService; + _textDocumentFactoryService = documentFactory; + _editorOptionsService = editorOptionsService; _taskQueue = new TaskQueue(listener, TaskScheduler.Default); _shutdownCancellationSource = new CancellationTokenSource(); diff --git a/src/EditorFeatures/Core/Interactive/SendToInteractiveSubmissionProvider.cs b/src/EditorFeatures/Core/Interactive/SendToInteractiveSubmissionProvider.cs index ae3f4c7138782..7daccf0b885f1 100644 --- a/src/EditorFeatures/Core/Interactive/SendToInteractiveSubmissionProvider.cs +++ b/src/EditorFeatures/Core/Interactive/SendToInteractiveSubmissionProvider.cs @@ -37,20 +37,20 @@ internal abstract class AbstractSendToInteractiveSubmissionProvider : ISendToInt string ISendToInteractiveSubmissionProvider.GetSelectedText(IEditorOptions editorOptions, EditorCommandArgs args, CancellationToken cancellationToken) { var selectedSpans = args.TextView.Selection.IsEmpty - ? GetExpandedLineAsync(editorOptions, args, cancellationToken).WaitAndGetResult(cancellationToken) + ? GetExpandedLine(editorOptions, args, cancellationToken) : args.TextView.Selection.GetSnapshotSpansOnBuffer(args.SubjectBuffer).Where(ss => ss.Length > 0); return GetSubmissionFromSelectedSpans(editorOptions, selectedSpans); } /// Returns the span for the selected line. Extends it if it is a part of a multi line statement or declaration. - private Task> GetExpandedLineAsync(IEditorOptions editorOptions, EditorCommandArgs args, CancellationToken cancellationToken) + private IEnumerable GetExpandedLine(IEditorOptions editorOptions, EditorCommandArgs args, CancellationToken cancellationToken) { var selectedSpans = GetSelectedLine(args.TextView); var candidateSubmission = GetSubmissionFromSelectedSpans(editorOptions, selectedSpans); return CanParseSubmission(candidateSubmission) - ? Task.FromResult(selectedSpans) - : ExpandSelectionAsync(selectedSpans, args, cancellationToken); + ? selectedSpans + : ExpandSelection(selectedSpans, args, cancellationToken); } /// Returns the span for the currently selected line. @@ -61,35 +61,19 @@ private static IEnumerable GetSelectedLine(ITextView textView) return new NormalizedSnapshotSpanCollection(span); } - private async Task> GetExecutableSyntaxTreeNodeSelectionAsync( - TextSpan selectionSpan, - EditorCommandArgs args, - ITextSnapshot snapshot, - CancellationToken cancellationToken) - { - var doc = args.SubjectBuffer.CurrentSnapshot.GetOpenDocumentInCurrentContextWithChanges(); - var semanticDocument = await SemanticDocument.CreateAsync(doc, cancellationToken).ConfigureAwait(false); - var root = semanticDocument.Root; - - return GetExecutableSyntaxTreeNodeSelection(selectionSpan, root) - .Select(span => new SnapshotSpan(snapshot, span.Start, span.Length)); - } - - private async Task> ExpandSelectionAsync(IEnumerable selectedSpans, EditorCommandArgs args, CancellationToken cancellationToken) + private IEnumerable ExpandSelection(IEnumerable selectedSpans, EditorCommandArgs args, CancellationToken cancellationToken) { var selectedSpansStart = selectedSpans.Min(span => span.Start); var selectedSpansEnd = selectedSpans.Max(span => span.End); var snapshot = args.TextView.TextSnapshot; - var newSpans = await GetExecutableSyntaxTreeNodeSelectionAsync( - TextSpan.FromBounds(selectedSpansStart, selectedSpansEnd), - args, - snapshot, - cancellationToken).ConfigureAwait(false); + var document = args.SubjectBuffer.CurrentSnapshot.GetOpenDocumentInCurrentContextWithChanges(); + var root = document.GetSyntaxRootSynchronously(cancellationToken); + + var newSpans = GetExecutableSyntaxTreeNodeSelection(TextSpan.FromBounds(selectedSpansStart, selectedSpansEnd), root). + Select(span => new SnapshotSpan(snapshot, span.Start, span.Length)); - return newSpans.Any() - ? newSpans.Select(n => new SnapshotSpan(snapshot, n.Span.Start, n.Span.Length)) - : selectedSpans; + return newSpans.Any() ? newSpans : selectedSpans; } private static string GetSubmissionFromSelectedSpans(IEditorOptions editorOptions, IEnumerable selectedSpans) diff --git a/src/EditorFeatures/Core/KeywordHighlighting/HighlighterViewTaggerProvider.cs b/src/EditorFeatures/Core/KeywordHighlighting/HighlighterViewTaggerProvider.cs index 3a170dd394e25..a13158791e6fc 100644 --- a/src/EditorFeatures/Core/KeywordHighlighting/HighlighterViewTaggerProvider.cs +++ b/src/EditorFeatures/Core/KeywordHighlighting/HighlighterViewTaggerProvider.cs @@ -102,8 +102,8 @@ protected override async Task ProduceTagsAsync( // want to actually go recompute things. Note: this only works for containment. If the // user moves their caret to the end of a highlighted reference, we do want to recompute // as they may now be at the start of some other reference that should be highlighted instead. - var existingTags = context.GetExistingContainingTags(new SnapshotPoint(snapshot, position)); - if (!existingTags.IsEmpty()) + var onExistingTags = context.HasExistingContainingTags(new SnapshotPoint(snapshot, position)); + if (onExistingTags) { context.SetSpansTagged(ImmutableArray.Empty); return; diff --git a/src/EditorFeatures/Core/LanguageServer/Handlers/CodeActions/CodeActionResolveHandler.cs b/src/EditorFeatures/Core/LanguageServer/Handlers/CodeActions/CodeActionResolveHandler.cs index 8bccffebf339a..0a2638c9d4880 100644 --- a/src/EditorFeatures/Core/LanguageServer/Handlers/CodeActions/CodeActionResolveHandler.cs +++ b/src/EditorFeatures/Core/LanguageServer/Handlers/CodeActions/CodeActionResolveHandler.cs @@ -108,7 +108,7 @@ public CodeActionResolveHandler( if (applyChangesOperations.Any()) { var solution = document.Project.Solution; - var textDiffService = solution.Workspace.Services.GetService(); + var textDiffService = solution.Services.GetService(); using var _ = ArrayBuilder.GetInstance(out var textDocumentEdits); foreach (var applyChangesOperation in applyChangesOperations) diff --git a/src/EditorFeatures/Core/LanguageServer/Handlers/Completion/CompletionHandler.cs b/src/EditorFeatures/Core/LanguageServer/Handlers/Completion/CompletionHandler.cs index 85451ddbb0ee9..090349cab9596 100644 --- a/src/EditorFeatures/Core/LanguageServer/Handlers/Completion/CompletionHandler.cs +++ b/src/EditorFeatures/Core/LanguageServer/Handlers/Completion/CompletionHandler.cs @@ -338,12 +338,9 @@ static void PromoteCommonCommitCharactersOntoList(LSP.VSInternalCompletionList c { var completionItem = completionList.Items[i]; var commitCharacters = completionItem.CommitCharacters; - if (commitCharacters == null) - { - // The commit characters on the item are null, this means the commit characters are actually - // the default commit characters we passed in the initialize request. - commitCharacters = defaultCommitCharacters; - } + // The commit characters on the item are null, this means the commit characters are actually + // the default commit characters we passed in the initialize request. + commitCharacters ??= defaultCommitCharacters; commitCharacterReferences.TryGetValue(commitCharacters, out var existingCount); existingCount++; @@ -461,7 +458,7 @@ private static (CompletionList CompletionList, bool IsIncomplete) FilterCompleti filterText, completionTrigger.Kind, GetFilterReason(completionTrigger), - recentItems: ImmutableArray.Empty, + isRecentItem: false, includeMatchSpans: false, index, out var matchResult)) diff --git a/src/EditorFeatures/Core/LanguageServer/Handlers/Completion/CompletionResolveHandler.cs b/src/EditorFeatures/Core/LanguageServer/Handlers/Completion/CompletionResolveHandler.cs index a889727b91779..a4b756666a5b0 100644 --- a/src/EditorFeatures/Core/LanguageServer/Handlers/Completion/CompletionResolveHandler.cs +++ b/src/EditorFeatures/Core/LanguageServer/Handlers/Completion/CompletionResolveHandler.cs @@ -11,7 +11,7 @@ using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.Internal.Log; using Microsoft.CodeAnalysis.LanguageServer.Handler.Completion; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Options; using Microsoft.VisualStudio.Text.Adornments; using Newtonsoft.Json.Linq; @@ -50,7 +50,7 @@ public CompletionResolveHandler(IGlobalOptionService globalOptions, CompletionLi var document = context.Document; Contract.ThrowIfNull(document); - var completionService = document.Project.LanguageServices.GetRequiredService(); + var completionService = document.Project.Services.GetRequiredService(); var cacheEntry = GetCompletionListCacheEntry(completionItem); if (cacheEntry == null) diff --git a/src/EditorFeatures/Core/LanguageServer/Handlers/Hover/HoverHandler.cs b/src/EditorFeatures/Core/LanguageServer/Handlers/Hover/HoverHandler.cs index 03bab585bfc54..8ea9d8e46ccc2 100644 --- a/src/EditorFeatures/Core/LanguageServer/Handlers/Hover/HoverHandler.cs +++ b/src/EditorFeatures/Core/LanguageServer/Handlers/Hover/HoverHandler.cs @@ -13,7 +13,7 @@ using Microsoft.CodeAnalysis.Editor.Implementation.IntelliSense.QuickInfo; using Microsoft.CodeAnalysis.Host; using Microsoft.CodeAnalysis.Host.Mef; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.QuickInfo; using Microsoft.CodeAnalysis.Text; @@ -51,7 +51,7 @@ public HoverHandler(IGlobalOptionService globalOptions) Contract.ThrowIfNull(document); var position = await document.GetPositionFromLinePositionAsync(ProtocolConversions.PositionToLinePosition(request.Position), cancellationToken).ConfigureAwait(false); - var quickInfoService = document.Project.LanguageServices.GetRequiredService(); + var quickInfoService = document.Project.Services.GetRequiredService(); var options = _globalOptions.GetSymbolDescriptionOptions(document.Project.Language); var info = await quickInfoService.GetQuickInfoAsync(document, position, options, cancellationToken).ConfigureAwait(false); if (info == null) @@ -68,7 +68,7 @@ public HoverHandler(IGlobalOptionService globalOptions) SemanticModel semanticModel, int position, SymbolDescriptionOptions options, - HostLanguageServices languageServices, + LanguageServices languageServices, CancellationToken cancellationToken) { Debug.Assert(semanticModel.Language is LanguageNames.CSharp or LanguageNames.VisualBasic); @@ -113,7 +113,7 @@ private static async Task GetHoverAsync( return new VSInternalHover { Range = ProtocolConversions.TextSpanToRange(info.Span, text), - Contents = new SumType, SumType[], MarkupContent>(string.Empty), + Contents = new SumType[], MarkupContent>(string.Empty), // Build the classified text without navigation actions - they are not serializable. // TODO - Switch to markup content once it supports classifications. // https://devdiv.visualstudio.com/DevDiv/_workitems/edit/918138 diff --git a/src/EditorFeatures/Core/LanguageServer/Handlers/References/FindUsagesLSPContext.cs b/src/EditorFeatures/Core/LanguageServer/Handlers/References/FindUsagesLSPContext.cs index 20aa4fef436e9..51ebd57f38bc5 100644 --- a/src/EditorFeatures/Core/LanguageServer/Handlers/References/FindUsagesLSPContext.cs +++ b/src/EditorFeatures/Core/LanguageServer/Handlers/References/FindUsagesLSPContext.cs @@ -245,7 +245,7 @@ public override async ValueTask OnReferenceFoundAsync(SourceReferenceItem refere return null; } - var options = _globalOptions.GetMetadataAsSourceOptions(_document.Project.LanguageServices); + var options = _globalOptions.GetMetadataAsSourceOptions(_document.Project.Services); var declarationFile = await _metadataAsSourceFileService.GetGeneratedFileAsync( _document.Project, symbol, signaturesOnly: true, options, cancellationToken).ConfigureAwait(false); diff --git a/src/EditorFeatures/Core/LanguageServer/Handlers/Rename/RenameHandler.cs b/src/EditorFeatures/Core/LanguageServer/Handlers/Rename/RenameHandler.cs index 7cf171728af02..e000558796ddc 100644 --- a/src/EditorFeatures/Core/LanguageServer/Handlers/Rename/RenameHandler.cs +++ b/src/EditorFeatures/Core/LanguageServer/Handlers/Rename/RenameHandler.cs @@ -43,7 +43,7 @@ public RenameHandler() Contract.ThrowIfNull(document); var oldSolution = document.Project.Solution; - var renameService = document.Project.LanguageServices.GetRequiredService(); + var renameService = document.Project.Services.GetRequiredService(); var position = await document.GetPositionFromLinePositionAsync(ProtocolConversions.PositionToLinePosition(request.Position), cancellationToken).ConfigureAwait(false); var renameInfo = await renameService.GetRenameInfoAsync(document, position, cancellationToken).ConfigureAwait(false); @@ -73,7 +73,7 @@ public RenameHandler() .SelectMany(p => p.GetChangedDocuments(onlyGetDocumentsWithTextChanges: true)) .GroupBy(docId => renamedSolution.GetRequiredDocument(docId).FilePath, StringComparer.OrdinalIgnoreCase).Select(group => group.First()); - var textDiffService = renamedSolution.Workspace.Services.GetRequiredService(); + var textDiffService = renamedSolution.Services.GetRequiredService(); var documentEdits = await ProtocolConversions.ChangedDocumentsToTextDocumentEditsAsync(changedDocuments, renamedSolution.GetRequiredDocument, oldSolution.GetRequiredDocument, textDiffService, cancellationToken).ConfigureAwait(false); diff --git a/src/EditorFeatures/Core/LanguageServer/Handlers/Symbols/DocumentSymbolsHandler.cs b/src/EditorFeatures/Core/LanguageServer/Handlers/Symbols/DocumentSymbolsHandler.cs index 7fe0045844257..0ecfec5b23e0d 100644 --- a/src/EditorFeatures/Core/LanguageServer/Handlers/Symbols/DocumentSymbolsHandler.cs +++ b/src/EditorFeatures/Core/LanguageServer/Handlers/Symbols/DocumentSymbolsHandler.cs @@ -25,7 +25,7 @@ namespace Microsoft.CodeAnalysis.LanguageServer.Handler /// [ExportCSharpVisualBasicStatelessLspService(typeof(DocumentSymbolsHandler)), Shared] [Method(Methods.TextDocumentDocumentSymbolName)] - internal class DocumentSymbolsHandler : IRequestHandler + internal class DocumentSymbolsHandler : IRequestHandler { public bool MutatesSolutionState => false; public bool RequiresLSPSolution => true; @@ -36,14 +36,14 @@ public DocumentSymbolsHandler() { } - public TextDocumentIdentifier GetTextDocumentIdentifier(DocumentSymbolParams request) => request.TextDocument; + public TextDocumentIdentifier GetTextDocumentIdentifier(RoslynDocumentSymbolParams request) => request.TextDocument; - public async Task HandleRequestAsync(DocumentSymbolParams request, RequestContext context, CancellationToken cancellationToken) + public async Task HandleRequestAsync(RoslynDocumentSymbolParams request, RequestContext context, CancellationToken cancellationToken) { var document = context.Document; Contract.ThrowIfNull(document); - var navBarService = document.Project.LanguageServices.GetRequiredService(); + var navBarService = document.Project.Services.GetRequiredService(); var navBarItems = await navBarService.GetItemsAsync(document, supportsCodeGeneration: false, forceFrozenPartialSemanticsForCrossProcessOperations: false, cancellationToken).ConfigureAwait(false); if (navBarItems.IsEmpty) return Array.Empty(); @@ -53,7 +53,7 @@ public async Task HandleRequestAsync(DocumentSymbolParams request, Req // TODO - Return more than 2 levels of symbols. // https://github.com/dotnet/roslyn/projects/45#card-20033869 using var _ = ArrayBuilder.GetInstance(out var symbols); - if (context.ClientCapabilities?.TextDocument?.DocumentSymbol?.HierarchicalDocumentSymbolSupport == true) + if (context.ClientCapabilities?.TextDocument?.DocumentSymbol?.HierarchicalDocumentSymbolSupport == true || request.UseHierarchicalSymbols) { // only top level ones foreach (var item in navBarItems) diff --git a/src/EditorFeatures/Core/LanguageServer/Handlers/Symbols/RoslynDocumentSymbolParams.cs b/src/EditorFeatures/Core/LanguageServer/Handlers/Symbols/RoslynDocumentSymbolParams.cs new file mode 100644 index 0000000000000..0b7852decf257 --- /dev/null +++ b/src/EditorFeatures/Core/LanguageServer/Handlers/Symbols/RoslynDocumentSymbolParams.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.VisualStudio.LanguageServer.Protocol; +using Newtonsoft.Json; + +namespace Microsoft.CodeAnalysis.LanguageServer.Handler +{ + /// + /// A parameter object that indicates whether the LSP client should use hierarchichal symbols. Inherits from DocumentSymbolParams. + /// + /// + /// The LSP client does not support hierarchical document symbols and we can't contribute to client capabilities as the extension. + /// This type is required in order to obtain a response of type DocumentSymbol[] for a document symbol request. + /// + internal class RoslynDocumentSymbolParams : DocumentSymbolParams + { + [JsonProperty(PropertyName = "useHierarchicalSymbols", DefaultValueHandling = DefaultValueHandling.Ignore)] + public bool UseHierarchicalSymbols { get; set; } + } +} diff --git a/src/EditorFeatures/Core/Microsoft.CodeAnalysis.EditorFeatures.csproj b/src/EditorFeatures/Core/Microsoft.CodeAnalysis.EditorFeatures.csproj index 54f652e4cd22d..724a6f0e8781e 100644 --- a/src/EditorFeatures/Core/Microsoft.CodeAnalysis.EditorFeatures.csproj +++ b/src/EditorFeatures/Core/Microsoft.CodeAnalysis.EditorFeatures.csproj @@ -105,6 +105,7 @@ + diff --git a/src/EditorFeatures/Core/NavigationBar/NavigationBarController_ModelComputation.cs b/src/EditorFeatures/Core/NavigationBar/NavigationBarController_ModelComputation.cs index 7cffdc9cdc534..ed03a513b68c4 100644 --- a/src/EditorFeatures/Core/NavigationBar/NavigationBarController_ModelComputation.cs +++ b/src/EditorFeatures/Core/NavigationBar/NavigationBarController_ModelComputation.cs @@ -49,6 +49,11 @@ internal partial class NavigationBarController // partial semantics, we can ensure we don't spend an inordinate amount of time computing and using full // compilation data (like skeleton assemblies). var forceFrozenPartialSemanticsForCrossProcessOperations = true; + + var workspace = textSnapshot.TextBuffer.GetWorkspace(); + if (workspace is null) + return null; + var document = textSnapshot.AsText().GetDocumentWithFrozenPartialSemantics(cancellationToken); if (document == null) return null; @@ -58,14 +63,19 @@ internal partial class NavigationBarController return null; // If these are navbars for a file that isn't even visible, then avoid doing any unnecessary computation - // work until far in teh future (or if visibility changes). This ensures our non-visible docs do settle + // work until far in the future (or if visibility changes). This ensures our non-visible docs do settle // once enough time has passed, while greatly reducing their impact on the system. await _visibilityTracker.DelayWhileNonVisibleAsync( _threadingContext, _subjectBuffer, DelayTimeSpan.NonFocus, cancellationToken).ConfigureAwait(false); using (Logger.LogBlock(FunctionId.NavigationBar_ComputeModelAsync, cancellationToken)) { - var items = await itemService.GetItemsAsync(document, forceFrozenPartialSemanticsForCrossProcessOperations, textSnapshot.Version, cancellationToken).ConfigureAwait(false); + var items = await itemService.GetItemsAsync( + document, + workspace.CanApplyChange(ApplyChangesKind.ChangeDocument), + forceFrozenPartialSemanticsForCrossProcessOperations, + textSnapshot.Version, + cancellationToken).ConfigureAwait(false); return new NavigationBarModel(itemService, items); } } diff --git a/src/EditorFeatures/Core/Options/EditorAnalyzerConfigOptions.cs b/src/EditorFeatures/Core/Options/EditorAnalyzerConfigOptions.cs index c0aca642e0ec4..1952af29dc142 100644 --- a/src/EditorFeatures/Core/Options/EditorAnalyzerConfigOptions.cs +++ b/src/EditorFeatures/Core/Options/EditorAnalyzerConfigOptions.cs @@ -15,11 +15,11 @@ namespace Microsoft.CodeAnalysis.Diagnostics { internal sealed class EditorAnalyzerConfigOptions : AnalyzerConfigOptions { - private readonly IDictionary _options; + private readonly IDictionary _configOptions; public EditorAnalyzerConfigOptions(IEditorOptions editorOptions) { - _options = (editorOptions.GetOptionValue(DefaultOptions.RawCodingConventionsSnapshotOptionName) as IDictionary) ?? + _configOptions = (editorOptions.GetOptionValue(DefaultOptions.RawCodingConventionsSnapshotOptionName) as IDictionary) ?? SpecializedCollections.EmptyDictionary(); } @@ -28,7 +28,7 @@ public override bool TryGetValue(string key, [NotNullWhen(true)] out string? val // TODO: the editor currently seems to store both lower-cased keys and original casing, the comparer is case-sensitive // https://devdiv.visualstudio.com/DevDiv/_workitems/edit/1556206 - if (_options.TryGetValue(key.ToLowerInvariant(), out var objectValue)) + if (_configOptions.TryGetValue(key.ToLowerInvariant(), out var objectValue)) { // TODO: Although the editor exposes values typed to object they are actually strings. value = objectValue switch @@ -46,7 +46,7 @@ public override bool TryGetValue(string key, [NotNullWhen(true)] out string? val } public override IEnumerable Keys - => _options.Keys.Where(IsLowercase); + => _configOptions.Keys.Where(IsLowercase); private static bool IsLowercase(string str) { diff --git a/src/EditorFeatures/Core/Options/EditorOptionsService.cs b/src/EditorFeatures/Core/Options/EditorOptionsService.cs new file mode 100644 index 0000000000000..6949a57b43465 --- /dev/null +++ b/src/EditorFeatures/Core/Options/EditorOptionsService.cs @@ -0,0 +1,32 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Collections.Generic; +using System.Composition; +using System.Text; +using Microsoft.CodeAnalysis.Host.Mef; +using Microsoft.VisualStudio.Text.Editor; + +namespace Microsoft.CodeAnalysis.Options; + +/// +/// Aggregates services necessary to retrieve editor options. +/// +[Export(typeof(EditorOptionsService)), Shared] +internal sealed class EditorOptionsService +{ + public readonly IGlobalOptionService GlobalOptions; + public readonly IEditorOptionsFactoryService Factory; + public readonly IIndentationManagerService IndentationManager; + + [ImportingConstructor] + [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] + public EditorOptionsService(IGlobalOptionService globalOptions, IEditorOptionsFactoryService factory, IIndentationManagerService indentationManager) + { + GlobalOptions = globalOptions; + Factory = factory; + IndentationManager = indentationManager; + } +} diff --git a/src/EditorFeatures/Core/Options/NavigationBarViewOptions.cs b/src/EditorFeatures/Core/Options/NavigationBarViewOptions.cs deleted file mode 100644 index cde4d9cbf4e2e..0000000000000 --- a/src/EditorFeatures/Core/Options/NavigationBarViewOptions.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; -using System.Collections.Immutable; -using System.Composition; -using Microsoft.CodeAnalysis.Host.Mef; -using Microsoft.CodeAnalysis.Options; -using Microsoft.CodeAnalysis.Options.Providers; - -namespace Microsoft.CodeAnalysis.Editor.Options -{ - internal sealed class NavigationBarViewOptions - { - private const string FeatureName = "NavigationBarOptions"; - - public static readonly PerLanguageOption2 ShowNavigationBar = new(FeatureName, "ShowNavigationBar", defaultValue: true); - } -} diff --git a/src/EditorFeatures/Core/Options/NavigationBarViewOptionsStorage.cs b/src/EditorFeatures/Core/Options/NavigationBarViewOptionsStorage.cs new file mode 100644 index 0000000000000..24d9f3fc65c87 --- /dev/null +++ b/src/EditorFeatures/Core/Options/NavigationBarViewOptionsStorage.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.Options; + +namespace Microsoft.CodeAnalysis.Editor.Options; + +internal sealed class NavigationBarViewOptionsStorage +{ + private const string FeatureName = "NavigationBarOptions"; + + public static readonly PerLanguageOption2 ShowNavigationBar = new( + FeatureName, "ShowNavigationBar", defaultValue: true, new RoamingProfileStorageLocation("TextEditor.%LANGUAGE%.Dropdown Bar")); +} diff --git a/src/EditorFeatures/Core/Options/SignatureHelpViewOptions.cs b/src/EditorFeatures/Core/Options/SignatureHelpViewOptions.cs deleted file mode 100644 index 0383174fb5338..0000000000000 --- a/src/EditorFeatures/Core/Options/SignatureHelpViewOptions.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; -using System.Collections.Immutable; -using System.Composition; -using Microsoft.CodeAnalysis.Host.Mef; -using Microsoft.CodeAnalysis.Options; -using Microsoft.CodeAnalysis.Options.Providers; - -namespace Microsoft.CodeAnalysis.Editor.Options -{ - internal sealed class SignatureHelpViewOptions - { - private const string FeatureName = "SignatureHelpOptions"; - - public static readonly PerLanguageOption2 ShowSignatureHelp = new(FeatureName, nameof(ShowSignatureHelp), defaultValue: true); - } -} diff --git a/src/EditorFeatures/Core/Options/SignatureHelpViewOptionsStorage.cs b/src/EditorFeatures/Core/Options/SignatureHelpViewOptionsStorage.cs new file mode 100644 index 0000000000000..b887e3fbdbaf3 --- /dev/null +++ b/src/EditorFeatures/Core/Options/SignatureHelpViewOptionsStorage.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.Options; + +namespace Microsoft.CodeAnalysis.Editor.Options; + +internal sealed class SignatureHelpViewOptionsStorage +{ + private const string FeatureName = "SignatureHelpOptions"; + + public static readonly PerLanguageOption2 ShowSignatureHelp = new( + FeatureName, "ShowSignatureHelp", defaultValue: true, new RoamingProfileStorageLocation("TextEditor.%LANGUAGE%.Auto List Params")); +} diff --git a/src/EditorFeatures/Core/Options/TextBufferOptionProviders.cs b/src/EditorFeatures/Core/Options/TextBufferOptionProviders.cs new file mode 100644 index 0000000000000..5ad427dea499f --- /dev/null +++ b/src/EditorFeatures/Core/Options/TextBufferOptionProviders.cs @@ -0,0 +1,94 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Collections.Generic; +using System.Text; +using Microsoft.CodeAnalysis.AddImport; +using Microsoft.CodeAnalysis.Diagnostics; +using Microsoft.CodeAnalysis.DocumentationComments; +using Microsoft.CodeAnalysis.Formatting; +using Microsoft.CodeAnalysis.Host; +using Microsoft.CodeAnalysis.Indentation; +using Microsoft.VisualStudio.Text; +using Microsoft.VisualStudio.Text.Editor; +using Microsoft.VisualStudio.Text.Editor.OptionsExtensionMethods; + +namespace Microsoft.CodeAnalysis.Options; + +internal static class TextBufferOptionProviders +{ + public static DocumentationCommentOptions GetDocumentationCommentOptions(this ITextBuffer textBuffer, EditorOptionsService optionsProvider, LanguageServices languageServices) + { + var editorOptions = optionsProvider.Factory.GetOptions(textBuffer); + var lineFormattingOptions = GetLineFormattingOptionsImpl(textBuffer, editorOptions, optionsProvider.IndentationManager, explicitFormat: false); + return optionsProvider.GlobalOptions.GetDocumentationCommentOptions(lineFormattingOptions, languageServices.Language); + } + + public static LineFormattingOptions GetLineFormattingOptions(this ITextBuffer textBuffer, EditorOptionsService optionsProvider, bool explicitFormat) + => GetLineFormattingOptionsImpl(textBuffer, optionsProvider.Factory.GetOptions(textBuffer), optionsProvider.IndentationManager, explicitFormat); + + private static LineFormattingOptions GetLineFormattingOptionsImpl(ITextBuffer textBuffer, IEditorOptions editorOptions, IIndentationManagerService indentationManager, bool explicitFormat) + { + indentationManager.GetIndentation(textBuffer, explicitFormat, out var convertTabsToSpaces, out var tabSize, out var indentSize); + + return new LineFormattingOptions() + { + UseTabs = !convertTabsToSpaces, + IndentationSize = indentSize, + TabSize = tabSize, + NewLine = editorOptions.GetNewLineCharacter(), + }; + } + + public static SyntaxFormattingOptions GetSyntaxFormattingOptions(this ITextBuffer textBuffer, EditorOptionsService optionsProvider, LanguageServices languageServices, bool explicitFormat) + => GetSyntaxFormattingOptionsImpl(textBuffer, optionsProvider.Factory.GetOptions(textBuffer), optionsProvider.IndentationManager, optionsProvider.GlobalOptions, languageServices, explicitFormat); + + private static SyntaxFormattingOptions GetSyntaxFormattingOptionsImpl(ITextBuffer textBuffer, IEditorOptions editorOptions, IIndentationManagerService indentationManager, IGlobalOptionService globalOptions, LanguageServices languageServices, bool explicitFormat) + { + var configOptions = new EditorAnalyzerConfigOptions(editorOptions); + var fallbackOptions = globalOptions.GetSyntaxFormattingOptions(languageServices); + var options = configOptions.GetSyntaxFormattingOptions(fallbackOptions, languageServices); + var lineFormattingOptions = GetLineFormattingOptionsImpl(textBuffer, editorOptions, indentationManager, explicitFormat); + + return options.With(lineFormattingOptions); + } + + public static IndentationOptions GetIndentationOptions(this ITextBuffer textBuffer, EditorOptionsService optionsProvider, LanguageServices languageServices, bool explicitFormat) + { + var editorOptions = optionsProvider.Factory.GetOptions(textBuffer); + var formattingOptions = GetSyntaxFormattingOptionsImpl(textBuffer, editorOptions, optionsProvider.IndentationManager, optionsProvider.GlobalOptions, languageServices, explicitFormat); + + return new IndentationOptions(formattingOptions) + { + AutoFormattingOptions = optionsProvider.GlobalOptions.GetAutoFormattingOptions(languageServices.Language), + // TODO: Call editorOptions.GetIndentStyle() instead (see https://github.com/dotnet/roslyn/issues/62204): + IndentStyle = optionsProvider.GlobalOptions.GetOption(IndentationOptionsStorage.SmartIndent, languageServices.Language) + }; + } + + public static AddImportPlacementOptions GetAddImportPlacementOptions(this ITextBuffer textBuffer, EditorOptionsService optionsProvider, LanguageServices languageServices, bool allowInHiddenRegions) + { + var editorOptions = optionsProvider.Factory.GetOptions(textBuffer); + var configOptions = new EditorAnalyzerConfigOptions(editorOptions); + var fallbackOptions = optionsProvider.GlobalOptions.GetAddImportPlacementOptions(languageServices); + return configOptions.GetAddImportPlacementOptions(allowInHiddenRegions, fallbackOptions, languageServices); + } + + public static IndentingStyle ToEditorIndentStyle(this FormattingOptions2.IndentStyle value) + => value switch + { + FormattingOptions2.IndentStyle.Smart => IndentingStyle.Smart, + FormattingOptions2.IndentStyle.Block => IndentingStyle.Block, + _ => IndentingStyle.None, + }; + + public static FormattingOptions2.IndentStyle ToIndentStyle(this IndentingStyle value) + => value switch + { + IndentingStyle.Smart => FormattingOptions2.IndentStyle.Smart, + IndentingStyle.Block => FormattingOptions2.IndentStyle.Block, + _ => FormattingOptions2.IndentStyle.None, + }; +} diff --git a/src/EditorFeatures/Core/Organizing/OrganizeDocumentCommandHandler.cs b/src/EditorFeatures/Core/Organizing/OrganizeDocumentCommandHandler.cs index 4f1ac82bfd641..a0cf2fe26b0dd 100644 --- a/src/EditorFeatures/Core/Organizing/OrganizeDocumentCommandHandler.cs +++ b/src/EditorFeatures/Core/Organizing/OrganizeDocumentCommandHandler.cs @@ -8,6 +8,7 @@ using System.ComponentModel.Composition; using System.Diagnostics.CodeAnalysis; using System.Threading; +using System.Threading.Tasks; using Microsoft.CodeAnalysis.Editor.Commanding.Commands; using Microsoft.CodeAnalysis.Editor.Shared.Extensions; using Microsoft.CodeAnalysis.Editor.Shared.Utilities; @@ -64,7 +65,8 @@ public bool ExecuteCommand(OrganizeDocumentCommandArgs args, CommandExecutionCon var newDocument = OrganizingService.OrganizeAsync(document, cancellationToken: cancellationToken).WaitAndGetResult(cancellationToken); if (document != newDocument) { - ApplyTextChange(document, newDocument); + var changes = newDocument.GetTextChangesAsync(document, cancellationToken).WaitAndGetResult(cancellationToken); + args.SubjectBuffer.ApplyChanges(changes); } } } @@ -82,7 +84,7 @@ private static CommandState GetCommandState(EditorCommandArgs args, Func(); + var organizeImportsService = workspace.Services.SolutionServices.GetProjectServices(args.SubjectBuffer).GetService(); return new CommandState(isAvailable: true, displayText: descriptionString(organizeImportsService)); } else @@ -144,7 +146,8 @@ private void SortImports(ITextBuffer subjectBuffer, IUIThreadOperationContext op var newDocument = organizeImportsService.OrganizeImportsAsync(document, options, cancellationToken).WaitAndGetResult(cancellationToken); if (document != newDocument) { - ApplyTextChange(document, newDocument); + var changes = newDocument.GetTextChangesAsync(document, cancellationToken).WaitAndGetResult(cancellationToken); + subjectBuffer.ApplyChanges(changes); } } } @@ -163,12 +166,10 @@ private void SortAndRemoveUnusedImports(ITextBuffer subjectBuffer, IUIThreadOper newDocument = organizeImportsService.OrganizeImportsAsync(newDocument, options, cancellationToken).WaitAndGetResult(cancellationToken); if (document != newDocument) { - ApplyTextChange(document, newDocument); + var changes = newDocument.GetTextChangesAsync(document, cancellationToken).WaitAndGetResult(cancellationToken); + subjectBuffer.ApplyChanges(changes); } } } - - protected static void ApplyTextChange(Document oldDocument, Document newDocument) - => oldDocument.Project.Solution.Workspace.ApplyDocumentChanges(newDocument, CancellationToken.None); } } diff --git a/src/EditorFeatures/Core/Preview/AbstractPreviewFactoryService.cs b/src/EditorFeatures/Core/Preview/AbstractPreviewFactoryService.cs index 111d81672b4c5..a0c747cd2e397 100644 --- a/src/EditorFeatures/Core/Preview/AbstractPreviewFactoryService.cs +++ b/src/EditorFeatures/Core/Preview/AbstractPreviewFactoryService.cs @@ -38,10 +38,9 @@ internal abstract class AbstractPreviewFactoryService : IPrev private readonly ITextBufferFactoryService _textBufferFactoryService; private readonly IContentTypeRegistryService _contentTypeRegistryService; private readonly IProjectionBufferFactoryService _projectionBufferFactoryService; - private readonly IEditorOptionsFactoryService _editorOptionsFactoryService; + private readonly EditorOptionsService _editorOptionsService; private readonly ITextDifferencingSelectorService _differenceSelectorService; private readonly IDifferenceBufferFactoryService _differenceBufferService; - private readonly IGlobalOptionService _globalOptions; protected readonly IThreadingContext ThreadingContext; @@ -52,22 +51,19 @@ public AbstractPreviewFactoryService( ITextBufferFactoryService textBufferFactoryService, IContentTypeRegistryService contentTypeRegistryService, IProjectionBufferFactoryService projectionBufferFactoryService, - IEditorOptionsFactoryService editorOptionsFactoryService, + EditorOptionsService editorOptionsService, ITextDifferencingSelectorService differenceSelectorService, IDifferenceBufferFactoryService differenceBufferService, - ITextViewRoleSet previewRoleSet, - IGlobalOptionService globalOptions) + ITextViewRoleSet previewRoleSet) { ThreadingContext = threadingContext; _textBufferFactoryService = textBufferFactoryService; _contentTypeRegistryService = contentTypeRegistryService; _projectionBufferFactoryService = projectionBufferFactoryService; - _editorOptionsFactoryService = editorOptionsFactoryService; + _editorOptionsService = editorOptionsService; _differenceSelectorService = differenceSelectorService; _differenceBufferService = differenceBufferService; - _previewRoleSet = previewRoleSet; - _globalOptions = globalOptions; } public SolutionPreviewResult? GetSolutionPreviews(Solution oldSolution, Solution? newSolution, CancellationToken cancellationToken) @@ -585,7 +581,7 @@ public Task CreateRemovedAnalyzerConfigDocumentPreviewV var originalBuffer = _projectionBufferFactoryService.CreateProjectionBufferWithoutIndentation( _contentTypeRegistryService, - _editorOptionsFactoryService.GlobalOptions, + _editorOptionsService.Factory.GlobalOptions, oldBuffer.CurrentSnapshot, "...", description, @@ -593,7 +589,7 @@ public Task CreateRemovedAnalyzerConfigDocumentPreviewV var changedBuffer = _projectionBufferFactoryService.CreateProjectionBufferWithoutIndentation( _contentTypeRegistryService, - _editorOptionsFactoryService.GlobalOptions, + _editorOptionsService.Factory.GlobalOptions, newBuffer.CurrentSnapshot, "...", description, @@ -682,7 +678,7 @@ private async ValueTask CreateNewDifferenceViewerAsync( rightWorkspace = null; }; - if (_globalOptions.GetOption(SolutionCrawlerRegistrationService.EnableSolutionCrawler)) + if (_editorOptionsService.GlobalOptions.GetOption(SolutionCrawlerRegistrationService.EnableSolutionCrawler)) { leftWorkspace?.EnableSolutionCrawler(); rightWorkspace?.EnableSolutionCrawler(); @@ -761,7 +757,7 @@ private IHierarchicalDifferenceCollection ComputeEditDifferences(TextDocument ol // Defer to the editor to figure out what changes the client made. var diffService = _differenceSelectorService.GetTextDifferencingService( - oldDocument.Project.LanguageServices.GetRequiredService().GetDefaultContentType()); + oldDocument.Project.Services.GetRequiredService().GetDefaultContentType()); diffService ??= _differenceSelectorService.DefaultTextDifferencingService; return diffService.DiffStrings(oldText.ToString(), newText.ToString(), new StringDifferenceOptions() diff --git a/src/EditorFeatures/Core/ReferenceHighlighting/ReferenceHighlightingViewTaggerProvider.cs b/src/EditorFeatures/Core/ReferenceHighlighting/ReferenceHighlightingViewTaggerProvider.cs index 288ab074fe7dd..a73fe83d13a8b 100644 --- a/src/EditorFeatures/Core/ReferenceHighlighting/ReferenceHighlightingViewTaggerProvider.cs +++ b/src/EditorFeatures/Core/ReferenceHighlighting/ReferenceHighlightingViewTaggerProvider.cs @@ -125,8 +125,8 @@ protected override Task ProduceTagsAsync( // want to actually go recompute things. Note: this only works for containment. If the // user moves their caret to the end of a highlighted reference, we do want to recompute // as they may now be at the start of some other reference that should be highlighted instead. - var existingTags = context.GetExistingContainingTags(caretPosition); - if (!existingTags.IsEmpty()) + var onExistingTags = context.HasExistingContainingTags(caretPosition); + if (onExistingTags) { context.SetSpansTagged(ImmutableArray.Empty); return Task.CompletedTask; diff --git a/src/EditorFeatures/Core/Remote/SolutionChecksumUpdater.cs b/src/EditorFeatures/Core/Remote/SolutionChecksumUpdater.cs index 254f8696bc54d..f54b3c2ad7bd4 100644 --- a/src/EditorFeatures/Core/Remote/SolutionChecksumUpdater.cs +++ b/src/EditorFeatures/Core/Remote/SolutionChecksumUpdater.cs @@ -32,20 +32,12 @@ internal sealed class SolutionChecksumUpdater private readonly AsyncBatchingWorkQueue<(Document? oldDocument, Document? newDocument)> _textChangeQueue; /// - /// Queue for kicking off the work to synchronize the primary workspace's solution. The cancellation token is - /// used so that we can stop the work when we enter the paused state. + /// Queue for kicking off the work to synchronize the primary workspace's solution. /// - private readonly AsyncBatchingWorkQueue _synchronizeWorkspaceQueue; + private readonly AsyncBatchingWorkQueue _synchronizeWorkspaceQueue; - /// - /// Cancellation series we use to stop work when we get paused. - /// - private readonly CancellationSeries _pauseCancellationSeries; - - /// - /// Cancellation token we trigger when we enter the paused state. - /// - private CancellationToken _currentWorkToken; + private readonly object _gate = new(); + private bool _isPaused; public SolutionChecksumUpdater( Workspace workspace, @@ -55,7 +47,6 @@ public SolutionChecksumUpdater( var listener = listenerProvider.GetListener(FeatureAttribute.SolutionChecksumUpdater); _globalOperationService = workspace.Services.GetRequiredService(); - _pauseCancellationSeries = new CancellationSeries(shutdownToken); _workspace = workspace; _textChangeQueue = new AsyncBatchingWorkQueue<(Document? oldDocument, Document? newDocument)>( @@ -67,10 +58,9 @@ public SolutionChecksumUpdater( // Use an equality comparer here as we will commonly get lots of change notifications that will all be // associated with the same cancellation token controlling that batch of work. No need to enqueue the same // token a huge number of times when we only need the single value of it when doing the work. - _synchronizeWorkspaceQueue = new AsyncBatchingWorkQueue( + _synchronizeWorkspaceQueue = new AsyncBatchingWorkQueue( DelayTimeSpan.NearImmediate, SynchronizePrimaryWorkspaceAsync, - EqualityComparer.Default, listener, shutdownToken); @@ -87,7 +77,6 @@ public void Shutdown() { // Try to stop any work that is in progress. PauseWork(); - _pauseCancellationSeries.Dispose(); _workspace.WorkspaceChanged -= OnWorkspaceChanged; _globalOperationService.Started -= OnGlobalOperationStarted; @@ -104,81 +93,54 @@ private void PauseWork() { // An expensive global operation started (like a build). Pause ourselves and cancel any outstanding work in // progress to synchronize the solution. - // - // Note: We purposefully ignore the cancellation token produced by CreateNext. The purpose here is to - // cancel the token controlling the current work, but not have any uncanceled token for new work to use when - // it comes in. - _pauseCancellationSeries.CreateNext(); + lock (_gate) + { + _synchronizeWorkspaceQueue.CancelExistingWork(); + _isPaused = true; + } } private void ResumeWork() { - // create a new token to control all the work we need to do while we're current unpaused. - var nextToken = _pauseCancellationSeries.CreateNext(); - _currentWorkToken = nextToken; - // Start synchronizing again. - _synchronizeWorkspaceQueue.AddWork(nextToken); + lock (_gate) + { + _isPaused = false; + _synchronizeWorkspaceQueue.AddWork(); + } } private void OnWorkspaceChanged(object? sender, WorkspaceChangeEventArgs e) { // 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. - var workToken = _currentWorkToken; - if (workToken.IsCancellationRequested) - return; + lock (_gate) + { + if (_isPaused) + return; + } if (e.Kind == WorkspaceChangeKind.DocumentChanged) { _textChangeQueue.AddWork((e.OldSolution.GetDocument(e.DocumentId), e.NewSolution.GetDocument(e.DocumentId))); } - _synchronizeWorkspaceQueue.AddWork(workToken); + _synchronizeWorkspaceQueue.AddWork(); } - private async ValueTask SynchronizePrimaryWorkspaceAsync( - ImmutableSegmentedList cancellationTokens, - CancellationToken disposalToken) + private async ValueTask SynchronizePrimaryWorkspaceAsync(CancellationToken cancellationToken) { var solution = _workspace.CurrentSolution; - if (solution.BranchId != _workspace.PrimaryBranchId) - return; - - // Because we dedupe the cancellation tokens we add to the set, and because we only add a new token once - // we've canceled the previous ones, there can only be at most one actual real cancellation token that is - // not already canceled. - var uncancelledToken = cancellationTokens.SingleOrNull(ct => !ct.IsCancellationRequested); - - // if we didn't get an actual non-canceled token back, then this batch was entirely canceled and we have - // nothing to do. - if (uncancelledToken is null) + var client = await RemoteHostClient.TryGetClientAsync(_workspace, cancellationToken).ConfigureAwait(false); + if (client == null) return; - // Create a token that will fire if we are disposed or if we get paused. - using var source = CancellationTokenSource.CreateLinkedTokenSource(uncancelledToken.Value, disposalToken); - try - { - // Now actually synchronize the workspace. - var cancellationToken = source.Token; - cancellationToken.ThrowIfCancellationRequested(); - - var client = await RemoteHostClient.TryGetClientAsync(_workspace, cancellationToken).ConfigureAwait(false); - if (client == null) - return; - - using (Logger.LogBlock(FunctionId.SolutionChecksumUpdater_SynchronizePrimaryWorkspace, cancellationToken)) - { - var workspaceVersion = solution.WorkspaceVersion; - await client.TryInvokeAsync( - solution, - (service, solution, cancellationToken) => service.SynchronizePrimaryWorkspaceAsync(solution, workspaceVersion, cancellationToken), - cancellationToken).ConfigureAwait(false); - } - } - catch (OperationCanceledException) when (!disposalToken.IsCancellationRequested) + using (Logger.LogBlock(FunctionId.SolutionChecksumUpdater_SynchronizePrimaryWorkspace, cancellationToken)) { - // Don't bubble up cancellation to the queue for our own internal cancellation. Just because we decided - // to cancel this batch isn't something the queue should be aware of. + var workspaceVersion = solution.WorkspaceVersion; + await client.TryInvokeAsync( + solution, + (service, solution, cancellationToken) => service.SynchronizePrimaryWorkspaceAsync(solution, workspaceVersion, cancellationToken), + cancellationToken).ConfigureAwait(false); } } diff --git a/src/EditorFeatures/Core/RenameTracking/RenameTrackingTaggerProvider.RenameTrackingCodeAction.cs b/src/EditorFeatures/Core/RenameTracking/RenameTrackingTaggerProvider.RenameTrackingCodeAction.cs index b253eaa2b6058..98188dbc2850b 100644 --- a/src/EditorFeatures/Core/RenameTracking/RenameTrackingTaggerProvider.RenameTrackingCodeAction.cs +++ b/src/EditorFeatures/Core/RenameTracking/RenameTrackingTaggerProvider.RenameTrackingCodeAction.cs @@ -91,7 +91,7 @@ private bool TryInitializeRenameTrackingCommitter(CancellationToken cancellation // The rename tracking could be dismissed while a codefix is still cached // in the lightbulb. If this happens, do not perform the rename requested // and instead let the user know their fix will not be applied. - _document.Project.Solution.Workspace.Services.GetService() + _document.Project.Solution.Services.GetService() ?.SendNotification(EditorFeaturesResources.The_rename_tracking_session_was_cancelled_and_is_no_longer_available, severity: NotificationSeverity.Error); return false; } @@ -118,7 +118,8 @@ public RenameTrackingCommitterOperation(RenameTrackingCommitter committer, IThre _threadingContext = threadingContext; } - internal override async Task TryApplyAsync(Workspace workspace, IProgressTracker progressTracker, CancellationToken cancellationToken) + internal override async Task TryApplyAsync( + Workspace workspace, Solution originalSolution, IProgressTracker progressTracker, CancellationToken cancellationToken) { var error = await _committer.TryCommitAsync(cancellationToken).ConfigureAwait(false); if (error == null) diff --git a/src/EditorFeatures/Core/RenameTracking/RenameTrackingTaggerProvider.RenameTrackingCommitter.cs b/src/EditorFeatures/Core/RenameTracking/RenameTrackingTaggerProvider.RenameTrackingCommitter.cs index 4c0e81397ca8e..08bb91a4fe739 100644 --- a/src/EditorFeatures/Core/RenameTracking/RenameTrackingTaggerProvider.RenameTrackingCommitter.cs +++ b/src/EditorFeatures/Core/RenameTracking/RenameTrackingTaggerProvider.RenameTrackingCommitter.cs @@ -12,7 +12,7 @@ using Microsoft.CodeAnalysis.Editor.Shared.Extensions; using Microsoft.CodeAnalysis.Editor.Shared.Utilities; using Microsoft.CodeAnalysis.Editor.Undo; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Notification; using Microsoft.CodeAnalysis.Rename; using Microsoft.CodeAnalysis.Shared.Extensions; diff --git a/src/EditorFeatures/Core/RenameTracking/RenameTrackingTaggerProvider.StateMachine.cs b/src/EditorFeatures/Core/RenameTracking/RenameTrackingTaggerProvider.StateMachine.cs index f3bcf09b49391..9a33678068f01 100644 --- a/src/EditorFeatures/Core/RenameTracking/RenameTrackingTaggerProvider.StateMachine.cs +++ b/src/EditorFeatures/Core/RenameTracking/RenameTrackingTaggerProvider.StateMachine.cs @@ -17,7 +17,7 @@ using Microsoft.CodeAnalysis.Editor.Shared.Utilities; using Microsoft.CodeAnalysis.ErrorReporting; using Microsoft.CodeAnalysis.Internal.Log; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Shared.TestHooks; diff --git a/src/EditorFeatures/Core/RenameTracking/RenameTrackingTaggerProvider.TrackingSession.cs b/src/EditorFeatures/Core/RenameTracking/RenameTrackingTaggerProvider.TrackingSession.cs index 23b0a0c5f2e84..01ad66a21c029 100644 --- a/src/EditorFeatures/Core/RenameTracking/RenameTrackingTaggerProvider.TrackingSession.cs +++ b/src/EditorFeatures/Core/RenameTracking/RenameTrackingTaggerProvider.TrackingSession.cs @@ -12,7 +12,7 @@ using Microsoft.CodeAnalysis.Editor.Shared.Extensions; using Microsoft.CodeAnalysis.Editor.Shared.Utilities; using Microsoft.CodeAnalysis.FindSymbols; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Rename; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Shared.TestHooks; diff --git a/src/EditorFeatures/Core/RenameTracking/RenameTrackingTaggerProvider.cs b/src/EditorFeatures/Core/RenameTracking/RenameTrackingTaggerProvider.cs index eccd539c59f90..b2ee3ecd34a67 100644 --- a/src/EditorFeatures/Core/RenameTracking/RenameTrackingTaggerProvider.cs +++ b/src/EditorFeatures/Core/RenameTracking/RenameTrackingTaggerProvider.cs @@ -86,8 +86,13 @@ internal static bool ResetRenameTrackingStateWorker(Workspace workspace, Documen textBuffer = text.Container.TryGetTextBuffer(); if (textBuffer == null) { - FailFast.Fail(string.Format("document with name {0} is open but textBuffer is null. Textcontainer is of type {1}. SourceText is: {2}", - document.Name, text.Container.GetType().FullName, text.ToString())); + var ex = new InvalidOperationException(string.Format( + "document with name {0} is open but textBuffer is null. Textcontainer is of type {1}. SourceText is: {2}", + document.Name, + text.Container.GetType().FullName, + text.ToString())); + FatalError.ReportAndCatch(ex); + return false; } if (textBuffer.Properties.TryGetProperty(typeof(StateMachine), out StateMachine stateMachine)) diff --git a/src/EditorFeatures/Core/Shared/Extensions/HostWorkspaceServicesExtensions.cs b/src/EditorFeatures/Core/Shared/Extensions/HostWorkspaceServicesExtensions.cs index 742e9d25f343b..b2065f7623599 100644 --- a/src/EditorFeatures/Core/Shared/Extensions/HostWorkspaceServicesExtensions.cs +++ b/src/EditorFeatures/Core/Shared/Extensions/HostWorkspaceServicesExtensions.cs @@ -18,14 +18,14 @@ namespace Microsoft.CodeAnalysis.Editor.Shared.Extensions { internal static class HostWorkspaceServicesExtensions { - public static HostLanguageServices? GetLanguageServices( - this HostWorkspaceServices workspaceServices, ITextBuffer textBuffer) + public static CodeAnalysis.Host.LanguageServices? GetProjectServices( + this SolutionServices workspaceServices, ITextBuffer textBuffer) { - return workspaceServices.GetLanguageServices(textBuffer.ContentType); + return workspaceServices.GetProjectServices(textBuffer.ContentType); } - public static HostLanguageServices? GetLanguageServices( - this HostWorkspaceServices workspaceServices, IContentType contentType) + public static CodeAnalysis.Host.LanguageServices? GetProjectServices( + this SolutionServices workspaceServices, IContentType contentType) { foreach (var language in workspaceServices.SupportedLanguages) { @@ -43,15 +43,15 @@ internal static class HostWorkspaceServicesExtensions /// internal static string? GetLanguageName(this ITextBuffer buffer) => Workspace.TryGetWorkspace(buffer.AsTextContainer(), out var workspace) ? - workspace.Services.GetLanguageServices(buffer.ContentType)?.Language : null; + workspace.Services.SolutionServices.GetProjectServices(buffer.ContentType)?.Language : null; /// /// A cache of host services -> (language name -> content type name). /// - private static readonly ConditionalWeakTable> s_hostServicesToContentTypeMap + private static readonly ConditionalWeakTable> s_hostServicesToContentTypeMap = new(); - private static string? GetDefaultContentTypeName(HostWorkspaceServices workspaceServices, string language) + private static string? GetDefaultContentTypeName(SolutionServices workspaceServices, string language) { if (!s_hostServicesToContentTypeMap.TryGetValue(workspaceServices, out var contentTypeMap)) { @@ -62,11 +62,11 @@ private static readonly ConditionalWeakTable CreateContentTypeMap(HostWorkspaceServices hostWorkspaceServices) + private static Dictionary CreateContentTypeMap(SolutionServices hostWorkspaceServices) { // Are we being hosted in a MEF host? If so, we can get content type information directly from the // metadata and avoid actually loading the assemblies - var mefHostServices = (IMefHostExportProvider)hostWorkspaceServices.HostServices; + var mefHostServices = hostWorkspaceServices.ExportProvider; if (mefHostServices != null) { @@ -89,7 +89,7 @@ private static Dictionary CreateContentTypeMap(HostWorkspaceServ } internal static IList SelectMatchingExtensionValues( - this HostWorkspaceServices workspaceServices, + this SolutionServices workspaceServices, IEnumerable> items, IContentType contentType) where TMetadata : ILanguageMetadata @@ -104,7 +104,7 @@ internal static IList SelectMatchingExtensionValues( } internal static IList SelectMatchingExtensionValues( - this HostWorkspaceServices workspaceServices, + this SolutionServices workspaceServices, IEnumerable> items, IContentType contentType, ITextViewRoleSet roleSet) @@ -126,7 +126,7 @@ internal static IList SelectMatchingExtensionValues( private static bool LanguageMatches( string language, IContentType contentType, - HostWorkspaceServices workspaceServices) + SolutionServices workspaceServices) { var defaultContentType = GetDefaultContentTypeName(workspaceServices, language); return (defaultContentType != null) ? contentType.IsOfType(defaultContentType) : false; diff --git a/src/EditorFeatures/Core/Shared/Extensions/IEditorOptionsFactoryServiceExtensions.cs b/src/EditorFeatures/Core/Shared/Extensions/IEditorOptionsFactoryServiceExtensions.cs deleted file mode 100644 index bb6420e22a647..0000000000000 --- a/src/EditorFeatures/Core/Shared/Extensions/IEditorOptionsFactoryServiceExtensions.cs +++ /dev/null @@ -1,47 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using Microsoft.CodeAnalysis.Text; -using Microsoft.VisualStudio.Text.Editor; - -namespace Microsoft.CodeAnalysis.Editor.Shared.Extensions -{ - internal static class IEditorOptionsFactoryServiceExtensions - { - public static IEditorOptions GetEditorOptions(this IEditorOptionsFactoryService editorOptionsFactory, SourceText text) - { - var textBuffer = text.Container.TryGetTextBuffer(); - if (textBuffer != null) - { - return editorOptionsFactory.GetOptions(textBuffer); - } - - return editorOptionsFactory.GlobalOptions; - } - - public static IEditorOptions GetEditorOptions(this IEditorOptionsFactoryService editorOptionsFactory, Document document) - { - if (document.TryGetText(out var text)) - { - return editorOptionsFactory.GetEditorOptions(text); - } - - return editorOptionsFactory.GlobalOptions; - } - - // This particular section is commented for future reference if there arises a need to implement a option serializer in the editor layer - // public static IOptionService GetFormattingOptions(this IEditorOptionsFactoryService editorOptionsFactory, Document document) - // { - // return CreateOptions(editorOptionsFactory.GetEditorOptions(document)); - // } - - // private static IOptionService CreateOptions(IEditorOptions editorOptions) - // { - // return new FormattingOptions( - // !editorOptions.IsConvertTabsToSpacesEnabled(), - // editorOptions.GetTabSize(), - // editorOptions.GetIndentSize()); - // } - } -} diff --git a/src/EditorFeatures/Core/Shared/Extensions/ITextBufferExtensions.cs b/src/EditorFeatures/Core/Shared/Extensions/ITextBufferExtensions.cs index f450c5f63ccce..ada51f9d5cb6a 100644 --- a/src/EditorFeatures/Core/Shared/Extensions/ITextBufferExtensions.cs +++ b/src/EditorFeatures/Core/Shared/Extensions/ITextBufferExtensions.cs @@ -2,10 +2,13 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using Microsoft.CodeAnalysis.Editor.Shared.Utilities; using Microsoft.CodeAnalysis.Text; +using Microsoft.CodeAnalysis.Text.Shared.Extensions; using Microsoft.VisualStudio.Text; +using Microsoft.VisualStudio.TextManager.Interop; namespace Microsoft.CodeAnalysis.Editor.Shared.Extensions { @@ -59,5 +62,33 @@ private static bool TryGetSupportsFeatureService(ITextBuffer buffer, [NotNullWhe return service != null; } + + public static ITextSnapshot ApplyChange(this ITextBuffer buffer, TextChange change) + { + if (buffer.Properties.TryGetProperty(typeof(IContainedDocument), out var containedDocument)) + { + return containedDocument.ApplyChanges(new[] { change }); + } + + using var edit = buffer.CreateEdit(EditOptions.DefaultMinimalChange, reiteratedVersionNumber: null, editTag: null); + edit.Replace(change.Span.ToSpan(), change.NewText); + return edit.Apply(); + } + + public static ITextSnapshot ApplyChanges(this ITextBuffer buffer, IEnumerable changes) + { + if (buffer.Properties.TryGetProperty(typeof(IContainedDocument), out var containedDocument)) + { + return containedDocument.ApplyChanges(changes); + } + + using var edit = buffer.CreateEdit(EditOptions.DefaultMinimalChange, reiteratedVersionNumber: null, editTag: null); + foreach (var change in changes) + { + edit.Replace(change.Span.ToSpan(), change.NewText); + } + + return edit.Apply(); + } } } diff --git a/src/EditorFeatures/Core/Shared/Extensions/ITextSnapshotExtensions.cs b/src/EditorFeatures/Core/Shared/Extensions/ITextSnapshotExtensions.cs index 27da8122805eb..c5b3b651a18ee 100644 --- a/src/EditorFeatures/Core/Shared/Extensions/ITextSnapshotExtensions.cs +++ b/src/EditorFeatures/Core/Shared/Extensions/ITextSnapshotExtensions.cs @@ -15,6 +15,7 @@ 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; @@ -25,26 +26,30 @@ internal static partial class ITextSnapshotExtensions /// /// format given snapshot and apply text changes to buffer /// - public static void FormatAndApplyToBuffer(this ITextSnapshot snapshot, TextSpan span, IGlobalOptionService globalOptions, CancellationToken cancellationToken) + public static void FormatAndApplyToBuffer( + this ITextBuffer textBuffer, + TextSpan span, + EditorOptionsService editorOptionsService, + CancellationToken cancellationToken) { - var document = snapshot.GetOpenDocumentInCurrentContextWithChanges(); + var document = textBuffer.CurrentSnapshot.GetOpenDocumentInCurrentContextWithChanges(); if (document == null) { return; } var documentSyntax = ParsedDocument.CreateSynchronously(document, cancellationToken); - var rules = FormattingRuleUtilities.GetFormattingRules(documentSyntax, document.Project.LanguageServices, span, additionalRules: null); + var rules = FormattingRuleUtilities.GetFormattingRules(documentSyntax, span, additionalRules: null); var formatter = document.GetRequiredLanguageService(); - var options = document.GetSyntaxFormattingOptionsAsync(globalOptions, cancellationToken).AsTask().WaitAndGetResult(cancellationToken); + var options = textBuffer.GetSyntaxFormattingOptions(editorOptionsService, document.Project.Services, explicitFormat: false); var result = formatter.GetFormattingResult(documentSyntax.Root, SpecializedCollections.SingletonEnumerable(span), options, rules, cancellationToken); var changes = result.GetTextChanges(cancellationToken); using (Logger.LogBlock(FunctionId.Formatting_ApplyResultToBuffer, cancellationToken)) { - document.Project.Solution.Workspace.ApplyTextChanges(document.Id, changes, cancellationToken); + textBuffer.ApplyChanges(changes); } } @@ -70,7 +75,7 @@ public static void FormatAndApplyToBuffer(this ITextSnapshot snapshot, TextSpan // partial mode is always cancellable using (operationContext.AddScope(allowCancellation: true, EditorFeaturesResources.Waiting_for_background_work_to_finish)) { - var service = document.Project.Solution.Workspace.Services.GetService(); + var service = document.Project.Solution.Services.GetService(); if (service != null) { // TODO: decide for prototype, we don't do anything complex and just ask workspace whether it is fully loaded diff --git a/src/EditorFeatures/Core/Shared/Extensions/ITextViewExtensions.cs b/src/EditorFeatures/Core/Shared/Extensions/ITextViewExtensions.cs index 47f7fed907156..b4fd8bae9af11 100644 --- a/src/EditorFeatures/Core/Shared/Extensions/ITextViewExtensions.cs +++ b/src/EditorFeatures/Core/Shared/Extensions/ITextViewExtensions.cs @@ -133,10 +133,7 @@ public static bool TryMoveCaretToAndEnsureVisible(this ITextView textView, Virtu { var outliningManager = outliningManagerService.GetOutliningManager(textView); - if (outliningManager != null) - { - outliningManager.ExpandAll(new SnapshotSpan(pointInView.Value, length: 0), match: _ => true); - } + outliningManager?.ExpandAll(new SnapshotSpan(pointInView.Value, length: 0), match: _ => true); } var newPosition = textView.Caret.MoveTo(new VirtualSnapshotPoint(pointInView.Value, point.VirtualSpaces)); diff --git a/src/EditorFeatures/Core/Shared/Extensions/WorkspaceExtensions.cs b/src/EditorFeatures/Core/Shared/Extensions/WorkspaceExtensions.cs index 86e400e9f4fc6..48416005e0eaf 100644 --- a/src/EditorFeatures/Core/Shared/Extensions/WorkspaceExtensions.cs +++ b/src/EditorFeatures/Core/Shared/Extensions/WorkspaceExtensions.cs @@ -36,13 +36,7 @@ internal static void ApplyTextChanges(this Workspace workspace, DocumentId id, I workspace.TryApplyChanges(newSolution); } - /// - /// Update the solution so that the document with the Id has the text changes - /// - internal static void ApplyTextChanges(this Workspace workspace, DocumentId id, TextChange textChange, CancellationToken cancellationToken) - => workspace.ApplyTextChanges(id, SpecializedCollections.SingletonEnumerable(textChange), cancellationToken); - - internal static Solution UpdateDocument(this Solution solution, DocumentId id, IEnumerable textChanges, CancellationToken cancellationToken) + private static Solution UpdateDocument(this Solution solution, DocumentId id, IEnumerable textChanges, CancellationToken cancellationToken) { var oldDocument = solution.GetRequiredDocument(id); var oldText = oldDocument.GetTextSynchronously(cancellationToken); diff --git a/src/EditorFeatures/Core/Shared/Tagging/Utilities/TagSpanIntervalTree.cs b/src/EditorFeatures/Core/Shared/Tagging/Utilities/TagSpanIntervalTree.cs index 118fd11be4c39..5e28526e7de05 100644 --- a/src/EditorFeatures/Core/Shared/Tagging/Utilities/TagSpanIntervalTree.cs +++ b/src/EditorFeatures/Core/Shared/Tagging/Utilities/TagSpanIntervalTree.cs @@ -33,21 +33,28 @@ public TagSpanIntervalTree(ITextBuffer textBuffer, var nodeValues = values?.Select(ts => new TagNode(ts, trackingMode)); - var introspector = new IntervalIntrospector(textBuffer.CurrentSnapshot); - _tree = IntervalTree.Create(introspector, nodeValues); + _tree = IntervalTree.Create(new IntervalIntrospector(textBuffer.CurrentSnapshot), nodeValues); } public ITextBuffer Buffer => _textBuffer; public SpanTrackingMode SpanTrackingMode => _spanTrackingMode; + public bool HasSpanThatContains(SnapshotPoint point) + { + var snapshot = point.Snapshot; + Debug.Assert(snapshot.TextBuffer == _textBuffer); + + return _tree.HasIntervalThatContains(point.Position, length: 0, new IntervalIntrospector(snapshot)); + } + public IList> GetIntersectingSpans(SnapshotSpan snapshotSpan) { var snapshot = snapshotSpan.Snapshot; Debug.Assert(snapshot.TextBuffer == _textBuffer); - var introspector = new IntervalIntrospector(snapshot); - var intersectingIntervals = _tree.GetIntervalsThatIntersectWith(snapshotSpan.Start, snapshotSpan.Length, introspector); + var intersectingIntervals = _tree.GetIntervalsThatIntersectWith( + snapshotSpan.Start, snapshotSpan.Length, new IntervalIntrospector(snapshot)); List>? result = null; foreach (var tagNode in intersectingIntervals) diff --git a/src/EditorFeatures/Core/Shared/Utilities/CaretPreservingEditTransaction.cs b/src/EditorFeatures/Core/Shared/Utilities/CaretPreservingEditTransaction.cs index 95e4622fc52e9..9719cfc3fc891 100644 --- a/src/EditorFeatures/Core/Shared/Utilities/CaretPreservingEditTransaction.cs +++ b/src/EditorFeatures/Core/Shared/Utilities/CaretPreservingEditTransaction.cs @@ -58,10 +58,7 @@ public void Complete() } _editorOperations.AddAfterTextBufferChangePrimitive(); - if (_transaction != null) - { - _transaction.Complete(); - } + _transaction?.Complete(); EndTransaction(); } @@ -73,10 +70,7 @@ public void Cancel() throw new InvalidOperationException(EditorFeaturesResources.The_transaction_is_already_complete); } - if (_transaction != null) - { - _transaction.Cancel(); - } + _transaction?.Cancel(); EndTransaction(); } diff --git a/src/EditorFeatures/Core/SmartIndent/SmartIndent.cs b/src/EditorFeatures/Core/SmartIndent/SmartIndent.cs index b1fbf68c91a66..dc102fa0ad08c 100644 --- a/src/EditorFeatures/Core/SmartIndent/SmartIndent.cs +++ b/src/EditorFeatures/Core/SmartIndent/SmartIndent.cs @@ -20,12 +20,12 @@ namespace Microsoft.CodeAnalysis.Editor.Implementation.SmartIndent internal partial class SmartIndent : ISmartIndent { private readonly ITextView _textView; - private readonly IGlobalOptionService _globalOptions; + private readonly EditorOptionsService _editorOptionsService; - public SmartIndent(ITextView textView, IGlobalOptionService globalOptions) + public SmartIndent(ITextView textView, EditorOptionsService editorOptionsService) { _textView = textView; - _globalOptions = globalOptions; + _editorOptionsService = editorOptionsService; } public int? GetDesiredIndentation(ITextSnapshotLine line) @@ -50,8 +50,9 @@ public void Dispose() if (newService == null) return null; - var indentationOptions = document.GetIndentationOptionsAsync(_globalOptions, cancellationToken).WaitAndGetResult_CanCallOnBackground(cancellationToken); - var result = newService.GetIndentation(document, line.LineNumber, indentationOptions, cancellationToken); + var indentationOptions = line.Snapshot.TextBuffer.GetIndentationOptions(_editorOptionsService, document.Project.Services, explicitFormat: false); + var parsedDocument = ParsedDocument.CreateSynchronously(document, cancellationToken); + var result = newService.GetIndentation(parsedDocument, line.LineNumber, indentationOptions, cancellationToken); return result.GetIndentation(_textView, line); } } diff --git a/src/EditorFeatures/Core/SmartIndent/SmartIndentProvider.cs b/src/EditorFeatures/Core/SmartIndent/SmartIndentProvider.cs index 52bab7b222477..304713a70565b 100644 --- a/src/EditorFeatures/Core/SmartIndent/SmartIndentProvider.cs +++ b/src/EditorFeatures/Core/SmartIndent/SmartIndentProvider.cs @@ -18,13 +18,13 @@ namespace Microsoft.CodeAnalysis.Editor.Implementation.SmartIndent [ContentType(ContentTypeNames.VisualBasicContentType)] internal sealed class SmartIndentProvider : ISmartIndentProvider { - private readonly IGlobalOptionService _globalOptions; + private readonly EditorOptionsService _editorOptionsService; [ImportingConstructor] [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] - public SmartIndentProvider(IGlobalOptionService globalOptions) + public SmartIndentProvider(EditorOptionsService editorOptionsService) { - _globalOptions = globalOptions; + _editorOptionsService = editorOptionsService; } public ISmartIndent? CreateSmartIndent(ITextView textView) @@ -34,12 +34,12 @@ public SmartIndentProvider(IGlobalOptionService globalOptions) throw new ArgumentNullException(nameof(textView)); } - if (!_globalOptions.GetOption(InternalFeatureOnOffOptions.SmartIndenter)) + if (!_editorOptionsService.GlobalOptions.GetOption(InternalFeatureOnOffOptions.SmartIndenter)) { return null; } - return new SmartIndent(textView, _globalOptions); + return new SmartIndent(textView, _editorOptionsService); } } } diff --git a/src/EditorFeatures/Core/SplitComment/SplitCommentCommandHandler.cs b/src/EditorFeatures/Core/SplitComment/SplitCommentCommandHandler.cs index 20204663b8ed3..394b31e67858c 100644 --- a/src/EditorFeatures/Core/SplitComment/SplitCommentCommandHandler.cs +++ b/src/EditorFeatures/Core/SplitComment/SplitCommentCommandHandler.cs @@ -10,7 +10,7 @@ using Microsoft.CodeAnalysis.Editor.Shared.Utilities; using Microsoft.CodeAnalysis.Formatting; using Microsoft.CodeAnalysis.Host.Mef; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Text; @@ -34,6 +34,8 @@ internal sealed class SplitCommentCommandHandler : ICommandHandler SplitCommentAsync( + private (Span replacementSpan, string replacementText)? SplitComment( + ParsedDocument document, ITextView textView, - Document document, - SnapshotSpan selectionSpan, - CancellationToken cancellationToken) + ITextBuffer textBuffer, + SnapshotSpan selectionSpan) { - var root = await document.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false); - var syntaxKinds = document.GetRequiredLanguageService(); - var trivia = root.FindTrivia(selectionSpan.Start); + var syntaxKinds = document.LanguageServices.GetRequiredService(); + var trivia = document.Root.FindTrivia(selectionSpan.Start); if (syntaxKinds.SingleLineCommentTrivia != trivia.RawKind) return null; - var splitCommentService = document.GetRequiredLanguageService(); + var splitCommentService = document.LanguageServices.GetRequiredService(); // if the user hits enter at `/$$/` we don't want to consider this a comment continuation. if (selectionSpan.Start < (trivia.SpanStart + splitCommentService.CommentStart.Length)) return null; - if (!splitCommentService.IsAllowed(root, trivia)) + if (!splitCommentService.IsAllowed(document.Root, trivia)) return null; // If the user hits enter at: // goo $$ // bar @@ -169,7 +175,7 @@ private static bool MatchesCommentStart(string commentStart, ITextSnapshotLine l var textSnapshot = selectionSpan.Snapshot; var triviaLine = textSnapshot.GetLineFromPosition(trivia.SpanStart); - var options = await document.GetLineFormattingOptionsAsync(_globalOptions, cancellationToken).ConfigureAwait(false); + var options = textBuffer.GetLineFormattingOptions(_editorOptionsService, explicitFormat: false); var replacementSpan = GetReplacementSpan(triviaLine, selectionSpan); var replacementText = GetReplacementText(textView, options, triviaLine, trivia, selectionSpan.Start); return (replacementSpan, replacementText); diff --git a/src/EditorFeatures/Core/Structure/AbstractStructureTaggerProvider.cs b/src/EditorFeatures/Core/Structure/AbstractStructureTaggerProvider.cs index 6db366c746186..0e699d2956b4b 100644 --- a/src/EditorFeatures/Core/Structure/AbstractStructureTaggerProvider.cs +++ b/src/EditorFeatures/Core/Structure/AbstractStructureTaggerProvider.cs @@ -47,19 +47,18 @@ internal abstract partial class AbstractStructureTaggerProvider : private const string ExternDeclaration = "extern"; private const string ImportsStatement = "Imports"; - protected readonly IEditorOptionsFactoryService EditorOptionsFactoryService; + protected readonly EditorOptionsService EditorOptionsService; protected readonly IProjectionBufferFactoryService ProjectionBufferFactoryService; protected AbstractStructureTaggerProvider( IThreadingContext threadingContext, - IEditorOptionsFactoryService editorOptionsFactoryService, + EditorOptionsService editorOptionsService, IProjectionBufferFactoryService projectionBufferFactoryService, - IGlobalOptionService globalOptions, ITextBufferVisibilityTracker? visibilityTracker, IAsynchronousOperationListenerProvider listenerProvider) - : base(threadingContext, globalOptions, visibilityTracker, listenerProvider.GetListener(FeatureAttribute.Outlining)) + : base(threadingContext, editorOptionsService.GlobalOptions, visibilityTracker, listenerProvider.GetListener(FeatureAttribute.Outlining)) { - EditorOptionsFactoryService = editorOptionsFactoryService; + EditorOptionsService = editorOptionsService; ProjectionBufferFactoryService = projectionBufferFactoryService; } @@ -351,7 +350,7 @@ private ITextBuffer CreateElisionBufferWithoutIndentation( SnapshotSpan shortHintSpan) { return ProjectionBufferFactoryService.CreateProjectionBufferWithoutIndentation( - EditorOptionsFactoryService.GlobalOptions, + EditorOptionsService.Factory.GlobalOptions, contentType: null, exposedSpans: shortHintSpan); } diff --git a/src/EditorFeatures/Core/SymbolDisplay/SymbolDescriptionOptionsStorage.cs b/src/EditorFeatures/Core/SymbolDisplay/SymbolDescriptionOptionsStorage.cs index 9f529f2c52777..f7f9a4ad40207 100644 --- a/src/EditorFeatures/Core/SymbolDisplay/SymbolDescriptionOptionsStorage.cs +++ b/src/EditorFeatures/Core/SymbolDisplay/SymbolDescriptionOptionsStorage.cs @@ -6,7 +6,7 @@ using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.QuickInfo; -namespace Microsoft.CodeAnalysis.LanguageServices +namespace Microsoft.CodeAnalysis.LanguageService { internal static class SymbolDescriptionOptionsStorage { diff --git a/src/EditorFeatures/Core/Tagging/TaggerContext.cs b/src/EditorFeatures/Core/Tagging/TaggerContext.cs index fa7e577764fbb..d22bd928088e8 100644 --- a/src/EditorFeatures/Core/Tagging/TaggerContext.cs +++ b/src/EditorFeatures/Core/Tagging/TaggerContext.cs @@ -86,15 +86,9 @@ public void ClearTags() public void SetSpansTagged(ImmutableArray spansTagged) => _spansTagged = spansTagged; - public IEnumerable> GetExistingContainingTags(SnapshotPoint point) - { - if (_existingTags != null && _existingTags.TryGetValue(point.Snapshot.TextBuffer, out var tree)) - { - return tree.GetIntersectingSpans(new SnapshotSpan(point.Snapshot, new Span(point, 0))) - .Where(s => s.Span.Contains(point)); - } - - return SpecializedCollections.EmptyEnumerable>(); - } + public bool HasExistingContainingTags(SnapshotPoint point) + => _existingTags != null && + _existingTags.TryGetValue(point.Snapshot.TextBuffer, out var tree) && + tree.HasSpanThatContains(point); } } diff --git a/src/EditorFeatures/Core/TextDiffing/EditorTextDifferencingService.cs b/src/EditorFeatures/Core/TextDiffing/EditorTextDifferencingService.cs index ac9b65740b1f1..950879950730a 100644 --- a/src/EditorFeatures/Core/TextDiffing/EditorTextDifferencingService.cs +++ b/src/EditorFeatures/Core/TextDiffing/EditorTextDifferencingService.cs @@ -37,7 +37,7 @@ public async Task> GetTextChangesAsync(Document oldDo var oldText = await oldDocument.GetTextAsync(cancellationToken).ConfigureAwait(false); var newText = await newDocument.GetTextAsync(cancellationToken).ConfigureAwait(false); - var diffService = _differenceSelectorService.GetTextDifferencingService(oldDocument.Project.LanguageServices.GetService().GetDefaultContentType()) + var diffService = _differenceSelectorService.GetTextDifferencingService(oldDocument.Project.Services.GetService().GetDefaultContentType()) ?? _differenceSelectorService.DefaultTextDifferencingService; var differenceOptions = GetDifferenceOptions(preferredDifferenceType); diff --git a/src/EditorFeatures/Core/Undo/EditorSourceTextUndoService.cs b/src/EditorFeatures/Core/Undo/EditorSourceTextUndoService.cs index 5cac788aec015..2d7768818cd4e 100644 --- a/src/EditorFeatures/Core/Undo/EditorSourceTextUndoService.cs +++ b/src/EditorFeatures/Core/Undo/EditorSourceTextUndoService.cs @@ -93,10 +93,7 @@ internal bool Begin(ITextUndoHistory undoHistory) public void Dispose() { - if (_transaction != null) - { - _transaction.Complete(); - } + _transaction?.Complete(); _service.EndUndoTransaction(this); } diff --git a/src/EditorFeatures/DiagnosticsTestUtilities/ChangeSignature/ChangeSignatureTestState.cs b/src/EditorFeatures/DiagnosticsTestUtilities/ChangeSignature/ChangeSignatureTestState.cs index 2a9e0f8425070..0e1eea18c0f71 100644 --- a/src/EditorFeatures/DiagnosticsTestUtilities/ChangeSignature/ChangeSignatureTestState.cs +++ b/src/EditorFeatures/DiagnosticsTestUtilities/ChangeSignature/ChangeSignatureTestState.cs @@ -44,11 +44,7 @@ public static ChangeSignatureTestState Create(string markup, string languageName _ => throw new ArgumentException("Invalid language name.") }; - if (options != null) - { - workspace.ApplyOptions(options); - } - + options?.SetGlobalOptions(workspace.GlobalOptions); return new ChangeSignatureTestState(workspace); } @@ -76,7 +72,7 @@ public TestChangeSignatureOptionsService TestChangeSignatureOptionsService { get { - return (TestChangeSignatureOptionsService)InvocationDocument.Project.Solution.Workspace.Services.GetRequiredService(); + return (TestChangeSignatureOptionsService)InvocationDocument.Project.Solution.Services.GetRequiredService(); } } @@ -100,10 +96,7 @@ public async Task GetParameterConfigurationAsync() public void Dispose() { - if (Workspace != null) - { - Workspace.Dispose(); - } + Workspace?.Dispose(); } } } diff --git a/src/EditorFeatures/DiagnosticsTestUtilities/CodeActions/AbstractCodeActionOrUserDiagnosticTest.cs b/src/EditorFeatures/DiagnosticsTestUtilities/CodeActions/AbstractCodeActionOrUserDiagnosticTest.cs index 48b1f7fb7d9f0..eb53a2ff7791d 100644 --- a/src/EditorFeatures/DiagnosticsTestUtilities/CodeActions/AbstractCodeActionOrUserDiagnosticTest.cs +++ b/src/EditorFeatures/DiagnosticsTestUtilities/CodeActions/AbstractCodeActionOrUserDiagnosticTest.cs @@ -766,16 +766,14 @@ protected static async Task> ApplyOperationsAndGetSolu Tuple result = null; foreach (var operation in operations) { - if (operation is ApplyChangesOperation && result == null) + if (operation is ApplyChangesOperation applyChangesOperation && result == null) { - var oldSolution = workspace.CurrentSolution; - var newSolution = ((ApplyChangesOperation)operation).ChangedSolution; - result = Tuple.Create(oldSolution, newSolution); + result = Tuple.Create(workspace.CurrentSolution, applyChangesOperation.ChangedSolution); } else if (operation.ApplyDuringTests) { var oldSolution = workspace.CurrentSolution; - await operation.TryApplyAsync(workspace, new ProgressTracker(), CancellationToken.None); + await operation.TryApplyAsync(workspace, oldSolution, new ProgressTracker(), CancellationToken.None); var newSolution = workspace.CurrentSolution; result = Tuple.Create(oldSolution, newSolution); } diff --git a/src/EditorFeatures/DiagnosticsTestUtilities/CodeActions/AbstractCodeActionTest.cs b/src/EditorFeatures/DiagnosticsTestUtilities/CodeActions/AbstractCodeActionTest.cs index 0cc536d9d6345..07f4dd868a160 100644 --- a/src/EditorFeatures/DiagnosticsTestUtilities/CodeActions/AbstractCodeActionTest.cs +++ b/src/EditorFeatures/DiagnosticsTestUtilities/CodeActions/AbstractCodeActionTest.cs @@ -131,7 +131,7 @@ protected async Task TestActionOnLinkedFiles( await VerifyPreviewContents(workspace, expectedPreviewContents, operations); var applyChangesOperation = operations.OfType().First(); - await applyChangesOperation.TryApplyAsync(workspace, new ProgressTracker(), CancellationToken.None); + await applyChangesOperation.TryApplyAsync(workspace, workspace.CurrentSolution, new ProgressTracker(), CancellationToken.None); foreach (var document in workspace.Documents) { diff --git a/src/EditorFeatures/DiagnosticsTestUtilities/CodeActions/SharedVerifierState.cs b/src/EditorFeatures/DiagnosticsTestUtilities/CodeActions/SharedVerifierState.cs index bbda01e197957..4a9d69196d525 100644 --- a/src/EditorFeatures/DiagnosticsTestUtilities/CodeActions/SharedVerifierState.cs +++ b/src/EditorFeatures/DiagnosticsTestUtilities/CodeActions/SharedVerifierState.cs @@ -52,7 +52,7 @@ public SharedVerifierState(AnalyzerTest test, string defaultFileE internal IdeAnalyzerOptions? IdeAnalyzerOptions { get; set; } internal IdeAnalyzerOptions GetIdeAnalyzerOptions(Project project) - => IdeAnalyzerOptions ?? IdeAnalyzerOptions.GetDefault(project.LanguageServices); + => IdeAnalyzerOptions ?? IdeAnalyzerOptions.GetDefault(project.Services); #endif internal void Apply() { diff --git a/src/EditorFeatures/Test/Attributes/AttributeTests.cs b/src/EditorFeatures/Test/Attributes/AttributeTests.cs index a38d454df66fe..afee395267424 100644 --- a/src/EditorFeatures/Test/Attributes/AttributeTests.cs +++ b/src/EditorFeatures/Test/Attributes/AttributeTests.cs @@ -5,11 +5,7 @@ #nullable disable using System; -using Microsoft.CodeAnalysis.Classification.Classifiers; -using Microsoft.CodeAnalysis.CodeRefactorings; -using Microsoft.CodeAnalysis.Editor; -using Microsoft.CodeAnalysis.Text; -using Roslyn.Test.Utilities; +using Microsoft.CodeAnalysis.BraceMatching; using Xunit; namespace Microsoft.CodeAnalysis.Editor.UnitTests.Attributes diff --git a/src/EditorFeatures/Test/CodeAnalysisResources.cs b/src/EditorFeatures/Test/CodeAnalysisResources.cs index ab2271a28a82e..210bb03afcff2 100644 --- a/src/EditorFeatures/Test/CodeAnalysisResources.cs +++ b/src/EditorFeatures/Test/CodeAnalysisResources.cs @@ -24,10 +24,7 @@ internal static class CodeAnalysisResources private static string GetString(string resourceName) { - if (s_codeAnalysisResourceManager == null) - { - s_codeAnalysisResourceManager = new ResourceManager(typeof(CodeAnalysisResources).FullName, typeof(Compilation).Assembly); - } + s_codeAnalysisResourceManager ??= new ResourceManager(typeof(CodeAnalysisResources).FullName, typeof(Compilation).Assembly); return s_codeAnalysisResourceManager.GetString(resourceName); } diff --git a/src/EditorFeatures/Test/CodeFixes/CodeFixServiceTests.cs b/src/EditorFeatures/Test/CodeFixes/CodeFixServiceTests.cs index f35455dc0d251..1aed974097c38 100644 --- a/src/EditorFeatures/Test/CodeFixes/CodeFixServiceTests.cs +++ b/src/EditorFeatures/Test/CodeFixes/CodeFixServiceTests.cs @@ -347,7 +347,7 @@ private static void GetDocumentAndExtensionManager( var reference = analyzerReference ?? new MockAnalyzerReference(); var project = workspace.CurrentSolution.Projects.Single().AddAnalyzerReference(reference); document = project.Documents.Single(); - extensionManager = (EditorLayerExtensionManager.ExtensionManager)document.Project.Solution.Workspace.Services.GetRequiredService(); + extensionManager = (EditorLayerExtensionManager.ExtensionManager)document.Project.Solution.Services.GetRequiredService(); } private static IEnumerable> CreateFixers() diff --git a/src/EditorFeatures/Test/CodeGeneration/AbstractCodeGenerationTests.cs b/src/EditorFeatures/Test/CodeGeneration/AbstractCodeGenerationTests.cs index 096f9d9102285..afe781416bb5a 100644 --- a/src/EditorFeatures/Test/CodeGeneration/AbstractCodeGenerationTests.cs +++ b/src/EditorFeatures/Test/CodeGeneration/AbstractCodeGenerationTests.cs @@ -39,7 +39,7 @@ private static SyntaxNode Simplify( var annotatedDocument = document.WithSyntaxRoot( root.WithAdditionalAnnotations(Simplifier.Annotation)); - var options = document.Project.LanguageServices.GetRequiredService().DefaultOptions; + var options = document.Project.Services.GetRequiredService().DefaultOptions; var simplifiedDocument = Simplifier.ReduceAsync(annotatedDocument, options, CancellationToken.None).Result; var rootNode = simplifiedDocument.GetRequiredSyntaxRootAsync(default).AsTask().Result; diff --git a/src/EditorFeatures/Test/CodeGeneration/CodeGenerationTests.CSharp.cs b/src/EditorFeatures/Test/CodeGeneration/CodeGenerationTests.CSharp.cs index e7706f9195b6b..18efe090391c1 100644 --- a/src/EditorFeatures/Test/CodeGeneration/CodeGenerationTests.CSharp.cs +++ b/src/EditorFeatures/Test/CodeGeneration/CodeGenerationTests.CSharp.cs @@ -14,6 +14,7 @@ using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.CodeStyle; using Microsoft.CodeAnalysis.CSharp.Syntax; +using Microsoft.CodeAnalysis.Editor.UnitTests.CodeActions; using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Test.Utilities; using Roslyn.Test.Utilities; @@ -220,6 +221,59 @@ await TestAddNamedTypeAsync(input, expected, modifiers: new Editing.DeclarationModifiers(isStatic: true)); } + [Fact, Trait(Traits.Feature, Traits.Features.CodeGeneration), WorkItem(544405, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/544405")] + public async Task AddStaticAbstractClass() + { + var input = "namespace [|N|] { }"; + var expected = @"namespace N +{ + public static class C + { + } +}"; + // note that 'abstract' is dropped here + await TestAddNamedTypeAsync(input, expected, + modifiers: new Editing.DeclarationModifiers(isStatic: true, isAbstract: true)); + } + + [Theory, Trait(Traits.Feature, Traits.Features.CodeGeneration), WorkItem(544405, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/544405")] + [InlineData(Accessibility.NotApplicable)] + [InlineData(Accessibility.Internal)] + [InlineData(Accessibility.Public)] + public async Task AddFileClass(Accessibility accessibility) + { + var input = "namespace [|N|] { }"; + var expected = @"namespace N +{ + file class C + { + } +}"; + // note: when invalid combinations of modifiers+accessibility are present here, + // we actually drop the accessibility. This is similar to what is done if someone declares a 'static abstract class C { }'. + await TestAddNamedTypeAsync(input, expected, + accessibility: accessibility, + modifiers: new Editing.DeclarationModifiers(isFile: true)); + } + + [Theory, Trait(Traits.Feature, Traits.Features.CodeGeneration), WorkItem(544405, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/544405")] + [InlineData("struct", TypeKind.Struct)] + [InlineData("interface", TypeKind.Interface)] + [InlineData("enum", TypeKind.Enum)] + public async Task AddFileType(string kindString, TypeKind typeKind) + { + var input = "namespace [|N|] { }"; + var expected = @"namespace N +{ + file " + kindString + @" C + { + } +}"; + await TestAddNamedTypeAsync(input, expected, + typeKind: typeKind, + modifiers: new Editing.DeclarationModifiers(isFile: true)); + } + [Fact, Trait(Traits.Feature, Traits.Features.CodeGeneration), WorkItem(544405, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/544405")] public async Task AddSealedClass() { @@ -1038,7 +1092,8 @@ await TestAddPropertyAsync(input, expected, parameters: Parameters(Parameter(typeof(int), "i")), getStatements: "return String.Empty;", isIndexer: true, - options: new Dictionary { + options: new OptionsCollection(LanguageNames.CSharp) + { { CSharpCodeStyleOptions.PreferExpressionBodiedAccessors, CSharpCodeStyleOptions.NeverWithSilentEnforcement }, { CSharpCodeStyleOptions.PreferExpressionBodiedIndexers, CSharpCodeStyleOptions.NeverWithSilentEnforcement }, }); diff --git a/src/EditorFeatures/Test/CodeGeneration/CodeGenerationTests.cs b/src/EditorFeatures/Test/CodeGeneration/CodeGenerationTests.cs index 28aa4628ac235..957ea93fc5d76 100644 --- a/src/EditorFeatures/Test/CodeGeneration/CodeGenerationTests.cs +++ b/src/EditorFeatures/Test/CodeGeneration/CodeGenerationTests.cs @@ -14,6 +14,7 @@ using Microsoft.CodeAnalysis.CodeGeneration; using Microsoft.CodeAnalysis.CSharp.Formatting; using Microsoft.CodeAnalysis.CSharp.Simplification; +using Microsoft.CodeAnalysis.Editor.UnitTests.CodeActions; using Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces; using Microsoft.CodeAnalysis.Formatting; using Microsoft.CodeAnalysis.Options; @@ -427,7 +428,7 @@ internal static async Task TestAddPropertyAsync( ImmutableArray> parameters = default, bool isIndexer = false, CodeGenerationContext context = null, - IDictionary options = null) + OptionsCollection options = null) { // This assumes that tests will not use place holders for get/set statements at the same time if (getStatements != null) @@ -442,14 +443,7 @@ internal static async Task TestAddPropertyAsync( using var testContext = await TestContext.CreateAsync(initial, expected); var workspace = testContext.Workspace; - if (options != null) - { - var optionSet = workspace.Options; - foreach (var (key, value) in options) - optionSet = optionSet.WithChangedOption(key, value); - - workspace.TryApplyChanges(workspace.CurrentSolution.WithOptions(optionSet)); - } + options?.SetGlobalOptions(workspace.GlobalOptions); var typeSymbol = GetTypeSymbol(type)(testContext.SemanticModel); var getParameterSymbols = GetParameterSymbols(parameters, testContext); @@ -884,7 +878,7 @@ public TestContext( this.Document = Workspace.CurrentSolution.Projects.Single().Documents.Single(); this.SemanticModel = semanticModel; this.SyntaxTree = SemanticModel.SyntaxTree; - this.Service = Document.Project.LanguageServices.GetService(); + this.Service = Document.Project.Services.GetService(); } public static async Task CreateAsync(string initial, string expected, string forceLanguage = null, bool ignoreResult = false) diff --git a/src/EditorFeatures/Test/CodeRefactorings/CodeRefactoringServiceTest.cs b/src/EditorFeatures/Test/CodeRefactorings/CodeRefactoringServiceTest.cs index 17f0a015cd6c0..be282d228a27b 100644 --- a/src/EditorFeatures/Test/CodeRefactorings/CodeRefactoringServiceTest.cs +++ b/src/EditorFeatures/Test/CodeRefactorings/CodeRefactoringServiceTest.cs @@ -113,7 +113,7 @@ private static async Task VerifyRefactoringDisabledAsync() var project = workspace.CurrentSolution.Projects.Single(); var document = project.Documents.Single(); - var extensionManager = (EditorLayerExtensionManager.ExtensionManager)document.Project.Solution.Workspace.Services.GetRequiredService(); + var extensionManager = (EditorLayerExtensionManager.ExtensionManager)document.Project.Solution.Services.GetRequiredService(); var result = await refactoringService.GetRefactoringsAsync(document, TextSpan.FromBounds(0, 0), CodeActionOptions.DefaultProvider, isBlocking: false, CancellationToken.None); Assert.True(extensionManager.IsDisabled(codeRefactoring)); Assert.False(extensionManager.IsIgnored(codeRefactoring)); diff --git a/src/EditorFeatures/Test/CommentSelection/CommentUncommentSelectionCommandHandlerTests.cs b/src/EditorFeatures/Test/CommentSelection/CommentUncommentSelectionCommandHandlerTests.cs index 33d869f821cc5..3e148ff21c10e 100644 --- a/src/EditorFeatures/Test/CommentSelection/CommentUncommentSelectionCommandHandlerTests.cs +++ b/src/EditorFeatures/Test/CommentSelection/CommentUncommentSelectionCommandHandlerTests.cs @@ -760,12 +760,12 @@ private static void CommentOrUncommentSelection( { var textUndoHistoryRegistry = exportProvider.GetExportedValue(); var editorOperationsFactory = exportProvider.GetExportedValue(); - var globalOptions = exportProvider.GetExportedValue(); - var commandHandler = new CommentUncommentSelectionCommandHandler(textUndoHistoryRegistry, editorOperationsFactory, globalOptions); + var editorOptionsService = exportProvider.GetExportedValue(); + var commandHandler = new CommentUncommentSelectionCommandHandler(textUndoHistoryRegistry, editorOperationsFactory, editorOptionsService); var service = new MockCommentSelectionService(supportBlockComments); - var edits = commandHandler.CollectEditsAsync( - null, service, textView.TextBuffer, textView.Selection.GetSnapshotSpansOnBuffer(textView.TextBuffer), operation, CancellationToken.None).GetAwaiter().GetResult(); + var edits = commandHandler.CollectEdits( + null, service, textView.TextBuffer, textView.Selection.GetSnapshotSpansOnBuffer(textView.TextBuffer), operation, CancellationToken.None); AssertEx.SetEqual(expectedChanges, edits.TextChanges); diff --git a/src/EditorFeatures/Test/Completion/CompletionServiceTests.cs b/src/EditorFeatures/Test/Completion/CompletionServiceTests.cs index a0d57073a7993..5cb2fe76b299a 100644 --- a/src/EditorFeatures/Test/Completion/CompletionServiceTests.cs +++ b/src/EditorFeatures/Test/Completion/CompletionServiceTests.cs @@ -12,7 +12,7 @@ using Microsoft.CodeAnalysis.Completion; using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Test.Utilities; @@ -41,15 +41,24 @@ void Method() { var nugetCompletionProvider = new DebugAssertTestCompletionProvider(); var reference = new MockAnalyzerReference(nugetCompletionProvider); var project = workspace.CurrentSolution.Projects.Single().AddAnalyzerReference(reference); - var completionService = project.LanguageServices.GetRequiredService(); + var completionService = project.Services.GetRequiredService(); var document = project.Documents.Single(); var caretPosition = workspace.DocumentWithCursor.CursorPosition ?? throw new InvalidOperationException(); var completions = await completionService.GetCompletionsAsync(document, caretPosition, CompletionOptions.Default, OptionValueSet.Empty); Assert.False(completions.IsEmpty); + var item = Assert.Single(completions.ItemsList.Where(item => item.ProviderName == typeof(DebugAssertTestCompletionProvider).FullName)); - Assert.Equal("Assertion failed", item.DisplayText); + Assert.Equal(nameof(DebugAssertTestCompletionProvider), item.DisplayText); + + var expectedDescriptionText = nameof(DebugAssertTestCompletionProvider); + var actualDescriptionText = (await completionService.GetDescriptionAsync(document, item, CompletionOptions.Default, SymbolDescriptionOptions.Default).ConfigureAwait(false))!.Text; + Assert.Equal(expectedDescriptionText, actualDescriptionText); + + var expectedChange = new TextChange(item.Span, nameof(DebugAssertTestCompletionProvider)); + var actualChange = (await completionService.GetChangeAsync(document, item).ConfigureAwait(false)).TextChange; + Assert.Equal(expectedChange, actualChange); } private class MockAnalyzerReference : AnalyzerReference, ICompletionProviderFactory @@ -93,11 +102,21 @@ public override bool ShouldTriggerCompletion(SourceText text, int caretPosition, public override async Task ProvideCompletionsAsync(CompletionContext context) { - var completionItem = CompletionItem.Create(displayText: "Assertion failed", displayTextSuffix: "", rules: CompletionItemRules.Default); + var completionItem = CompletionItem.Create(displayText: nameof(DebugAssertTestCompletionProvider), displayTextSuffix: "", rules: CompletionItemRules.Default); context.AddItem(completionItem); context.CompletionListSpan = await GetTextChangeSpanAsync(context.Document, context.CompletionListSpan, context.CancellationToken).ConfigureAwait(false); } + public override Task GetDescriptionAsync(Document document, CompletionItem item, CancellationToken cancellationToken) + { + return Task.FromResult(CompletionDescription.FromText(nameof(DebugAssertTestCompletionProvider))); + } + + public override Task GetChangeAsync(Document document, CompletionItem item, char? commitKey, CancellationToken cancellationToken) + { + return Task.FromResult(CompletionChange.Create(new TextChange(item.Span, nameof(DebugAssertTestCompletionProvider)))); + } + private static async Task GetTextChangeSpanAsync(Document document, TextSpan startSpan, CancellationToken cancellationToken) { var result = startSpan; diff --git a/src/EditorFeatures/Test/Diagnostics/DiagnosticAnalyzerServiceTests.cs b/src/EditorFeatures/Test/Diagnostics/DiagnosticAnalyzerServiceTests.cs index 9b5421622dcde..280c61ee150f8 100644 --- a/src/EditorFeatures/Test/Diagnostics/DiagnosticAnalyzerServiceTests.cs +++ b/src/EditorFeatures/Test/Diagnostics/DiagnosticAnalyzerServiceTests.cs @@ -51,7 +51,7 @@ private static AdhocWorkspace CreateWorkspace(Type[] additionalParts = null) => new(s_featuresCompositionWithMockDiagnosticUpdateSourceRegistrationService.AddParts(additionalParts).GetHostServices()); private static IGlobalOptionService GetGlobalOptions(Workspace workspace) - => ((IMefHostExportProvider)workspace.Services.HostServices).GetExportedValue(); + => workspace.Services.SolutionServices.ExportProvider.GetExportedValue(); private static void OpenDocumentAndMakeActive(Document document, Workspace workspace) { @@ -71,7 +71,7 @@ public async Task TestHasSuccessfullyLoadedBeingFalse() var document = GetDocumentFromIncompleteProject(workspace); - var exportProvider = (IMefHostExportProvider)workspace.Services.HostServices; + var exportProvider = workspace.Services.SolutionServices.ExportProvider; Assert.IsType(exportProvider.GetExportedValue()); var service = Assert.IsType(exportProvider.GetExportedValue()); var analyzer = service.CreateIncrementalAnalyzer(workspace); @@ -196,7 +196,7 @@ public async Task TestDisabledByDefaultAnalyzerEnabledWithEditorConfig(bool enab var applied = workspace.TryApplyChanges(document.Project.Solution); Assert.True(applied); - var exportProvider = (IMefHostExportProvider)workspace.Services.HostServices; + var exportProvider = workspace.Services.SolutionServices.ExportProvider; Assert.IsType(exportProvider.GetExportedValue()); var service = Assert.IsType(exportProvider.GetExportedValue()); var analyzer = service.CreateIncrementalAnalyzer(workspace); @@ -246,7 +246,7 @@ private static async Task TestAnalyzerAsync( Func, (bool, bool)> resultSetter, bool expectedSyntax, bool expectedSemantic) { - var exportProvider = (IMefHostExportProvider)workspace.Services.HostServices; + var exportProvider = workspace.Services.SolutionServices.ExportProvider; Assert.IsType(exportProvider.GetExportedValue()); var service = Assert.IsType(exportProvider.GetExportedValue()); @@ -280,7 +280,7 @@ public async Task TestOpenFileOnlyAnalyzerDiagnostics() { using var workspace = CreateWorkspace(); - var exportProvider = (IMefHostExportProvider)workspace.Services.HostServices; + var exportProvider = workspace.Services.SolutionServices.ExportProvider; var globalOptions = exportProvider.GetExportedValue(); var analyzerReference = new AnalyzerImageReference(ImmutableArray.Create(new OpenFileOnlyAnalyzer())); @@ -340,7 +340,7 @@ public async Task TestOpenFileOnlyAnalyzerDiagnostics() [Fact] public async Task TestSynchronizeWithBuild() { - using var workspace = CreateWorkspace(new[] { typeof(NoCompilationLanguageServiceFactory) }); + using var workspace = CreateWorkspace(new[] { typeof(NoCompilationLanguageService) }); var analyzerReference = new AnalyzerImageReference(ImmutableArray.Create(new NoNameAnalyzer())); workspace.TryApplyChanges(workspace.CurrentSolution.WithAnalyzerReferences(new[] { analyzerReference })); @@ -363,7 +363,7 @@ public async Task TestSynchronizeWithBuild() loader: TextLoader.From(TextAndVersion.Create(SourceText.From(""), VersionStamp.Create(), filePath)), filePath: filePath)); - var exportProvider = (IMefHostExportProvider)workspace.Services.HostServices; + var exportProvider = workspace.Services.SolutionServices.ExportProvider; Assert.IsType(exportProvider.GetExportedValue()); var service = Assert.IsType(exportProvider.GetExportedValue()); var analyzer = service.CreateIncrementalAnalyzer(workspace); @@ -413,7 +413,7 @@ await service.SynchronizeWithBuildAsync( public void TestHostAnalyzerOrdering() { using var workspace = CreateWorkspace(); - var exportProvider = (IMefHostExportProvider)workspace.Services.HostServices; + var exportProvider = workspace.Services.SolutionServices.ExportProvider; var analyzerReference = new AnalyzerImageReference(ImmutableArray.Create( new Priority20Analyzer(), @@ -485,7 +485,7 @@ public async Task TestHostAnalyzerErrorNotLeaking() loader: TextLoader.From(TextAndVersion.Create(SourceText.From("class A {}"), VersionStamp.Create(), filePath: "test.cs")), filePath: "test.cs")})); - var exportProvider = (IMefHostExportProvider)workspace.Services.HostServices; + var exportProvider = workspace.Services.SolutionServices.ExportProvider; Assert.IsType(exportProvider.GetExportedValue()); var service = Assert.IsType(exportProvider.GetExportedValue()); @@ -590,7 +590,7 @@ private static AdhocWorkspace CreateWorkspaceWithProjectAndAnalyzer(DiagnosticAn private static async Task TestFullSolutionAnalysisForProjectAsync(AdhocWorkspace workspace, Project project, bool expectAnalyzerExecuted) { - var exportProvider = (IMefHostExportProvider)workspace.Services.HostServices; + var exportProvider = workspace.Services.SolutionServices.ExportProvider; Assert.IsType(exportProvider.GetExportedValue()); var service = Assert.IsType(exportProvider.GetExportedValue()); var globalOptions = exportProvider.GetExportedValue(); @@ -649,7 +649,7 @@ internal async Task TestAdditionalFileAnalyzer(bool registerFromInitialize, bool var applied = workspace.TryApplyChanges(project.Solution); Assert.True(applied); - var exportProvider = (IMefHostExportProvider)workspace.Services.HostServices; + var exportProvider = workspace.Services.SolutionServices.ExportProvider; Assert.IsType(exportProvider.GetExportedValue()); var service = Assert.IsType(exportProvider.GetExportedValue()); @@ -1058,7 +1058,7 @@ internal async Task TestOnlyRequiredAnalyzerExecutedDuringDiagnosticComputation( workspace.TryApplyChanges(workspace.CurrentSolution.WithAnalyzerReferences(new[] { analyzerReference })); var project = workspace.CurrentSolution.Projects.Single(); var document = documentAnalysis ? project.Documents.Single() : null; - var ideAnalyzerOptions = IdeAnalyzerOptions.GetDefault(project.LanguageServices); + var ideAnalyzerOptions = IdeAnalyzerOptions.GetDefault(project.Services); var diagnosticComputer = new DiagnosticComputer(document, project, ideAnalyzerOptions, span: null, AnalysisKind.Semantic, new DiagnosticAnalyzerInfoCache()); var diagnosticsMapResults = await diagnosticComputer.GetDiagnosticsAsync(analyzerIdsToRequestDiagnostics, reportSuppressedDiagnostics: false, logPerformanceInfo: false, getTelemetryInfo: false, cancellationToken: CancellationToken.None); @@ -1104,7 +1104,7 @@ void M() var document = project.Documents.Single(); var diagnosticAnalyzerInfoCache = new DiagnosticAnalyzerInfoCache(); - var ideAnalyzerOptions = IdeAnalyzerOptions.GetDefault(project.LanguageServices); + var ideAnalyzerOptions = IdeAnalyzerOptions.GetDefault(project.Services); var kind = actionKind == AnalyzerRegisterActionKind.SyntaxTree ? AnalysisKind.Syntax : AnalysisKind.Semantic; var diagnosticComputer = new DiagnosticComputer(document, project, ideAnalyzerOptions, span: null, kind, diagnosticAnalyzerInfoCache); var analyzerIds = new[] { analyzer.GetAnalyzerId() }; diff --git a/src/EditorFeatures/Test/Diagnostics/DiagnosticsClassificationTaggerProviderTests.cs b/src/EditorFeatures/Test/Diagnostics/DiagnosticsClassificationTaggerProviderTests.cs index 88a70c38b607f..cac7238e24665 100644 --- a/src/EditorFeatures/Test/Diagnostics/DiagnosticsClassificationTaggerProviderTests.cs +++ b/src/EditorFeatures/Test/Diagnostics/DiagnosticsClassificationTaggerProviderTests.cs @@ -12,6 +12,7 @@ using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.Editor.UnitTests.Squiggles; using Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces; +using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Test.Utilities; using Microsoft.CodeAnalysis.Text; @@ -27,10 +28,11 @@ namespace Microsoft.CodeAnalysis.Editor.UnitTests.Diagnostics [UseExportProvider] public class DiagnosticsClassificationTaggerProviderTests { - [WpfFact, Trait(Traits.Feature, Traits.Features.Diagnostics)] - public async Task Test_FadingSpans() + [WpfTheory, Trait(Traits.Feature, Traits.Features.Diagnostics)] + [CombinatorialData] + public async Task Test_FadingSpans(bool throughAdditionalLocations) { - var analyzer = new Analyzer(); + var analyzer = new Analyzer(diagnosticId: "test", throughAdditionalLocations); var analyzerMap = new Dictionary> { { LanguageNames.CSharp, ImmutableArray.Create(analyzer) } @@ -43,23 +45,42 @@ public async Task Test_FadingSpans() // test first update await wrapper.WaitForTags(); - // We should get two spans, the 1-index and 2-index locations in the original diagnostic. var snapshot = workspace.Documents.First().GetTextBuffer().CurrentSnapshot; var spans = tagger.GetTags(snapshot.GetSnapshotSpanCollection()).ToList(); - Assert.Equal(2, spans.Count); + if (!throughAdditionalLocations) + { + // We should get a single tag span, which is diagnostic's primary location. + Assert.Equal(1, spans.Count); + + Assert.Equal(new Span(0, 10), spans[0].Span.Span); + + Assert.Equal(ClassificationTypeDefinitions.UnnecessaryCode, spans[0].Tag.ClassificationType.Classification); + } + else + { + // We should get two spans, the 1-index and 2-index additional locations in the original diagnostic. + Assert.Equal(2, spans.Count); - Assert.Equal(new Span(0, 1), spans[0].Span.Span); - Assert.Equal(new Span(9, 1), spans[1].Span.Span); + Assert.Equal(new Span(0, 1), spans[0].Span.Span); + Assert.Equal(new Span(9, 1), spans[1].Span.Span); - Assert.Equal(ClassificationTypeDefinitions.UnnecessaryCode, spans[0].Tag.ClassificationType.Classification); - Assert.Equal(ClassificationTypeDefinitions.UnnecessaryCode, spans[1].Tag.ClassificationType.Classification); + Assert.Equal(ClassificationTypeDefinitions.UnnecessaryCode, spans[0].Tag.ClassificationType.Classification); + Assert.Equal(ClassificationTypeDefinitions.UnnecessaryCode, spans[1].Tag.ClassificationType.Classification); + } } private class Analyzer : DiagnosticAnalyzer { - private readonly DiagnosticDescriptor _rule = new DiagnosticDescriptor( - "test", "test", "test", "test", DiagnosticSeverity.Error, true, - customTags: DiagnosticCustomTags.Create(isUnnecessary: true, isConfigurable: false, EnforceOnBuild.Never)); + private readonly bool _throughAdditionalLocations; + private readonly DiagnosticDescriptor _rule; + + public Analyzer(string diagnosticId, bool throughAdditionalLocations) + { + _throughAdditionalLocations = throughAdditionalLocations; + _rule = new( + diagnosticId, "test", "test", "test", DiagnosticSeverity.Error, true, + customTags: DiagnosticCustomTags.Create(isUnnecessary: true, isConfigurable: false, EnforceOnBuild.Never)); + } public override ImmutableArray SupportedDiagnostics => ImmutableArray.Create(_rule); @@ -68,18 +89,86 @@ public override void Initialize(AnalysisContext context) { context.RegisterSyntaxTreeAction(c => { - var additionalLocations = ImmutableArray.Create(Location.Create(c.Tree, new TextSpan(0, 10))); - var additionalUnnecessaryLocations = ImmutableArray.Create( - Location.Create(c.Tree, new TextSpan(0, 1)), - Location.Create(c.Tree, new TextSpan(9, 1))); - - c.ReportDiagnostic(DiagnosticHelper.CreateWithLocationTags( - _rule, Location.Create(c.Tree, new TextSpan(0, 10)), - ReportDiagnostic.Error, - additionalLocations, - additionalUnnecessaryLocations)); + var primaryLocation = Location.Create(c.Tree, new TextSpan(0, 10)); + if (!_throughAdditionalLocations) + { + c.ReportDiagnostic(DiagnosticHelper.Create( + _rule, primaryLocation, + ReportDiagnostic.Error, + additionalLocations: null, + properties: null)); + } + else + { + var additionalLocations = ImmutableArray.Create(Location.Create(c.Tree, new TextSpan(0, 10))); + var additionalUnnecessaryLocations = ImmutableArray.Create( + Location.Create(c.Tree, new TextSpan(0, 1)), + Location.Create(c.Tree, new TextSpan(9, 1))); + + c.ReportDiagnostic(DiagnosticHelper.CreateWithLocationTags( + _rule, primaryLocation, + ReportDiagnostic.Error, + additionalLocations, + additionalUnnecessaryLocations)); + } }); } } + + [WpfTheory, Trait(Traits.Feature, Traits.Features.Diagnostics)] + [WorkItem(62183, "https://github.com/dotnet/roslyn/issues/62183")] + [InlineData(IDEDiagnosticIds.RemoveUnnecessaryImportsDiagnosticId, true)] + [InlineData(IDEDiagnosticIds.RemoveUnnecessaryImportsDiagnosticId, false)] + [InlineData(IDEDiagnosticIds.RemoveUnreachableCodeDiagnosticId, true)] + [InlineData(IDEDiagnosticIds.RemoveUnreachableCodeDiagnosticId, false)] + public async Task Test_FadingOptions(string diagnosticId, bool fadingOptionValue) + { + var analyzer = new Analyzer(diagnosticId, throughAdditionalLocations: false); + var analyzerMap = new Dictionary> + { + { LanguageNames.CSharp, ImmutableArray.Create(analyzer) } + }; + + using var workspace = TestWorkspace.CreateCSharp(new string[] { "class A { }", "class E { }" }, parseOptions: CSharpParseOptions.Default, composition: SquiggleUtilities.CompositionWithSolutionCrawler); + + // Set fading option + var fadingOption = GetFadingOptionForDiagnostic(diagnosticId); + workspace.GlobalOptions.SetGlobalOption(new OptionKey(fadingOption, LanguageNames.CSharp), fadingOptionValue); + + // Add mapping from diagnostic ID to fading option + IDEDiagnosticIdToOptionMappingHelper.AddFadingOptionMapping(diagnosticId, fadingOption); + + // Set up the tagger + using var wrapper = new DiagnosticTaggerWrapper(workspace, analyzerMap); + var tagger = wrapper.TaggerProvider.CreateTagger(workspace.Documents.First().GetTextBuffer()); + using var disposable = tagger as IDisposable; + // test first update + await wrapper.WaitForTags(); + + var snapshot = workspace.Documents.First().GetTextBuffer().CurrentSnapshot; + var spans = tagger.GetTags(snapshot.GetSnapshotSpanCollection()).ToList(); + if (!fadingOptionValue) + { + // We should get no tag spans when the fading option is disabled. + Assert.Empty(spans); + } + else + { + // We should get a single tag span, which is diagnostic's primary location. + Assert.Equal(1, spans.Count); + + Assert.Equal(new Span(0, 10), spans[0].Span.Span); + + Assert.Equal(ClassificationTypeDefinitions.UnnecessaryCode, spans[0].Tag.ClassificationType.Classification); + } + } + + private static PerLanguageOption2 GetFadingOptionForDiagnostic(string diagnosticId) + => diagnosticId switch + { + IDEDiagnosticIds.RemoveUnnecessaryImportsDiagnosticId => FadingOptions.FadeOutUnusedImports, + IDEDiagnosticIds.RemoveUnreachableCodeDiagnosticId => FadingOptions.FadeOutUnreachableCode, + _ => throw ExceptionUtilities.UnexpectedValue(diagnosticId), + }; } } diff --git a/src/EditorFeatures/Test/Diagnostics/IDEDiagnosticIDConfigurationTests.cs b/src/EditorFeatures/Test/Diagnostics/IDEDiagnosticIDConfigurationTests.cs index de1bdc34c1c21..b60c62a4f5bc4 100644 --- a/src/EditorFeatures/Test/Diagnostics/IDEDiagnosticIDConfigurationTests.cs +++ b/src/EditorFeatures/Test/Diagnostics/IDEDiagnosticIDConfigurationTests.cs @@ -72,7 +72,8 @@ private static void ValidateHelpLinkForDiagnostic(string diagnosticId, string he { if (diagnosticId is "IDE0043" // Intentionally undocumented because it's being removed in favor of CA2241 or "IDE1007" - or "RemoveUnnecessaryImportsFixable" + or "RemoveUnnecessaryImportsFixable" // this diagnostic is hidden and not configurable. + or "IDE0005_gen" // this diagnostic is hidden and not configurable. or "RE0001" or "JSON001" or "JSON002") // Tracked by https://github.com/dotnet/roslyn/issues/48530 @@ -81,11 +82,6 @@ private static void ValidateHelpLinkForDiagnostic(string diagnosticId, string he return; } - if (diagnosticId == "IDE0005_gen") - { - diagnosticId = "IDE0005"; - } - if (helpLinkUri != $"https://docs.microsoft.com/dotnet/fundamentals/code-analysis/style-rules/{diagnosticId.ToLowerInvariant()}") { Assert.True(false, $"Invalid help link for {diagnosticId}"); @@ -864,7 +860,7 @@ No editorconfig based code style option No editorconfig based code style option # IDE0036, PreferredModifierOrder -csharp_preferred_modifier_order = public,private,protected,internal,static,extern,new,virtual,abstract,sealed,override,readonly,unsafe,required,volatile,async +csharp_preferred_modifier_order = public,private,protected,internal,file,static,extern,new,virtual,abstract,sealed,override,readonly,unsafe,required,volatile,async # IDE0037, PreferInferredTupleNames dotnet_style_prefer_inferred_tuple_names = true diff --git a/src/EditorFeatures/Test/Diagnostics/MockDiagnosticService.cs b/src/EditorFeatures/Test/Diagnostics/MockDiagnosticService.cs index 0443f019f2d49..3daad491a914c 100644 --- a/src/EditorFeatures/Test/Diagnostics/MockDiagnosticService.cs +++ b/src/EditorFeatures/Test/Diagnostics/MockDiagnosticService.cs @@ -25,24 +25,12 @@ internal class MockDiagnosticService : IDiagnosticService private DiagnosticData? _diagnostic; - public IGlobalOptionService GlobalOptions { get; } - public event EventHandler? DiagnosticsUpdated; [ImportingConstructor] [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] public MockDiagnosticService(IGlobalOptionService globalOptions) { - GlobalOptions = globalOptions; - } - - [Obsolete] - public ImmutableArray GetDiagnostics(Workspace workspace, ProjectId? projectId, DocumentId? documentId, object? id, bool includeSuppressedDiagnostics, CancellationToken cancellationToken) - => GetPushDiagnosticsAsync(workspace, projectId, documentId, id, includeSuppressedDiagnostics, DiagnosticMode.Default, cancellationToken).AsTask().WaitAndGetResult_CanCallOnBackground(cancellationToken); - - public ValueTask> GetPullDiagnosticsAsync(Workspace workspace, ProjectId? projectId, DocumentId? documentId, object? id, bool includeSuppressedDiagnostics, DiagnosticMode diagnosticMode, CancellationToken cancellationToken) - { - return new ValueTask>(GetDiagnostics(workspace, projectId, documentId)); } public ValueTask> GetPushDiagnosticsAsync(Workspace workspace, ProjectId? projectId, DocumentId? documentId, object? id, bool includeSuppressedDiagnostics, DiagnosticMode diagnosticMode, CancellationToken cancellationToken) diff --git a/src/EditorFeatures/Test/EditAndContinue/ActiveStatementsMapTests.cs b/src/EditorFeatures/Test/EditAndContinue/ActiveStatementsMapTests.cs index dca97ffde089e..3fea69cb64f3a 100644 --- a/src/EditorFeatures/Test/EditAndContinue/ActiveStatementsMapTests.cs +++ b/src/EditorFeatures/Test/EditAndContinue/ActiveStatementsMapTests.cs @@ -91,7 +91,7 @@ void F() var project = solution.Projects.Single(); var document = project.Documents.Single(); - var analyzer = project.LanguageServices.GetRequiredService(); + var analyzer = project.Services.GetRequiredService(); var documentPathMap = new Dictionary>(); @@ -126,6 +126,47 @@ ManagedActiveStatementDebugInfo CreateInfo(int startLine, int startColumn, int e }, oldSpans.Select(s => $"{s.UnmappedSpan} -> {s.Statement.Span} #{s.Statement.Ordinal}")); } + [Fact] + public async Task InvalidActiveStatements() + { + using var workspace = new TestWorkspace(composition: FeaturesTestCompositions.Features); + + var source = @" +class C +{ + void F() + { +S1(); + } +}"; + + var solution = workspace.CurrentSolution + .AddProject("proj", "proj", LanguageNames.CSharp) + .AddDocument("doc", SourceText.From(source, Encoding.UTF8), filePath: "a.cs").Project.Solution; + + var project = solution.Projects.Single(); + var document = project.Documents.Single(); + var analyzer = project.Services.GetRequiredService(); + + var documentPathMap = new Dictionary>(); + + var moduleId = Guid.NewGuid(); + var token = 0x06000001; + ManagedActiveStatementDebugInfo CreateInfo(int startLine, int startColumn, int endLine, int endColumn, string fileName) + => new(new(new(moduleId, token++, version: 1), ilOffset: 0), fileName, new SourceSpan(startLine, startColumn, endLine, endColumn), ActiveStatementFlags.MethodUpToDate); + + // Create a bad active span that is outside the document, but passes the `TryGetTextSpan` check in ActiveStatementMap + var debugInfos = ImmutableArray.Create( + CreateInfo(7, 9, 7, 10, "a.cs") + ); + + var map = ActiveStatementsMap.Create(debugInfos, remapping: ImmutableDictionary>.Empty); + + var oldSpans = await map.GetOldActiveStatementsAsync(analyzer, document, CancellationToken.None); + + AssertEx.Empty(oldSpans); + } + [Fact] public void ExpandMultiLineSpan() { @@ -156,7 +197,7 @@ static void F(Action a) var project = solution.Projects.Single(); var document = project.Documents.Single(); - var analyzer = project.LanguageServices.GetRequiredService(); + var analyzer = project.Services.GetRequiredService(); var documentPathMap = new Dictionary>(); diff --git a/src/EditorFeatures/Test/EditAndContinue/CompileTimeSolutionProviderTests.cs b/src/EditorFeatures/Test/EditAndContinue/CompileTimeSolutionProviderTests.cs index 3b42e4cf8c362..aabae5d7cd35a 100644 --- a/src/EditorFeatures/Test/EditAndContinue/CompileTimeSolutionProviderTests.cs +++ b/src/EditorFeatures/Test/EditAndContinue/CompileTimeSolutionProviderTests.cs @@ -17,6 +17,7 @@ using Microsoft.CodeAnalysis.Text; using Microsoft.VisualStudio.Debugger.Contracts.EditAndContinue; using Roslyn.Test.Utilities; +using Roslyn.Test.Utilities.TestGenerators; using Xunit; namespace Microsoft.CodeAnalysis.EditAndContinue.UnitTests @@ -80,5 +81,78 @@ public async Task TryGetCompileTimeDocumentAsync(string kind) AssertEx.Equal(new[] { documentId, designTimeDocumentId }, actualDesignTimeDocumentIds); } + + [Fact] + public async Task GeneratorOutputCachedBetweenAcrossCompileTimeSolutions() + { + var workspace = new TestWorkspace(composition: FeaturesTestCompositions.Features); + var projectId = ProjectId.CreateNewId(); + + var generatorInvocations = 0; + + var generator = new PipelineCallbackGenerator(context => + { + // We'll replicate a simple example of how the razor generator handles disabling here so the test + // functions similar to the real world + var isDisabled = context.AnalyzerConfigOptionsProvider.Select( + (o, ct) => o.GlobalOptions.TryGetValue("build_property.SuppressRazorSourceGenerator", out var value) && bool.Parse(value)); + + var sources = context.AdditionalTextsProvider.Combine(isDisabled).Select((pair, ct) => + { + var (additionalText, isDisabledFlag) = pair; + + if (isDisabledFlag) + return null; + + Interlocked.Increment(ref generatorInvocations); + return "// " + additionalText.GetText(ct)!.ToString(); + }); + + context.RegisterSourceOutput(sources, (context, s) => + { + if (s != null) + context.AddSource("hint", SourceText.From(s)); + }); + }); + + var analyzerConfigId = DocumentId.CreateNewId(projectId); + var additionalDocumentId = DocumentId.CreateNewId(projectId); + + var analyzerConfigText = "is_global = true\r\nbuild_property.SuppressRazorSourceGenerator = true"; + + workspace.SetCurrentSolution(s => s. + AddProject(ProjectInfo.Create(projectId, VersionStamp.Default, "proj", "proj", LanguageNames.CSharp)). + AddAnalyzerReference(projectId, new TestGeneratorReference(generator)). + AddAdditionalDocument(additionalDocumentId, "additional", SourceText.From(""), filePath: "additional.razor"). + AddAnalyzerConfigDocument(analyzerConfigId, "config", SourceText.From(analyzerConfigText), filePath: "Z:\\RazorSourceGenerator.razorencconfig"), + WorkspaceChangeKind.SolutionAdded); + + // Fetch a compilation first for the base solution; we're doing this because currently if we try to move the + // cached generator state to a snapshot that has no CompilationTracker at all, we won't update the state. + _ = await workspace.CurrentSolution.GetRequiredProject(projectId).GetCompilationAsync(); + + var provider = workspace.Services.GetRequiredService(); + var compileTimeSolution1 = provider.GetCompileTimeSolution(workspace.CurrentSolution); + + _ = await compileTimeSolution1.GetRequiredProject(projectId).GetCompilationAsync(); + + Assert.Equal(1, generatorInvocations); + + // Now do something that shouldn't force the generator to rerun; we must change this through the workspace since the + // service itself uses versions that won't change otherwise + var documentId = DocumentId.CreateNewId(projectId); + workspace.SetCurrentSolution( + s => s.AddDocument(documentId, "Test.cs", "// source file"), + WorkspaceChangeKind.DocumentAdded, + projectId, + documentId); + + var compileTimeSolution2 = provider.GetCompileTimeSolution(workspace.CurrentSolution); + Assert.NotSame(compileTimeSolution1, compileTimeSolution2); + + _ = await compileTimeSolution2.GetRequiredProject(projectId).GetCompilationAsync(); + + Assert.Equal(1, generatorInvocations); + } } } diff --git a/src/EditorFeatures/Test/EditAndContinue/EditAndContinueWorkspaceServiceTests.cs b/src/EditorFeatures/Test/EditAndContinue/EditAndContinueWorkspaceServiceTests.cs index c6c9c44711e08..f7d3e9aeb2517 100644 --- a/src/EditorFeatures/Test/EditAndContinue/EditAndContinueWorkspaceServiceTests.cs +++ b/src/EditorFeatures/Test/EditAndContinue/EditAndContinueWorkspaceServiceTests.cs @@ -209,7 +209,7 @@ private static void EndDebuggingSession(DebuggingSession session, ImmutableArray AssertEx.Equal(documentsWithRudeEdits.NullToEmpty(), documentsToReanalyze); } - private static async Task<(ManagedModuleUpdates updates, ImmutableArray diagnostics)> EmitSolutionUpdateAsync( + private static async Task<(ModuleUpdates updates, ImmutableArray diagnostics)> EmitSolutionUpdateAsync( DebuggingSession session, Solution solution, ActiveStatementSpanProvider activeStatementSpanProvider = null) @@ -488,7 +488,7 @@ public async Task StartDebuggingSession_CapturingDocuments(bool captureAllDocume sourceFileB.WriteAllText(sourceB2, encodingB); // prepare workspace as if it was loaded from project files: - using var _ = CreateWorkspace(out var solution, out var service, new[] { typeof(DummyLanguageService) }); + using var _ = CreateWorkspace(out var solution, out var service, new[] { typeof(NoCompilationLanguageService) }); var projectP = solution.AddProject("P", "P", LanguageNames.CSharp); solution = projectP.Solution; @@ -533,7 +533,7 @@ public async Task StartDebuggingSession_CapturingDocuments(bool captureAllDocume AddDocument(CreateDesignTimeOnlyDocument(projectP.Id, name: "dt2.cs", path: "dt2.cs")); // project that does not support EnC - the contents of documents in this project shouldn't be loaded: - var projectQ = solution.AddProject("Q", "Q", DummyLanguageService.LanguageName); + var projectQ = solution.AddProject("Q", "Q", NoCompilationConstants.LanguageName); solution = projectQ.Solution; solution = solution.AddDocument(DocumentInfo.Create( @@ -563,7 +563,7 @@ public async Task StartDebuggingSession_CapturingDocuments(bool captureAllDocume EnterBreakState(debuggingSession); var (updates, emitDiagnostics) = await EmitSolutionUpdateAsync(debuggingSession, solution); - Assert.Equal(ManagedModuleUpdateStatus.None, updates.Status); + Assert.Equal(ModuleUpdateStatus.None, updates.Status); Assert.Empty(updates.Updates); AssertEx.Equal(new[] { $"{projectP.Id}: Warning ENC1005: {string.Format(FeaturesResources.DocumentIsOutOfSyncWithDebuggee, sourceFileB.Path)}" }, InspectDiagnostics(emitDiagnostics)); @@ -578,7 +578,7 @@ public async Task ProjectNotBuilt() _mockCompilationOutputsProvider = _ => new MockCompilationOutputs(Guid.Empty); - await StartDebuggingSessionAsync(service, solution); + var debuggingSession = await StartDebuggingSessionAsync(service, solution); // no changes: var diagnostics = await service.GetDocumentDiagnosticsAsync(document1, s_noActiveSpans, CancellationToken.None); @@ -590,6 +590,14 @@ public async Task ProjectNotBuilt() diagnostics = await service.GetDocumentDiagnosticsAsync(document2, s_noActiveSpans, CancellationToken.None); Assert.Empty(diagnostics); + + // changes in the project are ignored: + var (updates, emitDiagnostics) = await EmitSolutionUpdateAsync(debuggingSession, solution); + Assert.Equal(ModuleUpdateStatus.None, updates.Status); + Assert.Empty(updates.Updates); + Assert.Empty(emitDiagnostics); + + EndDebuggingSession(debuggingSession); } [Fact] @@ -619,7 +627,7 @@ public async Task DifferentDocumentWithSameContent() // validate solution update status and emit - changes made during run mode are ignored: var (updates, _) = await EmitSolutionUpdateAsync(debuggingSession, solution); - Assert.Equal(ManagedModuleUpdateStatus.None, updates.Status); + Assert.Equal(ModuleUpdateStatus.None, updates.Status); EndDebuggingSession(debuggingSession); @@ -633,8 +641,8 @@ public async Task DifferentDocumentWithSameContent() [CombinatorialData] public async Task ProjectThatDoesNotSupportEnC(bool breakMode) { - using var _ = CreateWorkspace(out var solution, out var service, new[] { typeof(DummyLanguageService) }); - var project = solution.AddProject("dummy_proj", "dummy_proj", DummyLanguageService.LanguageName); + using var _ = CreateWorkspace(out var solution, out var service, new[] { typeof(NoCompilationLanguageService) }); + var project = solution.AddProject("dummy_proj", "dummy_proj", NoCompilationConstants.LanguageName); var document = project.AddDocument("test", SourceText.From("dummy1")); solution = document.Project.Solution; @@ -654,7 +662,7 @@ public async Task ProjectThatDoesNotSupportEnC(bool breakMode) // validate solution update status and emit: var (updates, emitDiagnostics) = await EmitSolutionUpdateAsync(debuggingSession, solution); - Assert.Equal(ManagedModuleUpdateStatus.None, updates.Status); + Assert.Equal(ModuleUpdateStatus.None, updates.Status); Assert.Empty(updates.Updates); Assert.Empty(emitDiagnostics); @@ -688,7 +696,7 @@ public async Task DesignTimeOnlyDocument() // validate solution update status and emit - changes made in design-time-only documents are ignored: var (updates, _) = await EmitSolutionUpdateAsync(debuggingSession, solution); - Assert.Equal(ManagedModuleUpdateStatus.None, updates.Status); + Assert.Equal(ModuleUpdateStatus.None, updates.Status); EndDebuggingSession(debuggingSession); @@ -727,12 +735,12 @@ public async Task DesignTimeOnlyDocument_Dynamic() // validate solution update status and emit: var (updates, emitDiagnostics) = await EmitSolutionUpdateAsync(debuggingSession, solution); - Assert.Equal(ManagedModuleUpdateStatus.None, updates.Status); + Assert.Equal(ModuleUpdateStatus.None, updates.Status); Assert.Empty(updates.Updates); Assert.Empty(emitDiagnostics); (updates, emitDiagnostics) = await EmitSolutionUpdateAsync(debuggingSession, solution); - Assert.Equal(ManagedModuleUpdateStatus.None, updates.Status); + Assert.Equal(ModuleUpdateStatus.None, updates.Status); Assert.Empty(updates.Updates); Assert.Empty(emitDiagnostics); } @@ -790,7 +798,7 @@ public async Task DesignTimeOnlyDocument_Wpf(bool delayLoad) // validate solution update status and emit: var (updates, emitDiagnostics) = await EmitSolutionUpdateAsync(debuggingSession, solution); - Assert.Equal(ManagedModuleUpdateStatus.None, updates.Status); + Assert.Equal(ModuleUpdateStatus.None, updates.Status); Assert.Empty(emitDiagnostics); if (delayLoad) @@ -799,7 +807,7 @@ public async Task DesignTimeOnlyDocument_Wpf(bool delayLoad) // validate solution update status and emit: (updates, emitDiagnostics) = await EmitSolutionUpdateAsync(debuggingSession, solution); - Assert.Equal(ManagedModuleUpdateStatus.None, updates.Status); + Assert.Equal(ModuleUpdateStatus.None, updates.Status); Assert.Empty(emitDiagnostics); } @@ -825,8 +833,11 @@ public async Task ErrorReadingModuleFile(bool breakMode) expectedErrorMessage = e.Message; } + var source1 = "class C { void M() { System.Console.WriteLine(1); } }"; + var source2 = "class C { void M() { System.Console.WriteLine(2); } }"; + using var _w = CreateWorkspace(out var solution, out var service); - (solution, var document1) = AddDefaultTestProject(solution, "class C1 { void M() { System.Console.WriteLine(1); } }"); + (solution, var document1) = AddDefaultTestProject(solution, source1); _mockCompilationOutputsProvider = _ => new CompilationOutputFiles(moduleFile.Path); @@ -838,7 +849,7 @@ public async Task ErrorReadingModuleFile(bool breakMode) } // change the source: - solution = solution.WithDocumentText(document1.Id, SourceText.From("class C1 { void M() { System.Console.WriteLine(2); } }")); + solution = solution.WithDocumentText(document1.Id, SourceText.From(source2, encoding: Encoding.UTF8)); var document2 = solution.GetDocument(document1.Id); // error not reported here since it might be intermittent and will be reported if the issue persist when applying the update: @@ -846,10 +857,19 @@ public async Task ErrorReadingModuleFile(bool breakMode) Assert.Empty(diagnostics); var (updates, emitDiagnostics) = await EmitSolutionUpdateAsync(debuggingSession, solution); - Assert.Equal(ManagedModuleUpdateStatus.RestartRequired, updates.Status); + Assert.Equal(ModuleUpdateStatus.RestartRequired, updates.Status); Assert.Empty(updates.Updates); AssertEx.Equal(new[] { $"{document2.Project.Id}: Error ENC1001: {string.Format(FeaturesResources.ErrorReadingFile, moduleFile.Path, expectedErrorMessage)}" }, InspectDiagnostics(emitDiagnostics)); + // correct the error: + EmitLibrary(source2); + + var (updates2, emitDiagnostics2) = await EmitSolutionUpdateAsync(debuggingSession, solution); + Assert.Equal(ModuleUpdateStatus.Ready, updates2.Status); + Assert.Empty(emitDiagnostics2); + + CommitSolutionUpdate(debuggingSession); + if (breakMode) { ExitBreakState(debuggingSession); @@ -861,8 +881,8 @@ public async Task ErrorReadingModuleFile(bool breakMode) { AssertEx.Equal(new[] { - "Debugging_EncSession: SolutionSessionId={00000000-AAAA-AAAA-AAAA-000000000000}|SessionId=1|SessionCount=1|EmptySessionCount=0|HotReloadSessionCount=0|EmptyHotReloadSessionCount=2", - "Debugging_EncSession_EditSession: SessionId=1|EditSessionId=2|HadCompilationErrors=False|HadRudeEdits=False|HadValidChanges=True|HadValidInsignificantChanges=False|RudeEditsCount=0|EmitDeltaErrorIdCount=1|InBreakState=True|Capabilities=31|ProjectIdsWithAppliedChanges=", + "Debugging_EncSession: SolutionSessionId={00000000-AAAA-AAAA-AAAA-000000000000}|SessionId=1|SessionCount=1|EmptySessionCount=0|HotReloadSessionCount=0|EmptyHotReloadSessionCount=3", + "Debugging_EncSession_EditSession: SessionId=1|EditSessionId=2|HadCompilationErrors=False|HadRudeEdits=False|HadValidChanges=True|HadValidInsignificantChanges=False|RudeEditsCount=0|EmitDeltaErrorIdCount=1|InBreakState=True|Capabilities=31|ProjectIdsWithAppliedChanges={00000000-AAAA-AAAA-AAAA-111111111111}", "Debugging_EncSession_EditSession_EmitDeltaErrorId: SessionId=1|EditSessionId=2|ErrorId=ENC1001" }, _telemetryLog); } @@ -870,8 +890,8 @@ public async Task ErrorReadingModuleFile(bool breakMode) { AssertEx.Equal(new[] { - "Debugging_EncSession: SolutionSessionId={00000000-AAAA-AAAA-AAAA-000000000000}|SessionId=1|SessionCount=0|EmptySessionCount=0|HotReloadSessionCount=1|EmptyHotReloadSessionCount=0", - "Debugging_EncSession_EditSession: SessionId=1|EditSessionId=2|HadCompilationErrors=False|HadRudeEdits=False|HadValidChanges=True|HadValidInsignificantChanges=False|RudeEditsCount=0|EmitDeltaErrorIdCount=1|InBreakState=False|Capabilities=31|ProjectIdsWithAppliedChanges=", + "Debugging_EncSession: SolutionSessionId={00000000-AAAA-AAAA-AAAA-000000000000}|SessionId=1|SessionCount=0|EmptySessionCount=0|HotReloadSessionCount=1|EmptyHotReloadSessionCount=1", + "Debugging_EncSession_EditSession: SessionId=1|EditSessionId=2|HadCompilationErrors=False|HadRudeEdits=False|HadValidChanges=True|HadValidInsignificantChanges=False|RudeEditsCount=0|EmitDeltaErrorIdCount=1|InBreakState=False|Capabilities=31|ProjectIdsWithAppliedChanges={00000000-AAAA-AAAA-AAAA-111111111111}", "Debugging_EncSession_EditSession_EmitDeltaErrorId: SessionId=1|EditSessionId=2|ErrorId=ENC1001" }, _telemetryLog); } @@ -918,7 +938,7 @@ 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(ManagedModuleUpdateStatus.None, updates.Status); + Assert.Equal(ModuleUpdateStatus.None, updates.Status); Assert.Empty(updates.Updates); AssertEx.Equal(new[] { $"{project.Id}: Warning ENC1006: {string.Format(FeaturesResources.UnableToReadSourceFileOrPdb, sourceFile.Path)}" }, InspectDiagnostics(emitDiagnostics)); @@ -965,7 +985,7 @@ 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(ManagedModuleUpdateStatus.None, updates.Status); + Assert.Equal(ModuleUpdateStatus.None, updates.Status); Assert.Empty(updates.Updates); AssertEx.Equal(new[] { $"{project.Id}: Warning ENC1006: {string.Format(FeaturesResources.UnableToReadSourceFileOrPdb, sourceFile.Path)}" }, InspectDiagnostics(emitDiagnostics)); @@ -973,7 +993,7 @@ public async Task ErrorReadingSourceFile() // try apply changes again: (updates, emitDiagnostics) = await EmitSolutionUpdateAsync(debuggingSession, solution); - Assert.Equal(ManagedModuleUpdateStatus.Ready, updates.Status); + Assert.Equal(ModuleUpdateStatus.Ready, updates.Status); Assert.NotEmpty(updates.Updates); Assert.Empty(emitDiagnostics); @@ -1027,7 +1047,7 @@ public async Task FileAdded(bool breakMode) Assert.Empty(diagnostics2); var (updates, emitDiagnostics) = await EmitSolutionUpdateAsync(debuggingSession, solution); - Assert.Equal(ManagedModuleUpdateStatus.Ready, updates.Status); + Assert.Equal(ModuleUpdateStatus.Ready, updates.Status); debuggingSession.DiscardSolutionUpdate(); if (breakMode) @@ -1113,7 +1133,7 @@ public async Task ModuleDisallowsEditAndContinue_NoChanges(bool breakMode) solution = solution.WithDocumentText(document0.Id, SourceText.From(source1)); var (updates, emitDiagnostics) = await EmitSolutionUpdateAsync(debuggingSession, solution); - Assert.Equal(ManagedModuleUpdateStatus.None, updates.Status); + Assert.Equal(ModuleUpdateStatus.None, updates.Status); Assert.Empty(updates.Updates); Assert.Empty(emitDiagnostics); @@ -1151,7 +1171,7 @@ public async Task ModuleDisallowsEditAndContinue_SourceGenerator_NoChanges() solution = solution.WithDocumentText(document1.Id, SourceText.From(source2)); var (updates, emitDiagnostics) = await EmitSolutionUpdateAsync(debuggingSession, solution); - Assert.Equal(ManagedModuleUpdateStatus.None, updates.Status); + Assert.Equal(ModuleUpdateStatus.None, updates.Status); Assert.Empty(updates.Updates); EndDebuggingSession(debuggingSession); @@ -1208,7 +1228,7 @@ void M() // validate solution update status and emit: var (updates, emitDiagnostics) = await EmitSolutionUpdateAsync(debuggingSession, solution); - Assert.Equal(ManagedModuleUpdateStatus.RestartRequired, updates.Status); + Assert.Equal(ModuleUpdateStatus.RestartRequired, updates.Status); Assert.Empty(updates.Updates); AssertEx.Equal(new[] { $"{document2.FilePath}: (5,0)-(5,32): Error ENC2016: {string.Format(FeaturesResources.EditAndContinueDisallowedByProject, document2.Project.Name, "*message*")}" }, InspectDiagnostics(emitDiagnostics)); @@ -1260,7 +1280,7 @@ public async Task Encodings() // EnC service queries for a document, which triggers read of the source file from disk. var (updates, _) = await EmitSolutionUpdateAsync(debuggingSession, solution); - Assert.Equal(ManagedModuleUpdateStatus.None, updates.Status); + Assert.Equal(ModuleUpdateStatus.None, updates.Status); EndDebuggingSession(debuggingSession); } @@ -1270,7 +1290,7 @@ public async Task Encodings() public async Task RudeEdits(bool breakMode) { var source1 = "class C1 { void M() { System.Console.WriteLine(1); } }"; - var source2 = "class C1 { void M1() { System.Console.WriteLine(1); } }"; + var source2 = "class C1 { void M() { System.Console.WriteLine(1); } }"; var moduleId = Guid.NewGuid(); @@ -1292,12 +1312,12 @@ public async Task RudeEdits(bool breakMode) var document2 = solution.GetDocument(document1.Id); var diagnostics1 = await service.GetDocumentDiagnosticsAsync(document2, s_noActiveSpans, CancellationToken.None); - AssertEx.Equal(new[] { "ENC0020: " + string.Format(FeaturesResources.Renaming_0_requires_restarting_the_application, FeaturesResources.method) }, + AssertEx.Equal(new[] { "ENC0021: " + string.Format(FeaturesResources.Adding_0_requires_restarting_the_application, FeaturesResources.type_parameter) }, diagnostics1.Select(d => $"{d.Id}: {d.GetMessage()}")); // validate solution update status and emit: var (updates, emitDiagnostics) = await EmitSolutionUpdateAsync(debuggingSession, solution); - Assert.Equal(ManagedModuleUpdateStatus.RestartRequired, updates.Status); + Assert.Equal(ModuleUpdateStatus.RestartRequired, updates.Status); Assert.Empty(updates.Updates); Assert.Empty(emitDiagnostics); @@ -1319,7 +1339,7 @@ public async Task RudeEdits(bool breakMode) { "Debugging_EncSession: SolutionSessionId={00000000-AAAA-AAAA-AAAA-000000000000}|SessionId=1|SessionCount=1|EmptySessionCount=0|HotReloadSessionCount=0|EmptyHotReloadSessionCount=2", "Debugging_EncSession_EditSession: SessionId=1|EditSessionId=2|HadCompilationErrors=False|HadRudeEdits=True|HadValidChanges=False|HadValidInsignificantChanges=False|RudeEditsCount=1|EmitDeltaErrorIdCount=0|InBreakState=True|Capabilities=31|ProjectIdsWithAppliedChanges=", - "Debugging_EncSession_EditSession_RudeEdit: SessionId=1|EditSessionId=2|RudeEditKind=20|RudeEditSyntaxKind=8875|RudeEditBlocking=True" + "Debugging_EncSession_EditSession_RudeEdit: SessionId=1|EditSessionId=2|RudeEditKind=21|RudeEditSyntaxKind=8910|RudeEditBlocking=True" }, _telemetryLog); } else @@ -1328,7 +1348,7 @@ public async Task RudeEdits(bool breakMode) { "Debugging_EncSession: SolutionSessionId={00000000-AAAA-AAAA-AAAA-000000000000}|SessionId=1|SessionCount=0|EmptySessionCount=0|HotReloadSessionCount=1|EmptyHotReloadSessionCount=0", "Debugging_EncSession_EditSession: SessionId=1|EditSessionId=2|HadCompilationErrors=False|HadRudeEdits=True|HadValidChanges=False|HadValidInsignificantChanges=False|RudeEditsCount=1|EmitDeltaErrorIdCount=0|InBreakState=False|Capabilities=31|ProjectIdsWithAppliedChanges=", - "Debugging_EncSession_EditSession_RudeEdit: SessionId=1|EditSessionId=2|RudeEditKind=20|RudeEditSyntaxKind=8875|RudeEditBlocking=True" + "Debugging_EncSession_EditSession_RudeEdit: SessionId=1|EditSessionId=2|RudeEditKind=21|RudeEditSyntaxKind=8910|RudeEditBlocking=True" }, _telemetryLog); } } @@ -1385,7 +1405,7 @@ public async Task DeferredApplyChangeWithActiveStatementRudeEdits() // apply the change: var (updates, emitDiagnostics) = await EmitSolutionUpdateAsync(debuggingSession, solution); - Assert.Equal(ManagedModuleUpdateStatus.Ready, updates.Status); + Assert.Equal(ModuleUpdateStatus.Ready, updates.Status); Assert.NotEmpty(updates.Updates); Assert.Empty(emitDiagnostics); @@ -1405,12 +1425,12 @@ public async Task DeferredApplyChangeWithActiveStatementRudeEdits() public async Task RudeEdits_SourceGenerators() { var sourceV1 = @" -/* GENERATE: class G { int X1 => 1; } */ +/* GENERATE: class G { int X1() => 1; } */ class C { int Y => 1; } "; var sourceV2 = @" -/* GENERATE: class G { int X2 => 1; } */ +/* GENERATE: class G { int X1() => 1; } */ class C { int Y => 2; } "; @@ -1430,11 +1450,11 @@ class C { int Y => 2; } var generatedDocument = (await solution.Projects.Single().GetSourceGeneratedDocumentsAsync()).Single(); var diagnostics1 = await service.GetDocumentDiagnosticsAsync(generatedDocument, s_noActiveSpans, CancellationToken.None); - AssertEx.Equal(new[] { "ENC0020: " + string.Format(FeaturesResources.Renaming_0_requires_restarting_the_application, FeaturesResources.property_) }, + AssertEx.Equal(new[] { "ENC0021: " + string.Format(FeaturesResources.Adding_0_requires_restarting_the_application, FeaturesResources.type_parameter) }, diagnostics1.Select(d => $"{d.Id}: {d.GetMessage()}")); var (updates, emitDiagnostics) = await EmitSolutionUpdateAsync(debuggingSession, solution); - Assert.Equal(ManagedModuleUpdateStatus.RestartRequired, updates.Status); + Assert.Equal(ModuleUpdateStatus.RestartRequired, updates.Status); Assert.Empty(updates.Updates); Assert.Empty(emitDiagnostics); @@ -1447,7 +1467,7 @@ public async Task RudeEdits_DocumentOutOfSync(bool breakMode) { var source0 = "class C1 { void M() { System.Console.WriteLine(0); } }"; var source1 = "class C1 { void M() { System.Console.WriteLine(1); } }"; - var source2 = "class C1 { void RenamedMethod() { System.Console.WriteLine(1); } }"; + var source2 = "class C1 { void M() { System.Console.WriteLine(1); } }"; var dir = Temp.CreateDirectory(); var sourceFile = dir.CreateFile("a.cs"); @@ -1487,7 +1507,7 @@ 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(ManagedModuleUpdateStatus.None, updates.Status); + Assert.Equal(ModuleUpdateStatus.None, updates.Status); Assert.Empty(updates.Updates); AssertEx.Equal(new[] { $"{project.Id}: Warning ENC1005: {string.Format(FeaturesResources.DocumentIsOutOfSyncWithDebuggee, sourceFile.Path)}" }, InspectDiagnostics(emitDiagnostics)); @@ -1500,17 +1520,21 @@ public async Task RudeEdits_DocumentOutOfSync(bool breakMode) // debugger query will trigger reload of out-of-sync file content: (updates, emitDiagnostics) = await EmitSolutionUpdateAsync(debuggingSession, solution); - Assert.Equal(ManagedModuleUpdateStatus.RestartRequired, updates.Status); + Assert.Equal(ModuleUpdateStatus.RestartRequired, updates.Status); Assert.Empty(updates.Updates); Assert.Empty(emitDiagnostics); // now we see the rude edit: diagnostics = await service.GetDocumentDiagnosticsAsync(document2, s_noActiveSpans, CancellationToken.None); - AssertEx.Equal(new[] { "ENC0020: " + string.Format(FeaturesResources.Renaming_0_requires_restarting_the_application, FeaturesResources.method) }, - diagnostics.Select(d => $"{d.Id}: {d.GetMessage()}")); + AssertEx.Equal(new[] + { + "ENC0038: " + FeaturesResources.Modifying_a_method_inside_the_context_of_a_generic_type_requires_restarting_the_application, + "ENC0021: " + string.Format(FeaturesResources.Adding_0_requires_restarting_the_application, FeaturesResources.type_parameter) + }, + diagnostics.Select(d => $"{d.Id}: {d.GetMessage()}")); (updates, emitDiagnostics) = await EmitSolutionUpdateAsync(debuggingSession, solution); - Assert.Equal(ManagedModuleUpdateStatus.RestartRequired, updates.Status); + Assert.Equal(ModuleUpdateStatus.RestartRequired, updates.Status); Assert.Empty(updates.Updates); Assert.Empty(emitDiagnostics); @@ -1531,8 +1555,9 @@ public async Task RudeEdits_DocumentOutOfSync(bool breakMode) AssertEx.Equal(new[] { "Debugging_EncSession: SolutionSessionId={00000000-AAAA-AAAA-AAAA-000000000000}|SessionId=1|SessionCount=1|EmptySessionCount=0|HotReloadSessionCount=0|EmptyHotReloadSessionCount=2", - "Debugging_EncSession_EditSession: SessionId=1|EditSessionId=2|HadCompilationErrors=False|HadRudeEdits=True|HadValidChanges=False|HadValidInsignificantChanges=False|RudeEditsCount=1|EmitDeltaErrorIdCount=0|InBreakState=True|Capabilities=31|ProjectIdsWithAppliedChanges=", - "Debugging_EncSession_EditSession_RudeEdit: SessionId=1|EditSessionId=2|RudeEditKind=20|RudeEditSyntaxKind=8875|RudeEditBlocking=True" + "Debugging_EncSession_EditSession: SessionId=1|EditSessionId=2|HadCompilationErrors=False|HadRudeEdits=True|HadValidChanges=False|HadValidInsignificantChanges=False|RudeEditsCount=2|EmitDeltaErrorIdCount=0|InBreakState=True|Capabilities=31|ProjectIdsWithAppliedChanges=", + "Debugging_EncSession_EditSession_RudeEdit: SessionId=1|EditSessionId=2|RudeEditKind=38|RudeEditSyntaxKind=8875|RudeEditBlocking=True", + "Debugging_EncSession_EditSession_RudeEdit: SessionId=1|EditSessionId=2|RudeEditKind=21|RudeEditSyntaxKind=8910|RudeEditBlocking=True" }, _telemetryLog); } else @@ -1540,8 +1565,9 @@ public async Task RudeEdits_DocumentOutOfSync(bool breakMode) AssertEx.Equal(new[] { "Debugging_EncSession: SolutionSessionId={00000000-AAAA-AAAA-AAAA-000000000000}|SessionId=1|SessionCount=0|EmptySessionCount=0|HotReloadSessionCount=1|EmptyHotReloadSessionCount=0", - "Debugging_EncSession_EditSession: SessionId=1|EditSessionId=2|HadCompilationErrors=False|HadRudeEdits=True|HadValidChanges=False|HadValidInsignificantChanges=False|RudeEditsCount=1|EmitDeltaErrorIdCount=0|InBreakState=False|Capabilities=31|ProjectIdsWithAppliedChanges=", - "Debugging_EncSession_EditSession_RudeEdit: SessionId=1|EditSessionId=2|RudeEditKind=20|RudeEditSyntaxKind=8875|RudeEditBlocking=True" + "Debugging_EncSession_EditSession: SessionId=1|EditSessionId=2|HadCompilationErrors=False|HadRudeEdits=True|HadValidChanges=False|HadValidInsignificantChanges=False|RudeEditsCount=2|EmitDeltaErrorIdCount=0|InBreakState=False|Capabilities=31|ProjectIdsWithAppliedChanges=", + "Debugging_EncSession_EditSession_RudeEdit: SessionId=1|EditSessionId=2|RudeEditKind=38|RudeEditSyntaxKind=8875|RudeEditBlocking=True", + "Debugging_EncSession_EditSession_RudeEdit: SessionId=1|EditSessionId=2|RudeEditKind=21|RudeEditSyntaxKind=8910|RudeEditBlocking=True" }, _telemetryLog); } } @@ -1583,7 +1609,7 @@ public async Task RudeEdits_DocumentWithoutSequencePoints() // validate solution update status and emit: var (updates, emitDiagnostics) = await EmitSolutionUpdateAsync(debuggingSession, solution); - Assert.Equal(ManagedModuleUpdateStatus.RestartRequired, updates.Status); + Assert.Equal(ModuleUpdateStatus.RestartRequired, updates.Status); Assert.Empty(updates.Updates); Assert.Empty(emitDiagnostics); @@ -1616,17 +1642,17 @@ public async Task RudeEdits_DelayLoadedModule() EnterBreakState(debuggingSession); // change the source (rude edit) before the library is loaded: - solution = solution.WithDocumentText(document1.Id, SourceText.From("class C { public void Renamed() { } }")); + solution = solution.WithDocumentText(document1.Id, SourceText.From("class C { public void M() { } }")); var document2 = solution.Projects.Single().Documents.Single(); // Rude Edits reported: var diagnostics = await service.GetDocumentDiagnosticsAsync(document2, s_noActiveSpans, CancellationToken.None); AssertEx.Equal( - new[] { "ENC0020: " + string.Format(FeaturesResources.Renaming_0_requires_restarting_the_application, FeaturesResources.method) }, + new[] { "ENC0021: " + string.Format(FeaturesResources.Adding_0_requires_restarting_the_application, FeaturesResources.type_parameter) }, diagnostics.Select(d => $"{d.Id}: {d.GetMessage()}")); var (updates, emitDiagnostics) = await EmitSolutionUpdateAsync(debuggingSession, solution); - Assert.Equal(ManagedModuleUpdateStatus.RestartRequired, updates.Status); + Assert.Equal(ModuleUpdateStatus.RestartRequired, updates.Status); Assert.Empty(updates.Updates); Assert.Empty(emitDiagnostics); @@ -1636,11 +1662,11 @@ public async Task RudeEdits_DelayLoadedModule() // Rude Edits still reported: diagnostics = await service.GetDocumentDiagnosticsAsync(document2, s_noActiveSpans, CancellationToken.None); AssertEx.Equal( - new[] { "ENC0020: " + string.Format(FeaturesResources.Renaming_0_requires_restarting_the_application, FeaturesResources.method) }, + new[] { "ENC0021: " + string.Format(FeaturesResources.Adding_0_requires_restarting_the_application, FeaturesResources.type_parameter) }, diagnostics.Select(d => $"{d.Id}: {d.GetMessage()}")); (updates, emitDiagnostics) = await EmitSolutionUpdateAsync(debuggingSession, solution); - Assert.Equal(ManagedModuleUpdateStatus.RestartRequired, updates.Status); + Assert.Equal(ModuleUpdateStatus.RestartRequired, updates.Status); Assert.Empty(updates.Updates); Assert.Empty(emitDiagnostics); @@ -1672,7 +1698,7 @@ public async Task SyntaxError() // validate solution update status and emit: var (updates, emitDiagnostics) = await EmitSolutionUpdateAsync(debuggingSession, solution); - Assert.Equal(ManagedModuleUpdateStatus.Blocked, updates.Status); + Assert.Equal(ModuleUpdateStatus.Blocked, updates.Status); Assert.Empty(updates.Updates); Assert.Empty(emitDiagnostics); @@ -1713,7 +1739,7 @@ public async Task SemanticError() // The EnC analyzer does not check for and block on all semantic errors as they are already reported by diagnostic analyzer. // Blocking update on semantic errors would be possible, but the status check is only an optimization to avoid emitting. var (updates, emitDiagnostics) = await EmitSolutionUpdateAsync(debuggingSession, solution); - Assert.Equal(ManagedModuleUpdateStatus.Blocked, updates.Status); + Assert.Equal(ModuleUpdateStatus.Blocked, updates.Status); Assert.Empty(updates.Updates); // TODO: https://github.com/dotnet/roslyn/issues/36061 @@ -1738,15 +1764,23 @@ public async Task HasChanges() { using var _ = CreateWorkspace(out var solution, out var service); + var pathA = Path.Combine(TempRoot.Root, "A.cs"); + var pathB = Path.Combine(TempRoot.Root, "B.cs"); + var pathC = Path.Combine(TempRoot.Root, "C.cs"); + var pathD = Path.Combine(TempRoot.Root, "D.cs"); + var pathX = Path.Combine(TempRoot.Root, "X"); + var pathY = Path.Combine(TempRoot.Root, "Y"); + var pathCommon = Path.Combine(TempRoot.Root, "Common.cs"); + solution = solution. AddProject("A", "A", "C#"). - AddDocument("A.cs", "class Program { void Main() { System.Console.WriteLine(1); } }", filePath: "A.cs").Project.Solution. + AddDocument("A.cs", "class Program { void Main() { System.Console.WriteLine(1); } }", filePath: pathA).Project.Solution. AddProject("B", "B", "C#"). - AddDocument("Common.cs", "class Common {}", filePath: "Common.cs").Project. - AddDocument("B.cs", "class B {}", filePath: "B.cs").Project.Solution. + AddDocument("Common.cs", "class Common {}", filePath: pathCommon).Project. + AddDocument("B.cs", "class B {}", filePath: pathB).Project.Solution. AddProject("C", "C", "C#"). - AddDocument("Common.cs", "class Common {}", filePath: "Common.cs").Project. - AddDocument("C.cs", "class C {}", filePath: "C.cs").Project.Solution; + AddDocument("Common.cs", "class Common {}", filePath: pathCommon).Project. + AddDocument("C.cs", "class C {}", filePath: pathC).Project.Solution; var debuggingSession = await StartDebuggingSessionAsync(service, solution); EnterBreakState(debuggingSession); @@ -1759,14 +1793,14 @@ public async Task HasChanges() Assert.True(await EditSession.HasChangesAsync(oldSolution, solution, CancellationToken.None)); - Assert.False(await EditSession.HasChangesAsync(oldSolution, solution, sourceFilePath: "Common.cs", CancellationToken.None)); - Assert.False(await EditSession.HasChangesAsync(oldSolution, solution, sourceFilePath: "B.cs", CancellationToken.None)); - Assert.True(await EditSession.HasChangesAsync(oldSolution, solution, sourceFilePath: "C.cs", CancellationToken.None)); + Assert.False(await EditSession.HasChangesAsync(oldSolution, solution, sourceFilePath: pathCommon, CancellationToken.None)); + Assert.False(await EditSession.HasChangesAsync(oldSolution, solution, sourceFilePath: pathB, CancellationToken.None)); + Assert.True(await EditSession.HasChangesAsync(oldSolution, solution, sourceFilePath: pathC, CancellationToken.None)); Assert.False(await EditSession.HasChangesAsync(oldSolution, solution, sourceFilePath: "NonexistentFile.cs", CancellationToken.None)); // All projects must have no errors. var (updates, _) = await EmitSolutionUpdateAsync(debuggingSession, solution); - Assert.Equal(ManagedModuleUpdateStatus.Blocked, updates.Status); + Assert.Equal(ModuleUpdateStatus.Blocked, updates.Status); // add a project: @@ -1869,7 +1903,7 @@ public async Task HasChanges_Documents(DocumentKind documentKind) Assert.Equal(1, generatorExecutionCount); - // + // // Update document to a different document snapshot but the same content // @@ -2032,7 +2066,7 @@ public async Task Project_Add() // TODO: https://github.com/dotnet/roslyn/issues/1204 // verify valid update - Assert.Equal(ManagedModuleUpdateStatus.None, updates.Status); + Assert.Equal(ModuleUpdateStatus.None, updates.Status); ExitBreakState(debuggingSession); @@ -2177,7 +2211,7 @@ int M() // validate solution update status and emit var (updates, emitDiagnostics) = await EmitSolutionUpdateAsync(debuggingSession, solution); Assert.Empty(emitDiagnostics); - Assert.Equal(ManagedModuleUpdateStatus.Ready, updates.Status); + Assert.Equal(ModuleUpdateStatus.Ready, updates.Status); // check that no types have been updated. this used to throw var delta = updates.Updates.Single(); @@ -2265,7 +2299,7 @@ public async Task ValidSignificantChange_EmitError() // solution update status after discarding an update (still has update ready): (updates, emitDiagnostics) = await EmitSolutionUpdateAsync(debuggingSession, solution); - Assert.Equal(ManagedModuleUpdateStatus.Blocked, updates.Status); + Assert.Equal(ModuleUpdateStatus.Blocked, updates.Status); AssertEx.Equal(new[] { $"{document2.FilePath}: (0,0)-(0,54): Error CS8055: {string.Format(CSharpResources.ERR_EncodinglessSyntaxTree)}" }, InspectDiagnostics(emitDiagnostics)); EndDebuggingSession(debuggingSession); @@ -2334,7 +2368,7 @@ public async Task ValidSignificantChange_ApplyBeforeFileWatcherEvent(bool saveDo var (updates, emitDiagnostics) = await EmitSolutionUpdateAsync(debuggingSession, solution); Assert.Empty(emitDiagnostics); - Assert.Equal(ManagedModuleUpdateStatus.Ready, updates.Status); + Assert.Equal(ModuleUpdateStatus.Ready, updates.Status); CommitSolutionUpdate(debuggingSession); ExitBreakState(debuggingSession); @@ -2350,11 +2384,11 @@ public async Task ValidSignificantChange_ApplyBeforeFileWatcherEvent(bool saveDo if (saveDocument) { - Assert.Equal(ManagedModuleUpdateStatus.None, updates.Status); + Assert.Equal(ModuleUpdateStatus.None, updates.Status); } else { - Assert.Equal(ManagedModuleUpdateStatus.Ready, updates.Status); + Assert.Equal(ModuleUpdateStatus.Ready, updates.Status); debuggingSession.DiscardSolutionUpdate(); } @@ -2409,7 +2443,7 @@ 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(ManagedModuleUpdateStatus.None, updates.Status); + Assert.Equal(ModuleUpdateStatus.None, updates.Status); AssertEx.Equal(new[] { $"{project.Id}: Warning ENC1005: {string.Format(FeaturesResources.DocumentIsOutOfSyncWithDebuggee, sourceFile.Path)}" }, InspectDiagnostics(emitDiagnostics)); // undo: @@ -2428,7 +2462,7 @@ public async Task ValidSignificantChange_FileUpdateNotObservedBeforeDebuggingSes Assert.Empty(emitDiagnostics); // the content actually hasn't changed: - Assert.Equal(ManagedModuleUpdateStatus.None, updates.Status); + Assert.Equal(ModuleUpdateStatus.None, updates.Status); EndDebuggingSession(debuggingSession); } @@ -2492,7 +2526,7 @@ public async Task ValidSignificantChange_AddedFileNotObservedBeforeDebuggingSess // No changes. var (updates, emitDiagnostics) = await EmitSolutionUpdateAsync(debuggingSession, solution); - Assert.Equal(ManagedModuleUpdateStatus.None, updates.Status); + Assert.Equal(ModuleUpdateStatus.None, updates.Status); AssertEx.Empty(emitDiagnostics); @@ -2532,7 +2566,7 @@ public async Task ValidSignificantChange_DocumentOutOfSync(bool delayLoad) // no changes have been made to the project var (updates, emitDiagnostics) = await EmitSolutionUpdateAsync(debuggingSession, solution); - Assert.Equal(ManagedModuleUpdateStatus.None, updates.Status); + Assert.Equal(ModuleUpdateStatus.None, updates.Status); Assert.Empty(updates.Updates); Assert.Empty(emitDiagnostics); @@ -2545,7 +2579,7 @@ public async Task ValidSignificantChange_DocumentOutOfSync(bool delayLoad) // the content of the file is now exactly the same as the compiled document, so there is no change to be applied: (updates, emitDiagnostics) = await EmitSolutionUpdateAsync(debuggingSession, solution); - Assert.Equal(ManagedModuleUpdateStatus.None, updates.Status); + Assert.Equal(ModuleUpdateStatus.None, updates.Status); Assert.Empty(emitDiagnostics); EndDebuggingSession(debuggingSession); @@ -2582,10 +2616,10 @@ public async Task ValidSignificantChange_EmitSuccessful(bool breakMode, bool com // validate solution update status and emit: var (updates, emitDiagnostics) = await EmitSolutionUpdateAsync(debuggingSession, solution); Assert.Empty(emitDiagnostics); - Assert.Equal(ManagedModuleUpdateStatus.Ready, updates.Status); + Assert.Equal(ModuleUpdateStatus.Ready, updates.Status); ValidateDelta(updates.Updates.Single()); - void ValidateDelta(ManagedModuleUpdate delta) + void ValidateDelta(ModuleUpdate delta) { // check emitted delta: Assert.Empty(delta.ActiveStatements); @@ -2632,7 +2666,7 @@ void ValidateDelta(ManagedModuleUpdate delta) // solution update status after committing an update: (updates, emitDiagnostics) = await EmitSolutionUpdateAsync(debuggingSession, solution); Assert.Empty(emitDiagnostics); - Assert.Equal(ManagedModuleUpdateStatus.None, updates.Status); + Assert.Equal(ModuleUpdateStatus.None, updates.Status); } else { @@ -2644,7 +2678,7 @@ void ValidateDelta(ManagedModuleUpdate delta) // solution update status after committing an update: (updates, emitDiagnostics) = await EmitSolutionUpdateAsync(debuggingSession, solution); Assert.Empty(emitDiagnostics); - Assert.Equal(ManagedModuleUpdateStatus.Ready, updates.Status); + Assert.Equal(ModuleUpdateStatus.Ready, updates.Status); ValidateDelta(updates.Updates.Single()); debuggingSession.DiscardSolutionUpdate(); @@ -2719,7 +2753,7 @@ public async Task ValidSignificantChange_EmitSuccessful_UpdateDeferred(bool comm // validate solution update status and emit: var (updates, emitDiagnostics) = await EmitSolutionUpdateAsync(debuggingSession, solution); - Assert.Equal(ManagedModuleUpdateStatus.Ready, updates.Status); + Assert.Equal(ModuleUpdateStatus.Ready, updates.Status); Assert.Empty(emitDiagnostics); // delta to apply: @@ -2770,7 +2804,7 @@ public async Task ValidSignificantChange_EmitSuccessful_UpdateDeferred(bool comm solution = solution.WithDocumentText(document3.Id, SourceText.From("class C1 { void M1() { int a = 3; System.Console.WriteLine(a); } void M2() { System.Console.WriteLine(2); } }", Encoding.UTF8)); (updates, emitDiagnostics) = await EmitSolutionUpdateAsync(debuggingSession, solution); - Assert.Equal(ManagedModuleUpdateStatus.Ready, updates.Status); + Assert.Equal(ModuleUpdateStatus.Ready, updates.Status); Assert.Empty(emitDiagnostics); debuggingSession.DiscardSolutionUpdate(); } @@ -2835,7 +2869,7 @@ partial class C { int Y = 2; } // validate solution update status and emit: var (updates, emitDiagnostics) = await EmitSolutionUpdateAsync(debuggingSession, solution); Assert.Empty(emitDiagnostics); - Assert.Equal(ManagedModuleUpdateStatus.Ready, updates.Status); + Assert.Equal(ModuleUpdateStatus.Ready, updates.Status); // check emitted delta: var delta = updates.Updates.Single(); @@ -2882,7 +2916,7 @@ class C { int Y => 2; } // validate solution update status and emit: var (updates, emitDiagnostics) = await EmitSolutionUpdateAsync(debuggingSession, solution); Assert.Empty(emitDiagnostics); - Assert.Equal(ManagedModuleUpdateStatus.Ready, updates.Status); + Assert.Equal(ModuleUpdateStatus.Ready, updates.Status); // check emitted delta: var delta = updates.Updates.Single(); @@ -2942,7 +2976,7 @@ int M() // validate solution update status and emit: var (updates, emitDiagnostics) = await EmitSolutionUpdateAsync(debuggingSession, solution); Assert.Empty(emitDiagnostics); - Assert.Equal(ManagedModuleUpdateStatus.Ready, updates.Status); + Assert.Equal(ModuleUpdateStatus.Ready, updates.Status); // check emitted delta: var delta = updates.Updates.Single(); @@ -2990,7 +3024,7 @@ partial class C { int X = 1; } // validate solution update status and emit: var (updates, emitDiagnostics) = await EmitSolutionUpdateAsync(debuggingSession, solution); Assert.Empty(emitDiagnostics); - Assert.Equal(ManagedModuleUpdateStatus.Ready, updates.Status); + Assert.Equal(ModuleUpdateStatus.Ready, updates.Status); // check emitted delta: var delta = updates.Updates.Single(); @@ -3038,7 +3072,7 @@ class C { int Y => 1; } // validate solution update status and emit: var (updates, emitDiagnostics) = await EmitSolutionUpdateAsync(debuggingSession, solution); Assert.Empty(emitDiagnostics); - Assert.Equal(ManagedModuleUpdateStatus.Ready, updates.Status); + Assert.Equal(ModuleUpdateStatus.Ready, updates.Status); // check emitted delta: var delta = updates.Updates.Single(); @@ -3082,7 +3116,7 @@ class C { int Y => 1; } // validate solution update status and emit: var (updates, emitDiagnostics) = await EmitSolutionUpdateAsync(debuggingSession, solution); Assert.Empty(emitDiagnostics); - Assert.Equal(ManagedModuleUpdateStatus.Ready, updates.Status); + Assert.Equal(ModuleUpdateStatus.Ready, updates.Status); // check emitted delta: var delta = updates.Updates.Single(); @@ -3123,7 +3157,7 @@ public async Task ValidSignificantChange_SourceGenerators_DocumentRemove() // validate solution update status and emit: var (updates, emitDiagnostics) = await EmitSolutionUpdateAsync(debuggingSession, solution); Assert.Empty(emitDiagnostics); - Assert.Equal(ManagedModuleUpdateStatus.Ready, updates.Status); + Assert.Equal(ModuleUpdateStatus.Ready, updates.Status); // check emitted delta: var delta = updates.Updates.Single(); @@ -3207,7 +3241,10 @@ public async Task TwoUpdatesWithLoadedAndUnloadedModule() (solution, var documentA) = AddDefaultTestProject(solution, source1); var projectA = documentA.Project; - var projectB = solution.AddProject("B", "A", "C#").AddMetadataReferences(projectA.MetadataReferences).AddDocument("DocB", source1, filePath: "DocB.cs").Project; + var projectB = solution.AddProject("B", "A", "C#"). + AddMetadataReferences(projectA.MetadataReferences). + AddDocument("DocB", source1, filePath: Path.Combine(TempRoot.Root, "DocB.cs")).Project; + solution = projectB.Solution; _mockCompilationOutputsProvider = project => @@ -3231,7 +3268,7 @@ public async Task TwoUpdatesWithLoadedAndUnloadedModule() // validate solution update status and emit: var (updates, emitDiagnostics) = await EmitSolutionUpdateAsync(debuggingSession, solution); - Assert.Equal(ManagedModuleUpdateStatus.Ready, updates.Status); + Assert.Equal(ModuleUpdateStatus.Ready, updates.Status); Assert.Empty(emitDiagnostics); var deltaA = updates.Updates.Single(d => d.Module == moduleIdA); @@ -3265,7 +3302,7 @@ public async Task TwoUpdatesWithLoadedAndUnloadedModule() // solution update status after committing an update:(updates, emitDiagnostics) = await EmitSolutionUpdateAsync(debuggingSession, solution); Assert.Empty(emitDiagnostics); - Assert.Equal(ManagedModuleUpdateStatus.Ready, updates.Status); + Assert.Equal(ModuleUpdateStatus.Ready, updates.Status); ExitBreakState(debuggingSession); EnterBreakState(debuggingSession); @@ -3279,7 +3316,7 @@ public async Task TwoUpdatesWithLoadedAndUnloadedModule() // validate solution update status and emit: (updates, emitDiagnostics) = await EmitSolutionUpdateAsync(debuggingSession, solution); - Assert.Equal(ManagedModuleUpdateStatus.Ready, updates.Status); + Assert.Equal(ModuleUpdateStatus.Ready, updates.Status); Assert.Empty(emitDiagnostics); deltaA = updates.Updates.Single(d => d.Module == moduleIdA); @@ -3319,7 +3356,7 @@ public async Task TwoUpdatesWithLoadedAndUnloadedModule() // solution update status after committing an update: (updates, emitDiagnostics) = await EmitSolutionUpdateAsync(debuggingSession, solution); Assert.Empty(emitDiagnostics); - Assert.Equal(ManagedModuleUpdateStatus.None, updates.Status); + Assert.Equal(ModuleUpdateStatus.None, updates.Status); ExitBreakState(debuggingSession); EndDebuggingSession(debuggingSession); @@ -3350,7 +3387,7 @@ public async Task ValidSignificantChange_BaselineCreationFailed_NoStream() var (updates, emitDiagnostics) = await EmitSolutionUpdateAsync(debuggingSession, solution); AssertEx.Equal(new[] { $"{document1.Project.Id}: Error ENC1001: {string.Format(FeaturesResources.ErrorReadingFile, "test-pdb", new FileNotFoundException().Message)}" }, InspectDiagnostics(emitDiagnostics)); - Assert.Equal(ManagedModuleUpdateStatus.RestartRequired, updates.Status); + Assert.Equal(ModuleUpdateStatus.RestartRequired, updates.Status); } [Fact] @@ -3383,7 +3420,7 @@ public async Task ValidSignificantChange_BaselineCreationFailed_AssemblyReadErro var (updates, emitDiagnostics) = await EmitSolutionUpdateAsync(debuggingSession, solution); AssertEx.Equal(new[] { $"{document.Project.Id}: Error ENC1001: {string.Format(FeaturesResources.ErrorReadingFile, "test-assembly", "*message*")}" }, InspectDiagnostics(emitDiagnostics)); - Assert.Equal(ManagedModuleUpdateStatus.RestartRequired, updates.Status); + Assert.Equal(ModuleUpdateStatus.RestartRequired, updates.Status); EndDebuggingSession(debuggingSession); @@ -3569,12 +3606,12 @@ public async Task ActiveStatements_SyntaxErrorOrOutOfSyncDocument(bool isOutOfSy [CombinatorialData] public async Task ActiveStatements_ForeignDocument(bool withPath, bool designTimeOnly) { - var composition = FeaturesTestCompositions.Features.AddParts(typeof(DummyLanguageService)); + var composition = FeaturesTestCompositions.Features.AddParts(typeof(NoCompilationLanguageService)); - using var _ = CreateWorkspace(out var solution, out var service, new[] { typeof(DummyLanguageService) }); + using var _ = CreateWorkspace(out var solution, out var service, new[] { typeof(NoCompilationLanguageService) }); - var project = solution.AddProject("dummy_proj", "dummy_proj", designTimeOnly ? LanguageNames.CSharp : DummyLanguageService.LanguageName); - var filePath = withPath ? Path.Combine(TempRoot.Root, "test") : null; + var project = solution.AddProject("dummy_proj", "dummy_proj", designTimeOnly ? LanguageNames.CSharp : NoCompilationConstants.LanguageName); + var filePath = withPath ? Path.Combine(TempRoot.Root, "test.cs") : null; var documentInfo = DocumentInfo.Create( DocumentId.CreateNewId(project.Id, "test"), @@ -3872,7 +3909,7 @@ void F() // validate solution update status and emit: var (updates, emitDiagnostics) = await EmitSolutionUpdateAsync(debuggingSession, solution); Assert.Empty(emitDiagnostics); - Assert.Equal(ManagedModuleUpdateStatus.Ready, updates.Status); + Assert.Equal(ModuleUpdateStatus.Ready, updates.Status); // check emitted delta: var delta = updates.Updates.Single(); @@ -3959,7 +3996,7 @@ int F() var (updates, emitDiagnostics) = await EmitSolutionUpdateAsync(debuggingSession, solution); Assert.Empty(emitDiagnostics); - Assert.Equal(ManagedModuleUpdateStatus.RestartRequired, updates.Status); + Assert.Equal(ModuleUpdateStatus.RestartRequired, updates.Status); // undo the change solution = solution.WithDocumentText(document.Id, SourceText.From(source1, Encoding.UTF8)); @@ -3976,7 +4013,7 @@ int F() // validate solution update status and emit (Hot Reload change): (updates, emitDiagnostics) = await EmitSolutionUpdateAsync(debuggingSession, solution); Assert.Empty(emitDiagnostics); - Assert.Equal(ManagedModuleUpdateStatus.Ready, updates.Status); + Assert.Equal(ModuleUpdateStatus.Ready, updates.Status); debuggingSession.DiscardSolutionUpdate(); EndDebuggingSession(debuggingSession); @@ -3990,7 +4027,7 @@ int F() /// Function remapping is produced for F v1 -> F v2. /// 2) Hot-reload edit F (without breaking) to version 3. /// Function remapping is not produced for F v2 -> F v3. If G ever returned to F it will be remapped from F v1 -> F v2, - /// where F v2 is considered stale code. This is consistent with the semantic of Hot Reload: Hot Reloaded changes do not have + /// where F v2 is considered stale code. This is consistent with the semantic of Hot Reload: Hot Reloaded changes do not have /// an effect until the method is called again. In this case the method is not called, it it returned into hence the stale /// version executes. /// 3) Break and apply EnC edit. This edit is to F v3 (Hot Reload) of the method. We will produce remapping F v3 -> v4. @@ -4042,7 +4079,7 @@ static void F() Assert.Empty(emitDiagnostics); Assert.Equal(0x06000003, updates.Updates.Single().UpdatedMethods.Single()); Assert.Equal(0x02000002, updates.Updates.Single().UpdatedTypes.Single()); - Assert.Equal(ManagedModuleUpdateStatus.Ready, updates.Status); + Assert.Equal(ModuleUpdateStatus.Ready, updates.Status); CommitSolutionUpdate(debuggingSession); @@ -4062,7 +4099,7 @@ static void F() Assert.Empty(emitDiagnostics); Assert.Equal(0x06000003, updates.Updates.Single().UpdatedMethods.Single()); Assert.Equal(0x02000002, updates.Updates.Single().UpdatedTypes.Single()); - Assert.Equal(ManagedModuleUpdateStatus.Ready, updates.Status); + Assert.Equal(ModuleUpdateStatus.Ready, updates.Status); CommitSolutionUpdate(debuggingSession); @@ -4098,7 +4135,7 @@ static void F() Assert.Empty(emitDiagnostics); Assert.Equal(0x06000003, updates.Updates.Single().UpdatedMethods.Single()); Assert.Equal(0x02000002, updates.Updates.Single().UpdatedTypes.Single()); - Assert.Equal(ManagedModuleUpdateStatus.Ready, updates.Status); + Assert.Equal(ModuleUpdateStatus.Ready, updates.Status); CommitSolutionUpdate(debuggingSession); @@ -4224,7 +4261,7 @@ static void F() Assert.Empty(emitDiagnostics); Assert.Equal(0x06000003, updates.Updates.Single().UpdatedMethods.Single()); Assert.Equal(0x02000002, updates.Updates.Single().UpdatedTypes.Single()); - Assert.Equal(ManagedModuleUpdateStatus.Ready, updates.Status); + Assert.Equal(ModuleUpdateStatus.Ready, updates.Status); CommitSolutionUpdate(debuggingSession); @@ -4284,7 +4321,7 @@ static void F() Assert.Empty(emitDiagnostics); Assert.Equal(0x06000003, updates.Updates.Single().UpdatedMethods.Single()); Assert.Equal(0x02000002, updates.Updates.Single().UpdatedTypes.Single()); - Assert.Equal(ManagedModuleUpdateStatus.Ready, updates.Status); + Assert.Equal(ModuleUpdateStatus.Ready, updates.Status); CommitSolutionUpdate(debuggingSession); @@ -4412,7 +4449,7 @@ public async Task WatchHotReloadServiceTest() 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 X() { System.Console.WriteLine(2); } }"; + var source3 = "class C { int M() { System.Console.WriteLine(2); } }"; var source4 = "class C { void M() { System.Console.WriteLine(2)/* missing semicolon */ }"; var dir = Temp.CreateDirectory(); @@ -4459,7 +4496,7 @@ public async Task WatchHotReloadServiceTest() result = await hotReload.EmitSolutionUpdateAsync(solution, CancellationToken.None); AssertEx.Equal( - new[] { "ENC0020: " + string.Format(FeaturesResources.Renaming_0_requires_restarting_the_application, FeaturesResources.method) }, + new[] { "ENC0009: " + string.Format(FeaturesResources.Updating_the_type_of_0_requires_restarting_the_application, FeaturesResources.method) }, result.diagnostics.Select(d => $"{d.Id}: {d.GetMessage()}")); Assert.Empty(result.updates); @@ -4479,7 +4516,7 @@ public async Task UnitTestingHotReloadServiceTest() { 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 X() { System.Console.WriteLine(2); } }"; + var source3 = "class C { int M() { System.Console.WriteLine(2); } }"; var source4 = "class C { void M() { System.Console.WriteLine(2)/* missing semicolon */ }"; var dir = Temp.CreateDirectory(); @@ -4525,7 +4562,7 @@ public async Task UnitTestingHotReloadServiceTest() // Rude edit result = await hotReload.EmitSolutionUpdateAsync(solution, commitUpdates: true, CancellationToken.None); AssertEx.Equal( - new[] { "ENC0020: " + string.Format(FeaturesResources.Renaming_0_requires_restarting_the_application, FeaturesResources.method) }, + new[] { "ENC0009: " + string.Format(FeaturesResources.Updating_the_type_of_0_requires_restarting_the_application, FeaturesResources.method) }, result.diagnostics.Select(d => $"{d.Id}: {d.GetMessage()}")); Assert.Empty(result.updates); diff --git a/src/EditorFeatures/Test/EditAndContinue/EditSessionActiveStatementsTests.cs b/src/EditorFeatures/Test/EditAndContinue/EditSessionActiveStatementsTests.cs index 036423ea9fae1..7be7c2b568a7c 100644 --- a/src/EditorFeatures/Test/EditAndContinue/EditSessionActiveStatementsTests.cs +++ b/src/EditorFeatures/Test/EditAndContinue/EditSessionActiveStatementsTests.cs @@ -17,6 +17,7 @@ using Microsoft.CodeAnalysis.Emit; using Microsoft.CodeAnalysis.Test.Utilities; using Microsoft.CodeAnalysis.Text; +using Microsoft.CodeAnalysis.UnitTests; using Moq; using Roslyn.Test.Utilities; using Roslyn.Utilities; @@ -31,7 +32,7 @@ namespace Microsoft.CodeAnalysis.EditAndContinue.UnitTests [UseExportProvider] public class EditSessionActiveStatementsTests : TestBase { - private static readonly TestComposition s_composition = EditorTestCompositions.EditorFeatures.AddParts(typeof(DummyLanguageService)); + private static readonly TestComposition s_composition = EditorTestCompositions.EditorFeatures.AddParts(typeof(NoCompilationLanguageService)); private static EditSession CreateEditSession( Solution solution, @@ -174,8 +175,8 @@ static void Main() var solution = AddDefaultTestSolution(workspace, markedSources); var projectId = solution.ProjectIds.Single(); - var dummyProject = solution.AddProject("dummy_proj", "dummy_proj", DummyLanguageService.LanguageName); - solution = dummyProject.Solution.AddDocument(DocumentId.CreateNewId(dummyProject.Id, DummyLanguageService.LanguageName), "a.dummy", ""); + var dummyProject = solution.AddProject("dummy_proj", "dummy_proj", NoCompilationConstants.LanguageName); + solution = dummyProject.Solution.AddDocument(DocumentId.CreateNewId(dummyProject.Id, NoCompilationConstants.LanguageName), "a.dummy", ""); var project = solution.GetProject(projectId); var document1 = project.Documents.Single(d => d.Name == "test1.cs"); var document2 = project.Documents.Single(d => d.Name == "test2.cs"); @@ -226,7 +227,7 @@ static void Main() // Exception Regions - var analyzer = solution.GetProject(projectId).LanguageServices.GetRequiredService(); + var analyzer = solution.GetProject(projectId).Services.GetRequiredService(); var oldActiveStatements1 = await baseActiveStatementsMap.GetOldActiveStatementsAsync(analyzer, document1, CancellationToken.None).ConfigureAwait(false); AssertEx.Equal(new[] @@ -353,7 +354,7 @@ static void F2() // Exception Regions - var analyzer = solution.GetProject(project.Id).LanguageServices.GetRequiredService(); + var analyzer = solution.GetProject(project.Id).Services.GetRequiredService(); var oldActiveStatements = await baseActiveStatementMap.GetOldActiveStatementsAsync(analyzer, document, CancellationToken.None).ConfigureAwait(false); // Note that the spans correspond to the base snapshot (V2). @@ -538,7 +539,7 @@ static void F4() // Exception Regions - var analyzer = solution.GetProject(project.Id).LanguageServices.GetRequiredService(); + var analyzer = solution.GetProject(project.Id).Services.GetRequiredService(); var oldActiveStatements = await baseActiveStatementMap.GetOldActiveStatementsAsync(analyzer, document, CancellationToken.None).ConfigureAwait(false); // Note that the spans correspond to the base snapshot (V2). @@ -684,7 +685,7 @@ static void F() // Exception Regions - var analyzer = solution.GetProject(project.Id).LanguageServices.GetRequiredService(); + var analyzer = solution.GetProject(project.Id).Services.GetRequiredService(); var oldActiveStatements = await baseActiveStatementMap.GetOldActiveStatementsAsync(analyzer, document, CancellationToken.None).ConfigureAwait(false); AssertEx.Equal(new[] diff --git a/src/EditorFeatures/Test/EditAndContinue/EmitSolutionUpdateResultsTests.cs b/src/EditorFeatures/Test/EditAndContinue/EmitSolutionUpdateResultsTests.cs index 7cead9c1238fd..5d9f2991d3aa8 100644 --- a/src/EditorFeatures/Test/EditAndContinue/EmitSolutionUpdateResultsTests.cs +++ b/src/EditorFeatures/Test/EditAndContinue/EmitSolutionUpdateResultsTests.cs @@ -93,7 +93,8 @@ public async Task GetHotReloadDiagnostics() (document.Id, ImmutableArray.Create(new RudeEditDiagnostic(RudeEditKind.Insert, TextSpan.FromBounds(1, 10), 123, new[] { "a" }))), (document.Id, ImmutableArray.Create(new RudeEditDiagnostic(RudeEditKind.Delete, TextSpan.FromBounds(1, 10), 123, new[] { "b" })))); - var actual = await EmitSolutionUpdateResults.GetHotReloadDiagnosticsAsync(solution, diagnosticData, rudeEdits, syntaxError, CancellationToken.None); + var updateStatus = ModuleUpdateStatus.Blocked; + var actual = await EmitSolutionUpdateResults.GetHotReloadDiagnosticsAsync(solution, diagnosticData, rudeEdits, syntaxError, updateStatus, CancellationToken.None); AssertEx.Equal(new[] { diff --git a/src/EditorFeatures/Test/EditAndContinue/Helpers/DummyLanguageService.cs b/src/EditorFeatures/Test/EditAndContinue/Helpers/DummyLanguageService.cs deleted file mode 100644 index 194d17f6b2620..0000000000000 --- a/src/EditorFeatures/Test/EditAndContinue/Helpers/DummyLanguageService.cs +++ /dev/null @@ -1,30 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -#nullable disable - -using System; -using System.Composition; -using Microsoft.CodeAnalysis.Host; -using Microsoft.CodeAnalysis.Host.Mef; - -namespace Microsoft.CodeAnalysis.EditAndContinue.UnitTests -{ - internal interface IDummyLanguageService : ILanguageService { } - - [ExportLanguageService(typeof(IDummyLanguageService), LanguageName, ServiceLayer.Test), Shared, PartNotDiscoverable] - internal class DummyLanguageService : IDummyLanguageService - { - public const string LanguageName = "Dummy"; - - [ImportingConstructor] - [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] - public DummyLanguageService() - { - } - - // do nothing - - } -} diff --git a/src/EditorFeatures/Test/EditAndContinue/RemoteEditAndContinueServiceTests.cs b/src/EditorFeatures/Test/EditAndContinue/RemoteEditAndContinueServiceTests.cs index 563045679f3f3..16afc6ed3ca84 100644 --- a/src/EditorFeatures/Test/EditAndContinue/RemoteEditAndContinueServiceTests.cs +++ b/src/EditorFeatures/Test/EditAndContinue/RemoteEditAndContinueServiceTests.cs @@ -187,17 +187,17 @@ void VerifyReanalyzeInvocation(ImmutableArray documentIds) Assert.Equal("proj", project.Name); AssertEx.Equal(activeSpans1, activeStatementSpanProvider(document1.Id, "test.cs", CancellationToken.None).AsTask().Result); - var deltas = ImmutableArray.Create(new ManagedModuleUpdate( - module: moduleId1, - ilDelta: ImmutableArray.Create(1, 2), - metadataDelta: ImmutableArray.Create(3, 4), - pdbDelta: ImmutableArray.Create(5, 6), - updatedMethods: ImmutableArray.Create(0x06000001), - updatedTypes: ImmutableArray.Create(0x02000001), - sequencePoints: ImmutableArray.Create(new SequencePointUpdates("file.cs", ImmutableArray.Create(new SourceLineUpdate(1, 2)))), - activeStatements: ImmutableArray.Create(new ManagedActiveStatementUpdate(instructionId1.Method.Method, instructionId1.ILOffset, span1.ToSourceSpan())), - exceptionRegions: ImmutableArray.Create(exceptionRegionUpdate1), - requiredCapabilities: EditAndContinueCapabilities.Baseline)); + var deltas = ImmutableArray.Create(new ModuleUpdate( + Module: moduleId1, + ILDelta: ImmutableArray.Create(1, 2), + MetadataDelta: ImmutableArray.Create(3, 4), + PdbDelta: ImmutableArray.Create(5, 6), + UpdatedMethods: ImmutableArray.Create(0x06000001), + UpdatedTypes: ImmutableArray.Create(0x02000001), + SequencePoints: ImmutableArray.Create(new SequencePointUpdates("file.cs", ImmutableArray.Create(new SourceLineUpdate(1, 2)))), + ActiveStatements: ImmutableArray.Create(new ManagedActiveStatementUpdate(instructionId1.Method.Method, instructionId1.ILOffset, span1.ToSourceSpan())), + ExceptionRegions: ImmutableArray.Create(exceptionRegionUpdate1), + RequiredCapabilities: EditAndContinueCapabilities.Baseline)); var syntaxTree = project.Documents.Single().GetSyntaxTreeSynchronously(CancellationToken.None)!; @@ -205,7 +205,7 @@ void VerifyReanalyzeInvocation(ImmutableArray documentIds) var projectDiagnostic = Diagnostic.Create(diagnosticDescriptor1, Location.None, new[] { "proj", "some error" }); var syntaxError = Diagnostic.Create(diagnosticDescriptor1, Location.Create(syntaxTree, TextSpan.FromBounds(1, 2)), new[] { "doc", "syntax error" }); - var updates = new ManagedModuleUpdates(ManagedModuleUpdateStatus.Ready, deltas); + var updates = new ModuleUpdates(ModuleUpdateStatus.Ready, deltas); var diagnostics = ImmutableArray.Create((project.Id, ImmutableArray.Create(documentDiagnostic, projectDiagnostic))); var documentsWithRudeEdits = ImmutableArray.Create((document1.Id, ImmutableArray.Empty)); @@ -217,7 +217,7 @@ void VerifyReanalyzeInvocation(ImmutableArray documentIds) VerifyReanalyzeInvocation(ImmutableArray.Create(document1.Id)); - Assert.Equal(ManagedModuleUpdateStatus.Ready, updates.Status); + Assert.Equal(ModuleUpdateStatus.Ready, updates.Status); Assert.Equal(1, emitDiagnosticsClearedCount); emitDiagnosticsClearedCount = 0; diff --git a/src/EditorFeatures/Test/EditAndContinue/TestSourceGenerator.cs b/src/EditorFeatures/Test/EditAndContinue/TestSourceGenerator.cs deleted file mode 100644 index 38eb2a0c921d4..0000000000000 --- a/src/EditorFeatures/Test/EditAndContinue/TestSourceGenerator.cs +++ /dev/null @@ -1,29 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using System; -using System.Collections.Immutable; -using Microsoft.CodeAnalysis.Diagnostics; - -namespace Microsoft.CodeAnalysis.EditAndContinue.UnitTests -{ - internal class TestSourceGenerator : DiagnosticAnalyzer, ISourceGenerator - { - public Action? ExecuteImpl; - - public override ImmutableArray SupportedDiagnostics - => throw new NotImplementedException(); - - public void Execute(GeneratorExecutionContext context) - => (ExecuteImpl ?? throw new NotImplementedException()).Invoke(context); - - public void Initialize(GeneratorInitializationContext context) - { - } - - public override void Initialize(AnalysisContext context) - { - } - } -} diff --git a/src/EditorFeatures/Test/EditAndContinue/TraceLogTests.cs b/src/EditorFeatures/Test/EditAndContinue/TraceLogTests.cs index 286996857456c..cfca7cd52e89c 100644 --- a/src/EditorFeatures/Test/EditAndContinue/TraceLogTests.cs +++ b/src/EditorFeatures/Test/EditAndContinue/TraceLogTests.cs @@ -2,8 +2,6 @@ // The .NET Foundation 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 Roslyn.Test.Utilities; @@ -16,22 +14,22 @@ public class TraceLogTests [Fact] public void Write() { - var log = new TraceLog(5, "log"); + var log = new TraceLog(5, "log", logDirectory: null); var projectId = ProjectId.CreateFromSerialized(Guid.Parse("5E40F37C-5AB3-495E-A3F2-4A244D177674"), debugName: "MyProject"); var diagnostic = Diagnostic.Create(EditAndContinueDiagnosticDescriptors.GetDescriptor(EditAndContinueErrorCode.ErrorReadingFile), Location.None, "file", "error"); log.Write("a"); - log.Write("b {0} {1} {2}", 1, "x", 3); + log.Write("b {0} {1} 0x{2:X8}", 1, "x", 255); log.Write("c"); - log.Write("d str={0} projectId={1} summary={2} diagnostic=`{3}`", (string)null, projectId, ProjectAnalysisSummary.RudeEdits, diagnostic); + log.Write("d str={0} projectId={1} summary={2} diagnostic=`{3}`", (string?)null, projectId, ProjectAnalysisSummary.RudeEdits, diagnostic); log.Write("e"); log.Write("f"); AssertEx.Equal(new[] { "f", - "b 1 x 3", + "b 1 x 0x000000FF", "c", $"d str= projectId=MyProject summary=RudeEdits diagnostic=`{diagnostic}`", "e" diff --git a/src/EditorFeatures/Test/MetadataAsSource/AbstractMetadataAsSourceTests.TestContext.cs b/src/EditorFeatures/Test/MetadataAsSource/AbstractMetadataAsSourceTests.TestContext.cs index 2b9987550081d..edeac000cb352 100644 --- a/src/EditorFeatures/Test/MetadataAsSource/AbstractMetadataAsSourceTests.TestContext.cs +++ b/src/EditorFeatures/Test/MetadataAsSource/AbstractMetadataAsSourceTests.TestContext.cs @@ -77,7 +77,7 @@ public Task GenerateSourceAsync(ISymbol symbol, Project? p Contract.ThrowIfNull(symbol); // Generate and hold onto the result so it can be disposed of with this context - return _metadataAsSourceService.GetGeneratedFileAsync(project, symbol, signaturesOnly, MetadataAsSourceOptions.GetDefault(project.LanguageServices)); + return _metadataAsSourceService.GetGeneratedFileAsync(project, symbol, signaturesOnly, MetadataAsSourceOptions.GetDefault(project.Services)); } public async Task GenerateSourceAsync( @@ -118,7 +118,7 @@ public async Task GenerateSourceAsync( } } - var options = MetadataAsSourceOptions.GetDefault(project.LanguageServices); + var options = MetadataAsSourceOptions.GetDefault(project.Services); if (fileScopedNamespaces) { diff --git a/src/EditorFeatures/Test/MetadataAsSource/MetadataAsSourceTests.CSharp.cs b/src/EditorFeatures/Test/MetadataAsSource/MetadataAsSourceTests.CSharp.cs index 1ee1da581f388..a340489bb147b 100644 --- a/src/EditorFeatures/Test/MetadataAsSource/MetadataAsSourceTests.CSharp.cs +++ b/src/EditorFeatures/Test/MetadataAsSource/MetadataAsSourceTests.CSharp.cs @@ -758,7 +758,11 @@ public class C public async Task TestRequiredProperty(bool signaturesOnly) { var metadataSource = """ - public class C { public required int Property { get; set; } } + public class C + { + public required int Property { get; set; } + public required int Field; + } namespace System.Runtime.CompilerServices { public sealed class RequiredMemberAttribute : Attribute { } @@ -783,14 +787,12 @@ public CompilerFeatureRequiredAttribute(string featureName) // {CodeAnalysisResources.InMemoryAssembly} #endregion -using System.Runtime.CompilerServices; - -[RequiredMember] public class [|C|] {{ + public required int Field; + public C(); - [RequiredMember] public required int Property {{ get; set; }} }}", false => $@"#region {FeaturesResources.Assembly} ReferencedAssembly, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null @@ -804,6 +806,9 @@ public class [|C|] [RequiredMember] public class [|C|] {{ + [RequiredMember] + public int Field; + [RequiredMember] public int Property {{ get; set; }} diff --git a/src/EditorFeatures/Test/Options/GlobalOptionsTests.cs b/src/EditorFeatures/Test/Options/GlobalOptionsTests.cs index 0b88199e75047..1260e97336794 100644 --- a/src/EditorFeatures/Test/Options/GlobalOptionsTests.cs +++ b/src/EditorFeatures/Test/Options/GlobalOptionsTests.cs @@ -11,6 +11,7 @@ using System.Reflection; using System.Runtime.Serialization; using Microsoft.CodeAnalysis.AddImport; +using Microsoft.CodeAnalysis.BraceMatching; using Microsoft.CodeAnalysis.Classification; using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeStyle; @@ -233,7 +234,7 @@ private static bool IsStoredInGlobalOptions(PropertyInfo property, string langua public void ReadingOptionsFromGlobalOptions(string language) { using var workspace = CreateWorkspace(out var globalOptions); - var languageServices = workspace.Services.GetLanguageServices(language); + var languageServices = workspace.Services.SolutionServices.GetLanguageServices(language); VerifyDataMembersHaveNonDefaultValues(globalOptions.GetIdeAnalyzerOptions(languageServices), IdeAnalyzerOptions.GetDefault(languageServices), language); VerifyDataMembersHaveNonDefaultValues(globalOptions.GetCodeActionOptions(languageServices), CodeActionOptions.GetDefault(languageServices), language); diff --git a/src/EditorFeatures/Test/Preview/PreviewWorkspaceTests.cs b/src/EditorFeatures/Test/Preview/PreviewWorkspaceTests.cs index e71e83510c11f..602a9a61f5f28 100644 --- a/src/EditorFeatures/Test/Preview/PreviewWorkspaceTests.cs +++ b/src/EditorFeatures/Test/Preview/PreviewWorkspaceTests.cs @@ -126,7 +126,7 @@ public async Task TestPreviewServices() var service = previewWorkspace.Services.GetService(); Assert.IsType(service); - var persistentService = previewWorkspace.Services.GetPersistentStorageService(); + var persistentService = previewWorkspace.Services.SolutionServices.GetPersistentStorageService(); await using var storage = await persistentService.GetStorageAsync(SolutionKey.ToSolutionKey(previewWorkspace.CurrentSolution), CancellationToken.None); Assert.IsType(storage); @@ -270,7 +270,7 @@ private static void ExecuteAnalyzers(PreviewWorkspace previewWorkspace, Immutabl { var analyzerOptions = new AnalyzerOptions(additionalFiles: ImmutableArray.Empty); var project = previewWorkspace.CurrentSolution.Projects.Single(); - var ideAnalyzerOptions = IdeAnalyzerOptions.GetDefault(project.LanguageServices); + var ideAnalyzerOptions = IdeAnalyzerOptions.GetDefault(project.Services); var workspaceAnalyzerOptions = new WorkspaceAnalyzerOptions(analyzerOptions, project.Solution, ideAnalyzerOptions); var compilationWithAnalyzersOptions = new CompilationWithAnalyzersOptions(workspaceAnalyzerOptions, onAnalyzerException: null, concurrentAnalysis: false, logAnalyzerExecutionTime: false); var compilation = project.GetRequiredCompilationAsync(CancellationToken.None).Result; diff --git a/src/EditorFeatures/Test/RenameTracking/RenameTrackingTestState.cs b/src/EditorFeatures/Test/RenameTracking/RenameTrackingTestState.cs index 85b953bc897c5..b0698e67f4b3e 100644 --- a/src/EditorFeatures/Test/RenameTracking/RenameTrackingTestState.cs +++ b/src/EditorFeatures/Test/RenameTracking/RenameTrackingTestState.cs @@ -201,7 +201,7 @@ public async Task AssertTag(string expectedFromName, string expectedToName, bool var operations = (await codeAction.GetOperationsAsync(CancellationToken.None)).ToArray(); Assert.Equal(1, operations.Length); - await operations[0].TryApplyAsync(this.Workspace, new ProgressTracker(), CancellationToken.None); + await operations[0].TryApplyAsync(this.Workspace, this.Workspace.CurrentSolution, new ProgressTracker(), CancellationToken.None); } } diff --git a/src/EditorFeatures/Test/Snippets/RoslynLSPSnippetConvertTests.cs b/src/EditorFeatures/Test/Snippets/RoslynLSPSnippetConvertTests.cs new file mode 100644 index 0000000000000..6ef8a702134b6 --- /dev/null +++ b/src/EditorFeatures/Test/Snippets/RoslynLSPSnippetConvertTests.cs @@ -0,0 +1,520 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation 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.Text; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces; +using Microsoft.CodeAnalysis.PooledObjects; +using Microsoft.CodeAnalysis.Shared.Extensions; +using Microsoft.CodeAnalysis.Snippets; +using Microsoft.CodeAnalysis.Test.Utilities; +using Microsoft.CodeAnalysis.Text; +using Roslyn.Test.Utilities; +using Xunit; + +namespace Microsoft.CodeAnalysis.Editor.UnitTests.Snippets +{ + [UseExportProvider] + public class RoslynLSPSnippetConvertTests + { + #region Edgecase extend TextChange tests + + [Fact, Trait(Traits.Feature, Traits.Features.RoslynLSPSnippetConverter)] + public Task TestExtendSnippetTextChangeForwardsForCaret() + { + var markup = +@"[|if ({|placeholder:true|}) +{ +}|] $$"; + + var expectedLSPSnippet = +@"if (${1:true}) +{ +} $0"; + + return TestAsync(markup, expectedLSPSnippet); + } + + [Fact, Trait(Traits.Feature, Traits.Features.RoslynLSPSnippetConverter)] + public Task TestExtendSnippetTextChangeBackwardsForCaret() + { + var markup = +@"$$ [|if ({|placeholder:true|}) +{ +}|]"; + + var expectedLSPSnippet = +@"$0 if (${1:true}) +{ +}"; + + return TestAsync(markup, expectedLSPSnippet); + } + + [Fact, Trait(Traits.Feature, Traits.Features.RoslynLSPSnippetConverter)] + public Task TestExtendSnippetTextChangeForwardsForPlaceholder() + { + var markup = +@"[|if (true) +{$$ +}|] {|placeholder:test|}"; + + var expectedLSPSnippet = +@"if (true) +{$0 +} ${1:test}"; + + return TestAsync(markup, expectedLSPSnippet); + } + + [Fact, Trait(Traits.Feature, Traits.Features.RoslynLSPSnippetConverter)] + public Task TestExtendSnippetTextChangeBackwardsForPlaceholder() + { + var markup = +@"{|placeholder:test|} [|if (true) +{$$ +}|]"; + + var expectedLSPSnippet = +@"${1:test} if (true) +{$0 +}"; + + return TestAsync(markup, expectedLSPSnippet); + } + + [Fact, Trait(Traits.Feature, Traits.Features.RoslynLSPSnippetConverter)] + public Task TestExtendSnippetTextChangeForwardsForPlaceholderThenCaret() + { + var markup = +@"[|if (true) +{ +}|] {|placeholder:test|} $$"; + + var expectedLSPSnippet = +@"if (true) +{ +} ${1:test} $0"; + + return TestAsync(markup, expectedLSPSnippet); + } + + [Fact, Trait(Traits.Feature, Traits.Features.RoslynLSPSnippetConverter)] + public Task TestExtendSnippetTextChangeForwardsForCaretThenPlaceholder() + { + var markup = +@"[|if (true) +{ +}|] $$ {|placeholder:test|}"; + + var expectedLSPSnippet = +@"if (true) +{ +} $0 ${1:test}"; + + return TestAsync(markup, expectedLSPSnippet); + } + + [Fact, Trait(Traits.Feature, Traits.Features.RoslynLSPSnippetConverter)] + public Task TestExtendSnippetTextChangeBackwardsForPlaceholderThenCaret() + { + var markup = +@"{|placeholder:test|} $$ [|if (true) +{ +}|]"; + + var expectedLSPSnippet = +@"${1:test} $0 if (true) +{ +}"; + + return TestAsync(markup, expectedLSPSnippet); + } + + [Fact, Trait(Traits.Feature, Traits.Features.RoslynLSPSnippetConverter)] + public Task TestExtendSnippetTextChangeBackwardsForCaretThenPlaceholder() + { + var markup = +@"$$ {|placeholder:test|} [|if (true) +{ +}|]"; + + var expectedLSPSnippet = +@"$0 ${1:test} if (true) +{ +}"; + + return TestAsync(markup, expectedLSPSnippet); + } + + [Fact, Trait(Traits.Feature, Traits.Features.RoslynLSPSnippetConverter)] + public Task TestExtendSnippetTextChangeBackwardsForCaretForwardsForPlaceholder() + { + var markup = +@"$$ [|if (true) +{ +}|] {|placeholder:test|}"; + + var expectedLSPSnippet = +@"$0 if (true) +{ +} ${1:test}"; + + return TestAsync(markup, expectedLSPSnippet); + } + + [Fact, Trait(Traits.Feature, Traits.Features.RoslynLSPSnippetConverter)] + public Task TestExtendSnippetTextChangeBackwardsForPlaceholderForwardsForCaret() + { + var markup = +@"{|placeholder:test|} [|if (true) +{ +}|] $$"; + + var expectedLSPSnippet = +@"${1:test} if (true) +{ +} $0"; + + return TestAsync(markup, expectedLSPSnippet); + } + + [Fact, Trait(Traits.Feature, Traits.Features.RoslynLSPSnippetConverter)] + public Task TestExtendSnippetTextChangeInMethodForwardsForCaret() + { + var markup = +@"public void Method() +{ + [|if ({|placeholder:true|}) + { + }|] $$ +}"; + + var expectedLSPSnippet = +@"if (${1:true}) + { + } $0"; + + return TestAsync(markup, expectedLSPSnippet); + } + + [Fact, Trait(Traits.Feature, Traits.Features.RoslynLSPSnippetConverter)] + public Task TestExtendSnippetTextChangeInMethodBackwardsForCaret() + { + var markup = +@"public void Method() +{ + $$ [|if ({|placeholder:true|}) + { + }|] +}"; + + var expectedLSPSnippet = +@"$0 if (${1:true}) + { + }"; + + return TestAsync(markup, expectedLSPSnippet); + } + + [Fact, Trait(Traits.Feature, Traits.Features.RoslynLSPSnippetConverter)] + public Task TestExtendSnippetTextChangeInMethodForwardsForPlaceholder() + { + var markup = +@"public void Method() +{ + [|if (true) + {$$ + }|] {|placeholder:test|} +}"; + + var expectedLSPSnippet = +@"if (true) + {$0 + } ${1:test}"; + + return TestAsync(markup, expectedLSPSnippet); + } + + [Fact, Trait(Traits.Feature, Traits.Features.RoslynLSPSnippetConverter)] + public Task TestExtendSnippetTextChangeInMethodBackwardsForPlaceholder() + { + var markup = +@"public void Method() +{ + {|placeholder:test|} [|if (true) + {$$ + }|]"; + + var expectedLSPSnippet = +@"${1:test} if (true) + {$0 + }"; + + return TestAsync(markup, expectedLSPSnippet); + } + + [Fact, Trait(Traits.Feature, Traits.Features.RoslynLSPSnippetConverter)] + public Task TestExtendSnippetTextChangeInMethodForwardsForPlaceholderThenCaret() + { + var markup = +@"public void Method() +{ + [|if (true) + { + }|] {|placeholder:test|} $$ +}"; + + var expectedLSPSnippet = +@"if (true) + { + } ${1:test} $0"; + + return TestAsync(markup, expectedLSPSnippet); + } + + [Fact, Trait(Traits.Feature, Traits.Features.RoslynLSPSnippetConverter)] + public Task TestExtendSnippetTextChangeInMethodForwardsForCaretThenPlaceholder() + { + var markup = +@"public void Method() +{ + [|if (true) + { + }|] $$ {|placeholder:test|} +}"; + + var expectedLSPSnippet = +@"if (true) + { + } $0 ${1:test}"; + + return TestAsync(markup, expectedLSPSnippet); + } + + [Fact, Trait(Traits.Feature, Traits.Features.RoslynLSPSnippetConverter)] + public Task TestExtendSnippetTextChangeInMethodBackwardsForPlaceholderThenCaret() + { + var markup = +@"public void Method() +{ + {|placeholder:test|} $$ [|if (true) + { + }|] +}"; + + var expectedLSPSnippet = +@"${1:test} $0 if (true) + { + }"; + + return TestAsync(markup, expectedLSPSnippet); + } + + [Fact, Trait(Traits.Feature, Traits.Features.RoslynLSPSnippetConverter)] + public Task TestExtendSnippetTextChangeInMethodBackwardsForCaretThenPlaceholder() + { + var markup = +@"public void Method() +{ + $$ {|placeholder:test|} [|if (true) + { + }|] +}"; + + var expectedLSPSnippet = +@"$0 ${1:test} if (true) + { + }"; + + return TestAsync(markup, expectedLSPSnippet); + } + + [Fact, Trait(Traits.Feature, Traits.Features.RoslynLSPSnippetConverter)] + public Task TestExtendSnippetTextChangeInMethodBackwardsForCaretForwardsForPlaceholder() + { + var markup = +@"public void Method() +{ + $$ [|if (true) + { + }|] {|placeholder:test|} +}"; + + var expectedLSPSnippet = +@"$0 if (true) + { + } ${1:test}"; + + return TestAsync(markup, expectedLSPSnippet); + } + + [Fact, Trait(Traits.Feature, Traits.Features.RoslynLSPSnippetConverter)] + public Task TestExtendSnippetTextChangeInMethodBackwardsForPlaceholderForwardsForCaret() + { + var markup = +@"public void Method() +{ + {|placeholder:test|} [|if (true) + { + }|] $$ +}"; + + var expectedLSPSnippet = +@"${1:test} if (true) + { + } $0"; + + return TestAsync(markup, expectedLSPSnippet); + } + + [Fact, Trait(Traits.Feature, Traits.Features.RoslynLSPSnippetConverter)] + public Task TestExtendSnippetTextChangeInMethodWithCodeBeforeAndAfterBackwardsForPlaceholderForwardsForCaret() + { + var markup = +@"public void Method() +{ + var x = 5; + {|placeholder:test|} [|if (true) + { + }|] $$ + + x = 3; +}"; + + var expectedLSPSnippet = +@"${1:test} if (true) + { + } $0"; + + return TestAsync(markup, expectedLSPSnippet); + } + + [Fact, Trait(Traits.Feature, Traits.Features.RoslynLSPSnippetConverter)] + public void TestExtendTextChangeInsertion() + { + var testString = "foo bar quux baz"; + using var workspace = CreateWorkspaceFromCode(testString); + var document = workspace.CurrentSolution.GetRequiredDocument(workspace.Documents.First().Id); + var lspSnippetString = RoslynLSPSnippetConverter.GenerateLSPSnippetAsync(document, caretPosition: 12, + ImmutableArray.Empty, new TextChange(new TextSpan(8, 0), "quux"), triggerLocation: 12, CancellationToken.None).Result; + AssertEx.EqualOrDiff("quux$0", lspSnippetString); + } + + [Fact, Trait(Traits.Feature, Traits.Features.RoslynLSPSnippetConverter)] + public void TestExtendTextChangeReplacement() + { + var testString = "foo bar quux baz"; + using var workspace = CreateWorkspaceFromCode(testString); + var document = workspace.CurrentSolution.GetRequiredDocument(workspace.Documents.First().Id); + var lspSnippetString = RoslynLSPSnippetConverter.GenerateLSPSnippetAsync(document, caretPosition: 12, + ImmutableArray.Empty, new TextChange(new TextSpan(4, 4), "bar quux"), triggerLocation: 12, CancellationToken.None).Result; + AssertEx.EqualOrDiff("bar quux$0", lspSnippetString); + } + + #endregion + + #region LSP Snippet generation tests + + [Fact, Trait(Traits.Feature, Traits.Features.RoslynLSPSnippetConverter)] + public Task TestForLoopSnippet() + { + var markup = +@"[|for (var {|placeholder1:i|} = 0; {|placeholder1:i|} < {|placeholder2:length|}; {|placeholder1:i|}++) +{$$ +}|]"; + + var expectedLSPSnippet = +@"for (var ${1:i} = 0; ${1:i} < ${2:length}; ${1:i}++) +{$0 +}"; + + return TestAsync(markup, expectedLSPSnippet); + } + + [Fact, Trait(Traits.Feature, Traits.Features.RoslynLSPSnippetConverter)] + public Task TestIfSnippetSamePlaceholderCursorLocation() + { + var markup = +@"public void Method() +{ + var x = 5; + [|if ({|placeholder:true|}$$) + { + }|] + + x = 3; +}"; + + var expectedLSPSnippet = +@"if (${1:true}$0) + { + }"; + + return TestAsync(markup, expectedLSPSnippet); + } + + [Fact, Trait(Traits.Feature, Traits.Features.RoslynLSPSnippetConverter)] + public Task TestIfSnippetSameCursorPlaceholderLocation() + { + var markup = +@"public void Method() +{ + var x = 5; + [|if ($${|placeholder:true|}) + { + }|] + + x = 3; +}"; + + var expectedLSPSnippet = +@"if ($0${1:true}) + { + }"; + + return TestAsync(markup, expectedLSPSnippet); + } + + #endregion + + protected static TestWorkspace CreateWorkspaceFromCode(string code) + => TestWorkspace.CreateCSharp(code); + + private static async Task TestAsync(string markup, string output) + { + MarkupTestFile.GetPositionAndSpans(markup, out var text, out var cursorPosition, out IDictionary> placeholderDictionary); + var stringSpan = placeholderDictionary[""].First(); + var textChange = new TextChange(new TextSpan(stringSpan.Start, 0), text.Substring(stringSpan.Start, stringSpan.Length)); + var placeholders = GetSnippetPlaceholders(text, placeholderDictionary); + using var workspace = CreateWorkspaceFromCode(markup); + var document = workspace.CurrentSolution.GetRequiredDocument(workspace.Documents.First().Id); + + var lspSnippetString = await RoslynLSPSnippetConverter.GenerateLSPSnippetAsync(document, cursorPosition!.Value, placeholders, textChange, stringSpan.Start, CancellationToken.None).ConfigureAwait(false); + AssertEx.EqualOrDiff(output, lspSnippetString); + } + + private static ImmutableArray GetSnippetPlaceholders(string text, IDictionary> placeholderDictionary) + { + using var _ = ArrayBuilder.GetInstance(out var arrayBuilder); + foreach (var kvp in placeholderDictionary) + { + if (kvp.Key.Length > 0) + { + var spans = kvp.Value; + var identifier = text.Substring(spans[0].Start, spans[0].Length); + var placeholders = spans.Select(span => span.Start).ToImmutableArray(); + arrayBuilder.Add(new SnippetPlaceholder(identifier, placeholders)); + } + } + + return arrayBuilder.ToImmutable(); + } + } +} diff --git a/src/EditorFeatures/Test/SolutionCrawler/WorkCoordinatorTests.cs b/src/EditorFeatures/Test/SolutionCrawler/WorkCoordinatorTests.cs index a21f0de048cec..69a34e723583b 100644 --- a/src/EditorFeatures/Test/SolutionCrawler/WorkCoordinatorTests.cs +++ b/src/EditorFeatures/Test/SolutionCrawler/WorkCoordinatorTests.cs @@ -1068,7 +1068,7 @@ public async Task AdditionalDocumentOpenedClosedEvents() //Assert.Equal(1, worker.ClosedNonSourceDocumentIds.Count); } - [Fact] + [Fact(Skip = "https://github.com/dotnet/roslyn/issues/62479")] public async Task AnalyzerConfigDocumentOpenedClosedEvents() { using var workspace = new WorkCoordinatorWorkspace(SolutionCrawlerWorkspaceKind, incrementalAnalyzer: typeof(AnalyzerProviderNoWaitNoBlock)); @@ -1603,7 +1603,7 @@ private static void MakeFirstDocumentActive(Project project) private static void MakeDocumentActive(Document document) { - var documentTrackingService = (TestDocumentTrackingService)document.Project.Solution.Workspace.Services.GetRequiredService(); + var documentTrackingService = (TestDocumentTrackingService)document.Project.Solution.Services.GetRequiredService(); documentTrackingService.SetActiveDocument(document.Id); } @@ -1634,7 +1634,7 @@ public static WorkCoordinatorWorkspace CreateWithAnalysisScope(BackgroundAnalysi { var workspace = new WorkCoordinatorWorkspace(workspaceKind, disablePartialSolutions, incrementalAnalyzer); - var globalOptions = ((IMefHostExportProvider)workspace.Services.HostServices).GetExportedValue(); + var globalOptions = workspace.Services.SolutionServices.ExportProvider.GetExportedValue(); globalOptions.SetGlobalOption(new OptionKey(SolutionCrawlerOptionsStorage.BackgroundAnalysisScopeOption, LanguageNames.CSharp), analysisScope); return workspace; diff --git a/src/EditorFeatures/Test/SymbolFinder/DependentTypeFinderTests.cs b/src/EditorFeatures/Test/SymbolFinder/DependentTypeFinderTests.cs index 306bf6cb8729e..455f5b56e0d1e 100644 --- a/src/EditorFeatures/Test/SymbolFinder/DependentTypeFinderTests.cs +++ b/src/EditorFeatures/Test/SymbolFinder/DependentTypeFinderTests.cs @@ -720,5 +720,76 @@ public class T_DependProject_Class : T_BaseProject_DerivedClass2 Assert.True(typesThatDerive.Any(t => t.Name == "T_DependProject_Class")); } } + + [Theory, CombinatorialData, WorkItem(1598801, "https://devdiv.visualstudio.com/DevDiv/_queries/edit/1598801")] + public async Task ImplementedInterface_CSharp1(TestHost host) + { + using var workspace = CreateWorkspace(host); + var solution = workspace.CurrentSolution; + + solution = AddProjectWithMetadataReferences(solution, "PortableProject1", LanguageNames.CSharp, @" +namespace N +{ + public interface I + { + void M(); + } +} +", MscorlibRefPortable); + + var portableProject1 = solution.Projects.Single(p => p.Name == "PortableProject1"); + + solution = AddProjectWithMetadataReferences(solution, "PortableProject2", LanguageNames.CSharp, @" +using N; +namespace M +{ + public class C : I + { + public void M() { } + } +} +", MscorlibRefPortable, portableProject1.Id); + + // get symbols for types + var compilation1 = await solution.Projects.Single(p => p.Name == "PortableProject1").GetCompilationAsync(); + var compilation2 = await solution.Projects.Single(p => p.Name == "PortableProject2").GetCompilationAsync(); + + var classSymbol = compilation2.GetTypeByMetadataName("M.C"); + var methodSymbol = classSymbol.GetMembers("M").Single(); + + var interfaceSymbol = compilation1.GetTypeByMetadataName("N.I"); + + var interfaceMembers = await SymbolFinder.FindImplementedInterfaceMembersArrayAsync(methodSymbol, solution, CancellationToken.None); + var interfaceMember = Assert.Single(interfaceMembers); + Assert.Equal(interfaceSymbol, interfaceMember.ContainingType); + } + + [Theory, CombinatorialData, WorkItem(1598801, "https://devdiv.visualstudio.com/DevDiv/_queries/edit/1598801")] + public async Task ImplementedInterface_CSharp2(TestHost host) + { + using var workspace = CreateWorkspace(host); + var solution = workspace.CurrentSolution; + + // create portable assembly with an abstract base class + solution = AddProjectWithMetadataReferences(solution, "PortableProject", LanguageNames.CSharp, @" +namespace N +{ + public interface I + { + void M(); + } +} +", MscorlibRefPortable); + + var portableProject1 = GetPortableProject(solution); + + // get symbols for types + var portableCompilation = await GetPortableProject(solution).GetCompilationAsync(); + var baseInterfaceSymbol = portableCompilation.GetTypeByMetadataName("N.I"); + var namespaceSymbol = baseInterfaceSymbol.ContainingNamespace; + + // verify that we don't crash here. + var implementedMembers = await SymbolFinder.FindImplementedInterfaceMembersArrayAsync(namespaceSymbol, solution, CancellationToken.None); + } } } diff --git a/src/EditorFeatures/Test/Utilities/SymbolEquivalenceComparerTests.cs b/src/EditorFeatures/Test/Utilities/SymbolEquivalenceComparerTests.cs index 546398a55763a..f811766668621 100644 --- a/src/EditorFeatures/Test/Utilities/SymbolEquivalenceComparerTests.cs +++ b/src/EditorFeatures/Test/Utilities/SymbolEquivalenceComparerTests.cs @@ -1768,11 +1768,8 @@ private static IMethodSymbol GetInvokedSymbol(Compilation compilati var method_root = method.DeclaringSyntaxReferences[0].GetSyntax(); var invocation = method_root.DescendantNodes().OfType().FirstOrDefault(); - if (invocation == null) - { - // vb method root is statement, but we need block to find body with invocation - invocation = method_root.Parent.DescendantNodes().OfType().First(); - } + // vb method root is statement, but we need block to find body with invocation + invocation ??= method_root.Parent.DescendantNodes().OfType().First(); var model = compilation.GetSemanticModel(invocation.SyntaxTree); var info = model.GetSymbolInfo(invocation); diff --git a/src/EditorFeatures/Test/Workspaces/TextFactoryTests.cs b/src/EditorFeatures/Test/Workspaces/TextFactoryTests.cs index 0968de1a3ea39..152ecfa34bf32 100644 --- a/src/EditorFeatures/Test/Workspaces/TextFactoryTests.cs +++ b/src/EditorFeatures/Test/Workspaces/TextFactoryTests.cs @@ -77,12 +77,12 @@ public async Task TestCreateFromTemporaryStorage() { using var workspace = new AdhocWorkspace(EditorTestCompositions.EditorFeatures.GetHostServices()); - var temporaryStorageService = Assert.IsType(workspace.Services.GetRequiredService()); + var temporaryStorageService = Assert.IsType(workspace.Services.GetRequiredService()); var text = SourceText.From("Hello, World!"); // Create a temporary storage location - using var temporaryStorage = temporaryStorageService.CreateTemporaryTextStorage(System.Threading.CancellationToken.None); + using var temporaryStorage = temporaryStorageService.CreateTemporaryTextStorage(); // Write text into it await temporaryStorage.WriteTextAsync(text); @@ -99,12 +99,12 @@ public async Task TestCreateFromTemporaryStorageWithEncoding() { using var workspace = new AdhocWorkspace(EditorTestCompositions.EditorFeatures.GetHostServices()); - var temporaryStorageService = Assert.IsType(workspace.Services.GetRequiredService()); + var temporaryStorageService = Assert.IsType(workspace.Services.GetRequiredService()); var text = SourceText.From("Hello, World!", Encoding.ASCII); // Create a temporary storage location - using var temporaryStorage = temporaryStorageService.CreateTemporaryTextStorage(System.Threading.CancellationToken.None); + using var temporaryStorage = temporaryStorageService.CreateTemporaryTextStorage(); // Write text into it await temporaryStorage.WriteTextAsync(text); diff --git a/src/EditorFeatures/Test2/Classification/ClassificationTests.vb b/src/EditorFeatures/Test2/Classification/ClassificationTests.vb index d4bf74d3fd83b..1c5392b9b9d86 100644 --- a/src/EditorFeatures/Test2/Classification/ClassificationTests.vb +++ b/src/EditorFeatures/Test2/Classification/ClassificationTests.vb @@ -9,6 +9,7 @@ Imports Microsoft.CodeAnalysis.Editor.Implementation.Classification Imports Microsoft.CodeAnalysis.Editor.Shared.Extensions Imports Microsoft.CodeAnalysis.Editor.Shared.Utilities Imports Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces +Imports Microsoft.CodeAnalysis.Host Imports Microsoft.CodeAnalysis.Host.Mef Imports Microsoft.CodeAnalysis.Options Imports Microsoft.CodeAnalysis.PooledObjects @@ -103,7 +104,7 @@ Namespace Microsoft.CodeAnalysis.Editor.UnitTests.Classification Using workspace = TestWorkspace.Create(workspaceDefinition, composition:=composition) Dim project = workspace.CurrentSolution.Projects.First(Function(p) p.Language = LanguageNames.CSharp) - Dim classificationService = project.LanguageServices.GetService(Of IClassificationService)() + Dim classificationService = project.Services.GetService(Of IClassificationService)() Dim wrongDocument = workspace.CurrentSolution.Projects.First(Function(p) p.Language = "NoCompilation").Documents.First() Dim text = Await wrongDocument.GetTextAsync(CancellationToken.None) @@ -127,7 +128,7 @@ Namespace Microsoft.CodeAnalysis.Editor.UnitTests.Classification Public Sub AddLexicalClassifications(text As SourceText, textSpan As TextSpan, result As ArrayBuilder(Of ClassifiedSpan), cancellationToken As CancellationToken) Implements IClassificationService.AddLexicalClassifications End Sub - Public Sub AddSyntacticClassifications(workspace As Workspace, root As SyntaxNode, textSpan As TextSpan, result As ArrayBuilder(Of ClassifiedSpan), cancellationToken As CancellationToken) Implements IClassificationService.AddSyntacticClassifications + Public Sub AddSyntacticClassifications(services As SolutionServices, root As SyntaxNode, textSpan As TextSpan, result As ArrayBuilder(Of ClassifiedSpan), cancellationToken As CancellationToken) Implements IClassificationService.AddSyntacticClassifications End Sub Public Function AddSemanticClassificationsAsync(document As Document, textSpan As TextSpan, options As ClassificationOptions, result As ArrayBuilder(Of ClassifiedSpan), cancellationToken As CancellationToken) As Task Implements IClassificationService.AddSemanticClassificationsAsync @@ -145,7 +146,7 @@ Namespace Microsoft.CodeAnalysis.Editor.UnitTests.Classification Return New ValueTask(Of TextChangeRange?) End Function - Public Function ComputeSyntacticChangeRange(workspace As Workspace, oldRoot As SyntaxNode, newRoot As SyntaxNode, timeout As TimeSpan, cancellationToken As CancellationToken) As TextChangeRange? Implements IClassificationService.ComputeSyntacticChangeRange + Public Function ComputeSyntacticChangeRange(services As SolutionServices, oldRoot As SyntaxNode, newRoot As SyntaxNode, timeout As TimeSpan, cancellationToken As CancellationToken) As TextChangeRange? Implements IClassificationService.ComputeSyntacticChangeRange Return Nothing End Function diff --git a/src/EditorFeatures/Test2/Diagnostics/AbstractCrossLanguageUserDiagnosticTest.vb b/src/EditorFeatures/Test2/Diagnostics/AbstractCrossLanguageUserDiagnosticTest.vb index 40539bebe9ccd..388b7d61e1333 100644 --- a/src/EditorFeatures/Test2/Diagnostics/AbstractCrossLanguageUserDiagnosticTest.vb +++ b/src/EditorFeatures/Test2/Diagnostics/AbstractCrossLanguageUserDiagnosticTest.vb @@ -9,7 +9,7 @@ Imports Microsoft.CodeAnalysis.CodeActions Imports Microsoft.CodeAnalysis.CodeFixes Imports Microsoft.CodeAnalysis.Diagnostics Imports Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces -Imports Microsoft.CodeAnalysis.LanguageServices +Imports Microsoft.CodeAnalysis.LanguageService Imports Microsoft.CodeAnalysis.UnitTests Imports Microsoft.CodeAnalysis.UnitTests.Diagnostics Imports Roslyn.Utilities diff --git a/src/EditorFeatures/Test2/Diagnostics/AddImport/AddImportCrossLanguageTests.vb b/src/EditorFeatures/Test2/Diagnostics/AddImport/AddImportCrossLanguageTests.vb index 7422320e0d605..6cc1b38bdac56 100644 --- a/src/EditorFeatures/Test2/Diagnostics/AddImport/AddImportCrossLanguageTests.vb +++ b/src/EditorFeatures/Test2/Diagnostics/AddImport/AddImportCrossLanguageTests.vb @@ -8,7 +8,7 @@ Imports Microsoft.CodeAnalysis.CSharp.AddImport Imports Microsoft.CodeAnalysis.Diagnostics Imports Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces Imports Microsoft.CodeAnalysis.Host.Mef -Imports Microsoft.CodeAnalysis.IncrementalCaches +Imports Microsoft.CodeAnalysis.FindSymbols.SymbolTree Imports Microsoft.CodeAnalysis.SolutionCrawler Imports Microsoft.CodeAnalysis.Tags Imports Microsoft.CodeAnalysis.VisualBasic.AddImport @@ -401,7 +401,7 @@ End Namespace Private Sub WaitForSolutionCrawler(workspace As TestWorkspace) Dim solutionCrawler = DirectCast(workspace.Services.GetService(Of ISolutionCrawlerRegistrationService), SolutionCrawlerRegistrationService) solutionCrawler.Register(workspace) - Dim provider = DirectCast(workspace.ExportProvider.GetExports(Of IWorkspaceServiceFactory).First( + Dim provider = DirectCast(workspace.ExportProvider.GetExports(Of IIncrementalAnalyzerProvider).First( Function(f) TypeOf f.Value Is SymbolTreeInfoIncrementalAnalyzerProvider).Value, SymbolTreeInfoIncrementalAnalyzerProvider) Dim analyzer = provider.CreateIncrementalAnalyzer(workspace) solutionCrawler.GetTestAccessor().WaitUntilCompletion(workspace, ImmutableArray.Create(analyzer)) diff --git a/src/EditorFeatures/Test2/Expansion/AbstractExpansionTest.vb b/src/EditorFeatures/Test2/Expansion/AbstractExpansionTest.vb index ebdb2c335fe71..8a42ca5f2a5aa 100644 --- a/src/EditorFeatures/Test2/Expansion/AbstractExpansionTest.vb +++ b/src/EditorFeatures/Test2/Expansion/AbstractExpansionTest.vb @@ -25,11 +25,10 @@ Namespace Microsoft.CodeAnalysis.Editor.UnitTests.Expansion End If Dim document = If(Not useLastProject, workspace.CurrentSolution.Projects.Single(), workspace.CurrentSolution.Projects.Last()).Documents.Single() - Dim languageServices = document.Project.LanguageServices Dim root = Await document.GetSyntaxRootAsync() - Dim cleanupOptions = CodeCleanupOptions.GetDefault(document.Project.LanguageServices) + Dim cleanupOptions = CodeCleanupOptions.GetDefault(document.Project.Services) If hostDocument.AnnotatedSpans.ContainsKey("Expand") Then For Each span In hostDocument.AnnotatedSpans("Expand") diff --git a/src/EditorFeatures/Test2/FindReferences/FindReferencesTests.MethodTypeParameterTypeSymbol.vb b/src/EditorFeatures/Test2/FindReferences/FindReferencesTests.MethodTypeParameterTypeSymbol.vb index 48e11e75c8f23..7075ecd754732 100644 --- a/src/EditorFeatures/Test2/FindReferences/FindReferencesTests.MethodTypeParameterTypeSymbol.vb +++ b/src/EditorFeatures/Test2/FindReferences/FindReferencesTests.MethodTypeParameterTypeSymbol.vb @@ -8,6 +8,7 @@ Imports Microsoft.CodeAnalysis.Remote.Testing Namespace Microsoft.CodeAnalysis.Editor.UnitTests.FindReferences Partial Public Class FindReferencesTests #Region "FAR on generic methods" + Public Async Function TestMethodType_Parameter1(kind As TestKind, host As TestHost) As Task Dim input = @@ -90,6 +91,43 @@ Namespace Microsoft.CodeAnalysis.Editor.UnitTests.FindReferences Await TestAPIAndFeature(input, kind, host) End Function + + + + Public Async Function TestMethodTypeParameter_NewConstraint_CSharp(kind As TestKind, host As TestHost) As Task + Dim input = + + + () where [|T|] : new() + { + new [|T|](); + } + }]]> + + + Await TestAPIAndFeature(input, kind, host) + End Function + + + + Public Async Function TestMethodTypeParameter_NewConstraint_VisualBasic(kind As TestKind, host As TestHost) As Task + Dim input = + + + + + + Await TestAPIAndFeature(input, kind, host) + End Function + #End Region #Region "FAR on generic partial methods" diff --git a/src/EditorFeatures/Test2/FindReferences/FindReferencesTests.TypeParameterTypeSymbol.vb b/src/EditorFeatures/Test2/FindReferences/FindReferencesTests.TypeParameterTypeSymbol.vb index 114f33acee0d5..e6b7d64798be4 100644 --- a/src/EditorFeatures/Test2/FindReferences/FindReferencesTests.TypeParameterTypeSymbol.vb +++ b/src/EditorFeatures/Test2/FindReferences/FindReferencesTests.TypeParameterTypeSymbol.vb @@ -27,6 +27,42 @@ Namespace Microsoft.CodeAnalysis.Editor.UnitTests.FindReferences Await TestAPIAndFeature(input, kind, host) End Function + + + Public Async Function TestTypeParameter_NewConstraint_CSharp(kind As TestKind, host As TestHost) As Task + Dim input = + + + where [|T|] : new() + { + void Goo() + { + new [|T|](); + } + }]]> + + + Await TestAPIAndFeature(input, kind, host) + End Function + + + + Public Async Function TestTypeParameter_NewConstraint_VisualBasic(kind As TestKind, host As TestHost) As Task + Dim input = + + + + + + Await TestAPIAndFeature(input, kind, host) + End Function + Public Async Function TestCSharp_LocalFunctionTypeParameter(kind As TestKind, host As TestHost) As Task diff --git a/src/EditorFeatures/Test2/InlineHints/AbstractInlineHintsTests.vb b/src/EditorFeatures/Test2/InlineHints/AbstractInlineHintsTests.vb index 2f3db4814600b..4cac10d5597da 100644 --- a/src/EditorFeatures/Test2/InlineHints/AbstractInlineHintsTests.vb +++ b/src/EditorFeatures/Test2/InlineHints/AbstractInlineHintsTests.vb @@ -7,7 +7,7 @@ Imports System.Threading Imports Microsoft.CodeAnalysis.Editor.InlineHints Imports Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces Imports Microsoft.CodeAnalysis.InlineHints -Imports Microsoft.CodeAnalysis.LanguageServices +Imports Microsoft.CodeAnalysis.LanguageService Imports Microsoft.CodeAnalysis.Options Imports Microsoft.CodeAnalysis.[Shared].Utilities Imports Microsoft.CodeAnalysis.Text diff --git a/src/EditorFeatures/Test2/InlineHints/CSharpInlineTypeHintsTests.vb b/src/EditorFeatures/Test2/InlineHints/CSharpInlineTypeHintsTests.vb index 079e457d776ff..d533701f1d8f2 100644 --- a/src/EditorFeatures/Test2/InlineHints/CSharpInlineTypeHintsTests.vb +++ b/src/EditorFeatures/Test2/InlineHints/CSharpInlineTypeHintsTests.vb @@ -131,6 +131,139 @@ class A Await VerifyTypeHints(input, output) End Function + + Public Async Function TestOutVarTuple() As Task + Dim input = + + + +class A +{ + void M(out (int, int) x) => x = default; + + void Main() + { + M(out var {|(int, int) :|}x); + } +} + + + + + Dim output = + + + +class A +{ + void M(out (int, int) x) => x = default; + + void Main() + { + M(out (int, int) x); + } +} + + + + + Await VerifyTypeHints(input, output) + End Function + + + Public Async Function TestForEachDeconstruction() As Task + Dim input = + + + +using System.Collections.Generic; + +class A +{ + void Main(IDictionary<int, string> d) + { + foreach (var ({|int :|}i, {|string :|}s) in d) + { + } + } +} + + + + + Dim output = + + + +using System.Collections.Generic; + +class A +{ + void Main(IDictionary<int, string> d) + { + foreach (var (i, s) in d) + { + } + } +} + + + + + Await VerifyTypeHints(input, output) + End Function + + + Public Async Function TestForEachDeconstruction_NestedTuples() As Task + Dim input = + + + +using System.Collections.Generic; + +class A +{ + void Main(IDictionary<int, (string, float)> d) + { + foreach (var ({|int :|}i, {|(string, float) :|}sf) in d) + { + } + + foreach (var ({|int :|}i, ({|string :|}s, {|float :|}f)) in d) + { + } + } +} + + + + + Dim output = + + + +using System.Collections.Generic; + +class A +{ + void Main(IDictionary<int, (string, float)> d) + { + foreach (var (i, sf) in d) + { + } + + foreach (var (i, (s, f)) in d) + { + } + } +} + + + + + Await VerifyTypeHints(input, output) + End Function + Public Async Function TestWithForeachVar() As Task Dim input = diff --git a/src/EditorFeatures/Test2/IntelliSense/AbstractIntellisenseQuickInfoBuilderTests.vb b/src/EditorFeatures/Test2/IntelliSense/AbstractIntellisenseQuickInfoBuilderTests.vb index 8ab07d30a0f9d..e0616f1c9d867 100644 --- a/src/EditorFeatures/Test2/IntelliSense/AbstractIntellisenseQuickInfoBuilderTests.vb +++ b/src/EditorFeatures/Test2/IntelliSense/AbstractIntellisenseQuickInfoBuilderTests.vb @@ -9,7 +9,7 @@ Imports Microsoft.CodeAnalysis.Editor.Host Imports Microsoft.CodeAnalysis.Editor.Implementation.IntelliSense.QuickInfo Imports Microsoft.CodeAnalysis.Editor.Shared.Utilities Imports Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces -Imports Microsoft.CodeAnalysis.LanguageServices +Imports Microsoft.CodeAnalysis.LanguageService Imports Microsoft.CodeAnalysis.QuickInfo Imports Microsoft.CodeAnalysis.Shared.TestHooks Imports Microsoft.VisualStudio.Core.Imaging diff --git a/src/EditorFeatures/Test2/IntelliSense/CSharpCompletionCommandHandlerTests.vb b/src/EditorFeatures/Test2/IntelliSense/CSharpCompletionCommandHandlerTests.vb index b3ca8a311e484..75e8dfdacda81 100644 --- a/src/EditorFeatures/Test2/IntelliSense/CSharpCompletionCommandHandlerTests.vb +++ b/src/EditorFeatures/Test2/IntelliSense/CSharpCompletionCommandHandlerTests.vb @@ -23,12 +23,141 @@ Imports Microsoft.VisualStudio.Text Imports Microsoft.VisualStudio.Text.Editor Imports Microsoft.VisualStudio.Text.Operations Imports Microsoft.VisualStudio.Text.Projection -Imports Roslyn.Utilities Namespace Microsoft.CodeAnalysis.Editor.UnitTests.IntelliSense <[UseExportProvider]> Public Class CSharpCompletionCommandHandlerTests + + + Public Async Function CompletionOnFileType_SameFile_NonQualified(showCompletionInArgumentLists As Boolean) As Task + Using state = TestStateFactory.CreateCSharpTestState( + +namespace NS +{ + file class FC { } + + class C + { + public static void M() + { + var x = new $$ + } + } +} + , + showCompletionInArgumentLists:=showCompletionInArgumentLists, languageVersion:=LanguageVersion.Preview) + + state.SendTypeChars("F") + Await state.AssertSelectedCompletionItem(displayText:="FC", isHardSelected:=True) + + state.SendTab() + Await state.AssertNoCompletionSession() + Assert.Contains("var x = new FC", state.GetLineTextFromCaretPosition(), StringComparison.Ordinal) + End Using + End Function + + + + Public Async Function CompletionOnFileType_SameFile_NamespaceQualified(showCompletionInArgumentLists As Boolean) As Task + Using state = TestStateFactory.CreateCSharpTestState( + +namespace NS +{ + file class FC { } + + class C + { + public static void M() + { + var x = new NS.$$ + } + } +} + , + showCompletionInArgumentLists:=showCompletionInArgumentLists, languageVersion:=LanguageVersion.Preview) + + state.SendTypeChars("F") + Await state.AssertSelectedCompletionItem(displayText:="FC", isHardSelected:=True) + + state.SendTab() + Await state.AssertNoCompletionSession() + Assert.Contains("var x = new NS.FC", state.GetLineTextFromCaretPosition(), StringComparison.Ordinal) + End Using + End Function + + + + Public Async Function CompletionOnFileType_DifferentFile_NonQualified(showCompletionInArgumentLists As Boolean) As Task + Using State = New TestState( + > + +namespace NS +{ + file class FC { } +} + + +namespace NS +{ + class C + { + public static void M() + { + var x = new $$ + } + } +} + + + , + excludedTypes:=Nothing, extraExportedTypes:=Nothing, + includeFormatCommandHandler:=False, workspaceKind:=Nothing) + + State.Workspace.GlobalOptions.SetGlobalOption( + New OptionKey(CompletionOptionsStorage.TriggerInArgumentLists, LanguageNames.CSharp), showCompletionInArgumentLists) + + State.SendTypeChars("F") + Await State.AssertCompletionItemsDoNotContainAny("FC") + End Using + End Function + + + + Public Async Function CompletionOnFileType_DifferentFile_NamespaceQualified(showCompletionInArgumentLists As Boolean) As Task + Using State = New TestState( + > + +namespace NS +{ + file class FC { } +} + + +namespace NS +{ + class C + { + public static void M() + { + var x = new NS.$$ + } + } +} + + + , + excludedTypes:=Nothing, extraExportedTypes:=Nothing, + includeFormatCommandHandler:=False, workspaceKind:=Nothing) + + State.Workspace.GlobalOptions.SetGlobalOption( + New OptionKey(CompletionOptionsStorage.TriggerInArgumentLists, LanguageNames.CSharp), showCompletionInArgumentLists) + + State.SendTypeChars("F") + Await State.AssertCompletionItemsDoNotContainAny("FC") + End Using + End Function + Public Async Function CompletionOnExtendedPropertyPattern_FirstNested(showCompletionInArgumentLists As Boolean) As Task @@ -5854,7 +5983,8 @@ class C showCompletionInArgumentLists:=showCompletionInArgumentLists) state.SendTypeChars("z") - Await state.AssertSelectedCompletionItem(displayText:="identifier", isHardSelected:=False) + Await state.AssertCompletionItemsContain(displayText:="identifier", displayTextSuffix:=Nothing) + state.AssertSuggestedItemSelected(displayText:="z") state.SendBackspace() state.SendTypeChars("i") @@ -6156,6 +6286,23 @@ class C Await state.AssertCompletionSession() Assert.True(state.HasSuggestedItem()) Await state.AssertSelectedCompletionItem(displayText:="sbyte", isSoftSelected:=True) + + state.SendTypeChars("xyzz") + Await state.AssertCompletionSession() + state.AssertSuggestedItemSelected(displayText:="sxyzz") + Await state.AssertSelectedCompletionItem(displayText:="sxyzz", isSoftSelected:=True) + + state.SendBackspace() + Await state.AssertCompletionSession() + state.AssertSuggestedItemSelected(displayText:="sxyz") + Await state.AssertSelectedCompletionItem(displayText:="sxyz", isSoftSelected:=True) + + state.SendBackspace() + state.SendBackspace() + state.SendBackspace() + Await state.AssertCompletionSession() + Assert.True(state.HasSuggestedItem()) + Await state.AssertSelectedCompletionItem(displayText:="sbyte", isSoftSelected:=True) End Using End Function @@ -6887,6 +7034,101 @@ namespace NS1 End Using End Function + + + Public Async Function ExpandedItemsShouldNotShowInExclusiveContext() As Task + Using state = TestStateFactory.CreateCSharpTestState( + +namespace CC +{ + public class DD + { + } +} +public class AA +{ + public AA DDProp1 { get; set; } + + private static void A() + { + AA a = new() + {$$ + }; + } +}) + + state.TextView.Options.SetOptionValue(DefaultOptions.ResponsiveCompletionOptionId, True) + state.Workspace.GlobalOptions.SetGlobalOption(New OptionKey(CompletionOptionsStorage.ForceExpandedCompletionIndexCreation), True) + state.Workspace.GlobalOptions.SetGlobalOption(New OptionKey(CompletionOptionsStorage.ShowItemsFromUnimportedNamespaces, LanguageNames.CSharp), True) + + state.SendInvokeCompletionList() + Await state.WaitForUIRenderedAsync() + + ' import completion is disabled, so we shouldn't have expander selected by default + state.AssertCompletionItemExpander(isAvailable:=True, isSelected:=False) + Await state.AssertCompletionItemsContain("DDProp1", "") + Await state.AssertCompletionItemsDoNotContainAny("DD") + + Dim session = Await state.GetCompletionSession() + Dim sessionData = CompletionSessionData.GetOrCreateSessionData(session) + Assert.Null(sessionData.ExpandedItemsTask) + + state.SendTypeChars("D") + Await state.WaitForAsynchronousOperationsAsync() + Await state.WaitForUIRenderedAsync() + + state.AssertCompletionItemExpander(isAvailable:=True, isSelected:=False) + Await state.AssertCompletionItemsContain("DDProp1", "") + Await state.AssertCompletionItemsDoNotContainAny("DD") + End Using + End Function + + + + Public Async Function ExpandedItemsShouldNotShowViaExpanderInExclusiveContext() As Task + Using state = TestStateFactory.CreateCSharpTestState( + +namespace CC +{ + public class DD + { + } +} +public class AA +{ + public AA Prop1 { get; set; } + public int Prop2 { get; set; } + + private static void A() + { + AA a = new() + {$$ + }; + } +}) + + state.Workspace.GlobalOptions.SetGlobalOption(New OptionKey(CompletionOptionsStorage.ForceExpandedCompletionIndexCreation), True) + state.Workspace.GlobalOptions.SetGlobalOption(New OptionKey(CompletionOptionsStorage.ShowItemsFromUnimportedNamespaces, LanguageNames.CSharp), False) + + state.SendInvokeCompletionList() + Await state.WaitForUIRenderedAsync() + + ' import completion is disabled, so we shouldn't have expander selected by default + state.AssertCompletionItemExpander(isAvailable:=True, isSelected:=False) + Await state.AssertCompletionItemsContain("Prop1", "") + Await state.AssertCompletionItemsDoNotContainAny("DD") + + state.SetCompletionItemExpanderState(isSelected:=True) + Await state.WaitForAsynchronousOperationsAsync() + Await state.WaitForUIRenderedAsync() + + ' since we are in exclusive context (property name provider is exclusive in this case), selceting expander is a no-op + state.AssertCompletionItemExpander(isAvailable:=True, isSelected:=True) + Await state.AssertCompletionItemsContain("Prop1", "") + Await state.AssertCompletionItemsDoNotContainAny("DD") + End Using + End Function + @@ -7815,6 +8057,56 @@ namespace NS End Using End Function + + + + Public Async Function TestShowCompletionsWhenTypingCompilerDirective_SingleDirectiveWord(showCompletionInArgumentLists As Boolean) As Task + Using state = TestStateFactory.CreateCSharpTestState( + , + showCompletionInArgumentLists:=showCompletionInArgumentLists) + + state.SendTypeChars(" ") + Await state.WaitForAsynchronousOperationsAsync() + + Await state.AssertCompletionItemsContainAll("disable", "enable", "restore") + End Using + End Function + + + + + Public Async Function TestShowCompletionsWhenTypingCompilerDirective_MultipleDirectiveWords(showCompletionInArgumentLists As Boolean) As Task + Using state = TestStateFactory.CreateCSharpTestState( + , + showCompletionInArgumentLists:=showCompletionInArgumentLists) + + state.SendTypeChars(" ") + Await state.WaitForAsynchronousOperationsAsync() + + Await state.AssertCompletionItemsContainAll("disable", "enable", "restore") + End Using + End Function + + + + + Public Async Function TestCompletionsWhenTypingCompilerDirective_DoNotCrashOnDocumentStart(showCompletionInArgumentLists As Boolean) As Task + Using state = TestStateFactory.CreateCSharpTestState( + , + showCompletionInArgumentLists:=showCompletionInArgumentLists) + + state.SendTypeChars(" ") + Await state.WaitForAsynchronousOperationsAsync() + + ' This assertion would fail if any unhandled exception was thrown during computing completions + Await state.AssertCompletionItemsDoNotContainAny("disable", "enable", "restore") + End Using + End Function + <[Shared]> @@ -9917,6 +10209,39 @@ class Class End Using End Function + + + + + + + Public Async Function TestSpecialTypeKeywordSelection(first As String, second As String) As Task + Using state = TestStateFactory.CreateCSharpTestState( + +using System; +class Class +{ + public void M() + { + $$ + } +}) + + ' filter text decides selection when no type can be inferred. + state.SendTypeChars(first) + Await state.AssertCompletionItemsContainAll(first, second) + Await state.AssertSelectedCompletionItem(displayText:=first, isHardSelected:=True) + state.SendTab() + + state.SendTypeChars(" x =") + + ' We should let what user has typed to dictate whether to select keyword or type form, even when we can infer the type. + state.SendTypeChars(second.Substring(0, 3)) + Await state.AssertCompletionItemsContainAll(first, second) + Await state.AssertSelectedCompletionItem(displayText:=second, isHardSelected:=True) + End Using + End Function + <[Shared]> @@ -9992,5 +10317,120 @@ namespace ReferencedNamespace2 End Using End Function + + + Public Async Function TestAdditionalFilterTexts() As Task + Using state = TestStateFactory.CreateCSharpTestState( + +class MyClass +{ + public void MyMethod() + { + $$ + } +} + , + extraExportedTypes:={GetType(ItemWithAdditionalFilterTextsProvider)}.ToList()) + + state.Workspace.GlobalOptions.SetGlobalOption(New OptionKey(CompletionOptionsStorage.ShowItemsFromUnimportedNamespaces, LanguageNames.CSharp), False) + + state.SendTypeChars(" ") + Await state.AssertCompletionItemsContainAll("Consolation", "Add code that write to console", "Add code that write line to console") + + ' "c" Matches all 3 item's FilterText, so select "Add code that write line to console" which was sorted alphabetically ahead of others + state.SendTypeChars("c") + Await state.AssertCompletionItemsContainAll("Add code that write to console", "Add code that write line to console", "Consolation") + Await state.AssertSelectedCompletionItem("Add code that write line to console", isHardSelected:=True) + + ' "cwl" only matches FilterText of "Add code that write line to console" + state.SendTypeChars("wl") + Await state.AssertCompletionItemsDoNotContainAny("Consolation", "Add code that write to console") + Await state.AssertSelectedCompletionItem("Add code that write line to console", isHardSelected:=True) + + ' "consol" matches FilterText of "Consolation" and AdditionalFilterTexts of other 2 items, and the pattern match scores are same (prefix) + ' but we select "Consolation" becaseu we prefer FilterText match over AdditionalFilterTexts match + state.SendBackspaces("wl".Length) + state.SendTypeChars("onsol") + Await state.AssertCompletionItemsContainAll("Consolation", "Add code that write to console", "Add code that write line to console") + Await state.AssertSelectedCompletionItem("Consolation", isHardSelected:=True) + + ' "consola" + state.SendTypeChars("a") + Await state.AssertCompletionItemsContain("Consolation", "") + Await state.AssertCompletionItemsDoNotContainAny("Add code that write to console", "Add code that write line to console") + Await state.AssertSelectedCompletionItem("Consolation", isHardSelected:=True) + + ' "console" is perfect match for "Add code that write to console" and "Add code that write line to console" (both of AdditionalFilterTexts) + ' so we select "Add code that write line to console", which was sorted higher alphabetically + state.SendBackspace() + state.SendTypeChars("e") + Await state.AssertCompletionItemsContainAll("Add code that write to console", "Add code that write line to console") + Await state.AssertCompletionItemsDoNotContainAny("Consolation") + Await state.AssertSelectedCompletionItem("Add code that write line to console", isHardSelected:=True) + + ' "write" is a perfect match for "Add code that write to console" and prefix match for "Add code that write line to console" (both of AdditionalFilterTexts) + ' so we select "Add code that write to console" + state.SendBackspaces("console".Length) + state.SendTypeChars("write") + Await state.AssertCompletionItemsContainAll("Add code that write to console", "Add code that write line to console") + Await state.AssertCompletionItemsDoNotContainAny("Consolation") + Await state.AssertSelectedCompletionItem("Add code that write to console", isHardSelected:=True) + + ' "writel" + state.SendTypeChars("l") + Await state.AssertCompletionItemsDoNotContainAny("Add code that write to console", "Consolation") + Await state.AssertSelectedCompletionItem("Add code that write line to console", isHardSelected:=True) + End Using + End Function + + + <[Shared]> + + Private Class ItemWithAdditionalFilterTextsProvider + Inherits CompletionProvider + + + + Public Sub New() + End Sub + + Public Overrides Function ProvideCompletionsAsync(context As CompletionContext) As Task + context.AddItem(CompletionItem.Create(displayText:="Consolation")) + context.AddItem(CompletionItem.Create(displayText:="Add code that write to console", filterText:="cw").WithAdditionalFilterTexts(ImmutableArray.Create("Console", "Write"))) + context.AddItem(CompletionItem.Create(displayText:="Add code that write line to console", filterText:="cwl").WithAdditionalFilterTexts(ImmutableArray.Create("Console", "WriteLine"))) + Return Task.CompletedTask + End Function + + Public Overrides Function ShouldTriggerCompletion(text As SourceText, caretPosition As Integer, trigger As CompletionTrigger, options As OptionSet) As Boolean + Return True + End Function + + Public Overrides Function GetChangeAsync(document As Document, item As CompletionItem, commitKey As Char?, cancellationToken As CancellationToken) As Task(Of CompletionChange) + Throw New NotImplementedException() + End Function + End Class + + + + Public Async Function TestSortingOfSameNamedCompletionItems() As Task + Using state = TestStateFactory.CreateCSharpTestState( + +class MyClass +{ + public void MyMethod() + { + $$ + } +} + ) + + state.Workspace.GlobalOptions.SetGlobalOption(New OptionKey(CompletionOptionsStorage.ShowItemsFromUnimportedNamespaces, LanguageNames.CSharp), False) + state.Workspace.GlobalOptions.SetGlobalOption(New OptionKey(CompletionOptionsStorage.ShowNewSnippetExperience, LanguageNames.CSharp), True) + state.SendTypeChars("cw") + Await state.AssertSelectedCompletionItem(displayText:="cw", inlineDescription:=Nothing, isHardSelected:=True) + state.SendDownKey() + Await state.AssertSelectedCompletionItem(displayText:="cw", inlineDescription:="Console.WriteLine", isHardSelected:=True) + End Using + End Function End Class End Namespace diff --git a/src/EditorFeatures/Test2/IntelliSense/CSharpCompletionCommandHandlerTests_HandleNonRoslynCompletionSources.vb b/src/EditorFeatures/Test2/IntelliSense/CSharpCompletionCommandHandlerTests_HandleNonRoslynCompletionSources.vb new file mode 100644 index 0000000000000..d29360f370136 --- /dev/null +++ b/src/EditorFeatures/Test2/IntelliSense/CSharpCompletionCommandHandlerTests_HandleNonRoslynCompletionSources.vb @@ -0,0 +1,107 @@ +' Licensed to the .NET Foundation under one or more agreements. +' The .NET Foundation licenses this file to you under the MIT license. +' See the LICENSE file in the project root for more information. + +Imports System.Collections.Immutable +Imports System.Threading +Imports Microsoft.CodeAnalysis.Editor.Implementation.IntelliSense.AsyncCompletion +Imports Microsoft.CodeAnalysis.Host.Mef +Imports Microsoft.CodeAnalysis.Text +Imports Microsoft.CodeAnalysis.Text.[Shared].Extensions +Imports Microsoft.VisualStudio.Language.Intellisense.AsyncCompletion +Imports Microsoft.VisualStudio.Language.Intellisense.AsyncCompletion.Data +Imports Microsoft.VisualStudio.Text +Imports Microsoft.VisualStudio.Text.Editor + +Namespace Microsoft.CodeAnalysis.Editor.UnitTests.IntelliSense + <[UseExportProvider]> + Public Class CSharpCompletionCommandHandlerTests_HandleNonRoslynCompletionSources + + + Public Async Function SingleItemFromNonRoslynSourceOnly() As Task + Using state = TestStateFactory.CreateCSharpTestState( + +public class ItemFromRoslynSource {} +public class C +{ + void M() + { + ItemFrom$$ + } +} + , + excludedTypes:={GetType(CompletionSourceProvider)}.ToList(), + extraExportedTypes:={GetType(MockCompletionSourceProvider)}.ToList()) + + state.SendInvokeCompletionList() + Dim session = Await state.GetCompletionSession() + Dim items = session.GetComputedItems(CancellationToken.None).Items + + Assert.True(items.Any(Function(i) i.DisplayText = "ItemFromMockSource")) + + End Using + End Function + + + Public Async Function HandleMultipleItemsFromBothSources() As Task + Using state = TestStateFactory.CreateCSharpTestState( + +public class ItemFromRoslynSource {} +public class C +{ + void M() + { + ItemFrom$$ + } +} + , + extraExportedTypes:={GetType(MockCompletionSourceProvider)}.ToList()) + + state.SendInvokeCompletionList() + Dim session = Await state.GetCompletionSession() + Dim items = session.GetComputedItems(CancellationToken.None).Items + + Assert.True({"ItemFromRoslynSource", "ItemFromMockSource"}.All(Function(t) items.Any(Function(i) i.DisplayText = t))) + + End Using + End Function + + + + + Private Class MockCompletionSourceProvider + Implements IAsyncCompletionSourceProvider + + + + Public Sub New() + End Sub + + Public Function GetOrCreate(textView As ITextView) As IAsyncCompletionSource Implements IAsyncCompletionSourceProvider.GetOrCreate + Return New MockCompletionSource() + End Function + End Class + + Private Class MockCompletionSource + Implements IAsyncCompletionSource + + Public Function GetCompletionContextAsync(session As IAsyncCompletionSession, trigger As CompletionTrigger, triggerLocation As SnapshotPoint, applicableToSpan As SnapshotSpan, token As CancellationToken) As Task(Of CompletionContext) Implements IAsyncCompletionSource.GetCompletionContextAsync + Dim item = New CompletionItem("ItemFromMockSource", Me) + Dim itemsList = session.CreateCompletionList({item}) + Return Task.FromResult(New CompletionContext(itemsList, suggestionItemOptions:=Nothing, InitialSelectionHint.RegularSelection, ImmutableArray(Of CompletionFilterWithState).Empty, isIncomplete:=False, Nothing)) + End Function + + Public Function GetDescriptionAsync(session As IAsyncCompletionSession, item As CompletionItem, token As CancellationToken) As Task(Of Object) Implements IAsyncCompletionSource.GetDescriptionAsync + Throw New NotImplementedException() + End Function + + Public Function InitializeCompletion(trigger As CompletionTrigger, triggerLocation As SnapshotPoint, token As CancellationToken) As CompletionStartData Implements IAsyncCompletionSource.InitializeCompletion + Dim document = triggerLocation.Snapshot.GetOpenDocumentInCurrentContextWithChanges() + Dim sourceText = document.GetTextSynchronously(CancellationToken.None) + Dim span = New SnapshotSpan(triggerLocation.Snapshot, CodeAnalysis.Completion.CommonCompletionUtilities.GetWordSpan(sourceText, triggerLocation.Position, + Function(c) Char.IsLetter(c), Function(c) Char.IsLetterOrDigit(c)).ToSpan()) + Return New CompletionStartData(CompletionParticipation.ProvidesItems, span) + End Function + End Class + End Class +End Namespace diff --git a/src/EditorFeatures/Test2/IntelliSense/CSharpSignatureHelpCommandHandlerTests.vb b/src/EditorFeatures/Test2/IntelliSense/CSharpSignatureHelpCommandHandlerTests.vb index 7e4556adaff71..98422df0558b6 100644 --- a/src/EditorFeatures/Test2/IntelliSense/CSharpSignatureHelpCommandHandlerTests.vb +++ b/src/EditorFeatures/Test2/IntelliSense/CSharpSignatureHelpCommandHandlerTests.vb @@ -884,7 +884,7 @@ class C , showCompletionInArgumentLists:=showCompletionInArgumentLists) ' disable implicit sig help then type a trigger character -> no session should be available - state.Workspace.GetService(Of IGlobalOptionService).SetGlobalOption(New OptionKey(SignatureHelpViewOptions.ShowSignatureHelp, LanguageNames.CSharp), False) + state.Workspace.GetService(Of IGlobalOptionService).SetGlobalOption(New OptionKey(SignatureHelpViewOptionsStorage.ShowSignatureHelp, LanguageNames.CSharp), False) state.SendTypeChars("(") Await state.AssertNoSignatureHelpSession() diff --git a/src/EditorFeatures/Test2/IntelliSense/CompletionRulesTests.vb b/src/EditorFeatures/Test2/IntelliSense/CompletionRulesTests.vb index 495c6101bca5b..4ae6ab59d4fb0 100644 --- a/src/EditorFeatures/Test2/IntelliSense/CompletionRulesTests.vb +++ b/src/EditorFeatures/Test2/IntelliSense/CompletionRulesTests.vb @@ -64,9 +64,9 @@ Namespace Microsoft.CodeAnalysis.Editor.UnitTests.IntelliSense MarkupTestFile.GetSpan(wordMarkup, word, wordMatchSpan) Dim item = CompletionItem.Create(word) - Assert.True(helper.MatchesPattern(item.FilterText, pattern, culture), $"Expected item {word} does not match {pattern}") + Assert.True(helper.MatchesPattern(item, pattern, culture), $"Expected item {word} does not match {pattern}") - Dim highlightedSpans = helper.GetHighlightedSpans(item.FilterText, pattern, culture) + Dim highlightedSpans = helper.GetHighlightedSpans(item, pattern, culture) Assert.NotEmpty(highlightedSpans) Assert.Equal(1, highlightedSpans.Length) Assert.Equal(wordMatchSpan, highlightedSpans(0)) @@ -79,9 +79,9 @@ Namespace Microsoft.CodeAnalysis.Editor.UnitTests.IntelliSense Dim helper = New CompletionHelper(isCaseSensitive:=True) For Each word In wordsToNotMatch Dim item = CompletionItem.Create(word) - Assert.False(helper.MatchesPattern(item.FilterText, pattern, culture), $"Unexpected item {word} matches {pattern}") + Assert.False(helper.MatchesPattern(item, pattern, culture), $"Unexpected item {word} matches {pattern}") - Dim highlightedSpans = helper.GetHighlightedSpans(item.FilterText, pattern, culture) + Dim highlightedSpans = helper.GetHighlightedSpans(item, pattern, culture) Assert.Empty(highlightedSpans) Next End Sub diff --git a/src/EditorFeatures/Test2/IntelliSense/CompletionServiceTests.vb b/src/EditorFeatures/Test2/IntelliSense/CompletionServiceTests.vb index 9e1f22981d40e..2ba76798790a8 100644 --- a/src/EditorFeatures/Test2/IntelliSense/CompletionServiceTests.vb +++ b/src/EditorFeatures/Test2/IntelliSense/CompletionServiceTests.vb @@ -5,6 +5,7 @@ Imports System.Composition Imports Microsoft.CodeAnalysis.Completion Imports Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces +Imports Microsoft.CodeAnalysis.Host Imports Microsoft.CodeAnalysis.Host.Mef Imports Microsoft.CodeAnalysis.Options Imports Microsoft.CodeAnalysis.Text @@ -30,7 +31,7 @@ Namespace Microsoft.CodeAnalysis.Editor.UnitTests.IntelliSense Using workspace = TestWorkspace.Create(workspaceDefinition, composition:=composition) Dim document = workspace.CurrentSolution.Projects.First.Documents.First - Dim completionService = New TestCompletionService(workspace) + Dim completionService = New TestCompletionService(workspace.Services.SolutionServices) Dim list = Await completionService.GetCompletionsAsync( document, caretPosition:=0, CompletionOptions.Default, OptionValueSet.Empty, CompletionTrigger.Invoke) @@ -44,8 +45,8 @@ Namespace Microsoft.CodeAnalysis.Editor.UnitTests.IntelliSense Friend Class TestCompletionService Inherits CompletionService - Public Sub New(workspace As Workspace) - MyBase.New(workspace) + Public Sub New(services As SolutionServices) + MyBase.New(services) End Sub Public Overrides ReadOnly Property Language As String diff --git a/src/EditorFeatures/Test2/IntelliSense/CompletionServiceTests_Exclusivitiy.vb b/src/EditorFeatures/Test2/IntelliSense/CompletionServiceTests_Exclusivitiy.vb index 57bdcee036d1c..fad5cd85951c8 100644 --- a/src/EditorFeatures/Test2/IntelliSense/CompletionServiceTests_Exclusivitiy.vb +++ b/src/EditorFeatures/Test2/IntelliSense/CompletionServiceTests_Exclusivitiy.vb @@ -7,6 +7,7 @@ Imports System.Composition Imports System.Threading.Tasks Imports Microsoft.CodeAnalysis.Completion Imports Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces +Imports Microsoft.CodeAnalysis.Host Imports Microsoft.CodeAnalysis.Host.Mef Imports Microsoft.CodeAnalysis.Options Imports Microsoft.CodeAnalysis.Text @@ -37,7 +38,7 @@ Namespace Microsoft.CodeAnalysis.Editor.UnitTests.IntelliSense Using workspace = TestWorkspace.Create(workspaceDefinition, composition:=composition) Dim document = workspace.CurrentSolution.Projects.First.Documents.First - Dim completionService = New TestCompletionService(workspace) + Dim completionService = New TestCompletionService(workspace.Services.SolutionServices) Dim list = Await completionService.GetCompletionsAsync( document, caretPosition:=0, CompletionOptions.Default, OptionValueSet.Empty, CompletionTrigger.Invoke) @@ -52,8 +53,8 @@ Namespace Microsoft.CodeAnalysis.Editor.UnitTests.IntelliSense Friend Class TestCompletionService Inherits CompletionService - Public Sub New(workspace As Workspace) - MyBase.New(workspace) + Public Sub New(services As SolutionServices) + MyBase.New(services) End Sub Public Overrides ReadOnly Property Language As String diff --git a/src/EditorFeatures/Test2/IntelliSense/SignatureHelpControllerTests.vb b/src/EditorFeatures/Test2/IntelliSense/SignatureHelpControllerTests.vb index ccc475a523cd8..6fb7fa91b8aca 100644 --- a/src/EditorFeatures/Test2/IntelliSense/SignatureHelpControllerTests.vb +++ b/src/EditorFeatures/Test2/IntelliSense/SignatureHelpControllerTests.vb @@ -276,21 +276,17 @@ Namespace Microsoft.CodeAnalysis.Editor.UnitTests.IntelliSense Optional provider As ISignatureHelpProvider = Nothing, Optional waitForPresentation As Boolean = False, Optional triggerSession As Boolean = True) As Controller - Dim document As Document = - (Function() - Dim w = TestWorkspace.CreateWorkspace( - - - - - - ) - Return w.CurrentSolution.GetDocument(w.Documents.Single().Id) - End Function)() - - Dim workspace = DirectCast(document.Project.Solution.Workspace, TestWorkspace) + Dim workspace = TestWorkspace.CreateWorkspace( + + + + + + ) + Dim document = workspace.CurrentSolution.GetDocument(workspace.Documents.Single().Id) + Dim threadingContext = workspace.GetService(Of IThreadingContext) - Dim bufferFactory As ITextBufferFactoryService = DirectCast(document.Project.Solution.Workspace, TestWorkspace).GetService(Of ITextBufferFactoryService) + Dim bufferFactory As ITextBufferFactoryService = workspace.GetService(Of ITextBufferFactoryService) Dim buffer = bufferFactory.CreateTextBuffer() Dim view = CreateMockTextView(buffer) Dim asyncListener = AsynchronousOperationListenerProvider.NullListener diff --git a/src/EditorFeatures/Test2/IntelliSense/VisualBasicSignatureHelpCommandHandlerTests.vb b/src/EditorFeatures/Test2/IntelliSense/VisualBasicSignatureHelpCommandHandlerTests.vb index 0257bc75979e0..cbe2eaeb82cd0 100644 --- a/src/EditorFeatures/Test2/IntelliSense/VisualBasicSignatureHelpCommandHandlerTests.vb +++ b/src/EditorFeatures/Test2/IntelliSense/VisualBasicSignatureHelpCommandHandlerTests.vb @@ -283,7 +283,7 @@ End Class ) ' disable implicit sig help then type a trigger character -> no session should be available - state.Workspace.GetService(Of IGlobalOptionService).SetGlobalOption(New OptionKey(SignatureHelpViewOptions.ShowSignatureHelp, LanguageNames.VisualBasic), False) + state.Workspace.GetService(Of IGlobalOptionService).SetGlobalOption(New OptionKey(SignatureHelpViewOptionsStorage.ShowSignatureHelp, LanguageNames.VisualBasic), False) state.SendTypeChars("(") Await state.AssertNoSignatureHelpSession() diff --git a/src/EditorFeatures/Test2/InteractivePaste/InteractivePasteCommandHandlerTests.vb b/src/EditorFeatures/Test2/InteractivePaste/InteractivePasteCommandHandlerTests.vb index 11ee202a02739..4a7b69ee0ec57 100644 --- a/src/EditorFeatures/Test2/InteractivePaste/InteractivePasteCommandHandlerTests.vb +++ b/src/EditorFeatures/Test2/InteractivePaste/InteractivePasteCommandHandlerTests.vb @@ -9,6 +9,7 @@ Imports Microsoft.CodeAnalysis.Editor.UnitTests.Utilities Imports Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces Imports Microsoft.CodeAnalysis.Interactive Imports Microsoft.VisualStudio.InteractiveWindow +Imports Microsoft.VisualStudio.Text.Editor Imports Microsoft.VisualStudio.Text.Editor.Commanding.Commands Imports Microsoft.VisualStudio.Text.Operations @@ -110,6 +111,8 @@ Namespace Microsoft.CodeAnalysis.Editor.UnitTests.InteractivePaste Dim textView = workspace.Documents.Single().GetTextView() Dim editorOperations = workspace.GetService(Of IEditorOperationsFactoryService)().GetEditorOperations(textView) + textView.Options.GlobalOptions.SetOptionValue(DefaultOptions.IndentStyleId, IndentingStyle.Smart) + editorOperations.InsertText("line1") editorOperations.InsertNewLine() editorOperations.InsertText("line2") @@ -148,6 +151,7 @@ Namespace Microsoft.CodeAnalysis.Editor.UnitTests.InteractivePaste Dim textView = workspace.Documents.Single().GetTextView() Dim editorOperations = workspace.GetService(Of IEditorOperationsFactoryService)().GetEditorOperations(textView) + textView.Options.GlobalOptions.SetOptionValue(DefaultOptions.IndentStyleId, IndentingStyle.Smart) editorOperations.InsertText("line1") editorOperations.InsertNewLine() @@ -192,6 +196,7 @@ Namespace Microsoft.CodeAnalysis.Editor.UnitTests.InteractivePaste Dim textView = workspace.Documents.Single().GetTextView() Dim editorOperations = workspace.GetService(Of IEditorOperationsFactoryService)().GetEditorOperations(textView) + textView.Options.GlobalOptions.SetOptionValue(DefaultOptions.IndentStyleId, IndentingStyle.Smart) editorOperations.InsertNewLine() editorOperations.InsertText("line1") diff --git a/src/EditorFeatures/Test2/LanguageServices/SyntaxFactsServiceTests.vb b/src/EditorFeatures/Test2/LanguageServices/SyntaxFactsServiceTests.vb index 980d34bd3225a..1cf54f514ae46 100644 --- a/src/EditorFeatures/Test2/LanguageServices/SyntaxFactsServiceTests.vb +++ b/src/EditorFeatures/Test2/LanguageServices/SyntaxFactsServiceTests.vb @@ -5,7 +5,7 @@ Imports System.Threading Imports System.Threading.Tasks Imports Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces -Imports Microsoft.CodeAnalysis.LanguageServices +Imports Microsoft.CodeAnalysis.LanguageService Imports Microsoft.CodeAnalysis.Text Namespace Microsoft.CodeAnalysis.Editor.UnitTests.LanguageServices diff --git a/src/EditorFeatures/Test2/NavigationBar/TestHelpers.vb b/src/EditorFeatures/Test2/NavigationBar/TestHelpers.vb index 5de020bb74c8b..ac74f95348fa3 100644 --- a/src/EditorFeatures/Test2/NavigationBar/TestHelpers.vb +++ b/src/EditorFeatures/Test2/NavigationBar/TestHelpers.vb @@ -10,7 +10,7 @@ Imports Microsoft.CodeAnalysis.Editor.Implementation.NavigationBar Imports Microsoft.CodeAnalysis.Editor.UnitTests.Extensions Imports Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces Imports Microsoft.CodeAnalysis.Editor.VisualBasic.NavigationBar -Imports Microsoft.CodeAnalysis.LanguageServices +Imports Microsoft.CodeAnalysis.LanguageService Imports Microsoft.CodeAnalysis.NavigationBar Imports Microsoft.CodeAnalysis.Remote.Testing Imports Microsoft.CodeAnalysis.Text @@ -38,7 +38,8 @@ Namespace Microsoft.CodeAnalysis.Editor.UnitTests.NavigationBar Dim snapshot = (Await document.GetTextAsync()).FindCorrespondingEditorTextSnapshot() Dim service = document.GetLanguageService(Of INavigationBarItemService)() - Dim actualItems = Await service.GetItemsAsync(document, forceFrozenPartialSemanticsForCrossProcessOperations:=False, snapshot.Version, Nothing) + Dim actualItems = Await service.GetItemsAsync( + document, workspaceSupportsDocumentChanges:=True, forceFrozenPartialSemanticsForCrossProcessOperations:=False, snapshot.Version, Nothing) AssertEqual(expectedItems, actualItems, document.GetLanguageService(Of ISyntaxFactsService)().IsCaseSensitive) End Using @@ -56,7 +57,8 @@ Namespace Microsoft.CodeAnalysis.Editor.UnitTests.NavigationBar Dim snapshot = (Await document.GetTextAsync()).FindCorrespondingEditorTextSnapshot() Dim service = document.GetLanguageService(Of INavigationBarItemService)() - Dim items = Await service.GetItemsAsync(document, forceFrozenPartialSemanticsForCrossProcessOperations:=False, snapshot.Version, Nothing) + Dim items = Await service.GetItemsAsync( + document, workspaceSupportsDocumentChanges:=True, forceFrozenPartialSemanticsForCrossProcessOperations:=False, snapshot.Version, Nothing) Dim hostDocument = workspace.Documents.Single(Function(d) d.CursorPosition.HasValue) Dim model As New NavigationBarModel(service, items) @@ -89,7 +91,8 @@ Namespace Microsoft.CodeAnalysis.Editor.UnitTests.NavigationBar Dim service = document.GetLanguageService(Of INavigationBarItemService)() - Dim items = Await service.GetItemsAsync(document, forceFrozenPartialSemanticsForCrossProcessOperations:=False, snapshot.Version, Nothing) + Dim items = Await service.GetItemsAsync( + document, workspaceSupportsDocumentChanges:=True, forceFrozenPartialSemanticsForCrossProcessOperations:=False, snapshot.Version, Nothing) Dim leftItem = items.Single(Function(i) i.Text = leftItemToSelectText) Dim rightItem = selectRightItem(leftItem.ChildItems) @@ -117,7 +120,8 @@ Namespace Microsoft.CodeAnalysis.Editor.UnitTests.NavigationBar Dim snapshot = (Await sourceDocument.GetTextAsync()).FindCorrespondingEditorTextSnapshot() Dim service = DirectCast(sourceDocument.GetLanguageService(Of INavigationBarItemService)(), AbstractEditorNavigationBarItemService) - Dim items = Await service.GetItemsAsync(sourceDocument, forceFrozenPartialSemanticsForCrossProcessOperations:=False, snapshot.Version, Nothing) + Dim items = Await service.GetItemsAsync( + sourceDocument, workspaceSupportsDocumentChanges:=True, forceFrozenPartialSemanticsForCrossProcessOperations:=False, snapshot.Version, Nothing) Dim leftItem = items.Single(Function(i) i.Text = leftItemToSelectText) Dim rightItem = leftItem.ChildItems.Single(Function(i) i.Text = rightItemToSelectText) diff --git a/src/EditorFeatures/Test2/Rename/InlineRenameTests.vb b/src/EditorFeatures/Test2/Rename/InlineRenameTests.vb index ba8115be3ea92..dae2380b1ef14 100644 --- a/src/EditorFeatures/Test2/Rename/InlineRenameTests.vb +++ b/src/EditorFeatures/Test2/Rename/InlineRenameTests.vb @@ -54,7 +54,7 @@ Namespace Microsoft.CodeAnalysis.Editor.UnitTests.Rename session.Commit() - Await VerifyTagsAreCorrect(workspace, "BarTest1") + Await VerifyTagsAreCorrect(workspace) VerifyFileName(workspace, "BarTest1") End Using End Function @@ -82,7 +82,7 @@ Namespace Microsoft.CodeAnalysis.Editor.UnitTests.Rename session.Commit() - Await VerifyTagsAreCorrect(workspace, "renamedtest") + Await VerifyTagsAreCorrect(workspace) End Using End Function @@ -136,7 +136,7 @@ class [|Test1$$|] textBuffer.Insert(selectedSpan, "<>") session.Commit() - Await VerifyTagsAreCorrect(workspace, "Test1<>") + Await VerifyTagsAreCorrect(workspace) VerifyFileName(workspace, "Test1") End Using End Function @@ -227,11 +227,11 @@ class Deconstructable Await WaitForRename(workspace) - Await VerifyTagsAreCorrect(workspace, "BarTest1") + Await VerifyTagsAreCorrect(workspace) session.Commit() - Await VerifyTagsAreCorrect(workspace, "BarTest1") + Await VerifyTagsAreCorrect(workspace) VerifyFileName(workspace, "BarTest1") End Using End Function @@ -260,11 +260,11 @@ class Deconstructable Dim replacementText = renameTextPrefix + originalTextToRename Await WaitForRename(workspace) - Await VerifyTagsAreCorrect(workspace, replacementText) + Await VerifyTagsAreCorrect(workspace) session.Commit() - Await VerifyTagsAreCorrect(workspace, replacementText) + Await VerifyTagsAreCorrect(workspace) If renameFile Then If fileToRename Is Nothing Then @@ -788,7 +788,7 @@ End Class session.Commit() - Await VerifyTagsAreCorrect(workspace, "goodynamic") + Await VerifyTagsAreCorrect(workspace) End Using End Function @@ -916,11 +916,11 @@ End Class textBuffer.Insert(caretPosition, "Bar") Await WaitForRename(workspace) - Await VerifyTagsAreCorrect(workspace, "BarTest1") + Await VerifyTagsAreCorrect(workspace) Await VerifyNoRenameTrackingTags(renameTrackingTagger, workspace, document) session.Commit() - Await VerifyTagsAreCorrect(workspace, "BarTest1") + Await VerifyTagsAreCorrect(workspace) VerifyFileName(workspace, "BarTest1") End Using End Function @@ -950,11 +950,11 @@ End Class textBuffer.Insert(caretPosition, "Bar") Await WaitForRename(workspace) - Await VerifyTagsAreCorrect(workspace, "BarTest1") + Await VerifyTagsAreCorrect(workspace) Await VerifyNoRenameTrackingTags(renameTrackingTagger, workspace, document) session.Commit() - Await VerifyTagsAreCorrect(workspace, "BarTest1") + Await VerifyTagsAreCorrect(workspace) VerifyFileName(workspace, "BarTest1") End Using End Function @@ -988,10 +988,10 @@ End Class textBuffer.Insert(caretPosition, "Bar") Await WaitForRename(workspace) - Await VerifyTagsAreCorrect(workspace, "BarTest1") + Await VerifyTagsAreCorrect(workspace) session.Commit() - Await VerifyTagsAreCorrect(workspace, "BarTest1") + Await VerifyTagsAreCorrect(workspace) Await VerifyNoRenameTrackingTags(renameTrackingTagger, workspace, document) VerifyFileName(workspace, "BarTest1") End Using @@ -1026,7 +1026,7 @@ End Class textBuffer.Insert(caretPosition, "Bar") Await WaitForRename(workspace) - Await VerifyTagsAreCorrect(workspace, "BarGoo") + Await VerifyTagsAreCorrect(workspace) session.Cancel() Await VerifyNoRenameTrackingTags(renameTrackingTagger, workspace, document) @@ -1063,10 +1063,10 @@ End Class textBuffer.Insert(caretPosition, "Bar") Await WaitForRename(workspace) - Await VerifyTagsAreCorrect(workspace, "BarTest1") + Await VerifyTagsAreCorrect(workspace) session.Commit() - Await VerifyTagsAreCorrect(workspace, "BarTest1") + Await VerifyTagsAreCorrect(workspace) Await VerifyNoRenameTrackingTags(renameTrackingTagger, workspace, document) VerifyFileName(workspace, "BarTest1") @@ -1106,7 +1106,7 @@ End Class session.Commit(previewChanges:=True) - Await VerifyTagsAreCorrect(workspace, "BarGoo") + Await VerifyTagsAreCorrect(workspace) Assert.True(previewService.Called) Assert.Equal(String.Format(EditorFeaturesResources.Preview_Changes_0, EditorFeaturesResources.Rename), previewService.Title) Assert.Equal(String.Format(EditorFeaturesResources.Rename_0_to_1_colon, "Goo", "BarGoo"), previewService.Description) @@ -1137,28 +1137,20 @@ End Class previewService.ReturnsNull = True Dim session = StartSession(workspace) - ' Type a bit in the file - Dim caretPosition = workspace.Documents.Single(Function(d) d.CursorPosition.HasValue).CursorPosition.Value - Dim textBuffer = workspace.Documents.Single().GetTextBuffer() - - textBuffer.Insert(caretPosition, "Bar") - + session.ApplyReplacementText("BarGoo", propagateEditImmediately:=True) session.Commit(previewChanges:=True) - Await VerifyTagsAreCorrect(workspace, "BarGoo") + Await VerifyTagsAreCorrect(workspace) Assert.True(previewService.Called) - ' Session should still be up; type some more - caretPosition = workspace.Documents.Single(Function(d) d.CursorPosition.HasValue).CursorPosition.Value - textBuffer.Insert(caretPosition, "Cat") + ' Session should still be up + session.ApplyReplacementText("CatBarGoo", propagateEditImmediately:=True) previewService.ReturnsNull = False previewService.Called = False session.Commit(previewChanges:=True) - Await VerifyTagsAreCorrect(workspace, "CatBarGoo") + Await VerifyTagsAreCorrect(workspace) Assert.True(previewService.Called) - - VerifyFileName(workspace, "Test1.cs") End Using End Function @@ -1197,14 +1189,14 @@ End Class textBuffer.Insert(caretPosition, "o") Await WaitForRename(workspace) - Await VerifyTagsAreCorrect(workspace, "Mo") + Await VerifyTagsAreCorrect(workspace) textBuffer.Insert(caretPosition + 1, "w") Await WaitForRename(workspace) - Await VerifyTagsAreCorrect(workspace, "Mow") + Await VerifyTagsAreCorrect(workspace) session.Commit() - Await VerifyTagsAreCorrect(workspace, "Mow") + Await VerifyTagsAreCorrect(workspace) End Using End Function @@ -1242,14 +1234,14 @@ End Class textBuffer.Insert(caretPosition, "a") Await WaitForRename(workspace) - Await VerifyTagsAreCorrect(workspace, "ma") + Await VerifyTagsAreCorrect(workspace) textBuffer.Insert(caretPosition + 1, "w") Await WaitForRename(workspace) - Await VerifyTagsAreCorrect(workspace, "maw") + Await VerifyTagsAreCorrect(workspace) session.Commit() - Await VerifyTagsAreCorrect(workspace, "maw") + Await VerifyTagsAreCorrect(workspace) End Using End Function @@ -1303,6 +1295,7 @@ class C Await editHandler.ApplyAsync( workspace, + workspace.CurrentSolution, workspace.CurrentSolution.GetDocument(workspace.Documents.Single().Id), Await actions.First().NestedCodeActions.First().GetOperationsAsync(CancellationToken.None), "unused", @@ -1325,11 +1318,11 @@ class C textBuffer.CurrentSnapshot.GetText()) ' Rename should still be active - Await VerifyTagsAreCorrect(workspace, "xyz") + Await VerifyTagsAreCorrect(workspace) textBuffer.Insert(caretPosition + 2, "q") Await WaitForRename(workspace) - Await VerifyTagsAreCorrect(workspace, "xyzq") + Await VerifyTagsAreCorrect(workspace) End Using End Function @@ -1358,10 +1351,10 @@ class C textBuffer.Insert(caretPosition, "a") Await WaitForRename(workspace) - Await VerifyTagsAreCorrect(workspace, "Ma") + Await VerifyTagsAreCorrect(workspace) session.Commit() - Await VerifyTagsAreCorrect(workspace, "Ma") + Await VerifyTagsAreCorrect(workspace) End Using End Function @@ -1390,10 +1383,10 @@ class C textBuffer.Insert(caretPosition, "a") Await WaitForRename(workspace) - Await VerifyTagsAreCorrect(workspace, "Ma") + Await VerifyTagsAreCorrect(workspace) session.Commit() - Await VerifyTagsAreCorrect(workspace, "Ma") + Await VerifyTagsAreCorrect(workspace) End Using End Function @@ -1424,10 +1417,10 @@ class C textBuffer.Insert(caretPosition, "a") Await WaitForRename(workspace) - Await VerifyTagsAreCorrect(workspace, "Ma") + Await VerifyTagsAreCorrect(workspace) session.Commit() - Await VerifyTagsAreCorrect(workspace, "Ma") + Await VerifyTagsAreCorrect(workspace) End Using End Function @@ -1458,10 +1451,10 @@ class C textBuffer.Insert(caretPosition, "a") Await WaitForRename(workspace) - Await VerifyTagsAreCorrect(workspace, "Ma") + Await VerifyTagsAreCorrect(workspace) session.Commit() - Await VerifyTagsAreCorrect(workspace, "Ma") + Await VerifyTagsAreCorrect(workspace) End Using End Function @@ -1521,7 +1514,7 @@ End Module textBuffer.Insert(caretPosition, "q") session.Commit() - Await VerifyTagsAreCorrect(workspace, "qp") + Await VerifyTagsAreCorrect(workspace) End Using End Function @@ -1551,7 +1544,7 @@ End Module session.Commit() - Await VerifyTagsAreCorrect(workspace, "x") + Await VerifyTagsAreCorrect(workspace) End Using End Function @@ -1595,7 +1588,7 @@ End Class session.Commit() - Await VerifyTagsAreCorrect(workspace, "xield1") + Await VerifyTagsAreCorrect(workspace) End Using End Function @@ -1896,7 +1889,7 @@ class [|$$Test1|] Dim committed = session.GetTestAccessor().CommitWorker(previewChanges:=False) Assert.False(committed) - Await VerifyTagsAreCorrect(workspace, "Test1") + Await VerifyTagsAreCorrect(workspace) End Using End Function @@ -1980,7 +1973,7 @@ class [|C|] session.Commit() - Await VerifyTagsAreCorrect(workspace, "BarGoo") + Await VerifyTagsAreCorrect(workspace) End Using End Function @@ -2010,7 +2003,7 @@ class [|C|] session.Commit() - Await VerifyTagsAreCorrect(workspace, "BarGoo") + Await VerifyTagsAreCorrect(workspace) End Using End Function @@ -2040,7 +2033,7 @@ class [|C|] session.Commit() - Await VerifyTagsAreCorrect(workspace, "BarGoo") + Await VerifyTagsAreCorrect(workspace) End Using End Function @@ -2075,7 +2068,7 @@ class [|C|] session.Commit() - Await VerifyTagsAreCorrect(workspace, "BarGoo") + Await VerifyTagsAreCorrect(workspace) End Using End Function @@ -2106,7 +2099,7 @@ class [|C|] session.Commit() - Await VerifyTagsAreCorrect(workspace, "Example") + Await VerifyTagsAreCorrect(workspace) End Using End Function diff --git a/src/EditorFeatures/Test2/Rename/RenameCommandHandlerTests.vb b/src/EditorFeatures/Test2/Rename/RenameCommandHandlerTests.vb index 89b402dda2697..1fdacf760ef53 100644 --- a/src/EditorFeatures/Test2/Rename/RenameCommandHandlerTests.vb +++ b/src/EditorFeatures/Test2/Rename/RenameCommandHandlerTests.vb @@ -3,9 +3,11 @@ ' See the LICENSE file in the project root for more information. Imports Microsoft.CodeAnalysis.Editor.Implementation.InlineRename +Imports Microsoft.CodeAnalysis.Editor.InlineRename Imports Microsoft.CodeAnalysis.Editor.Shared.Extensions Imports Microsoft.CodeAnalysis.Editor.UnitTests.Extensions Imports Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces +Imports Microsoft.CodeAnalysis.Options Imports Microsoft.CodeAnalysis.Text.Shared.Extensions Imports Microsoft.VisualStudio.Commanding Imports Microsoft.VisualStudio.Text @@ -143,6 +145,9 @@ End Class , host) Dim view = workspace.Documents.Single().GetTextView() + + view.Options.GlobalOptions.SetOptionValue(DefaultOptions.IndentStyleId, IndentingStyle.Smart) + view.Caret.MoveTo(New SnapshotPoint(view.TextBuffer.CurrentSnapshot, workspace.Documents.Single(Function(d) d.CursorPosition.HasValue).CursorPosition.Value)) Dim commandHandler = CreateCommandHandler(workspace) @@ -227,6 +232,11 @@ End Class , host) + ' This test specifically matters for the case where a user is typing in the editor + ' and is not intended to test the rename flyout tab behavior + Dim optionsService = workspace.GetService(Of IGlobalOptionService)() + optionsService.SetGlobalOption(New OptionKey(InlineRenameUIOptions.UseInlineAdornment), False) + Dim view = workspace.Documents.Single().GetTextView() view.Caret.MoveTo(New SnapshotPoint(view.TextBuffer.CurrentSnapshot, workspace.Documents.Single(Function(d) d.CursorPosition.HasValue).CursorPosition.Value)) @@ -326,7 +336,7 @@ class [|$$Goo|] // comment commandHandler.ExecuteCommand(New WordDeleteToEndCommandArgs(view, view.TextBuffer), Sub() AssertEx.Fail("Command should not have been passed to the editor."), Utilities.TestCommandExecutionContext.Create()) - Await VerifyTagsAreCorrect(workspace, "") + Await VerifyTagsAreCorrect(workspace) editorOperations.InsertText("this") Await WaitForRename(workspace) @@ -339,7 +349,7 @@ class [|$$Goo|] // comment commandHandler.ExecuteCommand(New WordDeleteToStartCommandArgs(view, view.TextBuffer), Sub() AssertEx.Fail("Command should not have been passed to the editor."), Utilities.TestCommandExecutionContext.Create()) - Await VerifyTagsAreCorrect(workspace, "s") + Await VerifyTagsAreCorrect(workspace) End Using End Function @@ -469,7 +479,7 @@ Goo f; Sub() editorOperations.InsertText("$"), Utilities.TestCommandExecutionContext.Create()) - Await VerifyTagsAreCorrect(workspace, "Goo") + Await VerifyTagsAreCorrect(workspace) session.Cancel() End Using @@ -515,7 +525,7 @@ Goo f; Sub() editorOperations.InsertText("Z"), Utilities.TestCommandExecutionContext.Create()) - Await VerifyTagsAreCorrect(workspace, "BGoo") + Await VerifyTagsAreCorrect(workspace) ' Rename session was indeed committed and is no longer active Assert.Null(workspace.GetService(Of IInlineRenameService).ActiveSession) @@ -556,7 +566,7 @@ Goo f; Sub() editorOperations.Delete(), Utilities.TestCommandExecutionContext.Create()) - Await VerifyTagsAreCorrect(workspace, "oo") + Await VerifyTagsAreCorrect(workspace) Assert.NotNull(workspace.GetService(Of IInlineRenameService).ActiveSession) session.Cancel() @@ -594,7 +604,7 @@ Goo f; Sub() editorOperations.Backspace(), Utilities.TestCommandExecutionContext.Create()) - Await VerifyTagsAreCorrect(workspace, "Go") + Await VerifyTagsAreCorrect(workspace) Assert.NotNull(workspace.GetService(Of IInlineRenameService).ActiveSession) session.Cancel() @@ -641,7 +651,7 @@ Goo f; Sub() editorOperations.Delete(), Utilities.TestCommandExecutionContext.Create()) - Await VerifyTagsAreCorrect(workspace, "BGoo") + Await VerifyTagsAreCorrect(workspace) ' Rename session was indeed committed and is no longer active Assert.Null(workspace.GetService(Of IInlineRenameService).ActiveSession) @@ -695,7 +705,7 @@ Goo f; Sub() editorOperations.InsertText("Z"), Utilities.TestCommandExecutionContext.Create()) - Await VerifyTagsAreCorrect(workspace, "BGoo") + Await VerifyTagsAreCorrect(workspace) ' Rename session was indeed committed and is no longer active Assert.Null(workspace.GetService(Of IInlineRenameService).ActiveSession) @@ -760,7 +770,7 @@ Goo f; Sub() editorOperations.InsertText("Z"), Utilities.TestCommandExecutionContext.Create()) - Await VerifyTagsAreCorrect(workspace, "BB") + Await VerifyTagsAreCorrect(workspace) ' Rename session was indeed committed and is no longer active Assert.Null(workspace.GetService(Of IInlineRenameService).ActiveSession) @@ -801,7 +811,7 @@ class Program commandHandler.ExecuteCommand(New TypeCharCommandArgs(view, view.TextBuffer, "Z"c), Sub() editorOperations.InsertText("Z"), Utilities.TestCommandExecutionContext.Create()) commandHandler.ExecuteCommand(New ReturnKeyCommandArgs(view, view.TextBuffer), Sub() Exit Sub, Utilities.TestCommandExecutionContext.Create()) - Await VerifyTagsAreCorrect(workspace, "Z") + Await VerifyTagsAreCorrect(workspace) End Using End Function @@ -842,7 +852,7 @@ partial class [|Program|] Sub() editorOperations.InsertText("Z"), Utilities.TestCommandExecutionContext.Create()) - Await VerifyTagsAreCorrect(workspace, "Z") + Await VerifyTagsAreCorrect(workspace) End Using End Function @@ -1061,7 +1071,7 @@ partial class [|Program|] ' Now save the document, which should commit Rename commandHandler.ExecuteCommand(New SaveCommandArgs(view, view.TextBuffer), Sub() Exit Sub, Utilities.TestCommandExecutionContext.Create()) - Await VerifyTagsAreCorrect(workspace, "BGoo") + Await VerifyTagsAreCorrect(workspace) ' Rename session was indeed committed and is no longer active Assert.Null(workspace.GetService(Of IInlineRenameService).ActiveSession) @@ -1244,7 +1254,7 @@ class [|C$$|] ' Verify rename session is still active Assert.NotNull(workspace.GetService(Of IInlineRenameService).ActiveSession) - Await VerifyTagsAreCorrect(workspace, commandInvokedString) + Await VerifyTagsAreCorrect(workspace) End Using End Function diff --git a/src/EditorFeatures/Test2/Rename/RenameEngineResult.vb b/src/EditorFeatures/Test2/Rename/RenameEngineResult.vb index 204737337cf56..b672d5e1ec86b 100644 --- a/src/EditorFeatures/Test2/Rename/RenameEngineResult.vb +++ b/src/EditorFeatures/Test2/Rename/RenameEngineResult.vb @@ -81,7 +81,7 @@ Namespace Microsoft.CodeAnalysis.Editor.UnitTests.Rename Dim document = workspace.CurrentSolution.GetDocument(cursorDocument.Id) - Dim symbol = RenameLocations.ReferenceProcessing.TryGetRenamableSymbolAsync(document, cursorPosition, CancellationToken.None).Result + Dim symbol = RenameUtilities.TryGetRenamableSymbolAsync(document, cursorPosition, CancellationToken.None).Result If symbol Is Nothing Then AssertEx.Fail("The symbol touching the $$ could not be found.") End If @@ -89,6 +89,7 @@ Namespace Microsoft.CodeAnalysis.Editor.UnitTests.Rename Dim result = GetConflictResolution(renameTo, workspace.CurrentSolution, symbol, renameOptions, host) If expectFailure Then + Assert.False(result.IsSuccessful) Assert.NotNull(result.ErrorMessage) Return engineResult Else @@ -126,14 +127,14 @@ Namespace Microsoft.CodeAnalysis.Editor.UnitTests.Rename Dim locations = Renamer.FindRenameLocationsAsync( solution, symbol, renameOptions, CodeActionOptions.DefaultProvider, CancellationToken.None).GetAwaiter().GetResult() - Return locations.ResolveConflictsAsync(renameTo, nonConflictSymbols:=Nothing, cancellationToken:=CancellationToken.None).GetAwaiter().GetResult() + Return locations.ResolveConflictsAsync(symbol, renameTo, nonConflictSymbolKeys:=Nothing, CancellationToken.None).GetAwaiter().GetResult() Else ' This tests that rename properly works when the entire call is remoted to OOP and the final result is ' marshaled back. Return Renamer.RenameSymbolAsync( solution, symbol, renameTo, renameOptions, CodeActionOptions.DefaultProvider, - nonConflictSymbols:=Nothing, CancellationToken.None).GetAwaiter().GetResult() + nonConflictSymbolKeys:=Nothing, CancellationToken.None).GetAwaiter().GetResult() End If End Function diff --git a/src/EditorFeatures/Test2/Rename/RenameTestHelpers.vb b/src/EditorFeatures/Test2/Rename/RenameTestHelpers.vb index afa6431bae7dc..a7e3d04ef9444 100644 --- a/src/EditorFeatures/Test2/Rename/RenameTestHelpers.vb +++ b/src/EditorFeatures/Test2/Rename/RenameTestHelpers.vb @@ -68,15 +68,8 @@ Namespace Microsoft.CodeAnalysis.Editor.UnitTests.Rename Assert.NotNull(result.LocalizedErrorMessage) End Sub - Public Async Function VerifyTagsAreCorrect(workspace As TestWorkspace, newIdentifierName As String) As Task + Public Async Function VerifyTagsAreCorrect(workspace As TestWorkspace) As Task Await WaitForRename(workspace) - For Each document In workspace.Documents - For Each selectedSpan In document.SelectedSpans - Dim trackingSpan = document.InitialTextSnapshot.CreateTrackingSpan(selectedSpan.ToSpan(), SpanTrackingMode.EdgeInclusive) - Assert.Equal(newIdentifierName, trackingSpan.GetText(document.GetTextBuffer().CurrentSnapshot).Trim) - Next - Next - For Each document In workspace.Documents For Each annotations In document.AnnotatedSpans Dim expectedReplacementText = annotations.Key diff --git a/src/EditorFeatures/Test2/Rename/DashboardTests.vb b/src/EditorFeatures/Test2/Rename/RenameViewModelTests.vb similarity index 94% rename from src/EditorFeatures/Test2/Rename/DashboardTests.vb rename to src/EditorFeatures/Test2/Rename/RenameViewModelTests.vb index 6a1906fa21596..3acca4ab4fffe 100644 --- a/src/EditorFeatures/Test2/Rename/DashboardTests.vb +++ b/src/EditorFeatures/Test2/Rename/RenameViewModelTests.vb @@ -11,11 +11,11 @@ Imports Microsoft.CodeAnalysis.Rename Namespace Microsoft.CodeAnalysis.Editor.UnitTests.Rename <[UseExportProvider]> - Public Class DashboardTests + Public Class RenameViewModelTests Public Async Function RenameWithNoOverload(host As RenameTestHost) As Task - Await VerifyDashboard( + Await VerifyViewModels( ( @@ -41,7 +41,7 @@ Namespace Microsoft.CodeAnalysis.Editor.UnitTests.Rename Public Async Function RenameWithOverload(host As RenameTestHost) As Task - Await VerifyDashboard( + Await VerifyViewModels( ( @@ -73,7 +73,7 @@ Namespace Microsoft.CodeAnalysis.Editor.UnitTests.Rename Public Async Function RenameWithInvalidOverload(host As RenameTestHost) As Task - Await VerifyDashboard( + Await VerifyViewModels( @@ -103,7 +103,7 @@ class Program Public Async Function RenameAttributeAlias(host As RenameTestHost) As Task - Await VerifyDashboard( + Await VerifyViewModels( ( @@ -123,7 +123,7 @@ class AttributeAttribute : System.Attribute { } Public Async Function RenameWithOverloadAndInStringsAndComments(host As RenameTestHost) As Task - Await VerifyDashboard( + Await VerifyViewModels( ( @@ -160,7 +160,7 @@ class AttributeAttribute : System.Attribute { } Public Async Function RenameInComments(host As RenameTestHost) As Task - Await VerifyDashboard( + Await VerifyViewModels( ( @@ -198,7 +198,7 @@ class $$Program Public Async Function RenameInStrings(host As RenameTestHost) As Task - Await VerifyDashboard( + Await VerifyViewModels( ( @@ -236,7 +236,7 @@ class $$Program Public Async Function RenameInCommentsAndStrings(host As RenameTestHost) As Task - Await VerifyDashboard( + Await VerifyViewModels( ( @@ -274,7 +274,7 @@ class $$Program Public Async Function NonConflictingEditWithMultipleLocations(host As RenameTestHost) As Task - Await VerifyDashboard( + Await VerifyViewModels( ( @@ -295,7 +295,7 @@ class $$Program Public Async Function NonConflictingEditWithSingleLocation(host As RenameTestHost) As Task - Await VerifyDashboard( + Await VerifyViewModels( ( @@ -316,7 +316,7 @@ class $$Program Public Async Function ParameterConflictingWithInstanceField(host As RenameTestHost) As Task - Await VerifyDashboard( + Await VerifyViewModels( ( @@ -341,7 +341,7 @@ class $$Program Public Async Function ParameterConflictingWithInstanceFieldMoreThanOnce(host As RenameTestHost) As Task - Await VerifyDashboard( + Await VerifyViewModels( ( @@ -365,7 +365,7 @@ class $$Program Public Async Function ParameterConflictingWithLocal_Unresolvable(host As RenameTestHost) As Task - Await VerifyDashboard( + Await VerifyViewModels( ( @@ -388,7 +388,7 @@ class $$Program Public Async Function MoreThanOneUnresolvableConflicts(host As RenameTestHost) As Task - Await VerifyDashboard( + Await VerifyViewModels( ( @@ -413,7 +413,7 @@ class $$Program Public Async Function ConflictsAcrossLanguages_Resolvable(host As RenameTestHost) As Task - Await VerifyDashboard( + Await VerifyViewModels( ( @@ -450,7 +450,7 @@ class $$Program Public Async Function RenameWithNameof_FromDefinition_DoesNotForceRenameOverloadsOption(host As RenameTestHost) As Task - Await VerifyDashboard( + Await VerifyViewModels( ( @@ -474,7 +474,7 @@ class C Public Async Function RenameWithNameof_FromReference_DoesForceRenameOverloadsOption(host As RenameTestHost) As Task - Await VerifyDashboard( + Await VerifyViewModels( ( @@ -498,7 +498,7 @@ class C Public Async Function RenameWithNameof_FromDefinition_WithRenameOverloads_Cascading(host As RenameTestHost) As Task - Await VerifyDashboard( + Await VerifyViewModels( ( @@ -530,7 +530,7 @@ class D : B hasRenameOverload:=True) End Function - Friend Shared Async Function VerifyDashboard( + Friend Shared Async Function VerifyViewModels( test As XElement, newName As String, searchResultText As String, @@ -613,6 +613,22 @@ class D : B Assert.Equal(severity, model.Severity) End Using + Using flyout = New RenameFlyout( + New RenameFlyoutViewModel(DirectCast(sessionInfo.Session, InlineRenameSession), selectionSpan:=Nothing, registerOleComponent:=False), ' Don't registerOleComponent in tests, it requires OleComponentManagers that don't exist in our host + textView:=cursorDocument.GetTextView()) + + Await WaitForRename(workspace) + + Dim model = DirectCast(flyout.DataContext, RenameFlyoutViewModel) + + Assert.Equal(hasRenameOverload, model.Session.HasRenameOverloads) + Assert.Equal(hasRenameOverload, model.IsRenameOverloadsVisible) + Assert.Equal(isRenameOverloadsEditable, model.IsRenameOverloadsEditable) + If Not isRenameOverloadsEditable Then + Assert.True(model.RenameOverloadsFlag) + End If + End Using + sessionInfo.Session.Cancel() End Using End Function @@ -620,7 +636,7 @@ class D : B Public Async Function RenameWithReferenceInUnchangeableDocument(host As RenameTestHost) As Task - Await VerifyDashboard( + Await VerifyViewModels( ( diff --git a/src/EditorFeatures/Test2/Simplification/AbstractSimplificationTests.vb b/src/EditorFeatures/Test2/Simplification/AbstractSimplificationTests.vb index 6e604bb4e1624..82bba15dcf661 100644 --- a/src/EditorFeatures/Test2/Simplification/AbstractSimplificationTests.vb +++ b/src/EditorFeatures/Test2/Simplification/AbstractSimplificationTests.vb @@ -5,6 +5,7 @@ Imports System.Collections.Immutable Imports Microsoft.CodeAnalysis Imports Microsoft.CodeAnalysis.CSharp +Imports Microsoft.CodeAnalysis.Editor.UnitTests.CodeActions Imports Microsoft.CodeAnalysis.Editor.UnitTests.Extensions Imports Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces Imports Microsoft.CodeAnalysis.Options @@ -16,7 +17,7 @@ Namespace Microsoft.CodeAnalysis.Editor.UnitTests.Simplification <[UseExportProvider]> Public MustInherit Class AbstractSimplificationTests - Private Protected Shared Async Function TestAsync(definition As XElement, expected As XElement, Optional options As Dictionary(Of OptionKey2, Object) = Nothing, Optional csharpParseOptions As CSharpParseOptions = Nothing) As System.Threading.Tasks.Task + Private Protected Shared Async Function TestAsync(definition As XElement, expected As XElement, Optional options As OptionsCollection = Nothing, Optional csharpParseOptions As CSharpParseOptions = Nothing) As System.Threading.Tasks.Task Using workspace = CreateTestWorkspace(definition, csharpParseOptions) Dim simplifiedDocument = Await SimplifyAsync(workspace, options).ConfigureAwait(False) Await AssertCodeEqual(expected, simplifiedDocument) @@ -35,11 +36,11 @@ Namespace Microsoft.CodeAnalysis.Editor.UnitTests.Simplification Return workspace End Function - Protected Shared Function SimplifyAsync(workspace As TestWorkspace) As System.Threading.Tasks.Task(Of Document) + Protected Shared Function SimplifyAsync(workspace As TestWorkspace) As Task(Of Document) Return SimplifyAsync(workspace, Nothing) End Function - Private Shared Async Function SimplifyAsync(workspace As TestWorkspace, options As Dictionary(Of OptionKey2, Object)) As System.Threading.Tasks.Task(Of Document) + Private Shared Async Function SimplifyAsync(workspace As TestWorkspace, options As OptionsCollection) As Task(Of Document) Dim hostDocument = workspace.Documents.Single() Dim spansToAddSimplifierAnnotation = hostDocument.AnnotatedSpans.Where(Function(kvp) kvp.Key.StartsWith("Simplify", StringComparison.Ordinal)) @@ -60,10 +61,12 @@ Namespace Microsoft.CodeAnalysis.Editor.UnitTests.Simplification Return Await SimplifyAsync(workspace, spansToAddSimplifierAnnotation, explicitSpansToSimplifyWithin, options) End Function - Private Shared Async Function SimplifyAsync(workspace As Workspace, - listOfLabelToAddSimplifierAnnotationSpans As IEnumerable(Of KeyValuePair(Of String, ImmutableArray(Of TextSpan))), - explicitSpansToSimplifyWithin As ImmutableArray(Of TextSpan), - options As Dictionary(Of OptionKey2, Object)) As Task(Of Document) + Private Shared Async Function SimplifyAsync( + workspace As TestWorkspace, + listOfLabelToAddSimplifierAnnotationSpans As IEnumerable(Of KeyValuePair(Of String, ImmutableArray(Of TextSpan))), + explicitSpansToSimplifyWithin As ImmutableArray(Of TextSpan), + options As OptionsCollection) As Task(Of Document) + Dim document = workspace.CurrentSolution.Projects.Single().Documents.Single() Dim root = Await document.GetSyntaxRootAsync() @@ -105,16 +108,12 @@ Namespace Microsoft.CodeAnalysis.Editor.UnitTests.Simplification End Select Next - Dim optionSet = workspace.Options - If options IsNot Nothing Then - For Each entry In options - optionSet = optionSet.WithChangedOption(entry.Key, entry.Value) - Next - End If + options?.SetGlobalOptions(workspace.GlobalOptions) document = document.WithSyntaxRoot(root) #Disable Warning RS0030 ' Do Not used banned APIs + Dim optionSet = options?.ToOptionSet() Dim simplifiedDocument As Document If Not explicitSpansToSimplifyWithin.IsDefaultOrEmpty Then simplifiedDocument = Await Simplifier.ReduceAsync(document, explicitSpansToSimplifyWithin, optionSet) diff --git a/src/EditorFeatures/Test2/Simplification/BlockSimplificationTests.vb b/src/EditorFeatures/Test2/Simplification/BlockSimplificationTests.vb index 90fc0be533c87..b674f4d52aa79 100644 --- a/src/EditorFeatures/Test2/Simplification/BlockSimplificationTests.vb +++ b/src/EditorFeatures/Test2/Simplification/BlockSimplificationTests.vb @@ -4,13 +4,17 @@ Imports Microsoft.CodeAnalysis.CodeStyle Imports Microsoft.CodeAnalysis.CSharp.CodeStyle +Imports Microsoft.CodeAnalysis.Editor.UnitTests.CodeActions Imports Microsoft.CodeAnalysis.Options Namespace Microsoft.CodeAnalysis.Editor.UnitTests.Simplification Public Class SimplificationTests Inherits AbstractSimplificationTests - Private Shared ReadOnly DoNotPreferBraces As Dictionary(Of OptionKey2, Object) = New Dictionary(Of OptionKey2, Object) From {{New OptionKey2(CSharpCodeStyleOptions.PreferBraces), New CodeStyleOption2(Of PreferBracesPreference)(PreferBracesPreference.None, NotificationOption2.Silent)}} + Private Shared ReadOnly DoNotPreferBraces As New OptionsCollection(LanguageNames.VisualBasic) From + { + {CSharpCodeStyleOptions.PreferBraces, New CodeStyleOption2(Of PreferBracesPreference)(PreferBracesPreference.None, NotificationOption2.Silent)} + } Public Async Function TestCSharp_DoNotSimplifyIfBlock() As Task diff --git a/src/EditorFeatures/Test2/Simplification/TypeInferenceSimplifierTests.vb b/src/EditorFeatures/Test2/Simplification/TypeInferenceSimplifierTests.vb index db2fd3f44ea15..0b3a2b744932a 100644 --- a/src/EditorFeatures/Test2/Simplification/TypeInferenceSimplifierTests.vb +++ b/src/EditorFeatures/Test2/Simplification/TypeInferenceSimplifierTests.vb @@ -70,9 +70,7 @@ Namespace Microsoft.CodeAnalysis.Editor.UnitTests.Simplification End Module - Dim simplificationOptionSet = New Dictionary(Of OptionKey2, Object) From {} - - Await TestAsync(input, expected, simplificationOptionSet) + Await TestAsync(input, expected) End Function @@ -102,9 +100,7 @@ Namespace Microsoft.CodeAnalysis.Editor.UnitTests.Simplification End Module - Dim simplificationOptionSet = New Dictionary(Of OptionKey2, Object) From {} - - Await TestAsync(input, expected, simplificationOptionSet) + Await TestAsync(input, expected) End Function @@ -167,9 +163,7 @@ Namespace Microsoft.CodeAnalysis.Editor.UnitTests.Simplification End Class - Dim simplificationOptionSet = New Dictionary(Of OptionKey2, Object) From {} - - Await TestAsync(input, expected, simplificationOptionSet) + Await TestAsync(input, expected) End Function @@ -204,9 +198,7 @@ Namespace Microsoft.CodeAnalysis.Editor.UnitTests.Simplification End Module - Dim simplificationOptionSet = New Dictionary(Of OptionKey2, Object) From {} - - Await TestAsync(input, expected, simplificationOptionSet) + Await TestAsync(input, expected) End Function @@ -255,9 +247,7 @@ Namespace Microsoft.CodeAnalysis.Editor.UnitTests.Simplification End Class - Dim simplificationOptionSet = New Dictionary(Of OptionKey2, Object) From {} - - Await TestAsync(input, expected, simplificationOptionSet) + Await TestAsync(input, expected) End Function @@ -305,9 +295,7 @@ Namespace Microsoft.CodeAnalysis.Editor.UnitTests.Simplification End Module - Dim simplificationOptionSet = New Dictionary(Of OptionKey2, Object) From {} - - Await TestAsync(input, expected, simplificationOptionSet) + Await TestAsync(input, expected) End Function @@ -358,9 +346,7 @@ Namespace Microsoft.CodeAnalysis.Editor.UnitTests.Simplification End Module - Dim simplificationOptionSet = New Dictionary(Of OptionKey2, Object) From {} - - Await TestAsync(input, expected, simplificationOptionSet) + Await TestAsync(input, expected) End Function @@ -409,9 +395,7 @@ Namespace Microsoft.CodeAnalysis.Editor.UnitTests.Simplification End Class - Dim simplificationOptionSet = New Dictionary(Of OptionKey2, Object) From {} - - Await TestAsync(input, expected, simplificationOptionSet) + Await TestAsync(input, expected) End Function #Region "Type Argument Expand/Reduce for Generic Method Calls - 639136" @@ -469,9 +453,7 @@ class D : C }]]> - Dim simplificationOptionSet = New Dictionary(Of OptionKey2, Object) From {} - - Await TestAsync(input, expected, simplificationOptionSet) + Await TestAsync(input, expected) End Function @@ -524,9 +506,7 @@ End Class ]]> - Dim simplificationOptionSet = New Dictionary(Of OptionKey2, Object) From {} - - Await TestAsync(input, expected, simplificationOptionSet) + Await TestAsync(input, expected) End Function @@ -570,9 +550,7 @@ Namespace X End Namespace - Dim simplificationOptionSet = New Dictionary(Of OptionKey2, Object) From {} - - Await TestAsync(input, expected, simplificationOptionSet) + Await TestAsync(input, expected) End Function @@ -620,9 +598,7 @@ Namespace Y End Namespace - Dim simplificationOptionSet = New Dictionary(Of OptionKey2, Object) From {} - - Await TestAsync(input, expected, simplificationOptionSet) + Await TestAsync(input, expected) End Function #End Region diff --git a/src/EditorFeatures/Test2/Simplification/TypeNameSimplifierTest.vb b/src/EditorFeatures/Test2/Simplification/TypeNameSimplifierTest.vb index 1cd3243a5bf57..6a6d36c273d19 100644 --- a/src/EditorFeatures/Test2/Simplification/TypeNameSimplifierTest.vb +++ b/src/EditorFeatures/Test2/Simplification/TypeNameSimplifierTest.vb @@ -4,6 +4,7 @@ Imports Microsoft.CodeAnalysis.CodeStyle Imports Microsoft.CodeAnalysis.CSharp.CodeStyle +Imports Microsoft.CodeAnalysis.Editor.UnitTests.CodeActions Imports Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces Imports Microsoft.CodeAnalysis.Options Imports Microsoft.CodeAnalysis.Simplification @@ -1470,7 +1471,7 @@ class C1 Public Async Function TestCSharpSimplifyToVarLocalDeclaration() As Task - Dim simplificationOption = New Dictionary(Of OptionKey2, Object) From { + Dim simplificationOption = New OptionsCollection(LanguageNames.CSharp) From { {CSharpCodeStyleOptions.VarForBuiltInTypes, CodeStyleOptions2.TrueWithSilentEnforcement}, {CSharpCodeStyleOptions.VarWhenTypeIsApparent, CodeStyleOptions2.TrueWithSilentEnforcement}, {CSharpCodeStyleOptions.VarElsewhere, CodeStyleOptions2.TrueWithSilentEnforcement} @@ -1508,7 +1509,7 @@ class Program Public Async Function TestCSharpSimplifyToVarForeachDecl() As Task - Dim simplificationOption = New Dictionary(Of OptionKey2, Object) From { + Dim simplificationOption = New OptionsCollection(LanguageNames.CSharp) From { {CSharpCodeStyleOptions.VarForBuiltInTypes, CodeStyleOptions2.TrueWithSilentEnforcement}, {CSharpCodeStyleOptions.VarWhenTypeIsApparent, CodeStyleOptions2.TrueWithSilentEnforcement}, {CSharpCodeStyleOptions.VarElsewhere, CodeStyleOptions2.TrueWithSilentEnforcement} @@ -1548,7 +1549,7 @@ class Program Public Async Function TestCSharpSimplifyToVarCorrect() As Task - Dim simplificationOption = New Dictionary(Of OptionKey2, Object) From { + Dim simplificationOption = New OptionsCollection(LanguageNames.CSharp) From { {CSharpCodeStyleOptions.VarForBuiltInTypes, CodeStyleOptions2.TrueWithSilentEnforcement}, {CSharpCodeStyleOptions.VarWhenTypeIsApparent, CodeStyleOptions2.TrueWithSilentEnforcement}, {CSharpCodeStyleOptions.VarElsewhere, CodeStyleOptions2.TrueWithSilentEnforcement} @@ -1618,7 +1619,7 @@ class Program Public Async Function TestCSharpSimplifyToVarCorrect_QualifiedTypeNames() As Task - Dim simplificationOption = New Dictionary(Of OptionKey2, Object) From { + Dim simplificationOption = New OptionsCollection(LanguageNames.CSharp) From { {CSharpCodeStyleOptions.VarForBuiltInTypes, CodeStyleOptions2.TrueWithSilentEnforcement}, {CSharpCodeStyleOptions.VarWhenTypeIsApparent, CodeStyleOptions2.TrueWithSilentEnforcement}, {CSharpCodeStyleOptions.VarElsewhere, CodeStyleOptions2.TrueWithSilentEnforcement} @@ -1667,9 +1668,6 @@ class Program Public Async Function TestCSharpSimplifyToVarDontSimplify() As Task - - Dim simplificationOption = New Dictionary(Of OptionKey2, Object) From {} - Dim input = @@ -1724,7 +1722,7 @@ class Program } - Await TestAsync(input, expected, simplificationOption) + Await TestAsync(input, expected) End Function @@ -2025,8 +2023,6 @@ class E Public Async Function TestDoNotSimplifyToGenericName() As Task - Dim simplificationOption = New Dictionary(Of OptionKey2, Object) From {} - Dim input = @@ -2081,13 +2077,11 @@ class E }]]> - Await TestAsync(input, expected, simplificationOption) + Await TestAsync(input, expected) End Function Public Async Function TestDontSimplifyAllNodes_SimplifyNestedType() As Task - Dim simplificationOption = New Dictionary(Of OptionKey2, Object) From {} - Dim input = @@ -2143,7 +2137,7 @@ static class M } }]]> - Await TestAsync(input, expected, simplificationOption) + Await TestAsync(input, expected) End Function @@ -2524,7 +2518,10 @@ class C } ]]> - Dim simplificationOptionSet = New Dictionary(Of OptionKey2, Object) From {{New OptionKey2(CodeStyleOptions2.QualifyFieldAccess, LanguageNames.CSharp), New CodeStyleOption2(Of Boolean)(True, NotificationOption2.Error)}} + Dim simplificationOptionSet = New OptionsCollection(LanguageNames.CSharp) From + { + {CodeStyleOptions2.QualifyFieldAccess, New CodeStyleOption2(Of Boolean)(True, NotificationOption2.Error)} + } Await TestAsync(input, expected, simplificationOptionSet) End Function @@ -4829,8 +4826,6 @@ End Class Public Async Function TestVisualBasic_DoNotSimplifyToGenericName() As Task - Dim simplificationOption = New Dictionary(Of OptionKey2, Object) From {} - Dim input = @@ -4877,13 +4872,11 @@ End Class ]]> - Await TestAsync(input, expected, simplificationOption) + Await TestAsync(input, expected) End Function Public Async Function TestVisualBasic_TestDontSimplifyAllNodes_SimplifyNestedType() As Task - Dim simplificationOption = New Dictionary(Of OptionKey2, Object) From {} - Dim input = @@ -4927,7 +4920,7 @@ NotInheritable Class M End Sub End Class]]> - Await TestAsync(input, expected, simplificationOption) + Await TestAsync(input, expected) End Function @@ -5953,27 +5946,28 @@ End Class #Region "Helpers" - Private Protected Shared Function QualifyFieldAccessOption(languageName As String) As Dictionary(Of OptionKey2, Object) - Return New Dictionary(Of OptionKey2, Object) From {{New OptionKey2(CodeStyleOptions2.QualifyFieldAccess, languageName), New CodeStyleOption2(Of Boolean)(True, NotificationOption2.Error)}} + Private Protected Shared Function QualifyFieldAccessOption(languageName As String) As OptionsCollection + Return New OptionsCollection(languageName) From {{CodeStyleOptions2.QualifyFieldAccess, New CodeStyleOption2(Of Boolean)(True, NotificationOption2.Error)}} End Function - Private Protected Shared Function QualifyPropertyAccessOption(languageName As String) As Dictionary(Of OptionKey2, Object) + Private Protected Shared Function QualifyPropertyAccessOption(languageName As String) As OptionsCollection Return QualifyPropertyAccessOptionWithNotification(languageName, NotificationOption2.Error) End Function - Private Protected Shared Function QualifyMethodAccessOption(languageName As String) As Dictionary(Of OptionKey2, Object) - Return New Dictionary(Of OptionKey2, Object) From {{New OptionKey2(CodeStyleOptions2.QualifyMethodAccess, languageName), New CodeStyleOption2(Of Boolean)(True, NotificationOption2.Error)}} + Private Protected Shared Function QualifyMethodAccessOption(languageName As String) As OptionsCollection + Return New OptionsCollection(languageName) From {{CodeStyleOptions2.QualifyMethodAccess, New CodeStyleOption2(Of Boolean)(True, NotificationOption2.Error)}} End Function - Private Protected Shared Function QualifyEventAccessOption(languageName As String) As Dictionary(Of OptionKey2, Object) - Return New Dictionary(Of OptionKey2, Object) From {{New OptionKey2(CodeStyleOptions2.QualifyEventAccess, languageName), New CodeStyleOption2(Of Boolean)(True, NotificationOption2.Error)}} + Private Protected Shared Function QualifyEventAccessOption(languageName As String) As OptionsCollection + Return New OptionsCollection(languageName) From {{CodeStyleOptions2.QualifyEventAccess, New CodeStyleOption2(Of Boolean)(True, NotificationOption2.Error)}} End Function - Private Protected Shared Function QualifyPropertyAccessOptionWithNotification(languageName As String, notification As NotificationOption2) As Dictionary(Of OptionKey2, Object) - Return New Dictionary(Of OptionKey2, Object) From {{New OptionKey2(CodeStyleOptions2.QualifyPropertyAccess, languageName), New CodeStyleOption2(Of Boolean)(True, notification)}} + Private Protected Shared Function QualifyPropertyAccessOptionWithNotification(languageName As String, notification As NotificationOption2) As OptionsCollection + Return New OptionsCollection(languageName) From {{CodeStyleOptions2.QualifyPropertyAccess, New CodeStyleOption2(Of Boolean)(True, notification)}} End Function - Private Shared ReadOnly DontPreferIntrinsicPredefinedTypeKeywordInDeclaration As Dictionary(Of OptionKey2, Object) = New Dictionary(Of OptionKey2, Object) From {{New OptionKey2(CodeStyleOptions2.PreferIntrinsicPredefinedTypeKeywordInDeclaration, LanguageNames.VisualBasic), CodeStyleOption2(Of Boolean).Default}} + Private Shared ReadOnly DontPreferIntrinsicPredefinedTypeKeywordInDeclaration As New OptionsCollection(LanguageNames.VisualBasic) From + {{CodeStyleOptions2.PreferIntrinsicPredefinedTypeKeywordInDeclaration, CodeStyleOption2(Of Boolean).Default}} #End Region diff --git a/src/EditorFeatures/Test2/Workspaces/SymbolDescriptionServiceTests.vb b/src/EditorFeatures/Test2/Workspaces/SymbolDescriptionServiceTests.vb index 4fb6a0cbb13ef..6e71ae438a938 100644 --- a/src/EditorFeatures/Test2/Workspaces/SymbolDescriptionServiceTests.vb +++ b/src/EditorFeatures/Test2/Workspaces/SymbolDescriptionServiceTests.vb @@ -7,7 +7,7 @@ Imports System.Threading.Tasks Imports Microsoft.CodeAnalysis Imports Microsoft.CodeAnalysis.FindSymbols Imports Microsoft.CodeAnalysis.Host -Imports Microsoft.CodeAnalysis.LanguageServices +Imports Microsoft.CodeAnalysis.LanguageService Namespace Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces diff --git a/src/EditorFeatures/TestUtilities/AbstractCommandHandlerTestState.cs b/src/EditorFeatures/TestUtilities/AbstractCommandHandlerTestState.cs index 26854a7e55c09..7a38ab30d4245 100644 --- a/src/EditorFeatures/TestUtilities/AbstractCommandHandlerTestState.cs +++ b/src/EditorFeatures/TestUtilities/AbstractCommandHandlerTestState.cs @@ -124,6 +124,8 @@ public AbstractCommandHandlerTestState( this.EditorOperations = GetService().GetEditorOperations(_textView); this.UndoHistoryRegistry = GetService(); + + _textView.Options.GlobalOptions.SetOptionValue(DefaultOptions.IndentStyleId, IndentingStyle.Smart); } public void Dispose() diff --git a/src/EditorFeatures/TestUtilities/AutomaticCompletion/AbstractAutomaticBraceCompletionTests.cs b/src/EditorFeatures/TestUtilities/AutomaticCompletion/AbstractAutomaticBraceCompletionTests.cs index 4daaf3a9f50d1..e72c4a51f9fc3 100644 --- a/src/EditorFeatures/TestUtilities/AutomaticCompletion/AbstractAutomaticBraceCompletionTests.cs +++ b/src/EditorFeatures/TestUtilities/AutomaticCompletion/AbstractAutomaticBraceCompletionTests.cs @@ -9,12 +9,14 @@ using System.Linq; using Microsoft.CodeAnalysis.AutomaticCompletion; using Microsoft.CodeAnalysis.Editor.Shared.Extensions; +using Microsoft.CodeAnalysis.Editor.UnitTests.CodeActions; using Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces; using Microsoft.CodeAnalysis.Formatting; using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Test.Utilities; using Microsoft.VisualStudio.Text; using Microsoft.VisualStudio.Text.BraceCompletion; +using Microsoft.VisualStudio.Text.Editor; using Roslyn.Test.Utilities; using Xunit; @@ -147,24 +149,19 @@ internal static void Type(IBraceCompletionSession session, string text) } } - internal static Holder CreateSession(TestWorkspace workspace, char opening, char closing, Dictionary changedOptionSet = null) + internal static Holder CreateSession(TestWorkspace workspace, char opening, char closing, OptionsCollection globalOptions = null) { - if (changedOptionSet != null) - { - var options = workspace.Options; - foreach (var entry in changedOptionSet) - { - options = options.WithChangedOption(entry.Key, entry.Value); - } - - workspace.TryApplyChanges(workspace.CurrentSolution.WithOptions(options)); - } - var document = workspace.Documents.First(); - var provider = Assert.IsType(workspace.ExportProvider.GetExportedValue()); + var provider = Assert.IsType(workspace.GetService()); + var openingPoint = new SnapshotPoint(document.GetTextBuffer().CurrentSnapshot, document.CursorPosition.Value); - if (provider.TryCreateSession(document.GetTextView(), openingPoint, opening, closing, out var session)) + var textView = document.GetTextView(); + + globalOptions?.SetGlobalOptions(workspace.GlobalOptions); + workspace.GlobalOptions.SetEditorOptions(textView.Options.GlobalOptions, document.Project.Language); + + if (provider.TryCreateSession(textView, openingPoint, opening, closing, out var session)) { return new Holder(workspace, session); } diff --git a/src/EditorFeatures/TestUtilities/AutomaticCompletion/AbstractAutomaticLineEnderTests.cs b/src/EditorFeatures/TestUtilities/AutomaticCompletion/AbstractAutomaticLineEnderTests.cs index 9462df03b59d8..4c4932e87b6b0 100644 --- a/src/EditorFeatures/TestUtilities/AutomaticCompletion/AbstractAutomaticLineEnderTests.cs +++ b/src/EditorFeatures/TestUtilities/AutomaticCompletion/AbstractAutomaticLineEnderTests.cs @@ -75,12 +75,13 @@ private void Test(string expected, string code, int position, bool useTabs, bool // WPF is required for some reason: https://github.com/dotnet/roslyn/issues/46286 using var workspace = TestWorkspace.Create(Language, compilationOptions: null, parseOptions: null, new[] { markupCode }, composition: EditorTestCompositions.EditorFeaturesWpf); - workspace.GlobalOptions.SetGlobalOption(new OptionKey(FormattingOptions2.UseTabs, Language), useTabs); - var view = workspace.Documents.Single().GetTextView(); var buffer = workspace.Documents.Single().GetTextBuffer(); var nextHandlerInvoked = false; + view.Options.GlobalOptions.SetOptionValue(DefaultOptions.ConvertTabsToSpacesOptionId, !useTabs); + view.Options.GlobalOptions.SetOptionValue(DefaultOptions.IndentStyleId, IndentingStyle.Smart); + view.Caret.MoveTo(new SnapshotPoint(buffer.CurrentSnapshot, workspace.Documents.Single(d => d.CursorPosition.HasValue).CursorPosition.Value)); var commandHandler = GetCommandHandler(workspace); diff --git a/src/EditorFeatures/TestUtilities/BraceHighlighting/MultiCharacterBraceHighlightingTests.cs b/src/EditorFeatures/TestUtilities/BraceHighlighting/MultiCharacterBraceHighlightingTests.cs index 9b8848a4bc59f..90c6f8d1c8eea 100644 --- a/src/EditorFeatures/TestUtilities/BraceHighlighting/MultiCharacterBraceHighlightingTests.cs +++ b/src/EditorFeatures/TestUtilities/BraceHighlighting/MultiCharacterBraceHighlightingTests.cs @@ -7,6 +7,7 @@ using System.Diagnostics; using System.Threading; using System.Threading.Tasks; +using Microsoft.CodeAnalysis.BraceMatching; using Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces; using Microsoft.CodeAnalysis.Test.Utilities; using Microsoft.CodeAnalysis.Text; diff --git a/src/EditorFeatures/TestUtilities/BraceMatching/AbstractBraceMatcherTests.cs b/src/EditorFeatures/TestUtilities/BraceMatching/AbstractBraceMatcherTests.cs index d8706354634eb..c29e64cf018fb 100644 --- a/src/EditorFeatures/TestUtilities/BraceMatching/AbstractBraceMatcherTests.cs +++ b/src/EditorFeatures/TestUtilities/BraceMatching/AbstractBraceMatcherTests.cs @@ -9,7 +9,7 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.Editor.Shared.Extensions; +using Microsoft.CodeAnalysis.BraceMatching; using Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces; using Microsoft.CodeAnalysis.Test.Utilities; using Microsoft.CodeAnalysis.Text; diff --git a/src/EditorFeatures/TestUtilities/Classification/FormattedClassification.cs b/src/EditorFeatures/TestUtilities/Classification/FormattedClassification.cs index 4d4c0a5e91d9d..3c2c02f28aaa5 100644 --- a/src/EditorFeatures/TestUtilities/Classification/FormattedClassification.cs +++ b/src/EditorFeatures/TestUtilities/Classification/FormattedClassification.cs @@ -5,12 +5,20 @@ #nullable disable using System; +using System.Collections.Immutable; using System.Linq; +using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Editor.UnitTests.Classification { public class FormattedClassification { + private static readonly ImmutableDictionary s_classificationPrefixToTestHelperMap = ImmutableDictionary.Empty + .Add("regex - ", "Regex.") + .Add("json - ", "Json.") + .Add("xml doc comment - ", "XmlDoc.") + .Add("xml literal - ", "VBXml"); + public string ClassificationName { get; } public string Text { get; } @@ -38,20 +46,15 @@ public override int GetHashCode() public override string ToString() { - if (ClassificationName.StartsWith("regex")) - { - var remainder = ClassificationName.Substring("regex - ".Length); - var parts = remainder.Split(' '); - var type = string.Join("", parts.Select(Capitalize)); - return "Regex." + $"{type}(\"{Text}\")"; - } - - if (ClassificationName.StartsWith("json")) + foreach (var kvp in s_classificationPrefixToTestHelperMap) { - var remainder = ClassificationName.Substring("json - ".Length); - var parts = remainder.Split(' '); - var type = string.Join("", parts.Select(Capitalize)); - return "Json." + $"{type}(\"{Text}\")"; + if (ClassificationName.StartsWith(kvp.Key)) + { + var remainder = ClassificationName.Substring(kvp.Key.Length); + var parts = remainder.Split(' '); + var type = string.Join("", parts.Select(Capitalize)); + return kvp.Value + $"{type}(\"{Text}\")"; + } } switch (ClassificationName) @@ -79,19 +82,111 @@ public override string ToString() return "Punctuation.Comma"; case "..": return "Punctuation.DotDot"; + case "<": + return "Punctuation.OpenAngle"; + case ">": + return "Punctuation.CloseAngle"; } goto default; case "operator": + case "operator - overloaded": + var operatorTypeName = ClassificationName switch + { + "operator" => "Operators", + "operator - overloaded" => "OverloadedOperators", + _ => throw ExceptionUtilities.Unreachable, + }; + switch (Text) { + case "&&": + return $"{operatorTypeName}.AmpersandAmpersand"; + case "&=": + return $"{operatorTypeName}.AmpersandEquals"; + case "*": + return $"{operatorTypeName}.Asterisk"; + case "*=": + return $"{operatorTypeName}.AsteriskEquals"; + case "|": + return $"{operatorTypeName}.Bar"; + case "||": + return $"{operatorTypeName}.BarBar"; + case "|=": + return $"{operatorTypeName}.BarEquals"; + case "^": + return $"{operatorTypeName}.Caret"; + case "^=": + return $"{operatorTypeName}.CaretEquals"; + case ":": + return $"{operatorTypeName}.Colon"; + case "::": + return $"{operatorTypeName}.ColonColon"; + case ":=": + return $"{operatorTypeName}.ColonEquals"; + case ".": + return $"{operatorTypeName}.Dot"; case "=": - return "Operators.Equals"; - case "++": - return "Operators.PlusPlus"; + return $"{operatorTypeName}.Equals"; + case "==": + return $"{operatorTypeName}.EqualsEquals"; case "=>": - return "Operators.EqualsGreaterThan"; + return $"{operatorTypeName}.EqualsGreaterThan"; + case "!": + return $"{operatorTypeName}.Exclamation"; + case "!=": + return $"{operatorTypeName}.ExclamationEquals"; + case ">": + return $"{operatorTypeName}.GreaterThan"; + case ">=": + return $"{operatorTypeName}.GreaterThanEquals"; + case ">>": + return $"{operatorTypeName}.GreaterThanGreaterThan"; + case ">>>": + return $"{operatorTypeName}.GreaterThanGreaterThanGreaterThan"; + case ">>=": + return $"{operatorTypeName}.GreaterThanGreaterThanEquals"; + case ">>>=": + return $"{operatorTypeName}.GreaterThanGreaterThanGreaterThanEquals"; + case "<": + return $"{operatorTypeName}.LessThan"; + case "<=": + return $"{operatorTypeName}.LessThanEquals"; + case "<>": + return $"{operatorTypeName}.LessThanGreaterThan"; + case "<<": + return $"{operatorTypeName}.LessThanLessThan"; + case "<<=": + return $"{operatorTypeName}.LessThanLessThanEquals"; + case "-": + return $"{operatorTypeName}.Minus"; + case "-=": + return $"{operatorTypeName}.MinusEquals"; + case "->": + return $"{operatorTypeName}.MinusGreaterThan"; + case "--": + return $"{operatorTypeName}.MinusMinus"; + case "%": + return $"{operatorTypeName}.Percent"; + case "%=": + return $"{operatorTypeName}.PercentEquals"; + case "+": + return $"{operatorTypeName}.Plus"; + case "+=": + return $"{operatorTypeName}.PlusEquals"; + case "++": + return $"{operatorTypeName}.PlusPlus"; + case "?": + return $"{operatorTypeName}.QuestionMark"; + case "??=": + return $"{operatorTypeName}.QuestionQuestionEquals"; + case "/": + return $"{operatorTypeName}.Slash"; + case "/=": + return $"{operatorTypeName}.SlashEquals"; + case "~": + return $"{operatorTypeName}.Tilde"; } goto default; @@ -99,8 +194,23 @@ public override string ToString() case "keyword - control": return $"ControlKeyword(\"{Text}\")"; + case "static symbol": + return $"Static(\"{Text}\")"; + + case "string - verbatim": + return $"Verbatim(\"{Text}\")"; + + case "string - escape character": + return $"Escape(\"{Text}\")"; + default: - return $"{Capitalize(ClassificationName)}(\"{Text}\")"; + var trimmedClassification = ClassificationName; + if (trimmedClassification.EndsWith(" name")) + { + trimmedClassification = trimmedClassification.Substring(0, trimmedClassification.Length - " name".Length); + } + + return $"{string.Join("", trimmedClassification.Split(' ').Select(Capitalize))}(\"{Text}\")"; } } diff --git a/src/EditorFeatures/TestUtilities/Classification/FormattedClassifications.cs b/src/EditorFeatures/TestUtilities/Classification/FormattedClassifications.cs index f3bb35e15a5da..127aafb3fa507 100644 --- a/src/EditorFeatures/TestUtilities/Classification/FormattedClassifications.cs +++ b/src/EditorFeatures/TestUtilities/Classification/FormattedClassifications.cs @@ -31,7 +31,7 @@ public static FormattedClassification Class(string text) => New(text, ClassificationTypeNames.ClassName); [DebuggerStepThrough] - public static FormattedClassification Record(string text) + public static FormattedClassification RecordClass(string text) => New(text, ClassificationTypeNames.RecordClassName); [DebuggerStepThrough] diff --git a/src/EditorFeatures/TestUtilities/Completion/AbstractArgumentProviderTests`1.cs b/src/EditorFeatures/TestUtilities/Completion/AbstractArgumentProviderTests`1.cs index 5bb6ecacf6ab8..be3c4bf9e4954 100644 --- a/src/EditorFeatures/TestUtilities/Completion/AbstractArgumentProviderTests`1.cs +++ b/src/EditorFeatures/TestUtilities/Completion/AbstractArgumentProviderTests`1.cs @@ -11,7 +11,7 @@ using Microsoft.CodeAnalysis.Editor.UnitTests; using Microsoft.CodeAnalysis.Editor.UnitTests.CodeActions; using Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.VisualStudio.Composition; diff --git a/src/EditorFeatures/TestUtilities/Completion/AbstractCompletionProviderTests.cs b/src/EditorFeatures/TestUtilities/Completion/AbstractCompletionProviderTests.cs index 2c0b863a785a6..2134574be5b31 100644 --- a/src/EditorFeatures/TestUtilities/Completion/AbstractCompletionProviderTests.cs +++ b/src/EditorFeatures/TestUtilities/Completion/AbstractCompletionProviderTests.cs @@ -19,7 +19,7 @@ using Microsoft.CodeAnalysis.Editor.UnitTests.CodeActions; using Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces; using Microsoft.CodeAnalysis.Host.Mef; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Test.Utilities; @@ -53,6 +53,7 @@ public abstract class AbstractCompletionProviderTests : TestB protected bool? ForceExpandedCompletionIndexCreation { get; set; } protected bool? HideAdvancedMembers { get; set; } protected bool? ShowNameSuggestions { get; set; } + protected bool? ShowNewSnippetExperience { get; set; } protected AbstractCompletionProviderTests() { @@ -84,6 +85,9 @@ private CompletionOptions GetCompletionOptions() if (ShowNameSuggestions.HasValue) options = options with { ShowNameSuggestions = ShowNameSuggestions.Value }; + if (ShowNewSnippetExperience.HasValue) + options = options with { ShowNewSnippetExperience = ShowNewSnippetExperience.Value }; + return options; } @@ -106,9 +110,9 @@ protected static async Task CanUseSpeculativeSemanticModelAsync(Document d internal virtual CompletionService GetCompletionService(Project project) { - var completionService = project.LanguageServices.GetRequiredService(); - var completionProviders = completionService.GetImportedProviders(); - var completionProvider = Assert.Single(completionProviders).Value; + var completionService = project.Services.GetRequiredService(); + var completionProviders = completionService.GetTestAccessor().GetAllProviders(ImmutableHashSet.Empty, project); + var completionProvider = Assert.Single(completionProviders); Assert.IsType(GetCompletionProviderType(), completionProvider); return completionService; @@ -471,7 +475,7 @@ private async Task VerifyCustomCommitProviderCheckResultsAsync(Document document Assert.Contains(itemToCommit, items.Select(x => x.DisplayText), GetStringComparer()); var firstItem = items.First(i => CompareItems(i.DisplayText, itemToCommit)); - if (service.GetProvider(firstItem) is ICustomCommitCompletionProvider customCommitCompletionProvider) + if (service.GetProvider(firstItem, document.Project) is ICustomCommitCompletionProvider customCommitCompletionProvider) { VerifyCustomCommitWorker(service, customCommitCompletionProvider, firstItem, codeBeforeCommit, expectedCodeAfterCommit, commitChar); } @@ -1056,7 +1060,7 @@ private void VerifyTextualTriggerCharacterWorker( TriggerInArgumentLists = showCompletionInArgumentLists }; - var isTextualTriggerCharacterResult = service.ShouldTriggerCompletion(document.Project, document.Project.LanguageServices, text, position + 1, trigger, options, document.Project.Solution.Options, GetRoles(document)); + var isTextualTriggerCharacterResult = service.ShouldTriggerCompletion(document.Project, document.Project.Services, text, position + 1, trigger, options, document.Project.Solution.Options, GetRoles(document)); if (expectedTriggerCharacter) { diff --git a/src/EditorFeatures/TestUtilities/Diagnostics/GenerateType/GenerateTypeTestState.cs b/src/EditorFeatures/TestUtilities/Diagnostics/GenerateType/GenerateTypeTestState.cs index a04329925ee8f..9f48c2c3dbb42 100644 --- a/src/EditorFeatures/TestUtilities/Diagnostics/GenerateType/GenerateTypeTestState.cs +++ b/src/EditorFeatures/TestUtilities/Diagnostics/GenerateType/GenerateTypeTestState.cs @@ -66,7 +66,7 @@ public TestGenerateTypeOptionsService TestGenerateTypeOptionsService { get { - return (TestGenerateTypeOptionsService)InvocationDocument.Project.Solution.Workspace.Services.GetRequiredService(); + return (TestGenerateTypeOptionsService)InvocationDocument.Project.Solution.Services.GetRequiredService(); } } @@ -74,16 +74,13 @@ public TestProjectManagementService TestProjectManagementService { get { - return (TestProjectManagementService)InvocationDocument.Project.Solution.Workspace.Services.GetService(); + return (TestProjectManagementService)InvocationDocument.Project.Solution.Services.GetService(); } } public void Dispose() { - if (Workspace != null) - { - Workspace.Dispose(); - } + Workspace?.Dispose(); } } } diff --git a/src/EditorFeatures/TestUtilities/Diagnostics/GenerateType/TestGenerateTypeOptionsService.cs b/src/EditorFeatures/TestUtilities/Diagnostics/GenerateType/TestGenerateTypeOptionsService.cs index 6d71e27b24d19..093c800d14a41 100644 --- a/src/EditorFeatures/TestUtilities/Diagnostics/GenerateType/TestGenerateTypeOptionsService.cs +++ b/src/EditorFeatures/TestUtilities/Diagnostics/GenerateType/TestGenerateTypeOptionsService.cs @@ -9,7 +9,7 @@ using System.Composition; using Microsoft.CodeAnalysis.GenerateType; using Microsoft.CodeAnalysis.Host.Mef; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Notification; using Microsoft.CodeAnalysis.ProjectManagement; @@ -52,10 +52,7 @@ public GenerateTypeOptionsResult GetGenerateTypeOptions( // Storing the actual values ClassName = className; GenerateTypeDialogOptions = generateTypeDialogOptions; - if (DefaultNamespace == null) - { - DefaultNamespace = projectManagementService.GetDefaultNamespace(Project, Project?.Solution.Workspace); - } + DefaultNamespace ??= projectManagementService.GetDefaultNamespace(Project, Project?.Solution.Workspace); return new GenerateTypeOptionsResult( accessibility: Accessibility, diff --git a/src/EditorFeatures/TestUtilities/Diagnostics/TestDiagnosticAnalyzerDriver.cs b/src/EditorFeatures/TestUtilities/Diagnostics/TestDiagnosticAnalyzerDriver.cs index 529c35c176cac..04d7fd4565325 100644 --- a/src/EditorFeatures/TestUtilities/Diagnostics/TestDiagnosticAnalyzerDriver.cs +++ b/src/EditorFeatures/TestUtilities/Diagnostics/TestDiagnosticAnalyzerDriver.cs @@ -33,7 +33,7 @@ public class TestDiagnosticAnalyzerDriver public TestDiagnosticAnalyzerDriver(Workspace workspace, bool includeSuppressedDiagnostics = false) { - var mefServices = (IMefHostExportProvider)workspace.Services.HostServices; + var mefServices = workspace.Services.SolutionServices.ExportProvider; Assert.IsType(mefServices.GetExportedValue()); _diagnosticAnalyzerService = Assert.IsType(mefServices.GetExportedValue()); diff --git a/src/EditorFeatures/TestUtilities/DocumentationComments/AbstractDocumentationCommentTests.cs b/src/EditorFeatures/TestUtilities/DocumentationComments/AbstractDocumentationCommentTests.cs index 91865cfae34c4..f7d9404e748e7 100644 --- a/src/EditorFeatures/TestUtilities/DocumentationComments/AbstractDocumentationCommentTests.cs +++ b/src/EditorFeatures/TestUtilities/DocumentationComments/AbstractDocumentationCommentTests.cs @@ -7,6 +7,7 @@ using System; using System.Linq; using Microsoft.CodeAnalysis.DocumentationComments; +using Microsoft.CodeAnalysis.Editor.UnitTests.CodeActions; using Microsoft.CodeAnalysis.Editor.UnitTests.Utilities; using Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces; using Microsoft.CodeAnalysis.Formatting; @@ -31,9 +32,9 @@ public abstract class AbstractDocumentationCommentTests protected abstract TestWorkspace CreateTestWorkspace(string code); - protected void VerifyTypingCharacter(string initialMarkup, string expectedMarkup, bool useTabs = false, bool autoGenerateXmlDocComments = true, string newLine = "\r\n") + internal void VerifyTypingCharacter(string initialMarkup, string expectedMarkup, bool useTabs = false, string newLine = "\r\n", bool trimTrailingWhiteSpace = false, OptionsCollection globalOptions = null) { - Verify(initialMarkup, expectedMarkup, useTabs, autoGenerateXmlDocComments, newLine: newLine, + Verify(initialMarkup, expectedMarkup, execute: (workspace, view, editorOperationsFactoryService) => { var commandHandler = CreateCommandHandler(workspace); @@ -42,14 +43,13 @@ protected void VerifyTypingCharacter(string initialMarkup, string expectedMarkup var nextHandler = CreateInsertTextHandler(view, DocumentationCommentCharacter.ToString()); commandHandler.ExecuteCommand(commandArgs, nextHandler, TestCommandExecutionContext.Create()); - }); + }, + useTabs, newLine, trimTrailingWhiteSpace, globalOptions); } - protected void VerifyPressingEnter(string initialMarkup, string expectedMarkup, bool useTabs = false, bool autoGenerateXmlDocComments = true, - Action setOptionsOpt = null) + internal void VerifyPressingEnter(string initialMarkup, string expectedMarkup, bool useTabs = false, string newLine = "\r\n", bool trimTrailingWhiteSpace = false, OptionsCollection globalOptions = null) { - Verify(initialMarkup, expectedMarkup, useTabs, autoGenerateXmlDocComments, - setOptionsOpt: setOptionsOpt, + Verify(initialMarkup, expectedMarkup, execute: (workspace, view, editorOperationsFactoryService) => { var commandHandler = CreateCommandHandler(workspace); @@ -57,12 +57,13 @@ protected void VerifyPressingEnter(string initialMarkup, string expectedMarkup, var commandArgs = new ReturnKeyCommandArgs(view, view.TextBuffer); var nextHandler = CreateInsertTextHandler(view, "\r\n"); commandHandler.ExecuteCommand(commandArgs, nextHandler, TestCommandExecutionContext.Create()); - }); + }, + useTabs, newLine, trimTrailingWhiteSpace, globalOptions); } - protected void VerifyInsertCommentCommand(string initialMarkup, string expectedMarkup, bool useTabs = false, bool autoGenerateXmlDocComments = true) + internal void VerifyInsertCommentCommand(string initialMarkup, string expectedMarkup, bool useTabs = false, string newLine = "\r\n", bool trimTrailingWhiteSpace = false, OptionsCollection globalOptions = null) { - Verify(initialMarkup, expectedMarkup, useTabs, autoGenerateXmlDocComments, + Verify(initialMarkup, expectedMarkup, execute: (workspace, view, editorOperationsFactoryService) => { var commandHandler = CreateCommandHandler(workspace); @@ -71,12 +72,13 @@ protected void VerifyInsertCommentCommand(string initialMarkup, string expectedM Action nextHandler = delegate { }; commandHandler.ExecuteCommand(commandArgs, nextHandler, TestCommandExecutionContext.Create()); - }); + }, + useTabs, newLine, trimTrailingWhiteSpace, globalOptions); } - protected void VerifyOpenLineAbove(string initialMarkup, string expectedMarkup, bool useTabs = false, bool autoGenerateXmlDocComments = true) + internal void VerifyOpenLineAbove(string initialMarkup, string expectedMarkup, bool useTabs = false, string newLine = "\r\n", bool trimTrailingWhiteSpace = false, OptionsCollection globalOptions = null) { - Verify(initialMarkup, expectedMarkup, useTabs, autoGenerateXmlDocComments, + Verify(initialMarkup, expectedMarkup, execute: (workspace, view, editorOperationsFactoryService) => { var commandHandler = CreateCommandHandler(workspace); @@ -89,12 +91,13 @@ void nextHandler() } commandHandler.ExecuteCommand(commandArgs, nextHandler, TestCommandExecutionContext.Create()); - }); + }, + useTabs, newLine, trimTrailingWhiteSpace, globalOptions); } - protected void VerifyOpenLineBelow(string initialMarkup, string expectedMarkup, bool useTabs = false, bool autoGenerateXmlDocComments = true) + internal void VerifyOpenLineBelow(string initialMarkup, string expectedMarkup, bool useTabs = false, string newLine = "\r\n", bool trimTrailingWhiteSpace = false, OptionsCollection globalOptions = null) { - Verify(initialMarkup, expectedMarkup, useTabs, autoGenerateXmlDocComments, + Verify(initialMarkup, expectedMarkup, execute: (workspace, view, editorOperationsFactoryService) => { var commandHandler = CreateCommandHandler(workspace); @@ -107,7 +110,8 @@ void nextHandler() } commandHandler.ExecuteCommand(commandArgs, nextHandler, TestCommandExecutionContext.Create()); - }); + }, + useTabs, newLine, trimTrailingWhiteSpace, globalOptions); } private static Action CreateInsertTextHandler(ITextView textView, string text) @@ -120,35 +124,36 @@ private static Action CreateInsertTextHandler(ITextView textView, string text) }; } - private void Verify(string initialMarkup, string expectedMarkup, bool useTabs, bool autoGenerateXmlDocComments, + private void Verify( + string initialMarkup, + string expectedMarkup, Action execute, - Action setOptionsOpt = null, string newLine = "\r\n") + bool useTabs, + string newLine, + bool trimTrailingWhiteSpace, + OptionsCollection globalOptions) { using (var workspace = CreateTestWorkspace(initialMarkup)) { var testDocument = workspace.Documents.Single(); - workspace.GlobalOptions.SetGlobalOption(new OptionKey(DocumentationCommentOptionsStorage.AutoXmlDocCommentGeneration, testDocument.Project.Language), autoGenerateXmlDocComments); - - var options = workspace.Options; - - options = options.WithChangedOption(FormattingOptions.UseTabs, testDocument.Project.Language, useTabs); - options = options.WithChangedOption(FormattingOptions.NewLine, testDocument.Project.Language, newLine); - workspace.TryApplyChanges(workspace.CurrentSolution.WithOptions(options)); - - setOptionsOpt?.Invoke(workspace); Assert.True(testDocument.CursorPosition.HasValue, "No caret position set!"); var startCaretPosition = testDocument.CursorPosition.Value; var view = testDocument.GetTextView(); + globalOptions?.SetGlobalOptions(workspace.GlobalOptions); + + var optionsFactory = workspace.GetService(); + var editorOptions = optionsFactory.GetOptions(view.TextBuffer); + editorOptions.SetOptionValue(DefaultOptions.ConvertTabsToSpacesOptionId, !useTabs); + editorOptions.SetOptionValue(DefaultOptions.NewLineCharacterOptionId, newLine); + view.Options.SetOptionValue(DefaultOptions.TrimTrailingWhiteSpaceOptionId, trimTrailingWhiteSpace); + if (testDocument.SelectedSpans.Any()) { var selectedSpan = testDocument.SelectedSpans[0]; - - var isReversed = selectedSpan.Start == startCaretPosition - ? true - : false; + var isReversed = selectedSpan.Start == startCaretPosition; view.Selection.Select(new SnapshotSpan(view.TextSnapshot, selectedSpan.Start, selectedSpan.Length), isReversed); } diff --git a/src/EditorFeatures/TestUtilities/EditAndContinue/EditAndContinueTestHelpers.cs b/src/EditorFeatures/TestUtilities/EditAndContinue/EditAndContinueTestHelpers.cs index 6a968c778d006..34e399d39809f 100644 --- a/src/EditorFeatures/TestUtilities/EditAndContinue/EditAndContinueTestHelpers.cs +++ b/src/EditorFeatures/TestUtilities/EditAndContinue/EditAndContinueTestHelpers.cs @@ -6,6 +6,7 @@ using System.Collections.Generic; using System.Collections.Immutable; using System.Diagnostics; +using System.IO; using System.Linq; using System.Threading; using Microsoft.CodeAnalysis.Differencing; @@ -44,6 +45,7 @@ internal abstract class EditAndContinueTestHelpers public abstract ImmutableArray GetDeclarators(ISymbol method); public abstract string LanguageName { get; } + public abstract string ProjectFileExtension { get; } public abstract TreeComparer TopSyntaxComparer { get; } private void VerifyDocumentActiveStatementsAndExceptionRegions( @@ -373,16 +375,19 @@ private static void VerifySyntaxMap( private void CreateProjects(EditScript[] editScripts, AdhocWorkspace workspace, TargetFramework targetFramework, out Project oldProject, out Project newProject) { - oldProject = workspace.AddProject("project", LanguageName).WithMetadataReferences(TargetFrameworkUtil.GetReferences(targetFramework)); - var documentIndex = 0; + var projectInfo = ProjectInfo.Create(ProjectId.CreateNewId(), VersionStamp.Create(), name: "project", assemblyName: "project", LanguageName, filePath: Path.Combine(TempRoot.Root, "project" + ProjectFileExtension)); + + oldProject = workspace.AddProject(projectInfo).WithMetadataReferences(TargetFrameworkUtil.GetReferences(targetFramework)); foreach (var editScript in editScripts) { - oldProject = oldProject.AddDocument(documentIndex.ToString(), editScript.Match.OldRoot).Project; - documentIndex++; + var oldRoot = editScript.Match.OldRoot; + var oldPath = oldRoot.SyntaxTree.FilePath; + var name = Path.GetFileNameWithoutExtension(oldPath); + oldProject = oldProject.AddDocument(name, oldRoot, filePath: oldPath).Project; } var newSolution = oldProject.Solution; - documentIndex = 0; + var documentIndex = 0; foreach (var oldDocument in oldProject.Documents) { newSolution = newSolution.WithDocumentSyntaxRoot(oldDocument.Id, editScripts[documentIndex].Match.NewRoot, PreservationMode.PreserveIdentity); diff --git a/src/EditorFeatures/TestUtilities/Extensions/WorkspaceExtensions.cs b/src/EditorFeatures/TestUtilities/Extensions/WorkspaceExtensions.cs deleted file mode 100644 index bf1e38f52d926..0000000000000 --- a/src/EditorFeatures/TestUtilities/Extensions/WorkspaceExtensions.cs +++ /dev/null @@ -1,33 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using System.Collections.Generic; -using System.Linq; -using Microsoft.CodeAnalysis.Options; - -namespace Microsoft.CodeAnalysis.Editor.UnitTests.Extensions -{ - public static class WorkspaceExtensions - { - public static void ApplyOptions(this Workspace workspace, IReadOnlyCollection>? options) - => workspace.ApplyOptions(options?.Select(kvp => (kvp.Key, kvp.Value))); - - internal static void ApplyOptions(this Workspace workspace, IReadOnlyCollection>? options) - => workspace.ApplyOptions(options?.Select(kvp => ((OptionKey)kvp.Key, kvp.Value))); - - private static void ApplyOptions(this Workspace workspace, IEnumerable<(OptionKey key, object value)>? options) - { - if (options != null) - { - var optionSet = workspace.Options; - foreach (var option in options) - { - optionSet = optionSet.WithChangedOption(option.key, option.value); - } - - workspace.TryApplyChanges(workspace.CurrentSolution.WithOptions(optionSet)); - } - } - } -} diff --git a/src/EditorFeatures/TestUtilities/ExtractInterface/ExtractInterfaceTestState.cs b/src/EditorFeatures/TestUtilities/ExtractInterface/ExtractInterfaceTestState.cs index 9a2a3a01af6ba..8cd693f1cb315 100644 --- a/src/EditorFeatures/TestUtilities/ExtractInterface/ExtractInterfaceTestState.cs +++ b/src/EditorFeatures/TestUtilities/ExtractInterface/ExtractInterfaceTestState.cs @@ -72,7 +72,7 @@ public TestExtractInterfaceOptionsService TestExtractInterfaceOptionsService { get { - return (TestExtractInterfaceOptionsService)ExtractFromDocument.Project.Solution.Workspace.Services.GetService(); + return (TestExtractInterfaceOptionsService)ExtractFromDocument.Project.Solution.Services.GetService(); } } @@ -130,10 +130,7 @@ public async Task ExtractViaCodeAction() public void Dispose() { - if (Workspace != null) - { - Workspace.Dispose(); - } + Workspace?.Dispose(); } } } diff --git a/src/EditorFeatures/TestUtilities/ExtractInterface/TestExtractInterfaceOptions.cs b/src/EditorFeatures/TestUtilities/ExtractInterface/TestExtractInterfaceOptions.cs index 1db5a8c70d8bf..b686071cb04e6 100644 --- a/src/EditorFeatures/TestUtilities/ExtractInterface/TestExtractInterfaceOptions.cs +++ b/src/EditorFeatures/TestUtilities/ExtractInterface/TestExtractInterfaceOptions.cs @@ -14,7 +14,7 @@ using Microsoft.CodeAnalysis.CodeGeneration; using Microsoft.CodeAnalysis.ExtractInterface; using Microsoft.CodeAnalysis.Host.Mef; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Notification; using Roslyn.Utilities; diff --git a/src/EditorFeatures/TestUtilities/Formatting/AbstractNewDocumentFormattingServiceTests.cs b/src/EditorFeatures/TestUtilities/Formatting/AbstractNewDocumentFormattingServiceTests.cs index e22b231b1aab5..61ed7700639f4 100644 --- a/src/EditorFeatures/TestUtilities/Formatting/AbstractNewDocumentFormattingServiceTests.cs +++ b/src/EditorFeatures/TestUtilities/Formatting/AbstractNewDocumentFormattingServiceTests.cs @@ -30,7 +30,7 @@ internal async Task TestAsync(string testCode, string expected, OptionsCollectio var solution = workspace.CurrentSolution; var document = workspace.CurrentSolution.Projects.First().Documents.First(); - var languageServices = document.Project.LanguageServices; + var languageServices = document.Project.Services; var cleanupOptions = options?.ToAnalyzerConfigOptions(languageServices).GetCodeCleanupOptions(allowImportsInHiddenRegions: false, fallbackOptions: null, languageServices) ?? diff --git a/src/EditorFeatures/TestUtilities/Formatting/CoreFormatterTestsBase.cs b/src/EditorFeatures/TestUtilities/Formatting/CoreFormatterTestsBase.cs index 81a541ff6fed8..71f2e18ff52b0 100644 --- a/src/EditorFeatures/TestUtilities/Formatting/CoreFormatterTestsBase.cs +++ b/src/EditorFeatures/TestUtilities/Formatting/CoreFormatterTestsBase.cs @@ -51,7 +51,7 @@ protected CoreFormatterTestsBase(ITestOutputHelper output) protected abstract SyntaxNode ParseCompilationUnit(string expected); internal static void TestIndentation( - int point, int? expectedIndentation, ITextView textView, TestHostDocument subjectDocument, IGlobalOptionService globalOptions) + int point, int? expectedIndentation, ITextView textView, TestHostDocument subjectDocument, EditorOptionsService editorOptionsService) { var textUndoHistory = new Mock(); var editorOperationsFactory = new Mock(); @@ -61,7 +61,7 @@ internal static void TestIndentation( var snapshot = subjectDocument.GetTextBuffer().CurrentSnapshot; var indentationLineFromBuffer = snapshot.GetLineFromPosition(point); - var provider = new SmartIndent(textView, globalOptions); + var provider = new SmartIndent(textView, editorOptionsService); var actualIndentation = provider.GetDesiredIndentation(indentationLineFromBuffer); Assert.Equal(expectedIndentation, actualIndentation.Value); @@ -75,12 +75,19 @@ internal void TestIndentation( bool useTabs) { var language = GetLanguageName(); - workspace.GlobalOptions.SetGlobalOption(new OptionKey(IndentationOptionsStorage.SmartIndent, language), indentStyle); - workspace.TryApplyChanges(workspace.CurrentSolution.WithOptions(workspace.Options - .WithChangedOption(FormattingOptions2.UseTabs, language, useTabs))); + var editorOptionsFactory = workspace.GetService(); + var document = workspace.Documents.First(); + var textBuffer = document.GetTextBuffer(); + var editorOptions = editorOptionsFactory.GetOptions(textBuffer); - var snapshot = workspace.Documents.First().GetTextBuffer().CurrentSnapshot; + editorOptions.SetOptionValue(DefaultOptions.IndentStyleId, indentStyle.ToEditorIndentStyle()); + editorOptions.SetOptionValue(DefaultOptions.ConvertTabsToSpacesOptionId, !useTabs); + + // Remove once https://github.com/dotnet/roslyn/issues/62204 is fixed: + workspace.GlobalOptions.SetGlobalOption(new OptionKey(IndentationOptionsStorage.SmartIndent, document.Project.Language), indentStyle); + + var snapshot = textBuffer.CurrentSnapshot; var bufferGraph = new Mock(MockBehavior.Strict); bufferGraph.Setup(x => x.MapUpToSnapshot(It.IsAny(), It.IsAny(), @@ -106,7 +113,9 @@ internal void TestIndentation( textView.Setup(x => x.BufferGraph).Returns(bufferGraph.Object); textView.SetupGet(x => x.TextSnapshot.TextBuffer).Returns(projectionBuffer.Object); - var provider = new SmartIndent(textView.Object, workspace.GlobalOptions); + var provider = new SmartIndent( + textView.Object, + workspace.GetService()); var indentationLineFromBuffer = snapshot.GetLineFromLineNumber(indentationLine); var actualIndentation = provider.GetDesiredIndentation(indentationLineFromBuffer); @@ -114,25 +123,16 @@ internal void TestIndentation( Assert.Equal(expectedIndentation, actualIndentation); } - private protected void AssertFormatWithView(string expectedWithMarker, string codeWithMarker, params (PerLanguageOption2 option, bool enabled)[] options) + private protected void AssertFormatWithView(string expectedWithMarker, string codeWithMarker, OptionsCollection options = null) { AssertFormatWithView(expectedWithMarker, codeWithMarker, parseOptions: null, options); } - private protected void AssertFormatWithView(string expectedWithMarker, string codeWithMarker, ParseOptions parseOptions, params (PerLanguageOption2 option, bool enabled)[] options) + private protected void AssertFormatWithView(string expectedWithMarker, string codeWithMarker, ParseOptions parseOptions, OptionsCollection options = null) { using var workspace = CreateWorkspace(codeWithMarker, parseOptions); - if (options != null) - { - var optionSet = workspace.Options; - foreach (var option in options) - { - optionSet = optionSet.WithChangedOption(option.option, GetLanguageName(), option.enabled); - } - - workspace.TryApplyChanges(workspace.CurrentSolution.WithOptions(optionSet)); - } + options?.SetGlobalOptions(workspace.GlobalOptions); // set up caret position var testDocument = workspace.Documents.Single(); @@ -201,7 +201,7 @@ private protected async Task AssertFormatAsync(string expected, string code, IEn var formattingService = document.GetRequiredLanguageService(); var formattingOptions = (options != null) ? - formattingService.GetFormattingOptions(options.ToAnalyzerConfigOptions(document.Project.LanguageServices), fallbackOptions: null) : + formattingService.GetFormattingOptions(options.ToAnalyzerConfigOptions(document.Project.Services), fallbackOptions: null) : formattingService.DefaultOptions; var rules = formattingRuleProvider.CreateRule(documentSyntax, 0).Concat(Formatter.GetDefaultFormattingRules(document)); @@ -213,7 +213,7 @@ private protected async Task AssertFormatAsync(string expected, string code, IEn internal void AssertFormatWithTransformation(Workspace workspace, string expected, SyntaxFormattingOptions options, IEnumerable rules, SyntaxNode root, IEnumerable spans) { - var newRootNode = Formatter.Format(root, spans, workspace.Services, options, rules, CancellationToken.None); + var newRootNode = Formatter.Format(root, spans, workspace.Services.SolutionServices, options, rules, CancellationToken.None); Assert.Equal(expected, newRootNode.ToFullString()); @@ -226,7 +226,7 @@ internal void AssertFormatWithTransformation(Workspace workspace, string expecte internal void AssertFormat(Workspace workspace, string expected, SyntaxFormattingOptions options, IEnumerable rules, ITextBuffer clonedBuffer, SyntaxNode root, IEnumerable spans) { - var result = Formatter.GetFormattedTextChanges(root, spans, workspace.Services, options, rules, CancellationToken.None); + var result = Formatter.GetFormattedTextChanges(root, spans, workspace.Services.SolutionServices, options, rules, CancellationToken.None); var actual = ApplyResultAndGetFormattedText(clonedBuffer, result); if (actual != expected) @@ -288,7 +288,7 @@ protected static void AssertFormatOnArbitraryNode(SyntaxNode node, string expect using var workspace = new AdhocWorkspace(); var formattingService = workspace.Services.GetLanguageServices(node.Language).GetRequiredService(); var options = formattingService.GetFormattingOptions(DictionaryAnalyzerConfigOptions.Empty, fallbackOptions: null); - var result = Formatter.Format(node, workspace.Services, options, CancellationToken.None); + var result = Formatter.Format(node, workspace.Services.SolutionServices, options, CancellationToken.None); var actual = result.GetText().ToString(); Assert.Equal(expected, actual); diff --git a/src/EditorFeatures/TestUtilities/GoToAdjacentMember/AbstractGoToAdjacentMemberTests.cs b/src/EditorFeatures/TestUtilities/GoToAdjacentMember/AbstractGoToAdjacentMemberTests.cs index 66e407b32b492..9d276dd1e6ff4 100644 --- a/src/EditorFeatures/TestUtilities/GoToAdjacentMember/AbstractGoToAdjacentMemberTests.cs +++ b/src/EditorFeatures/TestUtilities/GoToAdjacentMember/AbstractGoToAdjacentMemberTests.cs @@ -9,6 +9,8 @@ using System.Threading.Tasks; using Microsoft.CodeAnalysis.Editor.CommandHandlers; using Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces; +using Microsoft.CodeAnalysis.LanguageService; +using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Test.Utilities; using Roslyn.Utilities; using Xunit; @@ -37,12 +39,15 @@ protected async Task AssertNavigatedAsync(string code, bool next, SourceCodeKind { var hostDocument = workspace.DocumentWithCursor; var document = workspace.CurrentSolution.GetDocument(hostDocument.Id); - Assert.Empty((await document.GetSyntaxTreeAsync()).GetDiagnostics()); - var targetPosition = await GoToAdjacentMemberCommandHandler.GetTargetPositionAsync( - document, + var parsedDocument = await ParsedDocument.CreateAsync(document, CancellationToken.None); + Assert.Empty(parsedDocument.SyntaxTree.GetDiagnostics()); + var service = document.GetRequiredLanguageService(); + + var targetPosition = GoToAdjacentMemberCommandHandler.GetTargetPosition( + service, + parsedDocument.Root, hostDocument.CursorPosition.Value, - next, - CancellationToken.None); + next); Assert.NotNull(targetPosition); Assert.Equal(hostDocument.SelectedSpans.Single().Start, targetPosition.Value); @@ -60,13 +65,14 @@ protected async Task AssertNavigatedAsync(string code, bool next, SourceCodeKind { var hostDocument = workspace.DocumentWithCursor; var document = workspace.CurrentSolution.GetDocument(hostDocument.Id); - Assert.Empty((await document.GetSyntaxTreeAsync()).GetDiagnostics()); + var parsedDocument = await ParsedDocument.CreateAsync(document, CancellationToken.None); + Assert.Empty(parsedDocument.SyntaxTree.GetDiagnostics()); - return await GoToAdjacentMemberCommandHandler.GetTargetPositionAsync( - document, + return GoToAdjacentMemberCommandHandler.GetTargetPosition( + document.GetRequiredLanguageService(), + parsedDocument.Root, hostDocument.CursorPosition.Value, - next, - CancellationToken.None); + next); } } } diff --git a/src/EditorFeatures/TestUtilities/Microsoft.CodeAnalysis.EditorFeatures.Test.Utilities.csproj b/src/EditorFeatures/TestUtilities/Microsoft.CodeAnalysis.EditorFeatures.Test.Utilities.csproj index d54cdc7252b88..70283f6616bac 100644 --- a/src/EditorFeatures/TestUtilities/Microsoft.CodeAnalysis.EditorFeatures.Test.Utilities.csproj +++ b/src/EditorFeatures/TestUtilities/Microsoft.CodeAnalysis.EditorFeatures.Test.Utilities.csproj @@ -55,6 +55,7 @@ + diff --git a/src/EditorFeatures/TestUtilities/MoveStaticMembers/TestMoveStaticMembersService.cs b/src/EditorFeatures/TestUtilities/MoveStaticMembers/TestMoveStaticMembersService.cs index bc02f360ee914..ce7c381fafdf3 100644 --- a/src/EditorFeatures/TestUtilities/MoveStaticMembers/TestMoveStaticMembersService.cs +++ b/src/EditorFeatures/TestUtilities/MoveStaticMembers/TestMoveStaticMembersService.cs @@ -2,10 +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.Immutable; using System.Composition; +using System.Linq; +using System.Threading; using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.MoveStaticMembers; +using Microsoft.CodeAnalysis.Shared.Extensions; namespace Microsoft.CodeAnalysis.Test.Utilities.MoveStaticMembers { @@ -20,23 +24,46 @@ public TestMoveStaticMembersService() { } - public string? DestinationType { get; set; } + public string? DestinationName { get; set; } public ImmutableArray SelectedMembers { get; set; } + public ImmutableArray ExpectedPrecheckedMembers { get; set; } + public string? Filename { get; set; } - public MoveStaticMembersOptions GetMoveMembersToTypeOptions(Document document, INamedTypeSymbol selectedType, ISymbol? selectedNodeSymbol) + public bool CreateNew { get; set; } = true; + + public MoveStaticMembersOptions GetMoveMembersToTypeOptions(Document document, INamedTypeSymbol selectedType, ImmutableArray selectedNodeSymbols) { + if (!ExpectedPrecheckedMembers.IsEmpty) + { + // if we expect to have prechecked members and don't have the correct ones, error + var actualPrecheckedMembers = selectedNodeSymbols.SelectAsArray(n => n.Name).Sort(); + if (!ExpectedPrecheckedMembers.Sort().SequenceEqual(actualPrecheckedMembers)) + { + System.Diagnostics.Debug.Fail("Expected Prechecked members did not match recieved members"); + var errMsg = string.Format("Expected: {0} \n Actual: {1}", ExpectedPrecheckedMembers, actualPrecheckedMembers); + System.Diagnostics.Debug.Fail(errMsg); + throw new InvalidOperationException(errMsg); + } + } + var selectedMembers = selectedType.GetMembers().WhereAsArray(symbol => SelectedMembers.Contains(symbol.Name)); - var namespaceDisplay = selectedType.ContainingNamespace.IsGlobalNamespace - ? string.Empty - : selectedType.ContainingNamespace.ToDisplayString(); - // just return all the selected members - return new MoveStaticMembersOptions( - Filename!, - string.Join(".", namespaceDisplay, DestinationType!), - selectedMembers); + if (CreateNew) + { + var namespaceDisplay = selectedType.ContainingNamespace.IsGlobalNamespace + ? string.Empty + : selectedType.ContainingNamespace.ToDisplayString(); + // just return all the selected members + return new MoveStaticMembersOptions( + Filename!, + string.Join(".", namespaceDisplay, DestinationName!), + selectedMembers); + } + + var destination = selectedType.ContainingNamespace.GetAllTypes(CancellationToken.None).First(t => t.ToDisplayString() == DestinationName); + return new MoveStaticMembersOptions(destination, selectedMembers); } } } diff --git a/src/EditorFeatures/TestUtilities/MoveToNamespace/TestMoveToNamespaceOptionsService.cs b/src/EditorFeatures/TestUtilities/MoveToNamespace/TestMoveToNamespaceOptionsService.cs index 571d8ad9c4d3c..8f8d5514759af 100644 --- a/src/EditorFeatures/TestUtilities/MoveToNamespace/TestMoveToNamespaceOptionsService.cs +++ b/src/EditorFeatures/TestUtilities/MoveToNamespace/TestMoveToNamespaceOptionsService.cs @@ -8,7 +8,7 @@ using System.Collections.Immutable; using System.Composition; using Microsoft.CodeAnalysis.Host.Mef; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.MoveToNamespace; namespace Microsoft.CodeAnalysis.Test.Utilities.MoveToNamespace diff --git a/src/EditorFeatures/TestUtilities/PullMemberUp/TestPullMemberUpService.cs b/src/EditorFeatures/TestUtilities/PullMemberUp/TestPullMemberUpService.cs index e1c2742a638e7..1202cac72ec42 100644 --- a/src/EditorFeatures/TestUtilities/PullMemberUp/TestPullMemberUpService.cs +++ b/src/EditorFeatures/TestUtilities/PullMemberUp/TestPullMemberUpService.cs @@ -26,16 +26,17 @@ public TestPullMemberUpService(IEnumerable<(string member, bool makeAbstract)> s DestinationName = destinationName; } - public PullMembersUpOptions GetPullMemberUpOptions(Document document, ISymbol selectedNodeSymbol) + public PullMembersUpOptions GetPullMemberUpOptions(Document document, ImmutableArray selectedNodeSymbols) { - var members = selectedNodeSymbol.ContainingType.GetMembers().Where(member => MemberAndDestinationValidator.IsMemberValid(member)); + var containingType = selectedNodeSymbols[0].ContainingType; + var members = containingType.GetMembers().Where(member => MemberAndDestinationValidator.IsMemberValid(member)); var selectedMember = _selectedMembers == null ? members.Select(member => (member, false)) : _selectedMembers.Select(selection => (members.Single(symbol => symbol.Name == selection.member), selection.makeAbstract)); - var allInterfaces = selectedNodeSymbol.ContainingType.AllInterfaces; - var baseClass = selectedNodeSymbol.ContainingType.BaseType; + var allInterfaces = containingType.AllInterfaces; + var baseClass = containingType.BaseType; INamedTypeSymbol destination = null; if (DestinationName == null) @@ -44,7 +45,7 @@ public PullMembersUpOptions GetPullMemberUpOptions(Document document, ISymbol se if (destination == null) { - throw new ArgumentException($"No target base type for {selectedNodeSymbol}"); + throw new ArgumentException($"No target base type for {containingType}"); } } else diff --git a/src/EditorFeatures/TestUtilities/QuickInfo/AbstractSemanticQuickInfoSourceTests.cs b/src/EditorFeatures/TestUtilities/QuickInfo/AbstractSemanticQuickInfoSourceTests.cs index c461e8be32632..f64f4771682fc 100644 --- a/src/EditorFeatures/TestUtilities/QuickInfo/AbstractSemanticQuickInfoSourceTests.cs +++ b/src/EditorFeatures/TestUtilities/QuickInfo/AbstractSemanticQuickInfoSourceTests.cs @@ -10,7 +10,7 @@ using System.Linq; using System.Threading.Tasks; using Microsoft.CodeAnalysis.Editor.UnitTests.Classification; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.QuickInfo; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Test.Utilities; diff --git a/src/EditorFeatures/TestUtilities/SignatureHelp/AbstractSignatureHelpProviderTests.cs b/src/EditorFeatures/TestUtilities/SignatureHelp/AbstractSignatureHelpProviderTests.cs index e3c3a7189071c..e9ed6dcb8da8f 100644 --- a/src/EditorFeatures/TestUtilities/SignatureHelp/AbstractSignatureHelpProviderTests.cs +++ b/src/EditorFeatures/TestUtilities/SignatureHelp/AbstractSignatureHelpProviderTests.cs @@ -16,7 +16,7 @@ using Microsoft.CodeAnalysis.Completion; using Microsoft.CodeAnalysis.Editor.Implementation.IntelliSense.SignatureHelp.Presentation; using Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.SignatureHelp; using Microsoft.CodeAnalysis.Test.Utilities; diff --git a/src/EditorFeatures/TestUtilities/TodoComments/AbtractTodoCommentTests.cs b/src/EditorFeatures/TestUtilities/TodoComments/AbtractTodoCommentTests.cs index b05bc60a8f049..904c8af3cd898 100644 --- a/src/EditorFeatures/TestUtilities/TodoComments/AbtractTodoCommentTests.cs +++ b/src/EditorFeatures/TestUtilities/TodoComments/AbtractTodoCommentTests.cs @@ -19,15 +19,13 @@ namespace Microsoft.CodeAnalysis.Test.Utilities.TodoComments { public abstract class AbstractTodoCommentTests { - protected const string DefaultTokenList = "HACK:1|TODO:1|UNDONE:1|UnresolvedMergeConflict:0"; - protected abstract TestWorkspace CreateWorkspace(string codeWithMarker); protected async Task TestAsync(string codeWithMarker) { using var workspace = CreateWorkspace(codeWithMarker); - var tokenList = DefaultTokenList; + var tokenList = TodoCommentOptions.Default.TokenList; workspace.GlobalOptions.SetGlobalOption(new OptionKey(TodoCommentOptionsStorage.TokenList), tokenList); var hostDocument = workspace.Documents.First(); diff --git a/src/EditorFeatures/TestUtilities/TypeInferrer/TypeInferrerTestBase.cs b/src/EditorFeatures/TestUtilities/TypeInferrer/TypeInferrerTestBase.cs index 9a42a771ff5a7..316238a8b80f5 100644 --- a/src/EditorFeatures/TestUtilities/TypeInferrer/TypeInferrerTestBase.cs +++ b/src/EditorFeatures/TestUtilities/TypeInferrer/TypeInferrerTestBase.cs @@ -6,7 +6,7 @@ using System.Threading.Tasks; using Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Test.Utilities; using Microsoft.CodeAnalysis.Text; diff --git a/src/EditorFeatures/TestUtilities/Utilities/GlobalOptionsExtensions.cs b/src/EditorFeatures/TestUtilities/Utilities/GlobalOptionsExtensions.cs new file mode 100644 index 0000000000000..e0d2f9959d08b --- /dev/null +++ b/src/EditorFeatures/TestUtilities/Utilities/GlobalOptionsExtensions.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.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.Formatting; +using Microsoft.CodeAnalysis.Options; +using Microsoft.VisualStudio.Text.Editor; + +namespace Microsoft.CodeAnalysis.Test.Utilities; + +internal static class GlobalOptionsExtensions +{ + /// + /// Sets options stored in that are read by command handlers from the text editor to given . + /// + public static void SetEditorOptions(this IGlobalOptionService globalOptions, IEditorOptions editorOptions, string language) + { + editorOptions.SetOptionValue(DefaultOptions.IndentStyleId, globalOptions.GetOption(FormattingOptions2.SmartIndent, language).ToEditorIndentStyle()); + editorOptions.SetOptionValue(DefaultOptions.NewLineCharacterOptionId, globalOptions.GetOption(FormattingOptions2.NewLine, language)); + editorOptions.SetOptionValue(DefaultOptions.TabSizeOptionId, globalOptions.GetOption(FormattingOptions2.TabSize, language)); + editorOptions.SetOptionValue(DefaultOptions.IndentSizeOptionId, globalOptions.GetOption(FormattingOptions2.IndentationSize, language)); + editorOptions.SetOptionValue(DefaultOptions.ConvertTabsToSpacesOptionId, !globalOptions.GetOption(FormattingOptions2.UseTabs, language)); + } +} diff --git a/src/EditorFeatures/TestUtilities/Workspaces/TestHostDocument.cs b/src/EditorFeatures/TestUtilities/Workspaces/TestHostDocument.cs index ff1b09aab8c88..5ac6703cd3872 100644 --- a/src/EditorFeatures/TestUtilities/Workspaces/TestHostDocument.cs +++ b/src/EditorFeatures/TestUtilities/Workspaces/TestHostDocument.cs @@ -195,10 +195,7 @@ internal void SetProject(TestHostProject project) } } - if (_languageServiceProvider == null) - { - _languageServiceProvider = project.LanguageServiceProvider; - } + _languageServiceProvider ??= project.LanguageServiceProvider; } private class TestDocumentLoader : TextLoader diff --git a/src/EditorFeatures/TestUtilities/Workspaces/TestHostSolution.cs b/src/EditorFeatures/TestUtilities/Workspaces/TestHostSolution.cs index 9f041cd1c0e06..76444b1d83cda 100644 --- a/src/EditorFeatures/TestUtilities/Workspaces/TestHostSolution.cs +++ b/src/EditorFeatures/TestUtilities/Workspaces/TestHostSolution.cs @@ -7,7 +7,7 @@ using System.Collections.Generic; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Host; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Text; namespace Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces diff --git a/src/EditorFeatures/TestUtilities/Workspaces/TestWorkspace.cs b/src/EditorFeatures/TestUtilities/Workspaces/TestWorkspace.cs index 4af7bd190824a..6c43c13519a35 100644 --- a/src/EditorFeatures/TestUtilities/Workspaces/TestWorkspace.cs +++ b/src/EditorFeatures/TestUtilities/Workspaces/TestWorkspace.cs @@ -125,18 +125,12 @@ public TestHostDocument DocumentWithCursor protected override void OnDocumentTextChanged(Document document) { - if (_backgroundParser != null) - { - _backgroundParser.Parse(document); - } + _backgroundParser?.Parse(document); } protected override void OnDocumentClosing(DocumentId documentId) { - if (_backgroundParser != null) - { - _backgroundParser.CancelParse(documentId); - } + _backgroundParser?.CancelParse(documentId); } public new void RegisterText(SourceTextContainer text) @@ -168,10 +162,7 @@ protected override void Dispose(bool finalize) document.CloseTextView(); } - if (_backgroundParser != null) - { - _backgroundParser.CancelAllParses(); - } + _backgroundParser?.CancelAllParses(); base.Dispose(finalize); } @@ -843,11 +834,11 @@ internal ITextBuffer2 GetOrCreateBufferForPath(string? filePath, IContentType co // Ensure that the editor options on the text buffer matches that of the options that can be directly set in the workspace var editorOptions = ExportProvider.GetExportedValue().GetOptions(textBuffer); - var workspaceOptions = this.Options; + var globalOptions = GlobalOptions; - editorOptions.SetOptionValue(DefaultOptions.ConvertTabsToSpacesOptionId, !workspaceOptions.GetOption(FormattingOptions.UseTabs, languageName)); - editorOptions.SetOptionValue(DefaultOptions.TabSizeOptionId, workspaceOptions.GetOption(FormattingOptions.TabSize, languageName)); - editorOptions.SetOptionValue(DefaultOptions.IndentSizeOptionId, workspaceOptions.GetOption(FormattingOptions.IndentationSize, languageName)); + editorOptions.SetOptionValue(DefaultOptions.ConvertTabsToSpacesOptionId, !globalOptions.GetOption(FormattingOptions2.UseTabs, languageName)); + editorOptions.SetOptionValue(DefaultOptions.TabSizeOptionId, globalOptions.GetOption(FormattingOptions2.TabSize, languageName)); + editorOptions.SetOptionValue(DefaultOptions.IndentSizeOptionId, globalOptions.GetOption(FormattingOptions2.IndentationSize, languageName)); return textBuffer; }); diff --git a/src/EditorFeatures/TestUtilities/Workspaces/TestWorkspace_Create.cs b/src/EditorFeatures/TestUtilities/Workspaces/TestWorkspace_Create.cs index 3602ea8926fb1..1c94ed978e938 100644 --- a/src/EditorFeatures/TestUtilities/Workspaces/TestWorkspace_Create.cs +++ b/src/EditorFeatures/TestUtilities/Workspaces/TestWorkspace_Create.cs @@ -179,7 +179,7 @@ internal static TestWorkspace Create( extension = language; } - documentElements.Add(CreateDocumentElement(files[i], GetDefaultTestSourceDocumentName(index++, extension), parseOptions == null ? null : parseOptions[i])); + documentElements.Add(CreateDocumentElement(files[i], GetDefaultTestSourceDocumentName(index++, extension), parseOptions?[i])); } var workspaceElement = CreateWorkspaceElement( diff --git a/src/EditorFeatures/TestUtilities2/Intellisense/TestState.vb b/src/EditorFeatures/TestUtilities2/Intellisense/TestState.vb index 4310a552a29ef..c48fe682e2ec1 100644 --- a/src/EditorFeatures/TestUtilities2/Intellisense/TestState.vb +++ b/src/EditorFeatures/TestUtilities2/Intellisense/TestState.vb @@ -11,7 +11,7 @@ Imports Microsoft.CodeAnalysis.Editor.Implementation.IntelliSense.AsyncCompletio Imports Microsoft.CodeAnalysis.Editor.UnitTests.Extensions Imports Microsoft.CodeAnalysis.Editor.UnitTests.Utilities Imports Microsoft.CodeAnalysis.Formatting -Imports Microsoft.CodeAnalysis.LanguageServices +Imports Microsoft.CodeAnalysis.LanguageService Imports Microsoft.CodeAnalysis.Shared.TestHooks Imports Microsoft.CodeAnalysis.SignatureHelp Imports Microsoft.CodeAnalysis.Test.Utilities @@ -63,9 +63,9 @@ Namespace Microsoft.CodeAnalysis.Editor.UnitTests.IntelliSense ' Disable editor's responsive completion option to ensure a deterministic test behavior MyBase.TextView.Options.GlobalOptions.SetOptionValue(DefaultOptions.ResponsiveCompletionOptionId, False) + MyBase.TextView.Options.GlobalOptions.SetOptionValue(DefaultOptions.IndentStyleId, IndentingStyle.Smart) - Dim languageServices = Me.Workspace.CurrentSolution.Projects.First().LanguageServices - Dim language = languageServices.Language + Dim language = Me.Workspace.CurrentSolution.Projects.First().Language Me.SessionTestState = GetExportedValue(Of IIntelliSenseTestState)() @@ -127,6 +127,12 @@ Namespace Microsoft.CodeAnalysis.Editor.UnitTests.IntelliSense MyBase.SendReturn(Sub(a, n, c) handler.ExecuteCommand(a, n, c), Sub() EditorOperations.InsertNewLine()) End Sub + Public Sub SendBackspaces(count As Integer) + For i = 0 To count - 1 + Me.SendBackspace() + Next + End Sub + Public Overrides Sub SendBackspace() Dim compHandler = GetHandler(Of IChainedCommandHandler(Of BackspaceKeyCommandArgs))() MyBase.SendBackspace(Sub(a, n, c) compHandler.ExecuteCommand(a, n, c), AddressOf MyBase.SendBackspace) @@ -531,6 +537,14 @@ Namespace Microsoft.CodeAnalysis.Editor.UnitTests.IntelliSense Return computedItems.SuggestionItem IsNot Nothing End Function + Public Sub AssertSuggestedItemSelected(displayText As String) + Dim session = GetExportedValue(Of IAsyncCompletionBroker)().GetSession(TextView) + Assert.NotNull(session) + Dim computedItems = session.GetComputedItems(CancellationToken.None) + Assert.True(computedItems.SuggestionItemSelected) + Assert.Equal(computedItems.SuggestionItem.DisplayText, displayText) + End Sub + Public Function IsSoftSelected() As Boolean Dim session = GetExportedValue(Of IAsyncCompletionBroker)().GetSession(TextView) Assert.NotNull(session) diff --git a/src/EditorFeatures/VisualBasic/AutomaticCompletion/AutomaticLineEnderCommandHandler.vb b/src/EditorFeatures/VisualBasic/AutomaticCompletion/AutomaticLineEnderCommandHandler.vb index 78191f3f7a8ed..5d95701bf9851 100644 --- a/src/EditorFeatures/VisualBasic/AutomaticCompletion/AutomaticLineEnderCommandHandler.vb +++ b/src/EditorFeatures/VisualBasic/AutomaticCompletion/AutomaticLineEnderCommandHandler.vb @@ -11,6 +11,7 @@ Imports Microsoft.CodeAnalysis.Options Imports Microsoft.CodeAnalysis.Text Imports Microsoft.VisualStudio.Commanding Imports Microsoft.VisualStudio.Language.Intellisense.AsyncCompletion +Imports Microsoft.VisualStudio.Text.Editor Imports Microsoft.VisualStudio.Text.Editor.Commanding.Commands Imports Microsoft.VisualStudio.Text.Operations Imports Microsoft.VisualStudio.Utilities @@ -30,9 +31,9 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.AutomaticCompletion Public Sub New(undoRegistry As ITextUndoHistoryRegistry, editorOperations As IEditorOperationsFactoryService, - globalOptions As IGlobalOptionService) + editorOptionsService As EditorOptionsService) - MyBase.New(undoRegistry, editorOperations, globalOptions) + MyBase.New(undoRegistry, editorOperations, editorOptionsService) End Sub Protected Overrides Sub NextAction(editorOperation As IEditorOperations, nextAction As Action) diff --git a/src/EditorFeatures/VisualBasic/DocumentationComments/DocumentationCommentCommandHandler.vb b/src/EditorFeatures/VisualBasic/DocumentationComments/DocumentationCommentCommandHandler.vb index 395db41ad26b6..adf1516f82f55 100644 --- a/src/EditorFeatures/VisualBasic/DocumentationComments/DocumentationCommentCommandHandler.vb +++ b/src/EditorFeatures/VisualBasic/DocumentationComments/DocumentationCommentCommandHandler.vb @@ -11,6 +11,7 @@ Imports Microsoft.VisualStudio.Text.Operations Imports Microsoft.VisualStudio.Utilities Imports Microsoft.CodeAnalysis.DocumentationComments Imports Microsoft.CodeAnalysis.Options +Imports Microsoft.VisualStudio.Text.Editor Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.DocumentationComments @@ -27,9 +28,9 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.DocumentationComments uiThreadOperationExecutor As IUIThreadOperationExecutor, undoHistoryRegistry As ITextUndoHistoryRegistry, editorOperationsFactoryService As IEditorOperationsFactoryService, - globalOptions As IGlobalOptionService) + editorOptionsService As EditorOptionsService) - MyBase.New(uiThreadOperationExecutor, undoHistoryRegistry, editorOperationsFactoryService, globalOptions) + MyBase.New(uiThreadOperationExecutor, undoHistoryRegistry, editorOperationsFactoryService, editorOptionsService) End Sub Protected Overrides ReadOnly Property ExteriorTriviaText As String diff --git a/src/EditorFeatures/VisualBasic/EndConstructGeneration/EndConstructCommandHandler.vb b/src/EditorFeatures/VisualBasic/EndConstructGeneration/EndConstructCommandHandler.vb index 0c01dad43f02d..eda6cf180b9ac 100644 --- a/src/EditorFeatures/VisualBasic/EndConstructGeneration/EndConstructCommandHandler.vb +++ b/src/EditorFeatures/VisualBasic/EndConstructGeneration/EndConstructCommandHandler.vb @@ -141,11 +141,11 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.EndConstructGeneration Dim options = document.GetCodeCleanupOptionsAsync(_globalOptions, cancellationToken).AsTask().WaitAndGetResult(cancellationToken) Dim cleanDocument = CodeCleaner.CleanupAsync(document, GetSpanToCleanup(statement), Options, codeCleanups, cancellationToken:=cancellationToken).WaitAndGetResult(cancellationToken) + Dim changes = cleanDocument.GetTextChangesAsync(document, cancellationToken).WaitAndGetResult(cancellationToken) Using transaction = New CaretPreservingEditTransaction(VBEditorResources.End_Construct, view, _undoHistoryRegistry, _editorOperationsFactoryService) transaction.MergePolicy = AutomaticCodeChangeMergePolicy.Instance - - cleanDocument.Project.Solution.Workspace.ApplyDocumentChanges(cleanDocument, cancellationToken) + buffer.ApplyChanges(changes) transaction.Complete() End Using End Sub diff --git a/src/EditorFeatures/VisualBasic/EndConstructGeneration/ReplaceSpanResult.vb b/src/EditorFeatures/VisualBasic/EndConstructGeneration/ReplaceSpanResult.vb index ed1364118765b..909b925f7be53 100644 --- a/src/EditorFeatures/VisualBasic/EndConstructGeneration/ReplaceSpanResult.vb +++ b/src/EditorFeatures/VisualBasic/EndConstructGeneration/ReplaceSpanResult.vb @@ -37,12 +37,7 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.EndConstructGeneration Return End If - Dim oldSolution = document.Project.Solution.Workspace.CurrentSolution - Dim newSolution = oldSolution.UpdateDocument( - document.Id, SpecializedCollections.SingletonEnumerable( - New TextChange(_snapshotSpan.TranslateTo(current, SpanTrackingMode.EdgeExclusive).Span.ToTextSpan(), _replacementText)), CancellationToken.None) - - oldSolution.Workspace.TryApplyChanges(newSolution) + subjectBuffer.ApplyChange(New TextChange(_snapshotSpan.TranslateTo(current, SpanTrackingMode.EdgeExclusive).Span.ToTextSpan(), _replacementText)) Dim startPoint = _snapshotSpan.Start.TranslateTo(subjectBuffer.CurrentSnapshot, PointTrackingMode.Negative) If _newCaretPosition IsNot Nothing Then diff --git a/src/EditorFeatures/VisualBasic/EndConstructGeneration/SpitLinesResult.vb b/src/EditorFeatures/VisualBasic/EndConstructGeneration/SpitLinesResult.vb index 40bde45965f3a..547f1e94eb88f 100644 --- a/src/EditorFeatures/VisualBasic/EndConstructGeneration/SpitLinesResult.vb +++ b/src/EditorFeatures/VisualBasic/EndConstructGeneration/SpitLinesResult.vb @@ -49,8 +49,7 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.EndConstructGeneration ' in the buffer Dim joinedLines = If(_startOnCurrentLine, "", bufferNewLine) + String.Join(bufferNewLine, _lines) - document.Project.Solution.Workspace.ApplyTextChanges( - document.Id, SpecializedCollections.SingletonEnumerable(New TextChange(New TextSpan(caretPosition, 0), joinedLines)), CancellationToken.None) + subjectBuffer.ApplyChange(New TextChange(New TextSpan(caretPosition, 0), joinedLines)) SetIndentForFirstBlankLine(textView, subjectBuffer, smartIndentationService, currentLine) End Sub diff --git a/src/EditorFeatures/VisualBasic/EndConstructGeneration/VisualBasicEndConstructGenerationService.vb b/src/EditorFeatures/VisualBasic/EndConstructGeneration/VisualBasicEndConstructGenerationService.vb index c4ef6e59106d3..eb290da618bfd 100644 --- a/src/EditorFeatures/VisualBasic/EndConstructGeneration/VisualBasicEndConstructGenerationService.vb +++ b/src/EditorFeatures/VisualBasic/EndConstructGeneration/VisualBasicEndConstructGenerationService.vb @@ -323,22 +323,20 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.EndConstructGeneration Private Shared Function InsertEndTextAndUpdateCaretPosition( view As ITextView, + subjectBuffer As ITextBuffer, insertPosition As Integer, caretPosition As Integer, - endText As String, - cancellationToken As CancellationToken + endText As String ) As Boolean - Dim document = view.TextSnapshot.GetOpenDocumentInCurrentContextWithChanges() + Dim document = subjectBuffer.CurrentSnapshot.GetOpenDocumentInCurrentContextWithChanges() If document Is Nothing Then Return False End If - document.Project.Solution.Workspace.ApplyTextChanges( - document.Id, SpecializedCollections.SingletonEnumerable( - New TextChange(New TextSpan(insertPosition, 0), endText)), cancellationToken) + subjectBuffer.ApplyChange(New TextChange(New TextSpan(insertPosition, 0), endText)) - Dim caretPosAfterEdit = New SnapshotPoint(view.TextSnapshot, caretPosition) + Dim caretPosAfterEdit = New SnapshotPoint(subjectBuffer.CurrentSnapshot, caretPosition) view.TryMoveCaretToAndEnsureVisible(caretPosAfterEdit) @@ -369,7 +367,7 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.EndConstructGeneration End If Dim endText = "]]>" - Return InsertEndTextAndUpdateCaretPosition(textView, state.CaretPosition, state.TokenToLeft.Span.End, endText, cancellationToken) + Return InsertEndTextAndUpdateCaretPosition(textView, subjectBuffer, state.CaretPosition, state.TokenToLeft.Span.End, endText) End Using End Function @@ -397,7 +395,7 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.EndConstructGeneration End If Dim endText = "-->" - Return InsertEndTextAndUpdateCaretPosition(textView, state.CaretPosition, state.TokenToLeft.Span.End, endText, cancellationToken) + Return InsertEndTextAndUpdateCaretPosition(textView, subjectBuffer, state.CaretPosition, state.TokenToLeft.Span.End, endText) End Using End Function @@ -425,7 +423,7 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.EndConstructGeneration End If Dim endTagText = "" - Return InsertEndTextAndUpdateCaretPosition(textView, state.CaretPosition, state.TokenToLeft.Span.End, endTagText, cancellationToken) + Return InsertEndTextAndUpdateCaretPosition(textView, subjectBuffer, state.CaretPosition, state.TokenToLeft.Span.End, endTagText) End Using End Function @@ -449,7 +447,7 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.EndConstructGeneration End If Dim endText = " %>" ' NOTE: two spaces are inserted. The caret will be moved between them - Return InsertEndTextAndUpdateCaretPosition(textView, state.CaretPosition, state.TokenToLeft.Span.End + 1, endText, cancellationToken) + Return InsertEndTextAndUpdateCaretPosition(textView, subjectBuffer, state.CaretPosition, state.TokenToLeft.Span.End + 1, endText) End Using End Function @@ -478,7 +476,7 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.EndConstructGeneration End If Dim endText = "?>" - Return InsertEndTextAndUpdateCaretPosition(textView, state.CaretPosition, state.TokenToLeft.Span.End, endText, cancellationToken) + Return InsertEndTextAndUpdateCaretPosition(textView, subjectBuffer, state.CaretPosition, state.TokenToLeft.Span.End, endText) End Using End Function diff --git a/src/EditorFeatures/VisualBasic/LineCommit/CommitCommandHandler.vb b/src/EditorFeatures/VisualBasic/LineCommit/CommitCommandHandler.vb index 20acec003dedc..f9ab79e7898ba 100644 --- a/src/EditorFeatures/VisualBasic/LineCommit/CommitCommandHandler.vb +++ b/src/EditorFeatures/VisualBasic/LineCommit/CommitCommandHandler.vb @@ -240,7 +240,7 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.LineCommit Dim document = args.SubjectBuffer.CurrentSnapshot.GetOpenDocumentInCurrentContextWithChanges() If document IsNot Nothing Then - Dim formattingRuleService = document.Project.Solution.Workspace.Services.GetService(Of IHostDependentFormattingRuleFactoryService)() + Dim formattingRuleService = document.Project.Solution.Services.GetService(Of IHostDependentFormattingRuleFactoryService)() If formattingRuleService.ShouldNotFormatOrCommitOnPaste(document.Id) Then transaction.Complete() Return diff --git a/src/EditorFeatures/VisualBasic/LineCommit/CommitFormatter.vb b/src/EditorFeatures/VisualBasic/LineCommit/CommitFormatter.vb index 8571ecac956aa..cf753e036fbdc 100644 --- a/src/EditorFeatures/VisualBasic/LineCommit/CommitFormatter.vb +++ b/src/EditorFeatures/VisualBasic/LineCommit/CommitFormatter.vb @@ -32,16 +32,12 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.LineCommit p.Name <> PredefinedCodeCleanupProviderNames.Format End Function - Private ReadOnly _globalOptions As IGlobalOptionService - Private ReadOnly _indentationManager As IIndentationManagerService - Private ReadOnly _editorOptionsFactory As IEditorOptionsFactoryService + Private ReadOnly _editorOptionsService As EditorOptionsService - Public Sub New(indentationManager As IIndentationManagerService, editorOptionsFactory As IEditorOptionsFactoryService, globalOptions As IGlobalOptionService) - _indentationManager = indentationManager - _editorOptionsFactory = editorOptionsFactory - _globalOptions = globalOptions + Public Sub New(editorOptionsService As EditorOptionsService) + _editorOptionsService = editorOptionsService End Sub Public Sub CommitRegion(spanToFormat As SnapshotSpan, @@ -68,7 +64,7 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.LineCommit Return End If - If Not (isExplicitFormat OrElse _globalOptions.GetOption(FeatureOnOffOptions.PrettyListing, LanguageNames.VisualBasic)) Then + If Not (isExplicitFormat OrElse _editorOptionsService.GlobalOptions.GetOption(FeatureOnOffOptions.PrettyListing, LanguageNames.VisualBasic)) Then Return End If @@ -80,17 +76,16 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.LineCommit End If ' create commit formatting cleanup provider that has line commit specific behavior - Dim fallbackOptions = _globalOptions.GetVisualBasicSyntaxFormattingOptions() - Dim formattingOptions = _indentationManager.GetInferredFormattingOptions(buffer, _editorOptionsFactory, document.Project.LanguageServices, fallbackOptions, isExplicitFormat) + Dim formattingOptions = buffer.GetSyntaxFormattingOptions(_editorOptionsService, document.Project.Services, isExplicitFormat) Dim commitFormattingCleanup = GetCommitFormattingCleanupProvider( document.Id, - document.Project.LanguageServices, + document.Project.Services, formattingOptions, spanToFormat, baseSnapshot, baseTree, dirtyRegion, - document.GetSyntaxTreeSynchronously(cancellationToken), + tree, cancellationToken) Dim codeCleanups = CodeCleaner.GetDefaultProviders(document). @@ -98,7 +93,7 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.LineCommit Concat(commitFormattingCleanup) Dim cleanupService = document.GetRequiredLanguageService(Of ICodeCleanerService) - Dim cleanupOptions = document.GetCodeCleanupOptionsAsync(_globalOptions, cancellationToken).AsTask().WaitAndGetResult(cancellationToken) + Dim cleanupOptions = document.GetCodeCleanupOptionsAsync(_editorOptionsService.GlobalOptions, cancellationToken).AsTask().WaitAndGetResult(cancellationToken) Dim finalDocument As Document If useSemantics OrElse isExplicitFormat Then @@ -115,7 +110,7 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.LineCommit root, ImmutableArray.Create(textSpanToFormat), formattingOptions, - document.Project.Solution.Workspace.Services, + document.Project.Solution.Services, codeCleanups, cancellationToken).WaitAndGetResult(cancellationToken) @@ -131,7 +126,8 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.LineCommit End If End If - finalDocument.Project.Solution.Workspace.ApplyDocumentChanges(finalDocument, cancellationToken) + Dim changes = finalDocument.GetTextChangesAsync(document, cancellationToken).WaitAndGetResult(cancellationToken) + buffer.ApplyChanges(changes) End Using End Sub @@ -149,7 +145,7 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.LineCommit Private Shared Function GetCommitFormattingCleanupProvider( documentId As DocumentId, - languageServices As HostLanguageServices, + languageServices As CodeAnalysis.Host.LanguageServices, options As SyntaxFormattingOptions, spanToFormat As SnapshotSpan, oldSnapshot As ITextSnapshot, @@ -168,7 +164,7 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.LineCommit Private Shared Function GetFormattingRules( documentId As DocumentId, - languageServices As HostLanguageServices, + languageServices As CodeAnalysis.Host.LanguageServices, options As SyntaxFormattingOptions, spanToFormat As SnapshotSpan, oldDirtySpan As SnapshotSpan, @@ -192,7 +188,7 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.LineCommit ' workaround for VB razor case. ' if we are under VB razor, we always use anchor operation otherwise, due to our double formatting, everything will just get messed. ' this is really a hacky workaround we should remove this in dev14 - Dim formattingRuleService = languageServices.WorkspaceServices.GetService(Of IHostDependentFormattingRuleFactoryService)() + Dim formattingRuleService = languageServices.SolutionServices.GetService(Of IHostDependentFormattingRuleFactoryService)() If formattingRuleService IsNot Nothing Then If formattingRuleService.ShouldUseBaseIndentation(documentId) Then Return Formatter.GetDefaultFormattingRules(languageServices) @@ -230,7 +226,7 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.LineCommit End Function Private Shared Function GetNumberOfIndentOperations( - languageServices As HostLanguageServices, + languageServices As CodeAnalysis.Host.LanguageServices, options As SyntaxFormattingOptions, syntaxTree As SyntaxTree, span As SnapshotSpan, diff --git a/src/EditorFeatures/VisualBasic/Utilities/CommandHandlers/AbstractImplementAbstractClassOrInterfaceCommandHandler.vb b/src/EditorFeatures/VisualBasic/Utilities/CommandHandlers/AbstractImplementAbstractClassOrInterfaceCommandHandler.vb index da9fcb1d89f50..8cb816511fdaa 100644 --- a/src/EditorFeatures/VisualBasic/Utilities/CommandHandlers/AbstractImplementAbstractClassOrInterfaceCommandHandler.vb +++ b/src/EditorFeatures/VisualBasic/Utilities/CommandHandlers/AbstractImplementAbstractClassOrInterfaceCommandHandler.vb @@ -164,7 +164,7 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.Utilities.CommandHandlers Return False End If - Dim newDocument = TryGetNewDocument(document, _globalOptions.GetImplementTypeGenerationOptions(document.Project.LanguageServices), identifier, cancellationToken) + Dim newDocument = TryGetNewDocument(document, _globalOptions.GetImplementTypeGenerationOptions(document.Project.Services), identifier, cancellationToken) If newDocument Is Nothing Then Return False @@ -175,7 +175,8 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.Utilities.CommandHandlers newDocument = Simplifier.ReduceAsync(newDocument, Simplifier.Annotation, cleanupOptions.SimplifierOptions, cancellationToken).WaitAndGetResult(cancellationToken) newDocument = Formatter.FormatAsync(newDocument, Formatter.Annotation, cleanupOptions.FormattingOptions, cancellationToken).WaitAndGetResult(cancellationToken) - newDocument.Project.Solution.Workspace.ApplyDocumentChanges(newDocument, cancellationToken) + Dim changes = newDocument.GetTextChangesAsync(document, cancellationToken).WaitAndGetResult(cancellationToken) + args.SubjectBuffer.ApplyChanges(changes) ' Place the cursor back to where it logically was after this token = newDocument.GetSyntaxRootSynchronously(cancellationToken). diff --git a/src/EditorFeatures/VisualBasicTest/CaseCorrecting/CaseCorrectionServiceTests.vb b/src/EditorFeatures/VisualBasicTest/CaseCorrecting/CaseCorrectionServiceTests.vb index 1035780279cb6..6a7770a524df2 100644 --- a/src/EditorFeatures/VisualBasicTest/CaseCorrecting/CaseCorrectionServiceTests.vb +++ b/src/EditorFeatures/VisualBasicTest/CaseCorrecting/CaseCorrectionServiceTests.vb @@ -30,11 +30,10 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.CaseCorrecting Private Shared Async Function TestAsync(expected As String, workspace As TestWorkspace) As Task Dim hostDocument = workspace.Documents.First() - Dim buffer = hostDocument.GetTextBuffer() Dim document = workspace.CurrentSolution.GetDocument(hostDocument.Id) Dim span = (Await document.GetSyntaxRootAsync()).FullSpan - Dim options = CodeCleanupOptions.GetDefault(document.Project.LanguageServices) + Dim options = CodeCleanupOptions.GetDefault(document.Project.Services) Dim service = document.GetLanguageService(Of ICodeCleanerService) Dim newDocument = Await service.CleanupAsync( @@ -42,9 +41,7 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.CaseCorrecting ImmutableArray.Create(Of ICodeCleanupProvider)(New CaseCorrectionCodeCleanupProvider()), CancellationToken.None) - newDocument.Project.Solution.Workspace.ApplyDocumentChanges(newDocument, CancellationToken.None) - - Dim actual = buffer.CurrentSnapshot.GetText() + Dim actual = newDocument.GetTextSynchronously(CancellationToken.None).ToString() Assert.Equal(expected, actual) End Function diff --git a/src/EditorFeatures/VisualBasicTest/Classification/SyntacticClassifierTests.vb b/src/EditorFeatures/VisualBasicTest/Classification/SyntacticClassifierTests.vb index 54faae4ae9dd0..4f150e3ecbbed 100644 --- a/src/EditorFeatures/VisualBasicTest/Classification/SyntacticClassifierTests.vb +++ b/src/EditorFeatures/VisualBasicTest/Classification/SyntacticClassifierTests.vb @@ -5181,6 +5181,44 @@ end interface" Keyword("interface")) End Function + + Public Async Function TestConflictMarkers2(testHost As TestHost) As Task + Dim code = +"interface I +<<<<<<< Start + sub Goo() +||||||| Baseline + sub Removed() +======= + sub Bar() +>>>>>>> End +end interface" + + Await TestAsync( + code, + testHost, + Keyword("interface"), + [Interface]("I"), + Comment("<<<<<<< Start"), + Keyword("sub"), + Method("Goo"), + Punctuation.OpenParen, + Punctuation.CloseParen, + Comment("||||||| Baseline"), + Keyword("sub"), + Identifier("Removed"), + Punctuation.OpenParen, + Punctuation.CloseParen, + Comment("======="), + Keyword("sub"), + Identifier("Bar"), + Punctuation.OpenParen, + Punctuation.CloseParen, + Comment(">>>>>>> End"), + Keyword("end"), + Keyword("interface")) + End Function + Public Async Function TestConstField(testHost As TestHost) As Task Dim code = "Const Number = 42" diff --git a/src/EditorFeatures/VisualBasicTest/CodeActions/IntroduceParameter/IntroduceParameterTests.vb b/src/EditorFeatures/VisualBasicTest/CodeActions/IntroduceParameter/IntroduceParameterTests.vb index 81b5dded0aee7..cb19dac8e86e6 100644 --- a/src/EditorFeatures/VisualBasicTest/CodeActions/IntroduceParameter/IntroduceParameterTests.vb +++ b/src/EditorFeatures/VisualBasicTest/CodeActions/IntroduceParameter/IntroduceParameterTests.vb @@ -7,18 +7,10 @@ Imports Microsoft.CodeAnalysis.CodeActions Imports Microsoft.CodeAnalysis.CodeRefactorings Imports Microsoft.CodeAnalysis.VisualBasic.IntroduceVariable +Imports VerifyVB = Microsoft.CodeAnalysis.Editor.UnitTests.CodeActions.VisualBasicCodeRefactoringVerifier(Of Microsoft.CodeAnalysis.VisualBasic.IntroduceVariable.VisualBasicIntroduceParameterCodeRefactoringProvider) + Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.CodeRefactorings.IntroduceParameter Public Class IntroduceParameterTests - Inherits AbstractVisualBasicCodeActionTest - - Protected Overrides Function CreateCodeRefactoringProvider(workspace As Workspace, parameters As TestParameters) As CodeRefactoringProvider - Return New VisualBasicIntroduceParameterCodeRefactoringProvider() - End Function - - Protected Overrides Function MassageActions(actions As ImmutableArray(Of CodeAction)) As ImmutableArray(Of CodeAction) - Return GetNestedActions(actions) - End Function - Public Async Function TestExpressionWithNoMethodCallsCase() As Task Dim source = @@ -32,7 +24,12 @@ End Class" Sub M(x As Integer, y As Integer, z As Integer, num As Integer) End Sub End Class" - Await TestInRegularAndScriptAsync(source, expected, index:=0) + Await New VerifyVB.Test With + { + .TestCode = source, + .FixedCode = expected, + .CodeActionIndex = 0 + }.RunAsync() End Function @@ -48,7 +45,7 @@ End Class" M(z, y, x) End Sub End Class" - Await TestMissingInRegularAndScriptAsync(source) + Await VerifyVB.VerifyRefactoringAsync(source, source) End Function @@ -72,7 +69,12 @@ End Class" M(y, 5, 2, y.Length * 5 * 2) End Sub End Class" - Await TestInRegularAndScriptAsync(source, expected, index:=0) + Await New VerifyVB.Test With + { + .TestCode = source, + .FixedCode = expected, + .CodeActionIndex = 0 + }.RunAsync() End Function @@ -96,7 +98,12 @@ End Class" M(z, y, x, z * y * x) End Sub End Class" - Await TestInRegularAndScriptAsync(source, expected, index:=0) + Await New VerifyVB.Test With + { + .TestCode = source, + .FixedCode = expected, + .CodeActionIndex = 0 + }.RunAsync() End Function @@ -104,14 +111,14 @@ End Class" Dim source = "Class Program Sub M(x As Integer, y As Integer, z As Integer) - Dim num = [|x * y * z|], y = 0 + Dim num = [|x * {|BC32000:y|} * z|], {|BC30734:y|} = 0 End Sub Sub M1(x As Integer, y As Integer, z As Integer) M(z, y, x) End Sub End Class" - Await TestMissingInRegularAndScriptAsync(source) + Await VerifyVB.VerifyRefactoringAsync(source, source) End Function @@ -126,7 +133,7 @@ End Class" M(z, y, x) End Sub End Class" - Await TestMissingInRegularAndScriptAsync(source) + Await VerifyVB.VerifyRefactoringAsync(source, source) End Function @@ -139,7 +146,7 @@ End Class" Sub M1(x As Integer, y As Integer, z As Integer) M(z, y, x) - M(a + b, 5, x) + M({|BC30451:a|} + {|BC30451:b|}, 5, x) End Sub End Class" Dim expected = @@ -149,10 +156,15 @@ End Class" Sub M1(x As Integer, y As Integer, z As Integer) M(z, y, x, z * y * x) - M(a + b, 5, x, (a + b) * 5 * x) + M({|BC30451:a|} + {|BC30451:b|}, 5, x, ({|BC30451:a|} + {|BC30451:b|}) * 5 * x) End Sub End Class" - Await TestInRegularAndScriptAsync(source, expected, index:=0) + Await New VerifyVB.Test With + { + .TestCode = source, + .FixedCode = expected, + .CodeActionIndex = 0 + }.RunAsync() End Function @@ -178,7 +190,12 @@ End Class" M(z, y, x, z * y * x) End Sub End Class" - Await TestInRegularAndScriptAsync(source, expected, index:=3) + Await New VerifyVB.Test With + { + .TestCode = source, + .FixedCode = expected, + .CodeActionIndex = 3 + }.RunAsync() End Function @@ -198,7 +215,12 @@ End Class" Sub M(x As Integer, y As Integer, z As Integer, num As Integer) End Sub End Class" - Await TestInRegularAndScriptAsync(source, expected, index:=1) + Await New VerifyVB.Test With + { + .TestCode = source, + .FixedCode = expected, + .CodeActionIndex = 1 + }.RunAsync() End Function @@ -226,7 +248,12 @@ End Class" M(z, y, x, GetNum(z, y, x)) End Sub End Class" - Await TestInRegularAndScriptAsync(source, expected, index:=1) + Await New VerifyVB.Test With + { + .TestCode = source, + .FixedCode = expected, + .CodeActionIndex = 1 + }.RunAsync() End Function @@ -257,7 +284,12 @@ End Class" End Sub End Class" - Await TestInRegularAndScriptAsync(source, expected, index:=4) + Await New VerifyVB.Test With + { + .TestCode = source, + .FixedCode = expected, + .CodeActionIndex = 4 + }.RunAsync() End Function @@ -285,7 +317,12 @@ End Class" Me.M(z, y, x, GetNum(z, y, x)) End Sub End Class" - Await TestInRegularAndScriptAsync(source, expected, index:=1) + Await New VerifyVB.Test With + { + .TestCode = source, + .FixedCode = expected, + .CodeActionIndex = 1 + }.RunAsync() End Function @@ -313,7 +350,12 @@ End Class" Me?.M(z, y, x, Me?.GetNum(z, y, x)) End Sub End Class" - Await TestInRegularAndScriptAsync(source, expected, index:=1) + Await New VerifyVB.Test With + { + .TestCode = source, + .FixedCode = expected, + .CodeActionIndex = 1 + }.RunAsync() End Function @@ -357,7 +399,12 @@ Class B Return age End Function End Class" - Await TestInRegularAndScriptAsync(source, expected, index:=1) + Await New VerifyVB.Test With + { + .TestCode = source, + .FixedCode = expected, + .CodeActionIndex = 1 + }.RunAsync() End Function @@ -401,7 +448,12 @@ Class B Return age End Function End Class" - Await TestInRegularAndScriptAsync(source, expected, index:=1) + Await New VerifyVB.Test With + { + .TestCode = source, + .FixedCode = expected, + .CodeActionIndex = 1 + }.RunAsync() End Function @@ -445,7 +497,12 @@ Class B Return age End Function End Class" - Await TestInRegularAndScriptAsync(source, expected, index:=1) + Await New VerifyVB.Test With + { + .TestCode = source, + .FixedCode = expected, + .CodeActionIndex = 1 + }.RunAsync() End Function @@ -489,7 +546,12 @@ Class B Return age End Function End Class" - Await TestInRegularAndScriptAsync(source, expected, index:=1) + Await New VerifyVB.Test With + { + .TestCode = source, + .FixedCode = expected, + .CodeActionIndex = 1 + }.RunAsync() End Function @@ -518,7 +580,12 @@ End Class" End Sub End Class" - Await TestInRegularAndScriptAsync(source, expected, index:=2) + Await New VerifyVB.Test With + { + .TestCode = source, + .FixedCode = expected, + .CodeActionIndex = 2 + }.RunAsync() End Function @@ -537,7 +604,12 @@ End Class" End Sub End Class" - Await TestInRegularAndScriptAsync(source, expected, index:=0) + Await New VerifyVB.Test With + { + .TestCode = source, + .FixedCode = expected, + .CodeActionIndex = 0 + }.RunAsync() End Function @@ -556,7 +628,12 @@ End Class" End Function End Class" - Await TestInRegularAndScriptAsync(source, expected, index:=0) + Await New VerifyVB.Test With + { + .TestCode = source, + .FixedCode = expected, + .CodeActionIndex = 0 + }.RunAsync() End Function @@ -569,7 +646,7 @@ End Class" End Function End Class" - Await TestMissingInRegularAndScriptAsync(source) + Await VerifyVB.VerifyRefactoringAsync(source, source) End Function @@ -594,7 +671,12 @@ End Class" End Sub End Class" - Await TestInRegularAndScriptAsync(source, expected, index:=0) + Await New VerifyVB.Test With + { + .TestCode = source, + .FixedCode = expected, + .CodeActionIndex = 0 + }.RunAsync() End Function @@ -619,7 +701,12 @@ End Class" End Sub End Class" - Await TestInRegularAndScriptAsync(source, expected, index:=0) + Await New VerifyVB.Test With + { + .TestCode = source, + .FixedCode = expected, + .CodeActionIndex = 0 + }.RunAsync() End Function @@ -650,7 +737,12 @@ End Class" End Sub End Class" - Await TestInRegularAndScriptAsync(source, expected, index:=2) + Await New VerifyVB.Test With + { + .TestCode = source, + .FixedCode = expected, + .CodeActionIndex = 2 + }.RunAsync() End Function @@ -681,7 +773,12 @@ End Class" End Sub End Class" - Await TestInRegularAndScriptAsync(source, expected, index:=1) + Await New VerifyVB.Test With + { + .TestCode = source, + .FixedCode = expected, + .CodeActionIndex = 1 + }.RunAsync() End Function @@ -712,7 +809,12 @@ End Class" End Sub End Class" - Await TestInRegularAndScriptAsync(source, expected, index:=1) + Await New VerifyVB.Test With + { + .TestCode = source, + .FixedCode = expected, + .CodeActionIndex = 1 + }.RunAsync() End Function @@ -739,7 +841,12 @@ Class Program End Sub End Class" - Await TestInRegularAndScriptAsync(source, expected, index:=0) + Await New VerifyVB.Test With + { + .TestCode = source, + .FixedCode = expected, + .CodeActionIndex = 0 + }.RunAsync() End Function @@ -764,7 +871,12 @@ End Class" End Sub End Class" - Await TestInRegularAndScriptAsync(source, expected, index:=1) + Await New VerifyVB.Test With + { + .TestCode = source, + .FixedCode = expected, + .CodeActionIndex = 1 + }.RunAsync() End Function @@ -781,7 +893,7 @@ End Class" End Sub End Class" - Await TestMissingInRegularAndScriptAsync(source) + Await VerifyVB.VerifyRefactoringAsync(source, source) End Function @@ -799,7 +911,7 @@ End Class" End Property End Class" - Await TestMissingInRegularAndScriptAsync(source) + Await VerifyVB.VerifyRefactoringAsync(source, source) End Function @@ -817,7 +929,7 @@ End Class" End Property End Class" - Await TestMissingInRegularAndScriptAsync(source) + Await VerifyVB.VerifyRefactoringAsync(source, source) End Function @@ -828,7 +940,7 @@ End Class" Dim prod = [|1 * 5|] End Sub End Class" - Await TestMissingInRegularAndScriptAsync(source) + Await VerifyVB.VerifyRefactoringAsync(source, source) End Function @@ -839,7 +951,7 @@ End Class" End Sub End Class" - Await TestMissingInRegularAndScriptAsync(source) + Await VerifyVB.VerifyRefactoringAsync(source, source) End Function @@ -863,7 +975,12 @@ End Class" Public Sub M(x As Integer, y As Integer) End Sub End Class" - Await TestInRegularAndScriptAsync(source, expected, index:=0) + Await New VerifyVB.Test With + { + .TestCode = source, + .FixedCode = expected, + .CodeActionIndex = 0 + }.RunAsync() End Function @@ -876,7 +993,7 @@ End Class" End Function Sub M1() - M(z:=0, y:=2) + {|BC30455:M|}(z:=0, y:=2) End Sub End Class" Dim expected = @@ -886,11 +1003,16 @@ End Class" End Function Sub M1() - M(z:=0, num:=2 * 0, y:=2) + {|BC30455:M|}(z:=0, num:=2 * 0, y:=2) End Sub End Class" - Await TestInRegularAndScriptAsync(source, expected, index:=0) + Await New VerifyVB.Test With + { + .TestCode = source, + .FixedCode = expected, + .CodeActionIndex = 0 + }.RunAsync() End Function @@ -929,7 +1051,12 @@ Class A End Sub End Class" - Await TestInRegularAndScriptAsync(source, expected, index:=1) + Await New VerifyVB.Test With + { + .TestCode = source, + .FixedCode = expected, + .CodeActionIndex = 1 + }.RunAsync() End Function @@ -941,7 +1068,7 @@ End Class" End Function End Class" - Await TestMissingInRegularAndScriptAsync(source) + Await VerifyVB.VerifyRefactoringAsync(source, source) End Function @@ -963,7 +1090,7 @@ Class TestClass End Function End Class" - Await TestMissingInRegularAndScriptAsync(source) + Await VerifyVB.VerifyRefactoringAsync(source, source) End Function End Class End Namespace diff --git a/src/EditorFeatures/VisualBasicTest/CommentSelection/VisualBasicCommentSelectionTests.vb b/src/EditorFeatures/VisualBasicTest/CommentSelection/VisualBasicCommentSelectionTests.vb index 4f57d4ddce968..c718218239dc4 100644 --- a/src/EditorFeatures/VisualBasicTest/CommentSelection/VisualBasicCommentSelectionTests.vb +++ b/src/EditorFeatures/VisualBasicTest/CommentSelection/VisualBasicCommentSelectionTests.vb @@ -7,6 +7,7 @@ Imports Microsoft.CodeAnalysis Imports Microsoft.CodeAnalysis.CommentSelection Imports Microsoft.CodeAnalysis.Editor.UnitTests.Utilities Imports Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces +Imports Microsoft.CodeAnalysis.Options Imports Microsoft.CodeAnalysis.Text Imports Microsoft.VisualStudio.Text Imports Microsoft.VisualStudio.Text.Editor @@ -85,7 +86,7 @@ End Module Dim commandHandler = New CommentUncommentSelectionCommandHandler( workspace.GetService(Of ITextUndoHistoryRegistry), workspace.GetService(Of IEditorOperationsFactoryService), - workspace.GlobalOptions) + workspace.GetService(Of EditorOptionsService)) Dim textView = doc.GetTextView() Dim textBuffer = doc.GetTextBuffer() commandHandler.ExecuteCommand(textView, textBuffer, operation, TestCommandExecutionContext.Create()) diff --git a/src/EditorFeatures/VisualBasicTest/Completion/CompletionProviders/ObjectInitializerCompletionProviderTests.vb b/src/EditorFeatures/VisualBasicTest/Completion/CompletionProviders/ObjectInitializerCompletionProviderTests.vb index f76720939b514..dbd1c3061852b 100644 --- a/src/EditorFeatures/VisualBasicTest/Completion/CompletionProviders/ObjectInitializerCompletionProviderTests.vb +++ b/src/EditorFeatures/VisualBasicTest/Completion/CompletionProviders/ObjectInitializerCompletionProviderTests.vb @@ -462,7 +462,7 @@ End Program Dim document = workspace.CurrentSolution.GetDocument(hostDocument.Id) Dim service = GetCompletionService(document.Project) Dim completionList = Await GetCompletionListAsync(service, document, caretPosition, RoslynCompletion.CompletionTrigger.Invoke) - Assert.True(completionList.IsEmpty OrElse completionList.GetTestAccessor().IsExclusive, "Expected always exclusive") + Assert.True(completionList.IsEmpty OrElse completionList.IsExclusive, "Expected always exclusive") End Using End Function diff --git a/src/EditorFeatures/VisualBasicTest/ConflictMarkerResolution/ConflictMarkerResolutionTests.vb b/src/EditorFeatures/VisualBasicTest/ConflictMarkerResolution/ConflictMarkerResolutionTests.vb index 6ee2b5bf25d26..388ae2e7f6b93 100644 --- a/src/EditorFeatures/VisualBasicTest/ConflictMarkerResolution/ConflictMarkerResolutionTests.vb +++ b/src/EditorFeatures/VisualBasicTest/ConflictMarkerResolution/ConflictMarkerResolutionTests.vb @@ -268,6 +268,310 @@ end namespace" Dim fixedSource = " imports System +namespace N + class Program + end class + class Program2 + end class + + class Program3 + end class + class Program4 + end class +end namespace" + + Await New VerifyVB.Test With + { + .TestCode = source, + .FixedCode = fixedSource, + .NumberOfIncrementalIterations = 2, + .CodeActionIndex = 2, + .CodeActionEquivalenceKey = AbstractResolveConflictMarkerCodeFixProvider.TakeBothEquivalenceKey + }.RunAsync() + End Function + + + Public Async Function TestTakeTop1_WithBaseline() As Task + Dim source = +" +imports System + +namespace N +{|BC37284:<<<<<<< This is mine!|} + class Program + sub Main() + dim p as Program + Console.WriteLine(""My section"") + end sub + end class +{|BC37284:||||||| Baseline|} + class Removed + end class +{|BC37284:=======|} + class Program2 + sub Main2() + dim p as Program2 + Console.WriteLine(""Their section"") + end sub + end class +{|BC37284:>>>>>>> This is theirs!|} +end namespace" + Dim fixedSource = " +imports System + +namespace N + class Program + sub Main() + dim p as Program + Console.WriteLine(""My section"") + end sub + end class +end namespace" + + Await New VerifyVB.Test With + { + .TestCode = source, + .FixedCode = fixedSource, + .NumberOfIncrementalIterations = 1, + .CodeActionIndex = 0, + .CodeActionEquivalenceKey = AbstractResolveConflictMarkerCodeFixProvider.TakeTopEquivalenceKey + }.RunAsync() + End Function + + + Public Async Function TestTakeBottom1_WithBaseline() As Task + Dim source = +" +imports System + +namespace N +{|BC37284:<<<<<<< This is mine!|} + class Program + sub Main() + dim p as Program + Console.WriteLine(""My section"") + end sub + end class +{|BC37284:||||||| Baseline|} + class Removed + end class +{|BC37284:=======|} + class Program2 + sub Main2() + dim p as Program2 + Console.WriteLine(""Their section"") + end sub + end class +{|BC37284:>>>>>>> This is theirs!|} +end namespace" + Dim fixedSource = " +imports System + +namespace N + class Program2 + sub Main2() + dim p as Program2 + Console.WriteLine(""Their section"") + end sub + end class +end namespace" + + Await New VerifyVB.Test With + { + .TestCode = source, + .FixedCode = fixedSource, + .NumberOfIncrementalIterations = 1, + .CodeActionIndex = 1, + .CodeActionEquivalenceKey = AbstractResolveConflictMarkerCodeFixProvider.TakeBottomEquivalenceKey + }.RunAsync() + End Function + + + Public Async Function TestTakeBoth1_WithBaseline() As Task + Dim source = +" +imports System + +namespace N +{|BC37284:<<<<<<< This is mine!|} + class Program + sub Main() + dim p as Program + Console.WriteLine(""My section"") + end sub + end class +{|BC37284:||||||| Baseline|} + class Removed + end class +{|BC37284:=======|} + class Program2 + sub Main2() + dim p as Program2 + Console.WriteLine(""Their section"") + end sub + end class +{|BC37284:>>>>>>> This is theirs!|} +end namespace" + Dim fixedSource = " +imports System + +namespace N + class Program + sub Main() + dim p as Program + Console.WriteLine(""My section"") + end sub + end class + class Program2 + sub Main2() + dim p as Program2 + Console.WriteLine(""Their section"") + end sub + end class +end namespace" + + Await New VerifyVB.Test With + { + .TestCode = source, + .FixedCode = fixedSource, + .NumberOfIncrementalIterations = 1, + .CodeActionIndex = 2, + .CodeActionEquivalenceKey = AbstractResolveConflictMarkerCodeFixProvider.TakeBothEquivalenceKey + }.RunAsync() + End Function + + + Public Async Function TestFixAll1_WithBaseline() As Task + Dim source = +" +imports System + +namespace N +{|BC37284:<<<<<<< This is mine!|} + class Program + end class +{|BC37284:||||||| Baseline|} + class Removed + end class +{|BC37284:=======|} + class Program2 + end class +{|BC37284:>>>>>>> This is theirs!|} + +{|BC37284:<<<<<<< This is mine!|} + class Program3 + end class +{|BC37284:||||||| Baseline|} + class Removed2 + end class +{|BC37284:=======|} + class Program4 + end class +{|BC37284:>>>>>>> This is theirs!|} +end namespace" + Dim fixedSource = " +imports System + +namespace N + class Program + end class + + class Program3 + end class +end namespace" + + Await New VerifyVB.Test With + { + .TestCode = source, + .FixedCode = fixedSource, + .NumberOfIncrementalIterations = 2, + .CodeActionIndex = 0, + .CodeActionEquivalenceKey = AbstractResolveConflictMarkerCodeFixProvider.TakeTopEquivalenceKey + }.RunAsync() + End Function + + + Public Async Function TestFixAll2_WithBaseline() As Task + Dim source = +" +imports System + +namespace N +{|BC37284:<<<<<<< This is mine!|} + class Program + end class +{|BC37284:||||||||} + class Removed + end class +{|BC37284:=======|} + class Program2 + end class +{|BC37284:>>>>>>> This is theirs!|} + +{|BC37284:<<<<<<< This is mine!|} + class Program3 + end class +{|BC37284:||||||||} + class Removed2 + end class +{|BC37284:=======|} + class Program4 + end class +{|BC37284:>>>>>>> This is theirs!|} +end namespace" + Dim fixedSource = " +imports System + +namespace N + class Program2 + end class + + class Program4 + end class +end namespace" + + Await New VerifyVB.Test With + { + .TestCode = source, + .FixedCode = fixedSource, + .NumberOfIncrementalIterations = 2, + .CodeActionIndex = 1, + .CodeActionEquivalenceKey = AbstractResolveConflictMarkerCodeFixProvider.TakeBottomEquivalenceKey + }.RunAsync() + End Function + + + Public Async Function TestFixAll3_WithBaseline() As Task + Dim source = +" +imports System + +namespace N +{|BC37284:<<<<<<< This is mine!|} + class Program + end class +{|BC37284:||||||| Baseline|} + class Removed + end class +{|BC37284:=======|} + class Program2 + end class +{|BC37284:>>>>>>> This is theirs!|} + +{|BC37284:<<<<<<< This is mine!|} + class Program3 + end class +{|BC37284:||||||| Baseline|} + class Removed2 + end class +{|BC37284:=======|} + class Program4 + end class +{|BC37284:>>>>>>> This is theirs!|} +end namespace" + Dim fixedSource = " +imports System + namespace N class Program end class diff --git a/src/EditorFeatures/VisualBasicTest/Diagnostics/AddImport/AddImportTests_NuGet.vb b/src/EditorFeatures/VisualBasicTest/Diagnostics/AddImport/AddImportTests_NuGet.vb index 5014dfda6a901..a1acadaf083fe 100644 --- a/src/EditorFeatures/VisualBasicTest/Diagnostics/AddImport/AddImportTests_NuGet.vb +++ b/src/EditorFeatures/VisualBasicTest/Diagnostics/AddImport/AddImportTests_NuGet.vb @@ -49,7 +49,7 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.CodeActions.AddImp Public Async Function TestSearchPackageSingleName() As Task Dim installerServiceMock = New Mock(Of IPackageInstallerService)(MockBehavior.Strict) installerServiceMock.Setup(Function(i) i.IsEnabled(It.IsAny(Of ProjectId))).Returns(True) - installerServiceMock.Setup(Function(i) i.IsInstalled(It.IsAny(Of Workspace), It.IsAny(Of ProjectId), "NuGetPackage")).Returns(False) + installerServiceMock.Setup(Function(i) i.IsInstalled(It.IsAny(Of ProjectId), "NuGetPackage")).Returns(False) installerServiceMock.Setup(Function(i) i.GetInstalledVersions("NuGetPackage")).Returns(ImmutableArray(Of String).Empty) installerServiceMock.Setup(Function(i) i.TryGetPackageSources()).Returns(NuGetPackageSources) installerServiceMock.Setup(Function(s) s.TryInstallPackageAsync(It.IsAny(Of Workspace), It.IsAny(Of DocumentId), It.IsAny(Of String), "NuGetPackage", It.IsAny(Of String), It.IsAny(Of Boolean), It.IsAny(Of IProgressTracker)(), It.IsAny(Of CancellationToken))). @@ -78,7 +78,7 @@ End Class", fixProviderData:=New ProviderData(installerServiceMock.Object, packa Public Async Function TestSearchPackageMultipleNames() As Task Dim installerServiceMock = New Mock(Of IPackageInstallerService)(MockBehavior.Strict) installerServiceMock.Setup(Function(i) i.IsEnabled(It.IsAny(Of ProjectId))).Returns(True) - installerServiceMock.Setup(Function(i) i.IsInstalled(It.IsAny(Of Workspace), It.IsAny(Of ProjectId), "NuGetPackage")).Returns(False) + installerServiceMock.Setup(Function(i) i.IsInstalled(It.IsAny(Of ProjectId), "NuGetPackage")).Returns(False) installerServiceMock.Setup(Function(i) i.GetInstalledVersions("NuGetPackage")).Returns(ImmutableArray(Of String).Empty) installerServiceMock.Setup(Function(i) i.TryGetPackageSources()).Returns(NuGetPackageSources) installerServiceMock.Setup(Function(s) s.TryInstallPackageAsync(It.IsAny(Of Workspace), It.IsAny(Of DocumentId), It.IsAny(Of String), "NuGetPackage", It.IsAny(Of String), It.IsAny(Of Boolean), It.IsAny(Of IProgressTracker)(), It.IsAny(Of CancellationToken))). @@ -107,7 +107,7 @@ End Class", fixProviderData:=New ProviderData(installerServiceMock.Object, packa Public Async Function TestFailedInstallDoesNotChangeFile() As Task Dim installerServiceMock = New Mock(Of IPackageInstallerService)(MockBehavior.Strict) installerServiceMock.Setup(Function(i) i.IsEnabled(It.IsAny(Of ProjectId))).Returns(True) - installerServiceMock.Setup(Function(i) i.IsInstalled(It.IsAny(Of Workspace), It.IsAny(Of ProjectId), "NuGetPackage")).Returns(False) + installerServiceMock.Setup(Function(i) i.IsInstalled(It.IsAny(Of ProjectId), "NuGetPackage")).Returns(False) installerServiceMock.Setup(Function(i) i.GetInstalledVersions("NuGetPackage")).Returns(ImmutableArray(Of String).Empty) installerServiceMock.Setup(Function(i) i.TryGetPackageSources()).Returns(NuGetPackageSources) installerServiceMock.Setup(Function(s) s.TryInstallPackageAsync(It.IsAny(Of Workspace), It.IsAny(Of DocumentId), It.IsAny(Of String), "NuGetPackage", It.IsAny(Of String), It.IsAny(Of Boolean), It.IsAny(Of IProgressTracker)(), It.IsAny(Of CancellationToken))). @@ -135,7 +135,7 @@ End Class", fixProviderData:=New ProviderData(installerServiceMock.Object, packa Dim installerServiceMock = New Mock(Of IPackageInstallerService)(MockBehavior.Strict) installerServiceMock.Setup(Function(i) i.IsEnabled(It.IsAny(Of ProjectId))).Returns(True) installerServiceMock.Setup(Function(i) i.TryGetPackageSources()).Returns(NuGetPackageSources) - installerServiceMock.Setup(Function(s) s.IsInstalled(It.IsAny(Of Workspace)(), It.IsAny(Of ProjectId)(), "NuGetPackage")). + installerServiceMock.Setup(Function(s) s.IsInstalled(It.IsAny(Of ProjectId)(), "NuGetPackage")). Returns(True) Dim packageServiceMock = New Mock(Of ISymbolSearchService)(MockBehavior.Strict) @@ -156,7 +156,7 @@ New TestParameters(fixProviderData:=New ProviderData(installerServiceMock.Object Public Async Function TestOptionsOffered() As Task Dim installerServiceMock = New Mock(Of IPackageInstallerService)(MockBehavior.Strict) installerServiceMock.Setup(Function(i) i.IsEnabled(It.IsAny(Of ProjectId))).Returns(True) - installerServiceMock.Setup(Function(i) i.IsInstalled(It.IsAny(Of Workspace), It.IsAny(Of ProjectId), "NuGetPackage")).Returns(False) + installerServiceMock.Setup(Function(i) i.IsInstalled(It.IsAny(Of ProjectId), "NuGetPackage")).Returns(False) installerServiceMock.Setup(Function(i) i.GetProjectsWithInstalledPackage(It.IsAny(Of Solution), "NuGetPackage", "1.0")).Returns(ImmutableArray(Of Project).Empty) installerServiceMock.Setup(Function(i) i.GetProjectsWithInstalledPackage(It.IsAny(Of Solution), "NuGetPackage", "2.0")).Returns(ImmutableArray(Of Project).Empty) installerServiceMock.Setup(Function(i) i.TryGetPackageSources()).Returns(NuGetPackageSources) @@ -199,7 +199,7 @@ parameters:=New TestParameters(index:=2, fixProviderData:=data)) Public Async Function TestInstallGetsCalledNoVersion() As Task Dim installerServiceMock = New Mock(Of IPackageInstallerService)(MockBehavior.Strict) installerServiceMock.Setup(Function(i) i.IsEnabled(It.IsAny(Of ProjectId))).Returns(True) - installerServiceMock.Setup(Function(i) i.IsInstalled(It.IsAny(Of Workspace), It.IsAny(Of ProjectId), "NuGetPackage")).Returns(False) + installerServiceMock.Setup(Function(i) i.IsInstalled(It.IsAny(Of ProjectId), "NuGetPackage")).Returns(False) installerServiceMock.Setup(Function(i) i.GetInstalledVersions("NuGetPackage")).Returns(ImmutableArray(Of String).Empty) installerServiceMock.Setup(Function(i) i.TryGetPackageSources()).Returns(NuGetPackageSources) installerServiceMock.Setup(Function(s) s.TryInstallPackageAsync(It.IsAny(Of Workspace), It.IsAny(Of DocumentId), It.IsAny(Of String), "NuGetPackage", Nothing, It.IsAny(Of Boolean), It.IsAny(Of IProgressTracker)(), It.IsAny(Of CancellationToken))). @@ -229,7 +229,7 @@ End Class", fixProviderData:=New ProviderData(installerServiceMock.Object, packa Public Async Function TestInstallGetsCalledWithVersion() As Task Dim installerServiceMock = New Mock(Of IPackageInstallerService)(MockBehavior.Strict) installerServiceMock.Setup(Function(i) i.IsEnabled(It.IsAny(Of ProjectId))).Returns(True) - installerServiceMock.Setup(Function(i) i.IsInstalled(It.IsAny(Of Workspace), It.IsAny(Of ProjectId), "NuGetPackage")).Returns(False) + installerServiceMock.Setup(Function(i) i.IsInstalled(It.IsAny(Of ProjectId), "NuGetPackage")).Returns(False) installerServiceMock.Setup(Function(i) i.GetProjectsWithInstalledPackage(It.IsAny(Of Solution), "NuGetPackage", "1.0")).Returns(ImmutableArray(Of Project).Empty) installerServiceMock.Setup(Function(i) i.TryGetPackageSources()).Returns(NuGetPackageSources) installerServiceMock.Setup(Function(s) s.GetInstalledVersions("NuGetPackage")). diff --git a/src/EditorFeatures/VisualBasicTest/Diagnostics/Suppression/SuppressionAllCodeTests.vb b/src/EditorFeatures/VisualBasicTest/Diagnostics/Suppression/SuppressionAllCodeTests.vb index 4490dec7e006d..fa820e30dfc81 100644 --- a/src/EditorFeatures/VisualBasicTest/Diagnostics/Suppression/SuppressionAllCodeTests.vb +++ b/src/EditorFeatures/VisualBasicTest/Diagnostics/Suppression/SuppressionAllCodeTests.vb @@ -8,7 +8,7 @@ Imports Microsoft.CodeAnalysis.Editor.UnitTests Imports Microsoft.CodeAnalysis.Editor.UnitTests.Diagnostics Imports Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces Imports Microsoft.CodeAnalysis.VisualBasic.CodeFixes.Suppression -Imports Microsoft.CodeAnalysis.VisualBasic.LanguageServices +Imports Microsoft.CodeAnalysis.VisualBasic.LanguageService Imports Microsoft.CodeAnalysis.VisualBasic.Syntax Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.Diagnostics.Suppression diff --git a/src/EditorFeatures/VisualBasicTest/DocumentationComments/DocumentationCommentTests.vb b/src/EditorFeatures/VisualBasicTest/DocumentationComments/DocumentationCommentTests.vb index 889b5aaf8cf75..a0b86ea565627 100644 --- a/src/EditorFeatures/VisualBasicTest/DocumentationComments/DocumentationCommentTests.vb +++ b/src/EditorFeatures/VisualBasicTest/DocumentationComments/DocumentationCommentTests.vb @@ -2,7 +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.DocumentationComments Imports Microsoft.CodeAnalysis.Editor.UnitTests +Imports Microsoft.CodeAnalysis.Editor.UnitTests.CodeActions Imports Microsoft.CodeAnalysis.Editor.UnitTests.DocumentationComments Imports Microsoft.CodeAnalysis.Editor.UnitTests.Extensions Imports Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces @@ -28,7 +30,10 @@ End Class Class C End Class " - VerifyTypingCharacter(code, expected, autoGenerateXmlDocComments:=False) + VerifyTypingCharacter(code, expected, globalOptions:=New OptionsCollection(LanguageNames.VisualBasic) From + { + {DocumentationCommentOptionsStorage.AutoXmlDocCommentGeneration, False} + }) End Sub @@ -280,7 +285,10 @@ $$ Class C End Class " - VerifyPressingEnter(code, expected, autoGenerateXmlDocComments:=False) + VerifyPressingEnter(code, expected, globalOptions:=New OptionsCollection(LanguageNames.VisualBasic) From + { + {DocumentationCommentOptionsStorage.AutoXmlDocCommentGeneration, False} + }) End Sub @@ -548,7 +556,10 @@ End Class Class C End Class " - VerifyPressingEnter(code, expected, autoGenerateXmlDocComments:=False) + VerifyPressingEnter(code, expected, globalOptions:=New OptionsCollection(LanguageNames.VisualBasic) From + { + {DocumentationCommentOptionsStorage.AutoXmlDocCommentGeneration, False} + }) End Sub @@ -866,7 +877,10 @@ Class C End Class " - VerifyInsertCommentCommand(code, expected, autoGenerateXmlDocComments:=False) + VerifyInsertCommentCommand(code, expected, globalOptions:=New OptionsCollection(LanguageNames.VisualBasic) From + { + {DocumentationCommentOptionsStorage.AutoXmlDocCommentGeneration, False} + }) End Sub diff --git a/src/EditorFeatures/VisualBasicTest/EditAndContinue/ActiveStatementTests.vb b/src/EditorFeatures/VisualBasicTest/EditAndContinue/ActiveStatementTests.vb index f5aee999fa0a1..9853fc1001351 100644 --- a/src/EditorFeatures/VisualBasicTest/EditAndContinue/ActiveStatementTests.vb +++ b/src/EditorFeatures/VisualBasicTest/EditAndContinue/ActiveStatementTests.vb @@ -344,11 +344,8 @@ End Class Dim edits = GetTopEdits(src1, src2) Dim active = GetActiveStatements(src1, src2) - edits.VerifySemantics(active, - semanticEdits:= - { - SemanticEdit(SemanticEditKind.Delete, Function(c) c.GetMember("C.Goo"), deletedSymbolContainerProvider:=Function(c) c.GetMember("C")) - }) + edits.VerifySemanticDiagnostics(active, + Diagnostic(RudeEditKind.Delete, "Class C", DeletedSymbolDisplay(FeaturesResources.method, "Goo(a As Integer)"))) End Sub diff --git a/src/EditorFeatures/VisualBasicTest/EditAndContinue/Helpers/EditingTestBase.vb b/src/EditorFeatures/VisualBasicTest/EditAndContinue/Helpers/EditingTestBase.vb index 968c52d21ce66..8df47921fb8a3 100644 --- a/src/EditorFeatures/VisualBasicTest/EditAndContinue/Helpers/EditingTestBase.vb +++ b/src/EditorFeatures/VisualBasicTest/EditAndContinue/Helpers/EditingTestBase.vb @@ -3,6 +3,7 @@ ' See the LICENSE file in the project root for more information. Imports System.Collections.Immutable +Imports System.IO Imports Microsoft.CodeAnalysis.Differencing Imports Microsoft.CodeAnalysis.EditAndContinue Imports Microsoft.CodeAnalysis.EditAndContinue.Contracts @@ -102,11 +103,15 @@ End Namespace Return New DocumentAnalysisResultsDescription(activeStatements, semanticEdits, lineEdits:=Nothing, diagnostics) End Function + Private Shared Function GetDocumentFilePath(documentIndex As Integer) As String + Return Path.Combine(TempRoot.Root, documentIndex.ToString() & ".vb") + End Function + Private Shared Function ParseSource(markedSource As String, Optional documentIndex As Integer = 0) As SyntaxTree Return SyntaxFactory.ParseSyntaxTree( ActiveStatementsDescription.ClearTags(markedSource), VisualBasicParseOptions.Default.WithLanguageVersion(LanguageVersion.Latest), - path:=documentIndex.ToString()) + path:=GetDocumentFilePath(documentIndex)) End Function Friend Shared Function GetTopEdits(src1 As String, src2 As String, Optional documentIndex As Integer = 0) As EditScript(Of SyntaxNode) @@ -190,8 +195,8 @@ End Namespace End Select End Function - Friend Shared Function GetActiveStatements(oldSource As String, newSource As String, Optional flags As ActiveStatementFlags() = Nothing, Optional path As String = "0") As ActiveStatementsDescription - Return New ActiveStatementsDescription(oldSource, newSource, Function(source) SyntaxFactory.ParseSyntaxTree(source, path:=path), flags) + Friend Shared Function GetActiveStatements(oldSource As String, newSource As String, Optional flags As ActiveStatementFlags() = Nothing, Optional documentIndex As Integer = 0) As ActiveStatementsDescription + Return New ActiveStatementsDescription(oldSource, newSource, Function(source) SyntaxFactory.ParseSyntaxTree(source, path:=GetDocumentFilePath(documentIndex)), flags) End Function Friend Shared Function GetSyntaxMap(oldSource As String, newSource As String) As SyntaxMapDescription diff --git a/src/EditorFeatures/VisualBasicTest/EditAndContinue/Helpers/VisualBasicEditAndContinueTestHelpers.vb b/src/EditorFeatures/VisualBasicTest/EditAndContinue/Helpers/VisualBasicEditAndContinueTestHelpers.vb index 2c42b8ad76e5c..ca8a2c157ab5e 100644 --- a/src/EditorFeatures/VisualBasicTest/EditAndContinue/Helpers/VisualBasicEditAndContinueTestHelpers.vb +++ b/src/EditorFeatures/VisualBasicTest/EditAndContinue/Helpers/VisualBasicEditAndContinueTestHelpers.vb @@ -32,6 +32,12 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.EditAndContinue End Get End Property + Public Overrides ReadOnly Property ProjectFileExtension As String + Get + Return ".vbproj" + End Get + End Property + Public Overrides ReadOnly Property TopSyntaxComparer As TreeComparer(Of SyntaxNode) Get Return SyntaxComparer.TopLevel diff --git a/src/EditorFeatures/VisualBasicTest/EditAndContinue/TopLevelEditingTests.vb b/src/EditorFeatures/VisualBasicTest/EditAndContinue/TopLevelEditingTests.vb index f9f0a42d59f3d..1cc3bfdd29d2e 100644 --- a/src/EditorFeatures/VisualBasicTest/EditAndContinue/TopLevelEditingTests.vb +++ b/src/EditorFeatures/VisualBasicTest/EditAndContinue/TopLevelEditingTests.vb @@ -3925,34 +3925,26 @@ End Class Public Sub PartialMember_RenameInsertDelete() - ' The syntactic analysis for A And B produce rename edits since it doesn't see that the member was in fact moved. - ' TODO: Currently, we don't even pass rename edits to semantic analysis where we could handle them as updates. - Dim srcA1 = "Partial Class C" + vbCrLf + "Sub F1() : End Sub : End Class" Dim srcB1 = "Partial Class C" + vbCrLf + "Sub F2() : End Sub : End Class" Dim srcA2 = "Partial Class C" + vbCrLf + "Sub F2() : End Sub : End Class" Dim srcB2 = "Partial Class C" + vbCrLf + "Sub F1() : End Sub : End Class" - ' current outcome - GetTopEdits(srcA1, srcA2).VerifySemanticDiagnostics(Diagnostic(RudeEditKind.Renamed, "Sub F2()", FeaturesResources.method)) - GetTopEdits(srcB1, srcB2).VerifySemanticDiagnostics(Diagnostic(RudeEditKind.Renamed, "Sub F1()", FeaturesResources.method)) - - ' correct outcome - 'EditAndContinueValidation.VerifySemantics( - ' { GetTopEdits(srcA1, srcA2), GetTopEdits(srcB1, srcB2) }, - ' - ' { - ' DocumentResults(semanticEdits:= - ' { - ' SemanticEdit(SemanticEditKind.Update, c => c.GetMember(Of NamedTypeSymbol)("C").GetMember("F2")), - ' }), - ' - ' DocumentResults( - ' semanticEdits:= - ' { - ' SemanticEdit(SemanticEditKind.Update, c => c.GetMember(Of NamedTypeSymbol)("C").GetMember("F1")), - ' }) - ' }) + EditAndContinueValidation.VerifySemantics( + {GetTopEdits(srcA1, srcA2), GetTopEdits(srcB1, srcB2)}, + { + DocumentResults( + semanticEdits:= + { + SemanticEdit(SemanticEditKind.Update, Function(c) c.GetMember("C.F2")) + }), + DocumentResults( + semanticEdits:= + { + SemanticEdit(SemanticEditKind.Update, Function(c) c.GetMember("C.F1")) + }) + }, + capabilities:=EditAndContinueCapabilities.AddMethodToExistingType) End Sub @@ -4687,8 +4679,13 @@ Imports System.Runtime.InteropServices edits.VerifyEdits( "Update [Sub Goo]@11 -> [Sub Bar]@11") - edits.VerifySemanticDiagnostics( - Diagnostic(RudeEditKind.Renamed, "Sub Bar", FeaturesResources.method)) + edits.VerifySemantics( + semanticEdits:= + { + SemanticEdit(SemanticEditKind.Delete, Function(c) c.GetMember("C.Goo"), deletedSymbolContainerProvider:=Function(c) c.GetMember("C")), + SemanticEdit(SemanticEditKind.Insert, Function(c) c.GetMember("C.Bar")) + }, + capabilities:=EditAndContinueCapabilities.AddMethodToExistingType) End Sub @@ -5523,9 +5520,12 @@ Class C End Class" Dim edits = GetTopEdits(src1, src2) - edits.VerifySemanticDiagnostics( - Diagnostic(RudeEditKind.Delete, "Class C", DeletedSymbolDisplay(FeaturesResources.operator_, "+(d As C, g As C)")), - Diagnostic(RudeEditKind.Delete, "Class C", DeletedSymbolDisplay(FeaturesResources.operator_, "CType(d As C)"))) + edits.VerifySemantics( + semanticEdits:= + { + SemanticEdit(SemanticEditKind.Delete, Function(c) c.GetMember("C.op_Addition"), deletedSymbolContainerProvider:=Function(c) c.GetMember("C")), + SemanticEdit(SemanticEditKind.Delete, Function(c) c.GetMember("C.op_Explicit"), deletedSymbolContainerProvider:=Function(c) c.GetMember("C")) + }) End Sub @@ -5691,8 +5691,13 @@ End Class "Insert [b As Integer]@37", "Insert [b]@37") - edits.VerifySemanticDiagnostics( - Diagnostic(RudeEditKind.Insert, "b As Integer", FeaturesResources.parameter)) + edits.VerifySemantics( + semanticEdits:= + { + SemanticEdit(SemanticEditKind.Delete, Function(c) c.GetMembers("C..ctor").FirstOrDefault(Function(m) m.GetParameters().Length = 1), deletedSymbolContainerProvider:=Function(c) c.GetMember("C")), + SemanticEdit(SemanticEditKind.Insert, Function(c) c.GetMembers("C..ctor").FirstOrDefault(Function(m) m.GetParameters().Length = 2)) + }, + capabilities:=EditAndContinueCapabilities.AddMethodToExistingType) End Sub @@ -7198,8 +7203,14 @@ End Class "Insert [a]@14", "Delete [Event a As Action]@10") - edits.VerifySemanticDiagnostics( - Diagnostic(RudeEditKind.Delete, "Class C", DeletedSymbolDisplay(FeaturesResources.event_, "a"))) + edits.VerifySemantics( + semanticEdits:= + { + SemanticEdit(SemanticEditKind.Insert, Function(c) c.GetMember("C.a")), + SemanticEdit(SemanticEditKind.Delete, Function(c) c.GetMember("C.add_a"), deletedSymbolContainerProvider:=Function(c) c.GetMember("C")), + SemanticEdit(SemanticEditKind.Delete, Function(c) c.GetMember("C.remove_a"), deletedSymbolContainerProvider:=Function(c) c.GetMember("C")) + }, + capabilities:=EditAndContinueCapabilities.AddInstanceFieldToExistingType) End Sub @@ -7817,6 +7828,23 @@ End Class capabilities:=EditAndContinueCapabilities.AddMethodToExistingType) End Sub + + + + + Public Sub Property_Auto_Insert(modifiers As String) + Dim src1 = "Class C : End Class" + Dim src2 = "Class C +" & modifiers & " Property P As Integer +End Class" + + Dim edits = GetTopEdits(src1, src2) + + edits.VerifySemantics( + semanticEdits:={SemanticEdit(SemanticEditKind.Insert, Function(c) c.GetMember(Of NamedTypeSymbol)("C").GetMember("P"))}, + capabilities:=EditAndContinueCapabilities.AddMethodToExistingType Or EditAndContinueCapabilities.AddInstanceFieldToExistingType) + End Sub + Public Sub Property_Accessor_Get_AccessibilityModifier_Remove() ' Note that all tokens are aligned to avoid trivia edits. @@ -7932,8 +7960,11 @@ End Class" "Delete [value As Integer]@91", "Delete [value]@91") - edits.VerifySemanticDiagnostics( - Diagnostic(RudeEditKind.Delete, "Private ReadOnly Property P", DeletedSymbolDisplay(FeaturesResources.property_accessor, "P(value As Integer)"))) + edits.VerifySemantics( + semanticEdits:= + { + SemanticEdit(SemanticEditKind.Delete, Function(c) c.GetMember("C.set_P"), deletedSymbolContainerProvider:=Function(c) c.GetMember("C")) + }) End Sub @@ -7945,8 +7976,13 @@ End Class" edits.VerifyEdits( "Update [ReadOnly Property P As Integer]@10 -> [ReadOnly Property Q As Integer]@10") - edits.VerifySemanticDiagnostics( - Diagnostic(RudeEditKind.Renamed, "ReadOnly Property Q", FeaturesResources.property_)) + edits.VerifySemantics( + semanticEdits:= + { + SemanticEdit(SemanticEditKind.Delete, Function(c) c.GetMember("C.get_P"), deletedSymbolContainerProvider:=Function(c) c.GetMember("C")), + SemanticEdit(SemanticEditKind.Insert, Function(c) c.GetMember("C.get_Q")) + }, + capabilities:=EditAndContinueCapabilities.AddMethodToExistingType) End Sub @@ -7958,14 +7994,19 @@ End Class" edits.VerifyEdits( "Update [ReadOnly Property P As Integer]@10 -> [ReadOnly Property Q As Integer]@10") - edits.VerifySemanticDiagnostics( - Diagnostic(RudeEditKind.Renamed, "ReadOnly Property Q", FeaturesResources.property_)) + edits.VerifySemantics( + semanticEdits:= + { + SemanticEdit(SemanticEditKind.Delete, Function(c) c.GetMember("C.get_P"), deletedSymbolContainerProvider:=Function(c) c.GetMember("C")), + SemanticEdit(SemanticEditKind.Insert, Function(c) c.GetMember("C.get_Q")) + }, + capabilities:=EditAndContinueCapabilities.AddMethodToExistingType Or EditAndContinueCapabilities.AddInstanceFieldToExistingType) End Sub Public Sub PropertyInsert_IntoStruct() Dim src1 = "Structure S : Private a As Integer : End Structure" - Dim src2 = + Dim src2 = " Structure S Private a As Integer Private Property b As Integer @@ -7988,8 +8029,29 @@ Structure S Set End Set End Property -End Structure -.Value + + Private ReadOnly Property f As Integer + Get + Return 0 + End Get + End Property + + Private WriteOnly Property g As Integer + Set + End Set + End Property + + Private Shared ReadOnly Property h As Integer + Get + Return 0 + End Get + End Property + + Private Shared WriteOnly Property i As Integer + Set + End Set + End Property +End Structure" Dim edits = GetTopEdits(src1, src2) edits.VerifySemanticDiagnostics( @@ -9167,8 +9229,12 @@ End Class edits.VerifyEdits( "Delete [Private Property a As Integer = 1]@10") - edits.VerifySemanticDiagnostics( - Diagnostic(RudeEditKind.Delete, "Class C", DeletedSymbolDisplay(FeaturesResources.auto_property, "a"))) + edits.VerifySemantics( + semanticEdits:= + { + SemanticEdit(SemanticEditKind.Delete, Function(c) c.GetMember("C.get_a"), deletedSymbolContainerProvider:=Function(c) c.GetMember("C")), + SemanticEdit(SemanticEditKind.Delete, Function(c) c.GetMember("C.set_a"), deletedSymbolContainerProvider:=Function(c) c.GetMember("C")) + }) End Sub @@ -10168,8 +10234,17 @@ End Class edits.VerifyEdits( "Update [Custom Event E As Action]@10 -> [Custom Event F As Action]@10") - edits.VerifySemanticDiagnostics( - Diagnostic(RudeEditKind.Renamed, "Event F", FeaturesResources.event_)) + edits.VerifySemantics( + semanticEdits:= + { + SemanticEdit(SemanticEditKind.Delete, Function(c) c.GetMember("C.add_E"), deletedSymbolContainerProvider:=Function(c) c.GetMember("C")), + SemanticEdit(SemanticEditKind.Delete, Function(c) c.GetMember("C.remove_E"), deletedSymbolContainerProvider:=Function(c) c.GetMember("C")), + SemanticEdit(SemanticEditKind.Delete, Function(c) c.GetMember("C.raise_E"), deletedSymbolContainerProvider:=Function(c) c.GetMember("C")), + SemanticEdit(SemanticEditKind.Insert, Function(c) c.GetMember("C.add_F")), + SemanticEdit(SemanticEditKind.Insert, Function(c) c.GetMember("C.remove_F")), + SemanticEdit(SemanticEditKind.Insert, Function(c) c.GetMember("C.raise_F")) + }, + capabilities:=EditAndContinueCapabilities.AddMethodToExistingType) End Sub @@ -10212,9 +10287,7 @@ End Class "Update [value As Action]@142 -> [value As Action(Of String)]@164") edits.VerifySemanticDiagnostics( - Diagnostic(RudeEditKind.TypeUpdate, "Event E", FeaturesResources.event_), - Diagnostic(RudeEditKind.TypeUpdate, "value As Action(Of String)", FeaturesResources.parameter), - Diagnostic(RudeEditKind.TypeUpdate, "value As Action(Of String)", FeaturesResources.parameter)) + Diagnostic(RudeEditKind.TypeUpdate, "Event E", FeaturesResources.event_)) End Sub @@ -10247,7 +10320,8 @@ End Class " Dim edits = GetTopEdits(src1, src2) edits.VerifySemantics( - semanticEdits:={SemanticEdit(SemanticEditKind.Insert, Function(c) c.GetMember(Of NamedTypeSymbol)("C").GetMember("E"))}) + semanticEdits:={SemanticEdit(SemanticEditKind.Insert, Function(c) c.GetMember(Of NamedTypeSymbol)("C").GetMember("E"))}, + capabilities:=EditAndContinueCapabilities.AddMethodToExistingType) End Sub @@ -10277,8 +10351,13 @@ Class C End Class " Dim edits = GetTopEdits(src1, src2) - edits.VerifySemanticDiagnostics( - Diagnostic(RudeEditKind.Delete, "Class C", DeletedSymbolDisplay(FeaturesResources.event_, "E"))) + edits.VerifySemantics( + semanticEdits:= + { + SemanticEdit(SemanticEditKind.Delete, Function(c) c.GetMember("C.add_E"), deletedSymbolContainerProvider:=Function(c) c.GetMember("C")), + SemanticEdit(SemanticEditKind.Delete, Function(c) c.GetMember("C.remove_E"), deletedSymbolContainerProvider:=Function(c) c.GetMember("C")), + SemanticEdit(SemanticEditKind.Delete, Function(c) c.GetMember("C.raise_E"), deletedSymbolContainerProvider:=Function(c) c.GetMember("C")) + }) End Sub @@ -10460,6 +10539,20 @@ End Class edits.VerifySemanticDiagnostics( Diagnostic(RudeEditKind.TypeUpdate, "a As Object", FeaturesResources.parameter)) + + ' TODO: + ' edits.VerifySemantics( + ' ActiveStatementsDescription.Empty, + ' semanticEdits:= + ' { + ' SemanticEdit(SemanticEditKind.Delete, Function(c) c.GetMembers("C.get_P").FirstOrDefault(Function(m) m.GetParameters().Any(Function(p) p.Type.SpecialType = SpecialType.System_Int32)), deletedSymbolContainerProvider:=Function(c) c.GetMember("C")), + ' SemanticEdit(SemanticEditKind.Insert, Function(c) c.GetMembers("C.get_P").FirstOrDefault(Function(m) m.GetParameters().Any(Function(p) p.Type.SpecialType = SpecialType.System_Object))) + ' }, + ' capabilities:=EditAndContinueCapabilities.AddMethodToExistingType) + + ' edits.VerifySemanticDiagnostics( + ' {Diagnostic(RudeEditKind.ChangingTypeNotSupportedByRuntime, "a As Object", FeaturesResources.parameter)}, + ' capabilities:=EditAndContinueCapabilities.Baseline) End Sub @@ -10473,6 +10566,20 @@ End Class edits.VerifySemanticDiagnostics( Diagnostic(RudeEditKind.TypeUpdate, "a", FeaturesResources.parameter)) + + ' TODO: + ' edits.VerifySemantics( + ' ActiveStatementsDescription.Empty, + ' semanticEdits:= + ' { + ' SemanticEdit(SemanticEditKind.Delete, Function(c) c.GetMembers("C.get_P").FirstOrDefault(Function(m) m.GetParameters().Any(Function(p) p.Type.SpecialType = SpecialType.System_Int32)), deletedSymbolContainerProvider:=Function(c) c.GetMember("C")), + ' SemanticEdit(SemanticEditKind.Insert, Function(c) c.GetMembers("C.get_P").FirstOrDefault(Function(m) m.GetParameters().Any(Function(p) p.Type.SpecialType = SpecialType.System_Object))) + ' }, + ' capabilities:=EditAndContinueCapabilities.AddMethodToExistingType) + + ' edits.VerifySemanticDiagnostics( + ' {Diagnostic(RudeEditKind.ChangingTypeNotSupportedByRuntime, "a", FeaturesResources.parameter)}, + ' capabilities:=EditAndContinueCapabilities.Baseline) End Sub @@ -10511,8 +10618,13 @@ End Class "Insert [a As Integer]@24", "Insert [a]@24") - edits.VerifySemanticDiagnostics( - Diagnostic(RudeEditKind.Insert, "a As Integer", FeaturesResources.parameter)) + edits.VerifySemantics( + semanticEdits:= + { + SemanticEdit(SemanticEditKind.Delete, Function(c) c.GetMembers("C.M").FirstOrDefault(Function(m) m.GetParameters().Length = 0), deletedSymbolContainerProvider:=Function(c) c.GetMember("C")), + SemanticEdit(SemanticEditKind.Insert, Function(c) c.GetMembers("C.M").FirstOrDefault(Function(m) m.GetParameters().Length = 1)) + }, + capabilities:=EditAndContinueCapabilities.AddMethodToExistingType) End Sub @@ -10526,8 +10638,13 @@ End Class "Insert [ByRef b As Integer]@38", "Insert [b]@44") - edits.VerifySemanticDiagnostics( - Diagnostic(RudeEditKind.Insert, "ByRef b As Integer", FeaturesResources.parameter)) + edits.VerifySemantics( + semanticEdits:= + { + SemanticEdit(SemanticEditKind.Delete, Function(c) c.GetMembers("C.M").FirstOrDefault(Function(m) m.GetParameters().Length = 1), deletedSymbolContainerProvider:=Function(c) c.GetMember("C")), + SemanticEdit(SemanticEditKind.Insert, Function(c) c.GetMembers("C.M").FirstOrDefault(Function(m) m.GetParameters().Length = 2)) + }, + capabilities:=EditAndContinueCapabilities.AddMethodToExistingType) End Sub @@ -10553,8 +10670,13 @@ End Class "Insert [a As Integer]@24", "Insert [a]@24") - edits.VerifySemanticDiagnostics( - Diagnostic(RudeEditKind.Insert, "a As Integer", FeaturesResources.parameter)) + edits.VerifySemantics( + semanticEdits:= + { + SemanticEdit(SemanticEditKind.Delete, Function(c) c.GetMembers("C.M").FirstOrDefault(Function(m) m.GetParameters().Length = 0), deletedSymbolContainerProvider:=Function(c) c.GetMember("C")), + SemanticEdit(SemanticEditKind.Insert, Function(c) c.GetMembers("C.M").FirstOrDefault(Function(m) m.GetParameters().Length = 1)) + }, + capabilities:=EditAndContinueCapabilities.AddMethodToExistingType) End Sub @@ -10567,8 +10689,17 @@ End Class "Delete [a As Integer]@24", "Delete [a]@24") + edits.VerifySemantics( + semanticEdits:= + { + SemanticEdit(SemanticEditKind.Delete, Function(c) c.GetMembers("C.M").FirstOrDefault(Function(m) m.GetParameters().Length = 1), deletedSymbolContainerProvider:=Function(c) c.GetMember("C")), + SemanticEdit(SemanticEditKind.Insert, Function(c) c.GetMembers("C.M").FirstOrDefault(Function(m) m.GetParameters().Length = 0)) + }, + capabilities:=EditAndContinueCapabilities.AddMethodToExistingType) + edits.VerifySemanticDiagnostics( - Diagnostic(RudeEditKind.Delete, "Public Sub M()", DeletedSymbolDisplay(FeaturesResources.parameter, "a As Integer"))) + {Diagnostic(RudeEditKind.DeleteNotSupportedByRuntime, "Public Sub M()", DeletedSymbolDisplay(FeaturesResources.parameter, "a As Integer"))}, + capabilities:=EditAndContinueCapabilities.Baseline) End Sub @@ -10582,8 +10713,17 @@ End Class "Delete [a As Integer]@24", "Delete [a]@24") + edits.VerifySemantics( + semanticEdits:= + { + SemanticEdit(SemanticEditKind.Delete, Function(c) c.GetMembers("C.M").FirstOrDefault(Function(m) m.GetParameters().Length = 2), deletedSymbolContainerProvider:=Function(c) c.GetMember("C")), + SemanticEdit(SemanticEditKind.Insert, Function(c) c.GetMembers("C.M").FirstOrDefault(Function(m) m.GetParameters().Length = 1)) + }, + capabilities:=EditAndContinueCapabilities.AddMethodToExistingType) + edits.VerifySemanticDiagnostics( - Diagnostic(RudeEditKind.Delete, "Public Sub M(b As Integer)", DeletedSymbolDisplay(FeaturesResources.parameter, "a As Integer"))) + {Diagnostic(RudeEditKind.DeleteNotSupportedByRuntime, "Public Sub M(b As Integer)", DeletedSymbolDisplay(FeaturesResources.parameter, "a As Integer"))}, + capabilities:=EditAndContinueCapabilities.Baseline) End Sub @@ -10609,8 +10749,13 @@ End Class "Delete [a As Integer]@24", "Delete [a]@24") - edits.VerifySemanticDiagnostics( - Diagnostic(RudeEditKind.Delete, "Public Sub M", DeletedSymbolDisplay(FeaturesResources.parameter, "a As Integer"))) + edits.VerifySemantics( + semanticEdits:= + { + SemanticEdit(SemanticEditKind.Delete, Function(c) c.GetMembers("C.M").FirstOrDefault(Function(m) m.GetParameters().Length = 1), deletedSymbolContainerProvider:=Function(c) c.GetMember("C")), + SemanticEdit(SemanticEditKind.Insert, Function(c) c.GetMembers("C.M").FirstOrDefault(Function(m) m.GetParameters().Length = 0)) + }, + capabilities:=EditAndContinueCapabilities.AddMethodToExistingType) End Sub diff --git a/src/EditorFeatures/VisualBasicTest/EditAndContinue/VisualBasicEditAndContinueAnalyzerTests.vb b/src/EditorFeatures/VisualBasicTest/EditAndContinue/VisualBasicEditAndContinueAnalyzerTests.vb index 0535d0dc291ba..c7f64898e9f6f 100644 --- a/src/EditorFeatures/VisualBasicTest/EditAndContinue/VisualBasicEditAndContinueAnalyzerTests.vb +++ b/src/EditorFeatures/VisualBasicTest/EditAndContinue/VisualBasicEditAndContinueAnalyzerTests.vb @@ -3,6 +3,8 @@ ' 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.Differencing Imports Microsoft.CodeAnalysis.EditAndContinue @@ -21,6 +23,19 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.EditAndContinue.UnitTests EditorTestCompositions.EditorFeatures #Region "Helpers" + Private Shared Function CreateWorkspace() As TestWorkspace + Return New TestWorkspace(composition:=s_composition) + End Function + + Private Shared Function AddDefaultTestProject(solution As Solution, source As String) As Solution + + Dim pid = ProjectId.CreateNewId() + + Return solution. + AddProject(ProjectInfo.Create(pid, VersionStamp.Create(), "proj", "proj", LanguageNames.VisualBasic)).GetProject(pid). + AddDocument("test.vb", SourceText.From(source, Encoding.UTF8), filePath:=Path.Combine(TempRoot.Root, "test.vb")).Project.Solution + End Function + Private Shared Sub TestSpans(source As String, hasLabel As Func(Of SyntaxNode, Boolean)) Dim tree = SyntaxFactory.ParseSyntaxTree(ClearSource(source)) @@ -452,14 +467,13 @@ Class C End Class " - Using workspace = TestWorkspace.CreateVisualBasic(source1, composition:=s_composition) - - Dim oldSolution = workspace.CurrentSolution + Using workspace = CreateWorkspace() + Dim oldSolution = AddDefaultTestProject(workspace.CurrentSolution, source1) Dim oldProject = oldSolution.Projects.First() Dim oldDocument = oldProject.Documents.Single() Dim documentId = oldDocument.Id - Dim newSolution = workspace.CurrentSolution.WithDocumentText(documentId, SourceText.From(source2)) + Dim newSolution = oldSolution.WithDocumentText(documentId, SourceText.From(source2)) Dim oldText = Await oldDocument.GetTextAsync() Dim oldSyntaxRoot = Await oldDocument.GetSyntaxRootAsync() Dim newDocument = newSolution.GetDocument(documentId) @@ -509,8 +523,9 @@ Class C End Class " - Using workspace = TestWorkspace.CreateVisualBasic(source, composition:=s_composition) - Dim oldProject = workspace.CurrentSolution.Projects.Single() + Using workspace = CreateWorkspace() + Dim oldSolution = AddDefaultTestProject(workspace.CurrentSolution, source) + Dim oldProject = oldSolution.Projects.Single() Dim oldDocument = oldProject.Documents.Single() Dim result = Await AnalyzeDocumentAsync(oldProject, oldDocument) @@ -538,12 +553,12 @@ Class C End Class " - Using workspace = TestWorkspace.CreateVisualBasic(source1, composition:=s_composition) - Dim oldProject = workspace.CurrentSolution.Projects.Single() + Using workspace = CreateWorkspace() + Dim oldSolution = AddDefaultTestProject(workspace.CurrentSolution, source1) + Dim oldProject = oldSolution.Projects.Single() Dim oldDocument = oldProject.Documents.Single() Dim documentId = oldDocument.Id - Dim oldSolution = workspace.CurrentSolution - Dim newSolution = workspace.CurrentSolution.WithDocumentText(documentId, SourceText.From(source2)) + Dim newSolution = oldSolution.WithDocumentText(documentId, SourceText.From(source2)) Dim result = Await AnalyzeDocumentAsync(oldProject, newSolution.GetDocument(documentId)) @@ -564,8 +579,9 @@ Class C End Class " - Using workspace = TestWorkspace.CreateVisualBasic(source, composition:=s_composition) - Dim oldProject = workspace.CurrentSolution.Projects.Single() + Using workspace = CreateWorkspace() + Dim oldSolution = AddDefaultTestProject(workspace.CurrentSolution, source) + Dim oldProject = oldSolution.Projects.Single() Dim oldDocument = oldProject.Documents.Single() Dim result = Await AnalyzeDocumentAsync(oldProject, oldDocument) @@ -595,12 +611,12 @@ Class C End Class " - Using workspace = TestWorkspace.CreateVisualBasic(source1, composition:=s_composition) - Dim oldProject = workspace.CurrentSolution.Projects.Single() + Using workspace = CreateWorkspace() + Dim oldSolution = AddDefaultTestProject(workspace.CurrentSolution, source1) + Dim oldProject = oldSolution.Projects.Single() Dim oldDocument = oldProject.Documents.Single() Dim documentId = oldDocument.Id - Dim oldSolution = workspace.CurrentSolution - Dim newSolution = workspace.CurrentSolution.WithDocumentText(documentId, SourceText.From(source2)) + Dim newSolution = oldSolution.WithDocumentText(documentId, SourceText.From(source2)) Dim result = Await AnalyzeDocumentAsync(oldProject, newSolution.GetDocument(documentId)) @@ -627,11 +643,11 @@ Class C End Class " - Using workspace = TestWorkspace.CreateVisualBasic(source1, composition:=s_composition) - Dim oldSolution = workspace.CurrentSolution + Using workspace = CreateWorkspace() + Dim oldSolution = AddDefaultTestProject(workspace.CurrentSolution, source1) Dim oldProject = oldSolution.Projects.Single() Dim documentId = oldProject.Documents.Single().Id - Dim newSolution = workspace.CurrentSolution.WithDocumentText(documentId, SourceText.From(source2)) + Dim newSolution = oldSolution.WithDocumentText(documentId, SourceText.From(source2)) Dim result = Await AnalyzeDocumentAsync(oldProject, newSolution.GetDocument(documentId)) Assert.True(result.HasChanges) @@ -658,13 +674,11 @@ Class D End Class " - Using workspace = TestWorkspace.CreateVisualBasic(source1, composition:=s_composition) - Dim oldSolution = workspace.CurrentSolution + Using workspace = CreateWorkspace() + Dim oldSolution = AddDefaultTestProject(workspace.CurrentSolution, source1) Dim oldProject = oldSolution.Projects.Single() Dim newDocId = DocumentId.CreateNewId(oldProject.Id) - Dim newSolution = oldSolution.AddDocument(newDocId, "goo.vb", SourceText.From(source2)) - - workspace.TryApplyChanges(newSolution) + Dim newSolution = oldSolution.AddDocument(newDocId, "goo.vb", SourceText.From(source2), filePath:=Path.Combine(TempRoot.Root, "goo.vb")) Dim newProject = newSolution.Projects.Single() Dim changes = newProject.GetChanges(oldProject) diff --git a/src/EditorFeatures/VisualBasicTest/EndConstructGeneration/EndConstructTestingHelpers.vb b/src/EditorFeatures/VisualBasicTest/EndConstructGeneration/EndConstructTestingHelpers.vb index 0f144ae5cd0e8..3bbfef19e3760 100644 --- a/src/EditorFeatures/VisualBasicTest/EndConstructGeneration/EndConstructTestingHelpers.vb +++ b/src/EditorFeatures/VisualBasicTest/EndConstructGeneration/EndConstructTestingHelpers.vb @@ -213,6 +213,8 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.EndConstructGenera globalOptions.SetGlobalOption(New OptionKey(FeatureOnOffOptions.PrettyListing, LanguageNames.VisualBasic), False) Dim view = workspace.Documents.First().GetTextView() + view.Options.GlobalOptions.SetOptionValue(DefaultOptions.IndentStyleId, IndentingStyle.Smart) + Dim line = view.TextSnapshot.GetLineFromLineNumber(beforeCaret(0)) If beforeCaret(1) = -1 Then view.Caret.MoveTo(line.End) diff --git a/src/EditorFeatures/VisualBasicTest/ExtractMethod/ExtractMethodTests.vb b/src/EditorFeatures/VisualBasicTest/ExtractMethod/ExtractMethodTests.vb index 721209aebfd9a..dfa8b5066c47f 100644 --- a/src/EditorFeatures/VisualBasicTest/ExtractMethod/ExtractMethodTests.vb +++ b/src/EditorFeatures/VisualBasicTest/ExtractMethod/ExtractMethodTests.vb @@ -102,7 +102,7 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.ExtractMethod Assert.NotNull(document) Dim extractOptions = New ExtractMethodOptions() With {.DontPutOutOrRefOnStruct = dontPutOutOrRefOnStruct} - Dim cleanupOptions = CodeCleanupOptions.GetDefault(document.Project.LanguageServices) + Dim cleanupOptions = CodeCleanupOptions.GetDefault(document.Project.Services) Dim sdocument = Await SemanticDocument.CreateAsync(document, CancellationToken.None) Dim validator = New VisualBasicSelectionValidator(sdocument, snapshotSpan.Span.ToTextSpan(), extractOptions) @@ -115,7 +115,7 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.ExtractMethod Assert.True(selectedCode.ContainsValidContext) ' extract method - Dim extractGenerationOptions = New ExtractMethodGenerationOptions(CodeGenerationOptions.GetDefault(document.Project.LanguageServices)) With + Dim extractGenerationOptions = New ExtractMethodGenerationOptions(CodeGenerationOptions.GetDefault(document.Project.Services)) With { .ExtractOptions = extractOptions } diff --git a/src/EditorFeatures/VisualBasicTest/Formatting/Indentation/SmartIndenterTests.vb b/src/EditorFeatures/VisualBasicTest/Formatting/Indentation/SmartIndenterTests.vb index 39e3bc2e9bfee..5722c67857e52 100644 --- a/src/EditorFeatures/VisualBasicTest/Formatting/Indentation/SmartIndenterTests.vb +++ b/src/EditorFeatures/VisualBasicTest/Formatting/Indentation/SmartIndenterTests.vb @@ -7,7 +7,9 @@ Imports Microsoft.CodeAnalysis.Editor.UnitTests.Extensions Imports Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces Imports Microsoft.CodeAnalysis.Formatting Imports Microsoft.CodeAnalysis.Formatting.Rules +Imports Microsoft.CodeAnalysis.Options Imports Microsoft.VisualStudio.Text +Imports Microsoft.VisualStudio.Text.Editor Imports Xunit.Abstractions Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.Formatting.Indentation @@ -3004,10 +3006,19 @@ end class" factory.TextSpan = subjectDocument.SelectedSpans.Single() Dim indentationLine = projectedDocument.GetTextBuffer().CurrentSnapshot.GetLineFromPosition(projectedDocument.CursorPosition.Value) - Dim point = projectedDocument.GetTextView().BufferGraph.MapDownToBuffer(indentationLine.Start, PointTrackingMode.Negative, subjectDocument.GetTextBuffer(), PositionAffinity.Predecessor) + Dim textBuffer = subjectDocument.GetTextBuffer() + Dim point = projectedDocument.GetTextView().BufferGraph.MapDownToBuffer(indentationLine.Start, PointTrackingMode.Negative, textBuffer, PositionAffinity.Predecessor) + + Dim editorOptionsService = workspace.GetService(Of EditorOptionsService) + Dim editorOptions = editorOptionsService.Factory.GetOptions(textBuffer) + editorOptions.SetOptionValue(DefaultOptions.IndentStyleId, IndentingStyle.Smart) TestIndentation( - point.Value, expectedIndentation, projectedDocument.GetTextView(), subjectDocument, workspace.GlobalOptions) + point.Value, + expectedIndentation, + projectedDocument.GetTextView(), + subjectDocument, + editorOptionsService) End Using End Sub diff --git a/src/EditorFeatures/VisualBasicTest/Formatting/VisualBasicFormatterTestBase.vb b/src/EditorFeatures/VisualBasicTest/Formatting/VisualBasicFormatterTestBase.vb index e8489c56027d2..7a2abdf41f4bb 100644 --- a/src/EditorFeatures/VisualBasicTest/Formatting/VisualBasicFormatterTestBase.vb +++ b/src/EditorFeatures/VisualBasicTest/Formatting/VisualBasicFormatterTestBase.vb @@ -64,7 +64,7 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.Formatting Dim changes = Formatter.GetFormattedTextChanges( docSyntax.Root, workspace.Documents.First(Function(d) d.SelectedSpans.Any()).SelectedSpans, - workspace.Services, + workspace.Services.SolutionServices, options, rules, CancellationToken.None) diff --git a/src/EditorFeatures/VisualBasicTest/LineCommit/CommitTestData.vb b/src/EditorFeatures/VisualBasicTest/LineCommit/CommitTestData.vb index 9f9c29da79e5d..2098a98ebde0c 100644 --- a/src/EditorFeatures/VisualBasicTest/LineCommit/CommitTestData.vb +++ b/src/EditorFeatures/VisualBasicTest/LineCommit/CommitTestData.vb @@ -38,6 +38,8 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.LineCommit Public Sub New(workspace As TestWorkspace) Me.Workspace = workspace View = workspace.Documents.Single().GetTextView() + View.Options.GlobalOptions.SetOptionValue(DefaultOptions.IndentStyleId, IndentingStyle.Smart) + EditorOperations = workspace.GetService(Of IEditorOperationsFactoryService).GetEditorOperations(View) Dim position = workspace.Documents.Single(Function(d) d.CursorPosition.HasValue).CursorPosition.Value diff --git a/src/EditorFeatures/VisualBasicTest/MoveStaticMembers/VisualBasicMoveStaticMembersTests.vb b/src/EditorFeatures/VisualBasicTest/MoveStaticMembers/VisualBasicMoveStaticMembersTests.vb index fd4c3d85b4b84..180c252d741f3 100644 --- a/src/EditorFeatures/VisualBasicTest/MoveStaticMembers/VisualBasicMoveStaticMembersTests.vb +++ b/src/EditorFeatures/VisualBasicTest/MoveStaticMembers/VisualBasicMoveStaticMembersTests.vb @@ -14,7 +14,7 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.MoveStaticMembers Private Shared ReadOnly s_testServices As TestComposition = FeaturesTestCompositions.Features.AddParts(GetType(TestMoveStaticMembersService)) -#Region "Perform Actions From Options" +#Region "Perform New Type Action From Options" Public Async Function TestMoveField() As Task Dim initialMarkup = " @@ -41,6 +41,35 @@ End Namespace Await TestMovementNewFileAsync(initialMarkup, expectedText1, expectedText2, newFileName, selection, newTypeName) End Function + + + Public Async Function TestMoveField_MultipleDeclarators() As Task + Dim initialMarkup = " +Class Program + + Public Shared G[||]oo As Integer, Bar As Integer + +End Class +" + Dim newTypeName = "Class1Helpers" + Dim newFileName = "Class1Helpers.vb" + Dim selection = ImmutableArray.Create("Goo") + Dim expectedText1 = " +Class Program + + Public Shared Bar As Integer + +End Class +" + Dim expectedText2 = "Class Class1Helpers + + Public Shared Goo As Integer +End Class +" + + Await TestMovementNewFileAsync(initialMarkup, expectedText1, expectedText2, newFileName, selection, newTypeName) + End Function + Public Async Function TestMoveProperty() As Task Dim initialMarkup = " @@ -1936,6 +1965,445 @@ End Namespace End Function #End Region +#Region "Perform Existing Type Action From Options" + + Public Async Function TestMoveFieldToExistingType() As Task + Dim initialSourceMarkup = " +Public Class Class1 + Public Shared Test[||]Field As Integer = 0 +End Class" + Dim initialDestinationMarkup = " +Public Class Class1Helpers +End Class" + Dim newTypeName = "Class1Helpers" + Dim selection = ImmutableArray.Create("TestField") + Dim fixedSourceMarkup = " +Public Class Class1 +End Class" + Dim fixedDestinationMarkup = " +Public Class Class1Helpers + Public Shared TestField As Integer = 0 +End Class" + + Await TestMovementExistingFileAsync(initialSourceMarkup, + initialDestinationMarkup, + fixedSourceMarkup, + fixedDestinationMarkup, + newTypeName, + selection).ConfigureAwait(False) + End Function + + + Public Async Function TestMovePropertyToExistingType() As Task + Dim initialSourceMarkup = " +Public Class Class1 + Public Shared ReadOnly Property Test[||]Prop As Integer + Get + Return 0 + End Get + End Property +End Class" + Dim initialDestinationMarkup = " +Public Class Class1Helpers +End Class" + Dim newTypeName = "Class1Helpers" + Dim selection = ImmutableArray.Create("TestProp") + Dim fixedSourceMarkup = " +Public Class Class1 +End Class" + Dim fixedDestinationMarkup = " +Public Class Class1Helpers + Public Shared ReadOnly Property TestProp As Integer + Get + Return 0 + End Get + End Property +End Class" + + Await TestMovementExistingFileAsync(initialSourceMarkup, + initialDestinationMarkup, + fixedSourceMarkup, + fixedDestinationMarkup, + newTypeName, + selection).ConfigureAwait(False) + End Function + + + Public Async Function TestMoveEventToExistingType() As Task + Dim initialSourceMarkup = " +Imports System + +Public Class Class1 + Public Shared Event Test[||]Event As EventHandler +End Class" + Dim initialDestinationMarkup = " +Public Class Class1Helpers +End Class" + Dim newTypeName = "Class1Helpers" + Dim selection = ImmutableArray.Create("TestEvent") + Dim fixedSourceMarkup = " +Imports System + +Public Class Class1 +End Class" + Dim fixedDestinationMarkup = "Imports System + +Public Class Class1Helpers + Public Shared Event TestEvent As EventHandler +End Class" + + Await TestMovementExistingFileAsync(initialSourceMarkup, + initialDestinationMarkup, + fixedSourceMarkup, + fixedDestinationMarkup, + newTypeName, + selection).ConfigureAwait(False) + End Function + + + Public Async Function TestMoveFunctionToExistingType() As Task + Dim initialSourceMarkup = " +Public Class Class1 + Public Shared Function Test[||]Func() As Integer + Return 0 + End Function +End Class" + Dim initialDestinationMarkup = " +Public Class Class1Helpers +End Class" + Dim newTypeName = "Class1Helpers" + Dim selection = ImmutableArray.Create("TestFunc") + Dim fixedSourceMarkup = " +Public Class Class1 +End Class" + Dim fixedDestinationMarkup = " +Public Class Class1Helpers + Public Shared Function TestFunc() As Integer + Return 0 + End Function +End Class" + + Await TestMovementExistingFileAsync(initialSourceMarkup, + initialDestinationMarkup, + fixedSourceMarkup, + fixedDestinationMarkup, + newTypeName, + selection).ConfigureAwait(False) + End Function + + + Public Async Function TestMoveSubToExistingType() As Task + Dim initialSourceMarkup = " +Public Class Class1 + Public Shared Sub Test[||]Sub() + Return + End Sub +End Class" + Dim initialDestinationMarkup = " +Public Class Class1Helpers +End Class" + Dim newTypeName = "Class1Helpers" + Dim selection = ImmutableArray.Create("TestSub") + Dim fixedSourceMarkup = " +Public Class Class1 +End Class" + Dim fixedDestinationMarkup = " +Public Class Class1Helpers + Public Shared Sub TestSub() + Return + End Sub +End Class" + + Await TestMovementExistingFileAsync(initialSourceMarkup, + initialDestinationMarkup, + fixedSourceMarkup, + fixedDestinationMarkup, + newTypeName, + selection).ConfigureAwait(False) + End Function + + + Public Async Function TestMoveConstToExistingType() As Task + Dim initialSourceMarkup = " +Public Class Class1 + Public Const Test[||]Field As Integer = 0 +End Class" + Dim initialDestinationMarkup = " +Public Class Class1Helpers +End Class" + Dim newTypeName = "Class1Helpers" + Dim selection = ImmutableArray.Create("TestField") + Dim fixedSourceMarkup = " +Public Class Class1 +End Class" + Dim fixedDestinationMarkup = " +Public Class Class1Helpers + Public Const TestField As Integer = 0 +End Class" + + Await TestMovementExistingFileAsync(initialSourceMarkup, + initialDestinationMarkup, + fixedSourceMarkup, + fixedDestinationMarkup, + newTypeName, + selection).ConfigureAwait(False) + End Function + + + Public Async Function TestMoveExtensionFunctionToExistingType() As Task + Dim initialSourceMarkup = " +Imports System.Runtime.CompilerServices + +Public Module Class1 + + Public Function Test[||]Func(other As Other) As Integer + Return other.OtherInt + 2 + End Function +End Module + +Public Class Class2 + Public Function GetOtherInt() As Integer + Dim other = New Other() + Return other.TestFunc() + End Function +End Class + +Public Class Other + Public OtherInt As Integer + + Public Sub New() + OtherInt = 5 + End Sub +End Class" + Dim initialDestinationMarkup = " +Public Module Class1Helpers +End Module" + Dim newTypeName = "Class1Helpers" + Dim selection = ImmutableArray.Create("TestFunc") + Dim fixedSourceMarkup = " +Imports System.Runtime.CompilerServices + +Public Module Class1 +End Module + +Public Class Class2 + Public Function GetOtherInt() As Integer + Dim other = New Other() + Return other.TestFunc() + End Function +End Class + +Public Class Other + Public OtherInt As Integer + + Public Sub New() + OtherInt = 5 + End Sub +End Class" + Dim fixedDestinationMarkup = "Imports System.Runtime.CompilerServices + +Public Module Class1Helpers + + Public Function Test[||]Func(other As Other) As Integer + Return other.OtherInt + 2 + End Function +End Module" + + Await TestMovementExistingFileAsync(initialSourceMarkup, + initialDestinationMarkup, + fixedSourceMarkup, + fixedDestinationMarkup, + newTypeName, + selection).ConfigureAwait(False) + End Function + + + Public Async Function TestMoveFunctionToExistingTypeWithNamespace() As Task + Dim initialSourceMarkup = " +Namespace TestNs + Public Class Class1 + Public Shared Function Test[||]Func() As Integer + Return 0 + End Function + End Class +End Namespace" + Dim initialDestinationMarkup = " +Namespace TestNs + Public Class Class1Helpers + End Class +End Namespace" + Dim newTypeName = "TestNs.Class1Helpers" + Dim selection = ImmutableArray.Create("TestFunc") + Dim fixedSourceMarkup = " +Namespace TestNs + Public Class Class1 + End Class +End Namespace" + Dim fixedDestinationMarkup = " +Namespace TestNs + Public Class Class1Helpers + Public Shared Function TestFunc() As Integer + Return 0 + End Function + End Class +End Namespace" + + Await TestMovementExistingFileAsync(initialSourceMarkup, + initialDestinationMarkup, + fixedSourceMarkup, + fixedDestinationMarkup, + newTypeName, + selection).ConfigureAwait(False) + End Function + + + Public Async Function TestMoveFunctionToExistingTypeWithNewNamespace() As Task + Dim initialSourceMarkup = " +Public Class Class1 + Public Shared Function Test[||]Func() As Integer + Return 0 + End Function +End Class" + Dim initialDestinationMarkup = " +Namespace TestNs + Public Class Class1Helpers + End Class +End Namespace" + Dim newTypeName = "TestNs.Class1Helpers" + Dim selection = ImmutableArray.Create("TestFunc") + Dim fixedSourceMarkup = " +Public Class Class1 +End Class" + Dim fixedDestinationMarkup = " +Namespace TestNs + Public Class Class1Helpers + Public Shared Function TestFunc() As Integer + Return 0 + End Function + End Class +End Namespace" + + Await TestMovementExistingFileAsync(initialSourceMarkup, + initialDestinationMarkup, + fixedSourceMarkup, + fixedDestinationMarkup, + newTypeName, + selection).ConfigureAwait(False) + End Function + + + Public Async Function TestMoveFunctionToExistingTypeRefactorSourceUsage() As Task + Dim initialSourceMarkup = " +Public Class Class1 + Public Shared Function Test[||]Func() As Integer + Return 0 + End Function + + Public Shared Function TestFunc2() As Integer + Return TestFunc() + End Function +End Class" + Dim initialDestinationMarkup = " +Public Class Class1Helpers +End Class" + Dim newTypeName = "Class1Helpers" + Dim selection = ImmutableArray.Create("TestFunc") + Dim fixedSourceMarkup = " +Public Class Class1 + Public Shared Function TestFunc2() As Integer + Return Class1Helpers.TestFunc() + End Function +End Class" + Dim fixedDestinationMarkup = " +Public Class Class1Helpers + Public Shared Function TestFunc() As Integer + Return 0 + End Function +End Class" + + Await TestMovementExistingFileAsync(initialSourceMarkup, + initialDestinationMarkup, + fixedSourceMarkup, + fixedDestinationMarkup, + newTypeName, + selection).ConfigureAwait(False) + End Function + + + Public Async Function TestMoveFunctionToExistingModuleRefactorSourceUsage() As Task + Dim initialSourceMarkup = " +Public Module Class1 + Public Function Test[||]Func() As Integer + Return 0 + End Function + + Public Function TestFunc2() As Integer + Return TestFunc() + End Function +End Module" + Dim initialDestinationMarkup = " +Public Module Class1Helpers +End Module" + Dim newTypeName = "Class1Helpers" + Dim selection = ImmutableArray.Create("TestFunc") + Dim fixedSourceMarkup = " +Public Module Class1 + Public Function TestFunc2() As Integer + Return TestFunc() + End Function +End Module" + Dim fixedDestinationMarkup = " +Public Module Class1Helpers + Public Function TestFunc() As Integer + Return 0 + End Function +End Module" + + Await TestMovementExistingFileAsync(initialSourceMarkup, + initialDestinationMarkup, + fixedSourceMarkup, + fixedDestinationMarkup, + newTypeName, + selection).ConfigureAwait(False) + End Function + + + Public Async Function TestMoveFunctionToExistingTypeRefactorDestinationUsage() As Task + Dim initialSourceMarkup = " +Public Class Class1 + Public Shared Function Test[||]Func() As Integer + Return 0 + End Function +End Class" + Dim initialDestinationMarkup = " +Public Class Class1Helpers + Public Shared Function TestFunc2() As Integer + Return Class1.TestFunc() + End Function +End Class" + Dim newTypeName = "Class1Helpers" + Dim selection = ImmutableArray.Create("TestFunc") + Dim fixedSourceMarkup = " +Public Class Class1 +End Class" + Dim fixedDestinationMarkup = " +Public Class Class1Helpers + Public Shared Function TestFunc2() As Integer + Return Class1Helpers.TestFunc() + End Function + Public Shared Function TestFunc() As Integer + Return 0 + End Function +End Class" + + Await TestMovementExistingFileAsync(initialSourceMarkup, + initialDestinationMarkup, + fixedSourceMarkup, + fixedDestinationMarkup, + newTypeName, + selection).ConfigureAwait(False) + End Function +#End Region #Region "SelectionTests" @@ -2042,19 +2510,19 @@ End Namespace Await TestMovementNewFileAsync(initialMarkup, expectedText1, expectedText2, newFileName, selection, newTypeName) End Function + ' There seems to be some whitespace formatting errors when we select multiple members in the following tests + ' Mostly, when we "split" a variable, a newline should be added but isn't - Public Async Function TestSelectInMethodParens() As Task + Public Async Function TestSelectMultipleFieldDeclarations() As Task Dim initialMarkup = " Namespace TestNs Public Class Class1 - Public Shared Function TestFunc([||]) As Integer - Return 0 - End Function + [|Public Shared Foo As Integer = 0, Goo As Integer = 0|] End Class End Namespace" Dim newTypeName = "Class1Helpers" Dim newFileName = "Class1Helpers.vb" - Dim selection = ImmutableArray.Create("TestFunc") + Dim selection = ImmutableArray.Create("Foo", "Goo") Dim expectedText1 = " Namespace TestNs Public Class Class1 @@ -2062,14 +2530,222 @@ Namespace TestNs End Namespace" Dim expectedText2 = "Namespace TestNs Class Class1Helpers - Public Shared Function TestFunc() As Integer - Return 0 - End Function + Public Shared Foo As Integer = 0 + Public Shared Goo As Integer = 0 End Class End Namespace " - Await TestMovementNewFileAsync(initialMarkup, expectedText1, expectedText2, newFileName, selection, newTypeName) + Await TestMovementNewFileWithSelectionAsync(initialMarkup, expectedText1, expectedText2, newFileName, selection, newTypeName) + End Function + + + Public Async Function TestSelectOneOfMultipleFieldDeclarations() As Task + Dim initialMarkup = " +Namespace TestNs + Public Class Class1 + Public Shared F[||]oo As Integer = 0, Goo As Integer = 0 + End Class +End Namespace" + Dim newTypeName = "Class1Helpers" + Dim newFileName = "Class1Helpers.vb" + Dim selection = ImmutableArray.Create("Foo") + Dim expectedText1 = " +Namespace TestNs + Public Class Class1 + Public Shared Goo As Integer = 0 + End Class +End Namespace" + Dim expectedText2 = "Namespace TestNs + Class Class1Helpers + Public Shared Foo As Integer = 0 + End Class +End Namespace +" + + Await TestMovementNewFileWithSelectionAsync(initialMarkup, expectedText1, expectedText2, newFileName, selection, newTypeName) + End Function + + + Public Async Function TestSelectMultipleMembers1() As Task + Dim initialMarkup = " +Namespace TestNs + Public Class Class1 + [|Public Shared Foo As Integer = 0 + + Public Shared Function DoSomething() As Integer + Return 4 + End Function|] + End Class +End Namespace" + Dim newTypeName = "Class1Helpers" + Dim newFileName = "Class1Helpers.vb" + Dim selection = ImmutableArray.Create("Foo", "DoSomething") + Dim expectedText1 = " +Namespace TestNs + Public Class Class1 + End Class +End Namespace" + Dim expectedText2 = "Namespace TestNs + Class Class1Helpers + Public Shared Foo As Integer = 0 + + Public Shared Function DoSomething() As Integer + Return 4 + End Function + End Class +End Namespace +" + + Await TestMovementNewFileWithSelectionAsync(initialMarkup, expectedText1, expectedText2, newFileName, selection, newTypeName) + End Function + + + Public Async Function TestSelectMultipleMembers2() As Task + Dim initialMarkup = " +Namespace TestNs + Public Class Class1 + Public Shared Function DoSomething() As Integer + Return 4 + End [|Function + Public Shared Foo As Integer = 0|] + End Class +End Namespace" + Dim newTypeName = "Class1Helpers" + Dim newFileName = "Class1Helpers.vb" + Dim selection = ImmutableArray.Create("Foo") + Dim expectedText1 = " +Namespace TestNs + Public Class Class1 + Public Shared Function DoSomething() As Integer + Return 4 + End Function + End Class +End Namespace" + Dim expectedText2 = "Namespace TestNs + Class Class1Helpers + Public Shared Foo As Integer = 0 + End Class +End Namespace +" + + Await TestMovementNewFileWithSelectionAsync(initialMarkup, expectedText1, expectedText2, newFileName, selection, newTypeName) + End Function + + + Public Async Function TestSelectMultipleMembers3() As Task + Dim initialMarkup = " +Namespace TestNs + Public Class Class1 + Public Shared ReadOnly Property Prop As Integer + Get + Return 4 + [|End Get + End Property + Public Shared Foo As Integer = 0 + Public Shared Function DoSometh|]ing() As Integer + Return 4 + End Function + End Class +End Namespace" + Dim newTypeName = "Class1Helpers" + Dim newFileName = "Class1Helpers.vb" + Dim selection = ImmutableArray.Create("Foo", "DoSomething") + Dim expectedText1 = " +Namespace TestNs + Public Class Class1 + Public Shared ReadOnly Property Prop As Integer + Get + Return 4 + End Get + End Property + End Class +End Namespace" + Dim expectedText2 = "Namespace TestNs + Class Class1Helpers + Public Shared Foo As Integer = 0 + + Public Shared Function DoSomething() As Integer + Return 4 + End Function + End Class +End Namespace +" + + Await TestMovementNewFileWithSelectionAsync(initialMarkup, expectedText1, expectedText2, newFileName, selection, newTypeName) + End Function + + + Public Async Function TestSelectMultipleMembers4() As Task + Dim initialMarkup = " +Namespace TestNs + Public Class Class1 + Public Shared ReadOnly Property [|Prop As Integer + Get + Return 4 + End Get + End Property + Public Shared Foo As Integer = 0 + Public Shared F|]unction DoSomething() As Integer + Return 4 + End Function + End Class +End Namespace" + Dim newTypeName = "Class1Helpers" + Dim newFileName = "Class1Helpers.vb" + Dim selection = ImmutableArray.Create("Foo", "Prop") + Dim expectedText1 = " +Namespace TestNs + Public Class Class1 + Public Shared Function DoSomething() As Integer + Return 4 + End Function + End Class +End Namespace" + Dim expectedText2 = "Namespace TestNs + Class Class1Helpers + Public Shared Foo As Integer = 0 + + Public Shared ReadOnly Property Prop As Integer + Get + Return 4 + End Get + End Property + End Class +End Namespace +" + + Await TestMovementNewFileWithSelectionAsync(initialMarkup, expectedText1, expectedText2, newFileName, selection, newTypeName) + End Function + + + Public Async Function TestSelectInMethodParens() As Task + Dim initialMarkup = " +Namespace TestNs + Public Class Class1 + Public Shared Function TestFunc([||]) As Integer + Return 0 + End Function + End Class +End Namespace" + Dim newTypeName = "Class1Helpers" + Dim newFileName = "Class1Helpers.vb" + Dim selection = ImmutableArray.Create("TestFunc") + Dim expectedText1 = " +Namespace TestNs + Public Class Class1 + End Class +End Namespace" + Dim expectedText2 = "Namespace TestNs + Class Class1Helpers + Public Shared Function TestFunc() As Integer + Return 0 + End Function + End Class +End Namespace +" + + Await TestMovementNewFileAsync(initialMarkup, expectedText1, expectedText2, newFileName, selection, newTypeName) End Function @@ -2154,6 +2830,72 @@ End Namespace" Await TestNoRefactoringAsync(initialMarkup) End Function + + Public Async Function TestSelectInIncompleteField_NoAction1() As Task + Dim initialMarkup = " +Namespace TestNs + Public Class Class1 + Public[||]{|BC30203:|} + End Class +End Namespace" + + Await New Test("", ImmutableArray(Of String).Empty, "") With + { + .TestCode = initialMarkup, + .FixedCode = initialMarkup + }.RunAsync().ConfigureAwait(False) + End Function + + + Public Async Function TestSelectInIncompleteField_NoAction2() As Task + Dim initialMarkup = " +Namespace TestNs + Public Class Class1 + Public Sha[||] {|BC30205:TestField|} As Integer = 0 + End Class +End Namespace" + + Await New Test("", ImmutableArray(Of String).Empty, "") With + { + .TestCode = initialMarkup, + .FixedCode = initialMarkup + }.RunAsync().ConfigureAwait(False) + End Function + + + Public Async Function TestSelectNonEmptySpanInIncompleteField_NoAction() As Task + Dim initialMarkup = " +Namespace TestNs + Public Class Class1 + [|Public|]{|BC30203:|} + End Class +End Namespace" + + Await New Test("", ImmutableArray(Of String).Empty, "") With + { + .TestCode = initialMarkup, + .FixedCode = initialMarkup + }.RunAsync().ConfigureAwait(False) + End Function + + + Public Async Function TestSelectNonEmptySpanInsideMethodBlock_NoAction() As Task + Dim initialMarkup = " +Namespace TestNs + Public Class Class1 + Public Shared Function Foo() As Integer + [|Return 0|] + End Function + End Class +End Namespace" + + Await New Test("", ImmutableArray(Of String).Empty, "") With + { + .TestCode = initialMarkup, + .FixedCode = initialMarkup + }.RunAsync().ConfigureAwait(False) + End Function + Public Async Function TestSelectNonSharedProperty_NoAction() As Task Dim initialMarkup = " @@ -2171,7 +2913,7 @@ End Namespace" End Function - Public Async Function TestSelectPropertyGetter_NoAction() As Task + Public Async Function TestSelectPropertyGetter_NoAction1() As Task Dim initialMarkup = " Namespace TestNs Public Class Class1 @@ -2186,6 +2928,56 @@ End Namespace" Await TestNoRefactoringAsync(initialMarkup) End Function + + Public Async Function TestSelectPropertyGetter_NoAction2() As Task + Dim initialMarkup = " +Namespace TestNs + Public Class Class1 + Public Shared ReadOnly Property TestProperty As Integer + [|Get|] + Return 0 + End Get + End Property + End Class +End Namespace" + + Await TestNoRefactoringAsync(initialMarkup) + End Function + + + Public Async Function TestMovePropertyWithNonEmptySelection() As Task + Dim initialMarkup = " +Namespace TestNs + Public Class Class1 + Public Shared ReadOnly Property Test[|Property As Integer + Get + Return 0 + End Get|] + End Property + End Class +End Namespace" + Dim newTypeName = "Class1Helpers" + Dim newFileName = "Class1Helpers.vb" + Dim selection = ImmutableArray.Create("TestProperty") + Dim expectedText1 = " +Namespace TestNs + Public Class Class1 + End Class +End Namespace" + Dim expectedText2 = "Namespace TestNs + Class Class1Helpers + Public Shared ReadOnly Property TestProperty As Integer + Get + Return 0 + End Get + End Property + End Class +End Namespace +" + + Await TestMovementNewFileAsync(initialMarkup, expectedText1, expectedText2, newFileName, selection, newTypeName) + End Function + Public Async Function TestSelectConstructor1_NoAction() As Task Dim initialMarkup = " @@ -2233,10 +3025,14 @@ End Namespace" Public Sub New(destinationType As String, members As ImmutableArray(Of String), - newFileName As String) + newFileName As String, + Optional testPreselection As Boolean = False, + Optional newType As Boolean = True) _destinationType = destinationType _members = members _newFileName = newFileName + _testPreselection = testPreselection + _newType = newType End Sub Private ReadOnly _destinationType As String @@ -2245,14 +3041,23 @@ End Namespace" Private ReadOnly _newFileName As String + Private ReadOnly _testPreselection As Boolean + + Private ReadOnly _newType As Boolean + Protected Overrides Function CreateWorkspaceImpl() As Workspace Dim hostServices = s_testServices.GetHostServices() - Dim workspace = New AdhocWorkspace(hostServices) Dim optionsService = DirectCast(workspace.Services.GetRequiredService(Of IMoveStaticMembersOptionsService)(), TestMoveStaticMembersService) - optionsService.DestinationType = _destinationType + optionsService.DestinationName = _destinationType optionsService.Filename = _newFileName optionsService.SelectedMembers = _members + If _testPreselection Then + optionsService.ExpectedPrecheckedMembers = _members + Else + optionsService.ExpectedPrecheckedMembers = ImmutableArray(Of String).Empty + End If + optionsService.CreateNew = _newType Return workspace End Function @@ -2271,6 +3076,44 @@ End Namespace" } test.FixedState.Sources.Add(expectedSource) test.FixedState.Sources.Add((newFileName, expectedNewFile)) + Await test.RunAsync().ConfigureAwait(False) + End Function + + Private Shared Async Function TestMovementExistingFileAsync(initialSourceMarkup As String, + initialDestinationMarkup As String, + fixedSourceMarkup As String, + fixedDestinationMarkup As String, + destinationName As String, + selectedMembers As ImmutableArray(Of String), + Optional destinationFileName As String = Nothing) As Task + Dim test = New Test(destinationName, selectedMembers, destinationFileName, newType:=False) + test.TestState.Sources.Add(initialSourceMarkup) + test.FixedState.Sources.Add(fixedSourceMarkup) + + If destinationFileName IsNot Nothing Then + test.TestState.Sources.Add((destinationFileName, initialDestinationMarkup)) + test.FixedState.Sources.Add((destinationFileName, fixedDestinationMarkup)) + Else + test.TestState.Sources.Add(initialDestinationMarkup) + test.FixedState.Sources.Add(fixedDestinationMarkup) + End If + + Await test.RunAsync().ConfigureAwait(False) + End Function + + Private Shared Async Function TestMovementNewFileWithSelectionAsync(initialMarkup As String, + expectedSource As String, + expectedNewFile As String, + newFileName As String, + selectedMembers As ImmutableArray(Of String), + newTypeName As String) As Task + + Dim test = New Test(newTypeName, selectedMembers, newFileName, testPreselection:=True) With + { + .TestCode = initialMarkup + } + test.FixedState.Sources.Add(expectedSource) + test.FixedState.Sources.Add((newFileName, expectedNewFile)) Await test.RunAsync() End Function diff --git a/src/EditorFeatures/VisualBasicTest/QuickInfo/SemanticQuickInfoSourceTests.vb b/src/EditorFeatures/VisualBasicTest/QuickInfo/SemanticQuickInfoSourceTests.vb index ab39e8d700dfa..8ea805bb07c4a 100644 --- a/src/EditorFeatures/VisualBasicTest/QuickInfo/SemanticQuickInfoSourceTests.vb +++ b/src/EditorFeatures/VisualBasicTest/QuickInfo/SemanticQuickInfoSourceTests.vb @@ -7,7 +7,7 @@ Imports Microsoft.CodeAnalysis.Editor.UnitTests.Classification.FormattedClassifi Imports Microsoft.CodeAnalysis.Editor.UnitTests.Extensions Imports Microsoft.CodeAnalysis.Editor.UnitTests.QuickInfo Imports Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces -Imports Microsoft.CodeAnalysis.LanguageServices +Imports Microsoft.CodeAnalysis.LanguageService Imports Microsoft.CodeAnalysis.QuickInfo Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.QuickInfo diff --git a/src/EditorFeatures/VisualBasicTest/SimplifyTypeNames/SimplifyTypeNamesTests.vb b/src/EditorFeatures/VisualBasicTest/SimplifyTypeNames/SimplifyTypeNamesTests.vb index dccafe36519ac..b12e1d6a041a5 100644 --- a/src/EditorFeatures/VisualBasicTest/SimplifyTypeNames/SimplifyTypeNamesTests.vb +++ b/src/EditorFeatures/VisualBasicTest/SimplifyTypeNames/SimplifyTypeNamesTests.vb @@ -2421,7 +2421,7 @@ End Module Dim parameters2 As New TestParameters() Using workspace = CreateWorkspaceFromOptions(source.ToString(), parameters2) - workspace.ApplyOptions(PreferIntrinsicPredefinedTypeEverywhere()) + PreferIntrinsicPredefinedTypeEverywhere().SetGlobalOptions(workspace.GlobalOptions) Dim diagnostics = (Await GetDiagnosticsAsync(workspace, parameters2)).Where(Function(d) d.Id = IDEDiagnosticIds.PreferBuiltInOrFrameworkTypeDiagnosticId) Assert.Equal(1, diagnostics.Count) End Using diff --git a/src/EditorFeatures/VisualBasicTest/Squiggles/ErrorSquiggleProducerTests.vb b/src/EditorFeatures/VisualBasicTest/Squiggles/ErrorSquiggleProducerTests.vb index 6f0feff42f842..e3ef77f0bfc88 100644 --- a/src/EditorFeatures/VisualBasicTest/Squiggles/ErrorSquiggleProducerTests.vb +++ b/src/EditorFeatures/VisualBasicTest/Squiggles/ErrorSquiggleProducerTests.vb @@ -8,6 +8,7 @@ Imports Microsoft.CodeAnalysis.Classification Imports Microsoft.CodeAnalysis.CodeStyle Imports Microsoft.CodeAnalysis.Diagnostics Imports Microsoft.CodeAnalysis.Editor.Implementation.IntelliSense.QuickInfo +Imports Microsoft.CodeAnalysis.Editor.UnitTests.CodeActions Imports Microsoft.CodeAnalysis.Editor.UnitTests.Extensions Imports Microsoft.CodeAnalysis.Editor.UnitTests.Squiggles Imports Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces @@ -114,12 +115,11 @@ End Class" } Using workspace = TestWorkspace.CreateVisualBasic(content, composition:=SquiggleUtilities.CompositionWithSolutionCrawler) - Dim options As New Dictionary(Of OptionKey2, Object) Dim language = workspace.Projects.Single().Language - Dim preferIntrinsicPredefinedTypeOption = New OptionKey2(CodeStyleOptions2.PreferIntrinsicPredefinedTypeKeywordInDeclaration, language) - Dim preferIntrinsicPredefinedTypeOptionValue = New CodeStyleOption2(Of Boolean)(value:=True, notification:=NotificationOption2.Error) - options.Add(preferIntrinsicPredefinedTypeOption, preferIntrinsicPredefinedTypeOptionValue) - workspace.ApplyOptions(options) + + workspace.GlobalOptions.SetGlobalOption( + New OptionKey(CodeStyleOptions2.PreferIntrinsicPredefinedTypeKeywordInDeclaration, language), + New CodeStyleOption2(Of Boolean)(value:=True, notification:=NotificationOption2.Error)) Dim diagnosticsAndSpans = Await TestDiagnosticTagProducer(Of DiagnosticsSquiggleTaggerProvider, IErrorTag).GetDiagnosticsAndErrorSpans(workspace, analyzerMap) Dim spans = diagnosticsAndSpans.Item1.Zip(diagnosticsAndSpans.Item2, Function(diagostic, span) (diagostic, span)).OrderBy(Function(s) s.span.Span.Span.Start).ToImmutableArray() @@ -144,10 +144,10 @@ End Class" expectedToolTip = New ContainerElement( ContainerElementStyle.Wrapped, New ClassifiedTextElement( - New ClassifiedTextRun(ClassificationTypeNames.Text, "IDE0049", QuickInfoHyperLink.TestAccessor.CreateNavigationAction(new Uri("https://docs.microsoft.com/dotnet/fundamentals/code-analysis/style-rules/ide0049", UriKind.Absolute)), "https://docs.microsoft.com/dotnet/fundamentals/code-analysis/style-rules/ide0049"), + New ClassifiedTextRun(ClassificationTypeNames.Text, "IDE0049", QuickInfoHyperLink.TestAccessor.CreateNavigationAction(New Uri("https://docs.microsoft.com/dotnet/fundamentals/code-analysis/style-rules/ide0049", UriKind.Absolute)), "https://docs.microsoft.com/dotnet/fundamentals/code-analysis/style-rules/ide0049"), New ClassifiedTextRun(ClassificationTypeNames.Punctuation, ":"), New ClassifiedTextRun(ClassificationTypeNames.WhiteSpace, " "), - New ClassifiedTextRun(ClassificationTypeNames.Text, WorkspacesResources.Name_can_be_simplified))) + New ClassifiedTextRun(ClassificationTypeNames.Text, AnalyzersResources.Name_can_be_simplified))) Assert.Equal(PredefinedErrorTypeNames.SyntaxError, second.span.Tag.ErrorType) ToolTipAssert.EqualContent(expectedToolTip, second.span.Tag.ToolTipContent) diff --git a/src/EditorFeatures/VisualBasicTest/TypeInferrer/TypeInferrerTests.vb b/src/EditorFeatures/VisualBasicTest/TypeInferrer/TypeInferrerTests.vb index 888528b7d492e..aeed7b4095aeb 100644 --- a/src/EditorFeatures/VisualBasicTest/TypeInferrer/TypeInferrerTests.vb +++ b/src/EditorFeatures/VisualBasicTest/TypeInferrer/TypeInferrerTests.vb @@ -6,7 +6,7 @@ Imports System.Threading Imports Microsoft.CodeAnalysis Imports Microsoft.CodeAnalysis.Editor.UnitTests.TypeInferrer Imports Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces -Imports Microsoft.CodeAnalysis.LanguageServices +Imports Microsoft.CodeAnalysis.LanguageService Imports Microsoft.CodeAnalysis.Text Imports Microsoft.CodeAnalysis.VisualBasic.Extensions Imports Microsoft.CodeAnalysis.VisualBasic.Syntax diff --git a/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/Binders/EEMethodBinder.cs b/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/Binders/EEMethodBinder.cs index 5b197c99e8a73..c7b5cc398148e 100644 --- a/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/Binders/EEMethodBinder.cs +++ b/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/Binders/EEMethodBinder.cs @@ -44,7 +44,8 @@ internal EEMethodBinder(EEMethodSymbol method, MethodSymbol containingMethod, Bi var substitutedSourceMethod = method.SubstitutedSourceMethod; _parameterOffset = substitutedSourceMethod.IsStatic ? 0 : 1; _targetParameters = method.Parameters; - _sourceBinder = new InMethodBinder(substitutedSourceMethod, new BuckStopsHereBinder(next.Compilation)); + // https://github.com/dotnet/roslyn/issues/62334: add tests and adjust implementation to allow EE to access file types + _sourceBinder = new InMethodBinder(substitutedSourceMethod, new BuckStopsHereBinder(next.Compilation, associatedSyntaxTree: null)); } internal override void LookupSymbolsInSingleBinder(LookupResult result, string name, int arity, ConsList basesBeingResolved, LookupOptions options, Binder originalBinder, bool diagnose, ref CompoundUseSiteInfo useSiteInfo) diff --git a/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/CSharpExpressionCompiler.cs b/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/CSharpExpressionCompiler.cs index faad706ee6fac..d69d5dd1828ad 100644 --- a/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/CSharpExpressionCompiler.cs +++ b/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/CSharpExpressionCompiler.cs @@ -80,10 +80,7 @@ internal static EvaluationContext CreateTypeContext( // Re-use the previous compilation if possible. compilation = previousMetadataContext.Compilation; - if (compilation == null) - { - compilation = metadataBlocks.ToCompilation(moduleVersionId, kind); - } + compilation ??= metadataBlocks.ToCompilation(moduleVersionId, kind); var context = EvaluationContext.CreateTypeContext( compilation, diff --git a/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/CompilationContext.cs b/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/CompilationContext.cs index 7cd2b047799b1..c29de94be92eb 100644 --- a/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/CompilationContext.cs +++ b/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/CompilationContext.cs @@ -706,7 +706,8 @@ private static Binder CreateBinderChain( @namespace = @namespace.ContainingNamespace; } - Binder binder = new BuckStopsHereBinder(compilation); + // https://github.com/dotnet/roslyn/issues/62334: add tests and adjust implementation to allow EE to access file types + Binder binder = new BuckStopsHereBinder(compilation, associatedSyntaxTree: null); var hasImports = !importRecordGroups.IsDefaultOrEmpty; var numImportStringGroups = hasImports ? importRecordGroups.Length : 0; var currentStringGroup = numImportStringGroups - 1; diff --git a/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/EEAssemblyBuilder.cs b/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/EEAssemblyBuilder.cs index bb174945a96de..139f77c35008d 100644 --- a/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/EEAssemblyBuilder.cs +++ b/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/EEAssemblyBuilder.cs @@ -174,13 +174,13 @@ public override bool TryGetPreviousLambda(SyntaxNode lambdaOrLambdaBodySyntax, b return false; } - public override bool TryGetPreviousStateMachineState(SyntaxNode awaitOrYieldSyntax, out int stateOrdinal) + public override bool TryGetPreviousStateMachineState(SyntaxNode awaitOrYieldSyntax, out StateMachineState state) { - stateOrdinal = 0; + state = 0; return false; } - public override int? GetFirstUnusedStateMachineState(bool increasing) => null; + public override StateMachineState? GetFirstUnusedStateMachineState(bool increasing) => null; public override string? PreviousStateMachineTypeName => null; public override int PreviousHoistedLocalSlotCount => 0; public override int PreviousAwaiterSlotCount => 0; diff --git a/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/Symbols/EEMethodSymbol.cs b/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/Symbols/EEMethodSymbol.cs index cdb6bb56e93ba..6fb4e0fbc25e5 100644 --- a/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/Symbols/EEMethodSymbol.cs +++ b/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/Symbols/EEMethodSymbol.cs @@ -434,6 +434,8 @@ internal override ObsoleteAttributeData ObsoleteAttributeData internal sealed override UnmanagedCallersOnlyAttributeData GetUnmanagedCallersOnlyAttributeData(bool forceComplete) => throw ExceptionUtilities.Unreachable; + internal override bool HasUnscopedRefAttribute => false; + internal ResultProperties ResultProperties { get { return _lazyResultProperties; } diff --git a/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/Symbols/EENamedTypeSymbol.cs b/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/Symbols/EENamedTypeSymbol.cs index b6856a5f05ff1..2ee0b8d7df52f 100644 --- a/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/Symbols/EENamedTypeSymbol.cs +++ b/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/Symbols/EENamedTypeSymbol.cs @@ -159,6 +159,10 @@ internal override bool MangleName get { return false; } } + // https://github.com/dotnet/roslyn/issues/61999 + // Determine if 'null' is the right return value here + internal override SyntaxTree AssociatedSyntaxTree => null; + public override IEnumerable MemberNames { get { throw ExceptionUtilities.Unreachable; } diff --git a/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/Symbols/ObjectIdLocalSymbol.cs b/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/Symbols/ObjectIdLocalSymbol.cs index 830898802cdf2..a9a75c0c859ab 100644 --- a/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/Symbols/ObjectIdLocalSymbol.cs +++ b/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/Symbols/ObjectIdLocalSymbol.cs @@ -77,7 +77,7 @@ internal override BoundExpression GetAddress(BoundPseudoVariable variable) method.Name, m => method.TypeParameters.SelectAsArray(t => (TypeParameterSymbol)new SimpleTypeParameterSymbol(m, t.Ordinal, t.Name)), m => m.TypeParameters[0], // return type is <>T& - m => method.Parameters.SelectAsArray(p => SynthesizedParameterSymbol.Create(m, p.TypeWithAnnotations, p.Ordinal, p.RefKind, p.Name, p.Scope, p.RefCustomModifiers))); + m => method.Parameters.SelectAsArray(p => SynthesizedParameterSymbol.Create(m, p.TypeWithAnnotations, p.Ordinal, p.RefKind, p.Name, p.DeclaredScope, p.RefCustomModifiers))); var local = variable.LocalSymbol; return InvokeGetMethod(method.Construct(local.Type), variable.Syntax, local.Name); } diff --git a/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/Symbols/PlaceholderMethodSymbol.cs b/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/Symbols/PlaceholderMethodSymbol.cs index bed4b97588505..b7ba65e36fe68 100644 --- a/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/Symbols/PlaceholderMethodSymbol.cs +++ b/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/Symbols/PlaceholderMethodSymbol.cs @@ -218,6 +218,8 @@ internal override ObsoleteAttributeData ObsoleteAttributeData internal sealed override UnmanagedCallersOnlyAttributeData GetUnmanagedCallersOnlyAttributeData(bool forceComplete) => throw ExceptionUtilities.Unreachable; + internal override bool HasUnscopedRefAttribute => false; + internal override bool RequiresSecurityObject { get { return false; } diff --git a/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/SyntaxHelpers.cs b/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/SyntaxHelpers.cs index 324ca12d6ef86..22a3d620715de 100644 --- a/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/SyntaxHelpers.cs +++ b/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/SyntaxHelpers.cs @@ -15,7 +15,7 @@ namespace Microsoft.CodeAnalysis.CSharp.ExpressionEvaluator { internal static class SyntaxHelpers { - internal static readonly CSharpParseOptions ParseOptions = CSharpParseOptions.Default.WithLanguageVersion(LanguageVersionFacts.CSharpNext); // Used to be LanguageVersionFacts.CurrentVersion + internal static readonly CSharpParseOptions PreviewParseOptions = CSharpParseOptions.Default.WithLanguageVersion(LanguageVersion.Preview); // Used to be LanguageVersionFacts.CurrentVersion /// /// Parse expression. Returns null if there are any errors. @@ -203,7 +203,7 @@ private static ExpressionSyntax ParseDebuggerExpression(string text, bool consum private static InternalSyntax.ExpressionSyntax ParseDebuggerExpressionInternal(SourceText source, bool consumeFullText) { - using var lexer = new InternalSyntax.Lexer(source, ParseOptions, allowPreprocessorDirectives: false); + using var lexer = new InternalSyntax.Lexer(source, PreviewParseOptions, allowPreprocessorDirectives: false); using var parser = new InternalSyntax.LanguageParser(lexer, oldTree: null, changes: null, lexerMode: InternalSyntax.LexerMode.DebuggerSyntax); var node = parser.ParseExpression(); @@ -215,7 +215,7 @@ private static InternalSyntax.ExpressionSyntax ParseDebuggerExpressionInternal(S private static StatementSyntax ParseDebuggerStatement(string text) { var source = SourceText.From(text); - using var lexer = new InternalSyntax.Lexer(source, ParseOptions); + using var lexer = new InternalSyntax.Lexer(source, PreviewParseOptions); using var parser = new InternalSyntax.LanguageParser(lexer, oldTree: null, changes: null, lexerMode: InternalSyntax.LexerMode.DebuggerSyntax); var statement = parser.ParseStatement(); @@ -225,7 +225,7 @@ private static StatementSyntax ParseDebuggerStatement(string text) private static SyntaxTree CreateSyntaxTree(this InternalSyntax.CSharpSyntaxNode root, SourceText text) { - return CSharpSyntaxTree.CreateForDebugger((CSharpSyntaxNode)root.CreateRed(), text, ParseOptions); + return CSharpSyntaxTree.CreateForDebugger((CSharpSyntaxNode)root.CreateRed(), text, PreviewParseOptions); } private static ExpressionSyntax MakeDebuggerExpression(this InternalSyntax.ExpressionSyntax expression, SourceText text) diff --git a/src/ExpressionEvaluator/CSharp/Test/ExpressionCompiler/CompileExpressionsTests.cs b/src/ExpressionEvaluator/CSharp/Test/ExpressionCompiler/CompileExpressionsTests.cs index a57c5a235a6a4..e8442a32cbffd 100644 --- a/src/ExpressionEvaluator/CSharp/Test/ExpressionCompiler/CompileExpressionsTests.cs +++ b/src/ExpressionEvaluator/CSharp/Test/ExpressionCompiler/CompileExpressionsTests.cs @@ -352,7 +352,7 @@ static void G(out object o) out var errorMessages); Assert.Null(assembly); AssertEx.Equal( - new[] { $"(1,11): error CS8185: { CSharpResources.ERR_DeclarationExpressionNotPermitted }" }, + new[] { $"(1,11): error CS8185: {CSharpResources.ERR_DeclarationExpressionNotPermitted}" }, errorMessages); Assert.True(methodTokens.IsEmpty); }); diff --git a/src/ExpressionEvaluator/CSharp/Test/ExpressionCompiler/ExpressionCompilerTestBase.cs b/src/ExpressionEvaluator/CSharp/Test/ExpressionCompiler/ExpressionCompilerTestBase.cs index d01181be2fe0d..f67582c6f977b 100644 --- a/src/ExpressionEvaluator/CSharp/Test/ExpressionCompiler/ExpressionCompilerTestBase.cs +++ b/src/ExpressionEvaluator/CSharp/Test/ExpressionCompiler/ExpressionCompilerTestBase.cs @@ -341,7 +341,7 @@ internal CompilationTestData Evaluate( { var compilation = CreateCompilation( source, - parseOptions: SyntaxHelpers.ParseOptions, + parseOptions: SyntaxHelpers.PreviewParseOptions, options: (outputKind == OutputKind.DynamicallyLinkedLibrary) ? TestOptions.DebugDll : TestOptions.DebugExe, targetFramework: targetFramework); diff --git a/src/ExpressionEvaluator/CSharp/Test/ExpressionCompiler/ExpressionCompilerTests.cs b/src/ExpressionEvaluator/CSharp/Test/ExpressionCompiler/ExpressionCompilerTests.cs index 91544bfd1c0a3..a15f02fc92092 100644 --- a/src/ExpressionEvaluator/CSharp/Test/ExpressionCompiler/ExpressionCompilerTests.cs +++ b/src/ExpressionEvaluator/CSharp/Test/ExpressionCompiler/ExpressionCompilerTests.cs @@ -1729,7 +1729,7 @@ .maxstack 2 }"); } - [Fact] + [Fact(Skip = "https://github.com/dotnet/roslyn/issues/58449")] public void AssignMethodGroup() { var source = @@ -4187,7 +4187,7 @@ static void M() Assert.Equal("error CS1618: Cannot create delegate with 'C.F()' because it or a method it overrides has a Conditional attribute", error); } - [Fact] + [Fact(Skip = "https://github.com/dotnet/roslyn/issues/58449")] public void StaticDelegate() { var source = @@ -6982,7 +6982,7 @@ .locals init (System.Range V_0) //x }"); } - [Fact] + [Fact(Skip = "https://github.com/dotnet/roslyn/issues/61463")] public void RefField() { var source = diff --git a/src/ExpressionEvaluator/CSharp/Test/ExpressionCompiler/InstructionDecoderTests.cs b/src/ExpressionEvaluator/CSharp/Test/ExpressionCompiler/InstructionDecoderTests.cs index 643aac2ec98bd..37eceb09df401 100644 --- a/src/ExpressionEvaluator/CSharp/Test/ExpressionCompiler/InstructionDecoderTests.cs +++ b/src/ExpressionEvaluator/CSharp/Test/ExpressionCompiler/InstructionDecoderTests.cs @@ -426,10 +426,7 @@ private string GetName(string source, string methodName, DkmVariableInfoFlags ar } var name = instructionDecoder.GetName(method, includeParameterTypes, includeParameterNames, builder); - if (builder != null) - { - builder.Free(); - } + builder?.Free(); return name; } @@ -437,7 +434,7 @@ private string GetName(string source, string methodName, DkmVariableInfoFlags ar private string GetReturnTypeName(string source, string methodName, Type[] typeArguments = null) { var instructionDecoder = CSharpInstructionDecoder.Instance; - var serializedTypeArgumentNames = typeArguments?.Select(t => (t != null) ? t.AssemblyQualifiedName : null).ToArray(); + var serializedTypeArgumentNames = typeArguments?.Select(t => t?.AssemblyQualifiedName).ToArray(); var method = GetConstructedMethod(source, methodName, serializedTypeArgumentNames, instructionDecoder); return instructionDecoder.GetReturnTypeName(method); diff --git a/src/ExpressionEvaluator/CSharp/Test/ExpressionCompiler/MissingAssemblyTests.cs b/src/ExpressionEvaluator/CSharp/Test/ExpressionCompiler/MissingAssemblyTests.cs index 46d0e6f849c3a..0980ff3bb0f8b 100644 --- a/src/ExpressionEvaluator/CSharp/Test/ExpressionCompiler/MissingAssemblyTests.cs +++ b/src/ExpressionEvaluator/CSharp/Test/ExpressionCompiler/MissingAssemblyTests.cs @@ -669,7 +669,7 @@ void M() out errorMessage); Assert.Equal(2, numRetries); // Ensure that we actually retried and that we bailed out on the second retry if the same identity was seen in the diagnostics. - Assert.Equal($"error CS0012: { string.Format(CSharpResources.ERR_NoTypeDef, "MissingType", missingIdentity)}", errorMessage); + Assert.Equal($"error CS0012: {string.Format(CSharpResources.ERR_NoTypeDef, "MissingType", missingIdentity)}", errorMessage); }); } diff --git a/src/ExpressionEvaluator/CSharp/Test/ExpressionCompiler/ReferencedModulesTests.cs b/src/ExpressionEvaluator/CSharp/Test/ExpressionCompiler/ReferencedModulesTests.cs index 582f93d1505bd..28b5f7ce8a86c 100644 --- a/src/ExpressionEvaluator/CSharp/Test/ExpressionCompiler/ReferencedModulesTests.cs +++ b/src/ExpressionEvaluator/CSharp/Test/ExpressionCompiler/ReferencedModulesTests.cs @@ -914,7 +914,7 @@ IEnumerable CS0433Messages(string type) // Duplicate extension method, at method scope. ExpressionCompilerTestHelpers.CompileExpressionWithRetry(blocks, "x.F()", ImmutableArray.Empty, contextFactory, getMetaDataBytesPtr: null, errorMessage: out errorMessage, testData: out testData); - Assert.Equal($"error CS0121: { string.Format(CSharpResources.ERR_AmbigCall, "N.E.F(A)", "N.E.F(A)") }", errorMessage); + Assert.Equal($"error CS0121: {string.Format(CSharpResources.ERR_AmbigCall, "N.E.F(A)", "N.E.F(A)")}", errorMessage); // Same tests as above but in library that does not directly reference duplicates. GetContextState(runtime, "A", out blocks, out moduleVersionId, out symReader, out typeToken, out localSignatureToken); diff --git a/src/ExpressionEvaluator/Core/Source/ExpressionCompiler/ExpressionCompiler.cs b/src/ExpressionEvaluator/Core/Source/ExpressionCompiler/ExpressionCompiler.cs index 14f9fd413db72..d44ca8f76d609 100644 --- a/src/ExpressionEvaluator/Core/Source/ExpressionCompiler/ExpressionCompiler.cs +++ b/src/ExpressionEvaluator/Core/Source/ExpressionCompiler/ExpressionCompiler.cs @@ -424,10 +424,7 @@ internal static TResult CompileWithRetry( { if (!missingAssemblyIdentities.IsEmpty) { - if (assembliesLoadedInRetryLoop == null) - { - assembliesLoadedInRetryLoop = PooledHashSet.GetInstance(); - } + assembliesLoadedInRetryLoop ??= PooledHashSet.GetInstance(); // If any identities failed to add (they were already in the list), then don't retry. if (assembliesLoadedInRetryLoop.AddAll(missingAssemblyIdentities)) { diff --git a/src/ExpressionEvaluator/Core/Source/ExpressionCompiler/PDB/MethodDebugInfo.Native.cs b/src/ExpressionEvaluator/Core/Source/ExpressionCompiler/PDB/MethodDebugInfo.Native.cs index f87096fbaa0d0..ce459dbd3ad23 100644 --- a/src/ExpressionEvaluator/Core/Source/ExpressionCompiler/PDB/MethodDebugInfo.Native.cs +++ b/src/ExpressionEvaluator/Core/Source/ExpressionCompiler/PDB/MethodDebugInfo.Native.cs @@ -97,10 +97,7 @@ public static unsafe MethodDebugInfo ReadMethodDebugI try { var symMethod = symReader.GetMethodByVersion(methodToken, methodVersion); - if (symMethod != null) - { - symMethod.GetAllScopes(allScopes, containingScopes, ilOffset, isScopeEndInclusive: isVisualBasicMethod); - } + symMethod?.GetAllScopes(allScopes, containingScopes, ilOffset, isScopeEndInclusive: isVisualBasicMethod); ImmutableArray> importRecordGroups; ImmutableArray externAliasRecords; @@ -665,10 +662,7 @@ private static void GetConstants( } var dynamicFlags = default(ImmutableArray); - if (dynamicLocalConstantMap != null) - { - dynamicLocalConstantMap.TryGetValue(name, out dynamicFlags); - } + dynamicLocalConstantMap?.TryGetValue(name, out dynamicFlags); var tupleElementNames = default(ImmutableArray); if (tupleLocalConstantMap != null) diff --git a/src/ExpressionEvaluator/Core/Source/ResultProvider/Expansion/DebuggerTypeProxyExpansion.cs b/src/ExpressionEvaluator/Core/Source/ResultProvider/Expansion/DebuggerTypeProxyExpansion.cs index a93e485f8c5a1..d68eb03cd7a53 100644 --- a/src/ExpressionEvaluator/Core/Source/ResultProvider/Expansion/DebuggerTypeProxyExpansion.cs +++ b/src/ExpressionEvaluator/Core/Source/ResultProvider/Expansion/DebuggerTypeProxyExpansion.cs @@ -177,10 +177,7 @@ internal override void GetRows( bool visitAll, ref int index) { - if (_proxyItem != null) - { - _proxyItem.Expansion.GetRows(resultProvider, rows, inspectionContext, _proxyItem.ToDataItem(), _proxyItem.Value, startIndex, count, visitAll, ref index); - } + _proxyItem?.Expansion.GetRows(resultProvider, rows, inspectionContext, _proxyItem.ToDataItem(), _proxyItem.Value, startIndex, count, visitAll, ref index); if (InRange(startIndex, count, index)) { diff --git a/src/ExpressionEvaluator/Core/Source/ResultProvider/Expansion/RootHiddenExpansion.cs b/src/ExpressionEvaluator/Core/Source/ResultProvider/Expansion/RootHiddenExpansion.cs index 01d1ead860784..5c2547750bf6e 100644 --- a/src/ExpressionEvaluator/Core/Source/ResultProvider/Expansion/RootHiddenExpansion.cs +++ b/src/ExpressionEvaluator/Core/Source/ResultProvider/Expansion/RootHiddenExpansion.cs @@ -66,10 +66,7 @@ internal override void GetRows( ExpansionFlags.IncludeBaseMembers | ExpansionFlags.IncludeResultsView, supportsFavorites: false); var expansion = other.Expansion; - if (expansion != null) - { - expansion.GetRows(resultProvider, rows, inspectionContext, other.ToDataItem(), other.Value, startIndex, count, visitAll, ref index); - } + expansion?.GetRows(resultProvider, rows, inspectionContext, other.ToDataItem(), other.Value, startIndex, count, visitAll, ref index); } } } diff --git a/src/ExpressionEvaluator/Core/Source/ResultProvider/Expansion/TupleExpansion.cs b/src/ExpressionEvaluator/Core/Source/ResultProvider/Expansion/TupleExpansion.cs index e06c5febff354..cccd4427ea831 100644 --- a/src/ExpressionEvaluator/Core/Source/ResultProvider/Expansion/TupleExpansion.cs +++ b/src/ExpressionEvaluator/Core/Source/ResultProvider/Expansion/TupleExpansion.cs @@ -260,10 +260,7 @@ internal Fields(ReadOnlyCollection defaultView, bool includeRawView) private Fields GetFields() { - if (_lazyFields == null) - { - _lazyFields = GetFields(_typeAndInfo, _cardinality, _useRawView); - } + _lazyFields ??= GetFields(_typeAndInfo, _cardinality, _useRawView); return _lazyFields; } diff --git a/src/ExpressionEvaluator/Core/Source/ResultProvider/Helpers/TypeHelpers.cs b/src/ExpressionEvaluator/Core/Source/ResultProvider/Helpers/TypeHelpers.cs index 93f1840110eb3..1864e8eee82d6 100644 --- a/src/ExpressionEvaluator/Core/Source/ResultProvider/Helpers/TypeHelpers.cs +++ b/src/ExpressionEvaluator/Core/Source/ResultProvider/Helpers/TypeHelpers.cs @@ -557,10 +557,7 @@ private static Dictionary GetDebu { continue; } - if (result == null) - { - result = new Dictionary(); - } + result ??= new Dictionary(); // There can be multiple same attributes for derived classes. // Debugger provides attributes starting from derived classes and then up to base ones. diff --git a/src/ExpressionEvaluator/Core/Source/ResultProvider/ResultProvider.cs b/src/ExpressionEvaluator/Core/Source/ResultProvider/ResultProvider.cs index 721c759b4099b..22c3737825536 100644 --- a/src/ExpressionEvaluator/Core/Source/ResultProvider/ResultProvider.cs +++ b/src/ExpressionEvaluator/Core/Source/ResultProvider/ResultProvider.cs @@ -63,10 +63,7 @@ internal ResultProvider(IDkmClrFormatter2 formatter2, IDkmClrFullNameProvider fu void IDkmClrResultProvider.GetResult(DkmClrValue value, DkmWorkList workList, DkmClrType declaredType, DkmClrCustomTypeInfo declaredTypeInfo, DkmInspectionContext inspectionContext, ReadOnlyCollection formatSpecifiers, string resultName, string resultFullName, DkmCompletionRoutine completionRoutine) { - if (formatSpecifiers == null) - { - formatSpecifiers = Formatter.NoFormatSpecifiers; - } + formatSpecifiers ??= Formatter.NoFormatSpecifiers; if (resultFullName != null) { ReadOnlyCollection otherSpecifiers; @@ -608,12 +605,9 @@ internal EvalResult CreateDataItem( formatSpecifiers, flags, Formatter2.GetEditableValueString(value, inspectionContext, declaredTypeAndInfo.Info)); - if (expansion == null) - { - expansion = value.HasExceptionThrown() + expansion ??= value.HasExceptionThrown() ? this.GetTypeExpansion(inspectionContext, new TypeAndCustomInfo(value.Type), value, expansionFlags, supportsFavorites: false) : this.GetTypeExpansion(inspectionContext, declaredTypeAndInfo, value, expansionFlags, supportsFavorites: supportsFavorites); - } } return new EvalResult( diff --git a/src/ExpressionEvaluator/Core/Test/ExpressionCompiler/NamespaceTypeDefinitionNoBase.cs b/src/ExpressionEvaluator/Core/Test/ExpressionCompiler/NamespaceTypeDefinitionNoBase.cs index d602dcf4c985e..b2cf692ad5453 100644 --- a/src/ExpressionEvaluator/Core/Test/ExpressionCompiler/NamespaceTypeDefinitionNoBase.cs +++ b/src/ExpressionEvaluator/Core/Test/ExpressionCompiler/NamespaceTypeDefinitionNoBase.cs @@ -77,6 +77,10 @@ internal NamespaceTypeDefinitionNoBase(INamespaceTypeDefinition underlyingType) bool INamedTypeReference.MangleName => UnderlyingType.MangleName; +#nullable enable + string? INamedTypeReference.AssociatedFileIdentifier => UnderlyingType.AssociatedFileIdentifier; +#nullable disable + string INamedEntity.Name => UnderlyingType.Name; string INamespaceTypeReference.NamespaceName => UnderlyingType.NamespaceName; diff --git a/src/ExpressionEvaluator/Core/Test/ExpressionCompiler/RuntimeInstance.cs b/src/ExpressionEvaluator/Core/Test/ExpressionCompiler/RuntimeInstance.cs index adb8a635c3047..83916c46cba62 100644 --- a/src/ExpressionEvaluator/Core/Test/ExpressionCompiler/RuntimeInstance.cs +++ b/src/ExpressionEvaluator/Core/Test/ExpressionCompiler/RuntimeInstance.cs @@ -46,10 +46,7 @@ internal static RuntimeInstance Create( { var module = compilation.ToModuleInstance(debugFormat, includeLocalSignatures); - if (references == null) - { - references = ExpressionCompilerTestHelpers.GetEmittedReferences(compilation, module.GetMetadataReader()); - } + references ??= ExpressionCompilerTestHelpers.GetEmittedReferences(compilation, module.GetMetadataReader()); if (includeIntrinsicAssembly) { diff --git a/src/ExpressionEvaluator/Core/Test/ResultProvider/Debugger/Engine/DkmClrRuntimeInstance.cs b/src/ExpressionEvaluator/Core/Test/ResultProvider/Debugger/Engine/DkmClrRuntimeInstance.cs index dcbaba8b660e7..725443a2f5da2 100644 --- a/src/ExpressionEvaluator/Core/Test/ResultProvider/Debugger/Engine/DkmClrRuntimeInstance.cs +++ b/src/ExpressionEvaluator/Core/Test/ResultProvider/Debugger/Engine/DkmClrRuntimeInstance.cs @@ -47,10 +47,7 @@ internal DkmClrRuntimeInstance( bool enableNativeDebugging = false) : base(enableNativeDebugging) { - if (getModule == null) - { - getModule = (r, a) => new DkmClrModuleInstance(r, a, (a != null) ? new DkmModule(a.GetName().Name + ".dll") : null); - } + getModule ??= (r, a) => new DkmClrModuleInstance(r, a, (a != null) ? new DkmModule(a.GetName().Name + ".dll") : null); this.Assemblies = assemblies; this.Modules = assemblies.Select(a => getModule(this, a)).Where(m => m != null).ToArray(); _defaultModule = getModule(this, null); diff --git a/src/ExpressionEvaluator/Core/Test/ResultProvider/Debugger/Engine/DkmClrValue.cs b/src/ExpressionEvaluator/Core/Test/ResultProvider/Debugger/Engine/DkmClrValue.cs index c323cd1fb0f88..69fa61e36d87e 100644 --- a/src/ExpressionEvaluator/Core/Test/ResultProvider/Debugger/Engine/DkmClrValue.cs +++ b/src/ExpressionEvaluator/Core/Test/ResultProvider/Debugger/Engine/DkmClrValue.cs @@ -229,7 +229,7 @@ public string EvaluateToString(DkmInspectionContext inspectionContext) var rawValue = RawValue; Debug.Assert(rawValue != null || this.Type.GetLmrType().IsVoid(), "In our mock system, this should only happen for void."); - return rawValue == null ? null : rawValue.ToString(); + return rawValue?.ToString(); } /// diff --git a/src/ExpressionEvaluator/VisualBasic/Source/ExpressionCompiler/CompilationContext.vb b/src/ExpressionEvaluator/VisualBasic/Source/ExpressionCompiler/CompilationContext.vb index 4fc64229c0e1b..9d6b9aa540fc3 100644 --- a/src/ExpressionEvaluator/VisualBasic/Source/ExpressionCompiler/CompilationContext.vb +++ b/src/ExpressionEvaluator/VisualBasic/Source/ExpressionCompiler/CompilationContext.vb @@ -1144,7 +1144,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.ExpressionEvaluator Private Shared Function IsDisplayClassInstanceFieldName(name As String) As Boolean Debug.Assert(name IsNot Nothing) ' Verified by caller. Return name.StartsWith(GeneratedNameConstants.HoistedSpecialVariablePrefix & GeneratedNameConstants.ClosureVariablePrefix, StringComparison.Ordinal) OrElse - name.StartsWith(GeneratedNameConstants.StateMachineHoistedUserVariablePrefix & GeneratedNameConstants.ClosureVariablePrefix, StringComparison.Ordinal) OrElse + name.StartsWith(GeneratedNameConstants.StateMachineHoistedUserVariableOrDisplayClassPrefix & GeneratedNameConstants.ClosureVariablePrefix, StringComparison.Ordinal) OrElse name.StartsWith(GeneratedNameConstants.HoistedSpecialVariablePrefix & GeneratedNameConstants.DisplayClassPrefix, StringComparison.Ordinal) ' Async lambda case End Function @@ -1247,7 +1247,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.ExpressionEvaluator Debug.Assert(Not field.IsShared) variableKind = DisplayClassVariableKind.Local variableName = fieldName.Substring(GeneratedNameConstants.HoistedSpecialVariablePrefix.Length) - ElseIf GeneratedNameParser.TryParseStateMachineHoistedUserVariableName(fieldName, hoistedLocalName, hoistedLocalSlotIndex) Then + ElseIf GeneratedNameParser.TryParseStateMachineHoistedUserVariableOrDisplayClassName(fieldName, hoistedLocalName, hoistedLocalSlotIndex) Then Debug.Assert(Not field.IsShared) If Not inScopeHoistedLocalSlots.Contains(hoistedLocalSlotIndex) Then diff --git a/src/ExpressionEvaluator/VisualBasic/Source/ExpressionCompiler/EEAssemblyBuilder.vb b/src/ExpressionEvaluator/VisualBasic/Source/ExpressionCompiler/EEAssemblyBuilder.vb index aad85d9ce0e75..d44c9b520a0a3 100644 --- a/src/ExpressionEvaluator/VisualBasic/Source/ExpressionCompiler/EEAssemblyBuilder.vb +++ b/src/ExpressionEvaluator/VisualBasic/Source/ExpressionCompiler/EEAssemblyBuilder.vb @@ -191,12 +191,12 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.ExpressionEvaluator Return False End Function - Public Overrides Function TryGetPreviousStateMachineState(awaitOrYieldSyntax As SyntaxNode, ByRef stateOrdinal As Integer) As Boolean - stateOrdinal = 0 + Public Overrides Function TryGetPreviousStateMachineState(awaitOrYieldSyntax As SyntaxNode, ByRef state As StateMachineState) As Boolean + state = 0 Return False End Function - Public Overrides Function GetFirstUnusedStateMachineState(increasing As Boolean) As Integer? + Public Overrides Function GetFirstUnusedStateMachineState(increasing As Boolean) As StateMachineState? Return Nothing End Function diff --git a/src/ExpressionEvaluator/VisualBasic/Source/ExpressionCompiler/EvaluationContext.vb b/src/ExpressionEvaluator/VisualBasic/Source/ExpressionCompiler/EvaluationContext.vb index 436f91edad23a..ee1bace6d9ec1 100644 --- a/src/ExpressionEvaluator/VisualBasic/Source/ExpressionCompiler/EvaluationContext.vb +++ b/src/ExpressionEvaluator/VisualBasic/Source/ExpressionCompiler/EvaluationContext.vb @@ -181,7 +181,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.ExpressionEvaluator End If Dim localNames = debugInfo.LocalVariableNames.WhereAsArray( - Function(name) name Is Nothing OrElse Not name.StartsWith(GeneratedNameConstants.StateMachineHoistedUserVariablePrefix, StringComparison.Ordinal)) + Function(name) name Is Nothing OrElse Not name.StartsWith(GeneratedNameConstants.StateMachineHoistedUserVariableOrDisplayClassPrefix, StringComparison.Ordinal)) Dim localsBuilder = ArrayBuilder(Of LocalSymbol).GetInstance() MethodDebugInfo(Of TypeSymbol, LocalSymbol).GetLocals(localsBuilder, symbolProvider, localNames, localInfo, Nothing, debugInfo.TupleLocalMap) @@ -204,7 +204,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.ExpressionEvaluator For Each localName In allLocalNames Dim hoistedLocalName As String = Nothing Dim hoistedLocalSlot As Integer = 0 - If localName IsNot Nothing AndAlso GeneratedNameParser.TryParseStateMachineHoistedUserVariableName(localName, hoistedLocalName, hoistedLocalSlot) Then + If localName IsNot Nothing AndAlso GeneratedNameParser.TryParseStateMachineHoistedUserVariableOrDisplayClassName(localName, hoistedLocalName, hoistedLocalSlot) Then builder.Add(hoistedLocalSlot) End If Next diff --git a/src/Features/CSharp/Portable/AddImport/CSharpAddImportFeatureService.cs b/src/Features/CSharp/Portable/AddImport/CSharpAddImportFeatureService.cs index d683b1726eb6e..4a2f78f3aadf6 100644 --- a/src/Features/CSharp/Portable/AddImport/CSharpAddImportFeatureService.cs +++ b/src/Features/CSharp/Portable/AddImport/CSharpAddImportFeatureService.cs @@ -22,7 +22,7 @@ using Microsoft.CodeAnalysis.Formatting; using Microsoft.CodeAnalysis.Host; using Microsoft.CodeAnalysis.Host.Mef; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Shared.Extensions; @@ -285,7 +285,7 @@ private static bool InfoBoundSuccessfully(ISymbol operation) } protected override string GetDescription(IReadOnlyList nameParts) - => $"using { string.Join(".", nameParts) };"; + => $"using {string.Join(".", nameParts)};"; protected override (string description, bool hasExistingImport) GetDescription( Document document, diff --git a/src/Features/CSharp/Portable/BraceCompletion/AbstractCSharpBraceCompletionService.cs b/src/Features/CSharp/Portable/BraceCompletion/AbstractCSharpBraceCompletionService.cs index 394f8854fef39..3e0cc7c900725 100644 --- a/src/Features/CSharp/Portable/BraceCompletion/AbstractCSharpBraceCompletionService.cs +++ b/src/Features/CSharp/Portable/BraceCompletion/AbstractCSharpBraceCompletionService.cs @@ -3,8 +3,8 @@ // See the LICENSE file in the project root for more information. using Microsoft.CodeAnalysis.BraceCompletion; -using Microsoft.CodeAnalysis.CSharp.LanguageServices; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.CSharp.LanguageService; +using Microsoft.CodeAnalysis.LanguageService; namespace Microsoft.CodeAnalysis.CSharp.BraceCompletion { diff --git a/src/Features/CSharp/Portable/BraceCompletion/AbstractCurlyBraceOrBracketCompletionService.cs b/src/Features/CSharp/Portable/BraceCompletion/AbstractCurlyBraceOrBracketCompletionService.cs index 587e246fdbbcf..8bb45526c5d0a 100644 --- a/src/Features/CSharp/Portable/BraceCompletion/AbstractCurlyBraceOrBracketCompletionService.cs +++ b/src/Features/CSharp/Portable/BraceCompletion/AbstractCurlyBraceOrBracketCompletionService.cs @@ -33,7 +33,7 @@ internal abstract class AbstractCurlyBraceOrBracketCompletionService : AbstractC protected abstract int AdjustFormattingEndPoint(ParsedDocument document, int startPoint, int endPoint); - public sealed override async Task GetTextChangesAfterCompletionAsync(BraceCompletionContext context, IndentationOptions options, CancellationToken cancellationToken) + public sealed override BraceCompletionResult? GetTextChangesAfterCompletion(BraceCompletionContext context, IndentationOptions options, CancellationToken cancellationToken) { // After the closing brace is completed we need to format the span from the opening point to the closing point. // E.g. when the user triggers completion for an if statement ($$ is the caret location) we insert braces to get @@ -46,11 +46,8 @@ internal abstract class AbstractCurlyBraceOrBracketCompletionService : AbstractC return null; } - var documentSyntax = await ParsedDocument.CreateAsync(context.Document, cancellationToken).ConfigureAwait(false); - var (formattingChanges, finalCurlyBraceEnd) = FormatTrackingSpan( - documentSyntax, - context.Document.Project.LanguageServices, + context.Document, context.OpeningPoint, context.ClosingPoint, // We're not trying to format the indented block here, so no need to pass in additional rules. @@ -64,7 +61,7 @@ internal abstract class AbstractCurlyBraceOrBracketCompletionService : AbstractC } // The caret location should be at the start of the closing brace character. - var formattedText = documentSyntax.Text.WithChanges(formattingChanges); + var formattedText = context.Document.Text.WithChanges(formattingChanges); var caretLocation = formattedText.Lines.GetLinePosition(finalCurlyBraceEnd - 1); return new BraceCompletionResult(formattingChanges, caretLocation); @@ -88,7 +85,7 @@ private static bool ContainsOnlyWhitespace(SourceText text, int openingPosition, return true; } - public sealed override async Task GetTextChangeAfterReturnAsync( + public sealed override BraceCompletionResult? GetTextChangeAfterReturn( BraceCompletionContext context, IndentationOptions options, CancellationToken cancellationToken) @@ -96,7 +93,7 @@ private static bool ContainsOnlyWhitespace(SourceText text, int openingPosition, var document = context.Document; var closingPoint = context.ClosingPoint; var openingPoint = context.OpeningPoint; - var originalDocumentText = await document.GetTextAsync(cancellationToken).ConfigureAwait(false); + var originalDocumentText = document.Text; // check whether shape of the braces are what we support // shape must be either "{|}" or "{ }". | is where caret is. otherwise, we don't do any special behavior @@ -128,12 +125,11 @@ private static bool ContainsOnlyWhitespace(SourceText text, int openingPosition, closingPoint += newLineString.Length; } - var documentSyntax = await ParsedDocument.CreateAsync(document.WithText(textToFormat), cancellationToken).ConfigureAwait(false); + var documentToFormat = document.WithChangedText(textToFormat, cancellationToken); // Format the text that contains the newly inserted line. var (formattingChanges, newClosingPoint) = FormatTrackingSpan( - documentSyntax, - document.Project.LanguageServices, + documentToFormat, openingPoint, closingPoint, braceFormattingIndentationRules: GetBraceFormattingIndentationRulesAfterReturn(options), @@ -148,9 +144,8 @@ private static bool ContainsOnlyWhitespace(SourceText text, int openingPosition, Debug.Assert(desiredCaretLine.GetFirstNonWhitespacePosition() == null, "the line between the formatted braces is not empty"); // Set the caret position to the properly indented column in the desired line. - var newDocument = document.WithText(formattedText); - var newDocumentText = await newDocument.GetTextAsync(cancellationToken).ConfigureAwait(false); - var caretPosition = GetIndentedLinePosition(newDocument, newDocumentText, desiredCaretLine.LineNumber, options, cancellationToken); + var newDocument = document.WithChangedText(formattedText, cancellationToken); + var caretPosition = GetIndentedLinePosition(newDocument, newDocument.Text, desiredCaretLine.LineNumber, options, cancellationToken); // The new line edit is calculated against the original text, d0, to get text d1. // The formatting edits are calculated against d1 to get text d2. @@ -164,9 +159,9 @@ static TextLine GetLineBetweenCurlys(int closingPosition, SourceText text) return text.Lines[closingBraceLineNumber - 1]; } - static LinePosition GetIndentedLinePosition(Document document, SourceText sourceText, int lineNumber, IndentationOptions options, CancellationToken cancellationToken) + static LinePosition GetIndentedLinePosition(ParsedDocument document, SourceText sourceText, int lineNumber, IndentationOptions options, CancellationToken cancellationToken) { - var indentationService = document.GetRequiredLanguageService(); + var indentationService = document.LanguageServices.GetRequiredService(); var indentation = indentationService.GetIndentation(document, lineNumber, options, cancellationToken); var baseLinePosition = sourceText.Lines.GetLinePosition(indentation.BasePosition); @@ -210,7 +205,6 @@ static ImmutableArray GetMergedChanges(TextChange newLineEdit, Immut /// private (ImmutableArray textChanges, int finalBraceEnd) FormatTrackingSpan( ParsedDocument document, - HostLanguageServices languageServices, int openingPoint, int closingPoint, ImmutableArray braceFormattingIndentationRules, @@ -239,13 +233,13 @@ static ImmutableArray GetMergedChanges(TextChange newLineEdit, Immut } var spanToFormat = TextSpan.FromBounds(Math.Max(startPoint, 0), endPoint); - var rules = FormattingRuleUtilities.GetFormattingRules(document, languageServices, spanToFormat, braceFormattingIndentationRules); + var rules = FormattingRuleUtilities.GetFormattingRules(document, spanToFormat, braceFormattingIndentationRules); // Annotate the original closing brace so we can find it after formatting. var annotatedRoot = GetSyntaxRootWithAnnotatedClosingBrace(document.Root, closingPoint); var result = Formatter.GetFormattingResult( - annotatedRoot, SpecializedCollections.SingletonEnumerable(spanToFormat), languageServices.WorkspaceServices, options.FormattingOptions, rules, cancellationToken); + annotatedRoot, SpecializedCollections.SingletonEnumerable(spanToFormat), document.SolutionServices, options.FormattingOptions, rules, cancellationToken); if (result == null) { diff --git a/src/Features/CSharp/Portable/BraceCompletion/BracketBraceCompletionService.cs b/src/Features/CSharp/Portable/BraceCompletion/BracketBraceCompletionService.cs index 92883d1a3531a..bce21752a0f9f 100644 --- a/src/Features/CSharp/Portable/BraceCompletion/BracketBraceCompletionService.cs +++ b/src/Features/CSharp/Portable/BraceCompletion/BracketBraceCompletionService.cs @@ -33,8 +33,8 @@ public BracketBraceCompletionService() protected override char ClosingBrace => Bracket.CloseCharacter; - public override Task AllowOverTypeAsync(BraceCompletionContext context, CancellationToken cancellationToken) - => AllowOverTypeInUserCodeWithValidClosingTokenAsync(context, cancellationToken); + public override bool AllowOverType(BraceCompletionContext context, CancellationToken cancellationToken) + => AllowOverTypeInUserCodeWithValidClosingToken(context, cancellationToken); protected override bool IsValidOpeningBraceToken(SyntaxToken token) => token.IsKind(SyntaxKind.OpenBracketToken); diff --git a/src/Features/CSharp/Portable/BraceCompletion/CharLiteralBraceCompletionService.cs b/src/Features/CSharp/Portable/BraceCompletion/CharLiteralBraceCompletionService.cs index af0ce72935a8a..f5ba3719023ce 100644 --- a/src/Features/CSharp/Portable/BraceCompletion/CharLiteralBraceCompletionService.cs +++ b/src/Features/CSharp/Portable/BraceCompletion/CharLiteralBraceCompletionService.cs @@ -7,9 +7,9 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.BraceCompletion; -using Microsoft.CodeAnalysis.CSharp.LanguageServices; +using Microsoft.CodeAnalysis.CSharp.LanguageService; using Microsoft.CodeAnalysis.Host.Mef; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.CSharp.BraceCompletion @@ -28,8 +28,8 @@ public CharLiteralBraceCompletionService() protected override char ClosingBrace => SingleQuote.CloseCharacter; - public override Task AllowOverTypeAsync(BraceCompletionContext braceCompletionContext, CancellationToken cancellationToken) - => AllowOverTypeWithValidClosingTokenAsync(braceCompletionContext, cancellationToken); + public override bool AllowOverType(BraceCompletionContext braceCompletionContext, CancellationToken cancellationToken) + => AllowOverTypeWithValidClosingToken(braceCompletionContext); protected override bool IsValidOpeningBraceToken(SyntaxToken token) => token.IsKind(SyntaxKind.CharacterLiteralToken); diff --git a/src/Features/CSharp/Portable/BraceCompletion/CurlyBraceCompletionService.cs b/src/Features/CSharp/Portable/BraceCompletion/CurlyBraceCompletionService.cs index 84ef6b5f3ddbc..7a74140a5ba0b 100644 --- a/src/Features/CSharp/Portable/BraceCompletion/CurlyBraceCompletionService.cs +++ b/src/Features/CSharp/Portable/BraceCompletion/CurlyBraceCompletionService.cs @@ -38,18 +38,18 @@ public CurlyBraceCompletionService() protected override char ClosingBrace => CurlyBrace.CloseCharacter; - public override Task AllowOverTypeAsync(BraceCompletionContext context, CancellationToken cancellationToken) - => AllowOverTypeInUserCodeWithValidClosingTokenAsync(context, cancellationToken); + public override bool AllowOverType(BraceCompletionContext context, CancellationToken cancellationToken) + => AllowOverTypeInUserCodeWithValidClosingToken(context, cancellationToken); - public override async Task CanProvideBraceCompletionAsync(char brace, int openingPosition, Document document, CancellationToken cancellationToken) + public override bool CanProvideBraceCompletion(char brace, int openingPosition, ParsedDocument document, CancellationToken cancellationToken) { // Only potentially valid for curly brace completion if not in an interpolation brace completion context. - if (OpeningBrace == brace && await InterpolationBraceCompletionService.IsPositionInInterpolationContextAsync(document, openingPosition, cancellationToken).ConfigureAwait(false)) + if (OpeningBrace == brace && InterpolationBraceCompletionService.IsPositionInInterpolationContext(document, openingPosition)) { return false; } - return await base.CanProvideBraceCompletionAsync(brace, openingPosition, document, cancellationToken).ConfigureAwait(false); + return base.CanProvideBraceCompletion(brace, openingPosition, document, cancellationToken); } protected override bool IsValidOpeningBraceToken(SyntaxToken token) diff --git a/src/Features/CSharp/Portable/BraceCompletion/InterpolatedStringBraceCompletionService.cs b/src/Features/CSharp/Portable/BraceCompletion/InterpolatedStringBraceCompletionService.cs index f31579ba3cdf6..ff854a671c08a 100644 --- a/src/Features/CSharp/Portable/BraceCompletion/InterpolatedStringBraceCompletionService.cs +++ b/src/Features/CSharp/Portable/BraceCompletion/InterpolatedStringBraceCompletionService.cs @@ -31,15 +31,15 @@ public InterpolatedStringBraceCompletionService() protected override char OpeningBrace => DoubleQuote.OpenCharacter; protected override char ClosingBrace => DoubleQuote.CloseCharacter; - public override Task AllowOverTypeAsync(BraceCompletionContext context, CancellationToken cancellationToken) - => AllowOverTypeWithValidClosingTokenAsync(context, cancellationToken); + public override bool AllowOverType(BraceCompletionContext context, CancellationToken cancellationToken) + => AllowOverTypeWithValidClosingToken(context); /// /// Only return this service as valid when we're starting an interpolated string. /// Otherwise double quotes should be completed using the /// - public override async Task CanProvideBraceCompletionAsync(char brace, int openingPosition, Document document, CancellationToken cancellationToken) - => OpeningBrace == brace && await IsPositionInInterpolatedStringContextAsync(document, openingPosition, cancellationToken).ConfigureAwait(false); + public override bool CanProvideBraceCompletion(char brace, int openingPosition, ParsedDocument document, CancellationToken cancellationToken) + => OpeningBrace == brace && IsPositionInInterpolatedStringContext(document, openingPosition, cancellationToken); protected override bool IsValidOpeningBraceToken(SyntaxToken leftToken) => leftToken.IsKind(SyntaxKind.InterpolatedStringStartToken) || leftToken.IsKind(SyntaxKind.InterpolatedVerbatimStringStartToken); @@ -53,9 +53,9 @@ protected override bool IsValidOpenBraceTokenAtPosition(SourceText text, SyntaxT /// /// Returns true when the input position could be starting an interpolated string if opening quotes were typed. /// - public static async Task IsPositionInInterpolatedStringContextAsync(Document document, int position, CancellationToken cancellationToken) + public static bool IsPositionInInterpolatedStringContext(ParsedDocument document, int position, CancellationToken cancellationToken) { - var text = await document.GetTextAsync(cancellationToken).ConfigureAwait(false); + var text = document.Text; var start = position - 1; if (start < 0) @@ -73,9 +73,7 @@ public static async Task IsPositionInInterpolatedStringContextAsync(Docume return false; // Verify that we are actually in an location allowed for an interpolated string. - var root = await document.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false); - - var token = root.FindToken(start); + var token = document.Root.FindToken(start); if (token.Kind() is not SyntaxKind.InterpolatedStringStartToken and not SyntaxKind.InterpolatedVerbatimStringStartToken and not SyntaxKind.StringLiteralToken and @@ -86,8 +84,8 @@ not SyntaxKind.StringLiteralToken and var previousToken = token.GetPreviousToken(); - return root.SyntaxTree.IsExpressionContext(token.SpanStart, previousToken, attributes: true, cancellationToken) - || root.SyntaxTree.IsStatementContext(token.SpanStart, previousToken, cancellationToken); + return document.SyntaxTree.IsExpressionContext(token.SpanStart, previousToken, attributes: true, cancellationToken) + || document.SyntaxTree.IsStatementContext(token.SpanStart, previousToken, cancellationToken); } } } diff --git a/src/Features/CSharp/Portable/BraceCompletion/InterpolationBraceCompletionService.cs b/src/Features/CSharp/Portable/BraceCompletion/InterpolationBraceCompletionService.cs index 3a0136c11b129..0490bc8a2d4ad 100644 --- a/src/Features/CSharp/Portable/BraceCompletion/InterpolationBraceCompletionService.cs +++ b/src/Features/CSharp/Portable/BraceCompletion/InterpolationBraceCompletionService.cs @@ -30,15 +30,15 @@ public InterpolationBraceCompletionService() protected override char OpeningBrace => CurlyBrace.OpenCharacter; protected override char ClosingBrace => CurlyBrace.CloseCharacter; - public override Task AllowOverTypeAsync(BraceCompletionContext context, CancellationToken cancellationToken) - => AllowOverTypeWithValidClosingTokenAsync(context, cancellationToken); + public override bool AllowOverType(BraceCompletionContext context, CancellationToken cancellationToken) + => AllowOverTypeWithValidClosingToken(context); /// /// Only return this service as valid when we're typing curly braces inside an interpolated string. /// Otherwise curly braces should be completed using the /// - public override async Task CanProvideBraceCompletionAsync(char brace, int openingPosition, Document document, CancellationToken cancellationToken) - => OpeningBrace == brace && await IsPositionInInterpolationContextAsync(document, openingPosition, cancellationToken).ConfigureAwait(false); + public override bool CanProvideBraceCompletion(char brace, int openingPosition, ParsedDocument document, CancellationToken cancellationToken) + => OpeningBrace == brace && IsPositionInInterpolationContext(document, openingPosition); protected override bool IsValidOpenBraceTokenAtPosition(SourceText text, SyntaxToken token, int position) => IsValidOpeningBraceToken(token) && token.SpanStart == position; @@ -52,19 +52,17 @@ protected override bool IsValidClosingBraceToken(SyntaxToken token) /// /// Returns true when the input position could be starting an interpolation expression if a curly brace was typed. /// - public static async Task IsPositionInInterpolationContextAsync(Document document, int position, CancellationToken cancellationToken) + public static bool IsPositionInInterpolationContext(ParsedDocument document, int position) { // First, check to see if the character to the left of the position is an open curly. // If it is, we shouldn't complete because the user may be trying to escape a curly. // E.g. they are trying to type $"{{" - if (await CouldEscapePreviousOpenBraceAsync('{', position, document, cancellationToken).ConfigureAwait(false)) + if (CouldEscapePreviousOpenBrace('{', position, document.Text)) { return false; } - var root = await document.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false); - var token = root.FindTokenOnLeftOfPosition(position); - + var token = document.Root.FindTokenOnLeftOfPosition(position); if (!token.Span.IntersectsWith(position)) { return false; diff --git a/src/Features/CSharp/Portable/BraceCompletion/LessAndGreaterThanBraceCompletionService.cs b/src/Features/CSharp/Portable/BraceCompletion/LessAndGreaterThanBraceCompletionService.cs index b5d9bb0ae160e..4fbf8cb446456 100644 --- a/src/Features/CSharp/Portable/BraceCompletion/LessAndGreaterThanBraceCompletionService.cs +++ b/src/Features/CSharp/Portable/BraceCompletion/LessAndGreaterThanBraceCompletionService.cs @@ -30,8 +30,8 @@ public LessAndGreaterThanBraceCompletionService() protected override char OpeningBrace => LessAndGreaterThan.OpenCharacter; protected override char ClosingBrace => LessAndGreaterThan.CloseCharacter; - public override Task AllowOverTypeAsync(BraceCompletionContext context, CancellationToken cancellationToken) - => AllowOverTypeInUserCodeWithValidClosingTokenAsync(context, cancellationToken); + public override bool AllowOverType(BraceCompletionContext context, CancellationToken cancellationToken) + => AllowOverTypeInUserCodeWithValidClosingToken(context, cancellationToken); protected override bool IsValidOpeningBraceToken(SyntaxToken token) => token.IsKind(SyntaxKind.LessThanToken); @@ -39,21 +39,20 @@ protected override bool IsValidOpeningBraceToken(SyntaxToken token) protected override bool IsValidClosingBraceToken(SyntaxToken token) => token.IsKind(SyntaxKind.GreaterThanToken); - protected override async ValueTask IsValidOpenBraceTokenAtPositionAsync(Document document, SyntaxToken token, int position, CancellationToken cancellationToken) + protected override Task IsValidOpenBraceTokenAtPositionAsync(Document document, SyntaxToken token, int position, CancellationToken cancellationToken) { // check what parser thinks about the newly typed "<" and only proceed if parser thinks it is "<" of // type argument or parameter list - return token.CheckParent(n => n.LessThanToken == token) || + if (token.CheckParent(n => n.LessThanToken == token) || token.CheckParent(n => n.LessThanToken == token) || - token.CheckParent(n => n.LessThanToken == token) || - await PossibleTypeArgumentAsync(document, token, cancellationToken).ConfigureAwait(false); - } + token.CheckParent(n => n.LessThanToken == token)) + { + return Task.FromResult(true); + } - private static async ValueTask PossibleTypeArgumentAsync(Document document, SyntaxToken token, CancellationToken cancellationToken) - { // type argument can be easily ambiguous with normal < operations if (token.Parent is not BinaryExpressionSyntax(SyntaxKind.LessThanExpression) node || node.OperatorToken != token) - return false; + return Task.FromResult(false); // type_argument_list only shows up in the following grammar construct: // @@ -63,11 +62,16 @@ private static async ValueTask PossibleTypeArgumentAsync(Document document // So if the prior token is not an identifier, this could not be a type-argument-list. var previousToken = token.GetPreviousToken(); if (previousToken.Parent is not IdentifierNameSyntax identifier) - return false; + return Task.FromResult(false); + + return IsSemanticTypeArgumentAsync(document, node.SpanStart, identifier, cancellationToken); - var semanticModel = await document.ReuseExistingSpeculativeModelAsync(node.SpanStart, cancellationToken).ConfigureAwait(false); - var info = semanticModel.GetSymbolInfo(identifier, cancellationToken); - return info.CandidateSymbols.Any(static s => s.GetArity() > 0); + static async Task IsSemanticTypeArgumentAsync(Document document, int position, IdentifierNameSyntax identifier, CancellationToken cancellationToken) + { + var semanticModel = await document.ReuseExistingSpeculativeModelAsync(position, cancellationToken).ConfigureAwait(false); + var info = semanticModel.GetSymbolInfo(identifier, cancellationToken); + return info.CandidateSymbols.Any(static s => s.GetArity() > 0); + } } } } diff --git a/src/Features/CSharp/Portable/BraceCompletion/ParenthesisBraceCompletionService.cs b/src/Features/CSharp/Portable/BraceCompletion/ParenthesisBraceCompletionService.cs index 6728253f62f11..21e2ea31cf96a 100644 --- a/src/Features/CSharp/Portable/BraceCompletion/ParenthesisBraceCompletionService.cs +++ b/src/Features/CSharp/Portable/BraceCompletion/ParenthesisBraceCompletionService.cs @@ -9,7 +9,7 @@ using Microsoft.CodeAnalysis.BraceCompletion; using Microsoft.CodeAnalysis.CSharp.Extensions; using Microsoft.CodeAnalysis.Host.Mef; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Text; @@ -27,8 +27,8 @@ public ParenthesisBraceCompletionService() protected override char OpeningBrace => Parenthesis.OpenCharacter; protected override char ClosingBrace => Parenthesis.CloseCharacter; - public override Task AllowOverTypeAsync(BraceCompletionContext context, CancellationToken cancellationToken) - => AllowOverTypeInUserCodeWithValidClosingTokenAsync(context, cancellationToken); + public override bool AllowOverType(BraceCompletionContext context, CancellationToken cancellationToken) + => AllowOverTypeInUserCodeWithValidClosingToken(context, cancellationToken); protected override bool IsValidOpeningBraceToken(SyntaxToken token) => token.IsKind(SyntaxKind.OpenParenToken); diff --git a/src/Features/CSharp/Portable/BraceCompletion/StringLiteralBraceCompletionService.cs b/src/Features/CSharp/Portable/BraceCompletion/StringLiteralBraceCompletionService.cs index d6b2777dc1128..11f5290aa5522 100644 --- a/src/Features/CSharp/Portable/BraceCompletion/StringLiteralBraceCompletionService.cs +++ b/src/Features/CSharp/Portable/BraceCompletion/StringLiteralBraceCompletionService.cs @@ -9,7 +9,7 @@ using Microsoft.CodeAnalysis.BraceCompletion; using Microsoft.CodeAnalysis.CSharp.Extensions; using Microsoft.CodeAnalysis.Host.Mef; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Text; using Roslyn.Utilities; @@ -28,18 +28,18 @@ public StringLiteralBraceCompletionService() protected override char OpeningBrace => DoubleQuote.OpenCharacter; protected override char ClosingBrace => DoubleQuote.CloseCharacter; - public override Task AllowOverTypeAsync(BraceCompletionContext context, CancellationToken cancellationToken) - => AllowOverTypeWithValidClosingTokenAsync(context, cancellationToken); + public override bool AllowOverType(BraceCompletionContext context, CancellationToken cancellationToken) + => AllowOverTypeWithValidClosingToken(context); - public override async Task CanProvideBraceCompletionAsync(char brace, int openingPosition, Document document, CancellationToken cancellationToken) + public override bool CanProvideBraceCompletion(char brace, int openingPosition, ParsedDocument document, CancellationToken cancellationToken) { // Only potentially valid for string literal completion if not in an interpolated string brace completion context. - if (OpeningBrace == brace && await InterpolatedStringBraceCompletionService.IsPositionInInterpolatedStringContextAsync(document, openingPosition, cancellationToken).ConfigureAwait(false)) + if (OpeningBrace == brace && InterpolatedStringBraceCompletionService.IsPositionInInterpolatedStringContext(document, openingPosition, cancellationToken)) { return false; } - return await base.CanProvideBraceCompletionAsync(brace, openingPosition, document, cancellationToken).ConfigureAwait(false); + return base.CanProvideBraceCompletion(brace, openingPosition, document, cancellationToken); } protected override bool IsValidOpeningBraceToken(SyntaxToken token) => token.IsKind(SyntaxKind.StringLiteralToken); diff --git a/src/EditorFeatures/CSharp/BraceMatching/AbstractCSharpBraceMatcher.cs b/src/Features/CSharp/Portable/BraceMatching/AbstractCSharpBraceMatcher.cs similarity index 91% rename from src/EditorFeatures/CSharp/BraceMatching/AbstractCSharpBraceMatcher.cs rename to src/Features/CSharp/Portable/BraceMatching/AbstractCSharpBraceMatcher.cs index 0a3ec3be5557b..1e45c7aa47af1 100644 --- a/src/EditorFeatures/CSharp/BraceMatching/AbstractCSharpBraceMatcher.cs +++ b/src/Features/CSharp/Portable/BraceMatching/AbstractCSharpBraceMatcher.cs @@ -5,7 +5,7 @@ using Microsoft.CodeAnalysis.BraceMatching; using Microsoft.CodeAnalysis.CSharp; -namespace Microsoft.CodeAnalysis.Editor.CSharp.BraceMatching +namespace Microsoft.CodeAnalysis.CSharp.BraceMatching { internal abstract class AbstractCSharpBraceMatcher : AbstractBraceMatcher { diff --git a/src/EditorFeatures/CSharp/BraceMatching/CSharpDirectiveTriviaBraceMatcher.cs b/src/Features/CSharp/Portable/BraceMatching/CSharpDirectiveTriviaBraceMatcher.cs similarity index 90% rename from src/EditorFeatures/CSharp/BraceMatching/CSharpDirectiveTriviaBraceMatcher.cs rename to src/Features/CSharp/Portable/BraceMatching/CSharpDirectiveTriviaBraceMatcher.cs index 0da4f21b82113..32bd7062c9884 100644 --- a/src/EditorFeatures/CSharp/BraceMatching/CSharpDirectiveTriviaBraceMatcher.cs +++ b/src/Features/CSharp/Portable/BraceMatching/CSharpDirectiveTriviaBraceMatcher.cs @@ -4,17 +4,18 @@ using System; using System.Collections.Generic; -using System.ComponentModel.Composition; +using System.Composition; using System.Linq; using System.Threading; +using Microsoft.CodeAnalysis.BraceMatching; using Microsoft.CodeAnalysis.CSharp.Extensions; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.Text; -namespace Microsoft.CodeAnalysis.Editor.CSharp.BraceMatching +namespace Microsoft.CodeAnalysis.CSharp.BraceMatching { - [ExportBraceMatcher(LanguageNames.CSharp)] + [ExportBraceMatcher(LanguageNames.CSharp), Shared] internal class CSharpDirectiveTriviaBraceMatcher : AbstractDirectiveTriviaBraceMatcher GetSelectedNodeAsync(CodeRefactoringContext context) - => NodeSelectionHelpers.GetSelectedDeclarationOrVariableAsync(context); + protected override Task> GetSelectedNodesAsync(CodeRefactoringContext context) + => NodeSelectionHelpers.GetSelectedDeclarationsOrVariablesAsync(context); } } diff --git a/src/Features/CSharp/Portable/CodeRefactorings/InlineMethod/CSharpInlineMethodRefactoringProvider.cs b/src/Features/CSharp/Portable/CodeRefactorings/InlineMethod/CSharpInlineMethodRefactoringProvider.cs index 29ef1b50136fc..b7d5485c9688f 100644 --- a/src/Features/CSharp/Portable/CodeRefactorings/InlineMethod/CSharpInlineMethodRefactoringProvider.cs +++ b/src/Features/CSharp/Portable/CodeRefactorings/InlineMethod/CSharpInlineMethodRefactoringProvider.cs @@ -7,7 +7,7 @@ using Microsoft.CodeAnalysis.CodeRefactorings; using Microsoft.CodeAnalysis.CSharp.CodeGeneration; using Microsoft.CodeAnalysis.CSharp.Extensions; -using Microsoft.CodeAnalysis.CSharp.LanguageServices; +using Microsoft.CodeAnalysis.CSharp.LanguageService; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.InlineMethod; diff --git a/src/Features/CSharp/Portable/CodeRefactorings/InlineTemporary/InlineTemporaryCodeRefactoringProvider.cs b/src/Features/CSharp/Portable/CodeRefactorings/InlineTemporary/InlineTemporaryCodeRefactoringProvider.cs index 25a6209aa7959..9288cdce76b8e 100644 --- a/src/Features/CSharp/Portable/CodeRefactorings/InlineTemporary/InlineTemporaryCodeRefactoringProvider.cs +++ b/src/Features/CSharp/Portable/CodeRefactorings/InlineTemporary/InlineTemporaryCodeRefactoringProvider.cs @@ -41,7 +41,7 @@ public CSharpInlineTemporaryCodeRefactoringProvider() public override async Task ComputeRefactoringsAsync(CodeRefactoringContext context) { var (document, _, cancellationToken) = context; - if (document.Project.Solution.Workspace.Kind == WorkspaceKind.MiscellaneousFiles) + if (document.Project.Solution.WorkspaceKind == WorkspaceKind.MiscellaneousFiles) { return; } @@ -136,8 +136,6 @@ private static SyntaxAnnotation CreateConflictAnnotation() private static async Task InlineTemporaryAsync(Document document, VariableDeclaratorSyntax declarator, CancellationToken cancellationToken) { - var workspace = document.Project.Solution.Workspace; - // Create the expression that we're actually going to inline. var expressionToInline = await CreateExpressionToInlineAsync(document, declarator, cancellationToken).ConfigureAwait(false); expressionToInline = expressionToInline.Parenthesize().WithAdditionalAnnotations(Formatter.Annotation, Simplifier.Annotation, ExpressionAnnotation); diff --git a/src/Features/CSharp/Portable/CodeRefactorings/MoveStaticMembers/CSharpMoveStaticMembersRefactoringProvider.cs b/src/Features/CSharp/Portable/CodeRefactorings/MoveStaticMembers/CSharpMoveStaticMembersRefactoringProvider.cs index b90f4cf55611f..c5e636d2a11ae 100644 --- a/src/Features/CSharp/Portable/CodeRefactorings/MoveStaticMembers/CSharpMoveStaticMembersRefactoringProvider.cs +++ b/src/Features/CSharp/Portable/CodeRefactorings/MoveStaticMembers/CSharpMoveStaticMembersRefactoringProvider.cs @@ -3,6 +3,7 @@ // See the LICENSE file in the project root for more information. using System; +using System.Collections.Immutable; using System.Composition; using System.Threading.Tasks; using Microsoft.CodeAnalysis.CodeRefactorings; @@ -20,7 +21,7 @@ public CSharpMoveStaticMembersRefactoringProvider() : base() { } - protected override Task GetSelectedNodeAsync(CodeRefactoringContext context) - => NodeSelectionHelpers.GetSelectedDeclarationOrVariableAsync(context); + protected override Task> GetSelectedNodesAsync(CodeRefactoringContext context) + => NodeSelectionHelpers.GetSelectedDeclarationsOrVariablesAsync(context); } } diff --git a/src/Features/CSharp/Portable/CodeRefactorings/NodeSelectionHelpers.cs b/src/Features/CSharp/Portable/CodeRefactorings/NodeSelectionHelpers.cs index f4b1718276817..eff81f847fc66 100644 --- a/src/Features/CSharp/Portable/CodeRefactorings/NodeSelectionHelpers.cs +++ b/src/Features/CSharp/Portable/CodeRefactorings/NodeSelectionHelpers.cs @@ -4,22 +4,66 @@ #nullable disable +using System; +using System.Collections.Immutable; +using System.Linq; using System.Threading.Tasks; using Microsoft.CodeAnalysis.CodeRefactorings; +using Microsoft.CodeAnalysis.CSharp.LanguageService; using Microsoft.CodeAnalysis.CSharp.Syntax; +using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.CSharp.CodeRefactorings { internal static class NodeSelectionHelpers { - internal static async Task GetSelectedDeclarationOrVariableAsync(CodeRefactoringContext context) + internal static async Task> GetSelectedDeclarationsOrVariablesAsync(CodeRefactoringContext context) { - // Consider: - // MemberDeclaration: member that can be declared in type (those are the ones we can pull up) - // VariableDeclaratorSyntax: for fields the MemberDeclaration can actually represent multiple declarations, e.g. `int a = 0, b = 1;`. - // ..Since the user might want to select & pull up only one of them (e.g. `int a = 0, [|b = 1|];` we also look for closest VariableDeclaratorSyntax. - return await context.TryGetRelevantNodeAsync().ConfigureAwait(false) as SyntaxNode ?? - await context.TryGetRelevantNodeAsync().ConfigureAwait(false); + var (document, span, cancellationToken) = context; + if (span.IsEmpty) + { + // if the span is empty then we are only selecting one "member" (which could include a field which declared multiple actual members) + // Consider: + // MemberDeclaration: member that can be declared in type (those are the ones we can pull up) + // VariableDeclaratorSyntax: for fields the MemberDeclaration can actually represent multiple declarations, e.g. `int a = 0, b = 1;`. + // ..Since the user might want to select & pull up only one of them (e.g. `int a = 0, [|b = 1|];` we also look for closest VariableDeclaratorSyntax. + var memberDeclaration = await context.TryGetRelevantNodeAsync().ConfigureAwait(false); + if (memberDeclaration == null) + { + // could not find a member, we may be directly on a variable declaration + var varDeclarator = await context.TryGetRelevantNodeAsync().ConfigureAwait(false); + return varDeclarator == null + ? ImmutableArray.Empty + : ImmutableArray.Create(varDeclarator); + } + else + { + return memberDeclaration switch + { + FieldDeclarationSyntax fieldDeclaration => fieldDeclaration.Declaration.Variables.AsImmutable(), + EventFieldDeclarationSyntax eventFieldDeclaration => eventFieldDeclaration.Declaration.Variables.AsImmutable(), + IncompleteMemberSyntax or GlobalStatementSyntax => ImmutableArray.Empty, + _ => ImmutableArray.Create(memberDeclaration), + }; + } + } + else + { + // if the span is non-empty, then we get potentially multiple members + // Note: even though this method handles the empty span case, we don't use it because it doesn't correctly + // pick up on keywords before the declaration, such as "public static int". + // We could potentially use it for every case if that behavior changes + var tree = await document.GetSyntaxTreeAsync(cancellationToken).ConfigureAwait(false); + var members = await CSharpSelectedMembers.Instance.GetSelectedMembersAsync(tree, span, allowPartialSelection: true, cancellationToken).ConfigureAwait(false); + // if we get a node that would not have an obtainable symbol (such as the ones below) + // we return an empty list instead of filtering so we don't get other potentially + // malformed syntax nodes. + // Consider pub[||] static int Foo; + // Which has 2 member nodes (an incomplete and a field), but we'd only expect one + return members.Any(m => m is GlobalStatementSyntax or IncompleteMemberSyntax) + ? ImmutableArray.Empty + : members; + } } } } diff --git a/src/Features/CSharp/Portable/CodeRefactorings/PullMemberUp/CSharpPullMemberUpCodeRefactoringProvider.cs b/src/Features/CSharp/Portable/CodeRefactorings/PullMemberUp/CSharpPullMemberUpCodeRefactoringProvider.cs index cccf4be8ca8aa..bcb349c494c74 100644 --- a/src/Features/CSharp/Portable/CodeRefactorings/PullMemberUp/CSharpPullMemberUpCodeRefactoringProvider.cs +++ b/src/Features/CSharp/Portable/CodeRefactorings/PullMemberUp/CSharpPullMemberUpCodeRefactoringProvider.cs @@ -5,6 +5,7 @@ #nullable disable using System; +using System.Collections.Immutable; using System.Composition; using System.Diagnostics.CodeAnalysis; using System.Threading.Tasks; @@ -33,7 +34,7 @@ public CSharpPullMemberUpCodeRefactoringProvider() : this(service: null) { } - protected override Task GetSelectedNodeAsync(CodeRefactoringContext context) - => NodeSelectionHelpers.GetSelectedDeclarationOrVariableAsync(context); + protected override Task> GetSelectedNodesAsync(CodeRefactoringContext context) + => NodeSelectionHelpers.GetSelectedDeclarationsOrVariablesAsync(context); } } diff --git a/src/Features/CSharp/Portable/CodeRefactorings/SyncNamespace/CSharpChangeNamespaceService.cs b/src/Features/CSharp/Portable/CodeRefactorings/SyncNamespace/CSharpChangeNamespaceService.cs index 7cecb5f55106a..3d6c582623523 100644 --- a/src/Features/CSharp/Portable/CodeRefactorings/SyncNamespace/CSharpChangeNamespaceService.cs +++ b/src/Features/CSharp/Portable/CodeRefactorings/SyncNamespace/CSharpChangeNamespaceService.cs @@ -15,7 +15,7 @@ using Microsoft.CodeAnalysis.CSharp.Extensions; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Host.Mef; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Text; @@ -38,7 +38,7 @@ public CSharpChangeNamespaceService() SyntaxNode container, CancellationToken cancellationToken) { - if (document.Project.Solution.Workspace.Kind == WorkspaceKind.MiscellaneousFiles + if (document.Project.Solution.WorkspaceKind == WorkspaceKind.MiscellaneousFiles || document.IsGeneratedCode(cancellationToken)) { return default; diff --git a/src/Features/CSharp/Portable/CodeRefactorings/UseExplicitOrImplicitType/AbstractUseTypeCodeRefactoringProvider.cs b/src/Features/CSharp/Portable/CodeRefactorings/UseExplicitOrImplicitType/AbstractUseTypeCodeRefactoringProvider.cs index e98ef32c730ee..54e86a4bdcb90 100644 --- a/src/Features/CSharp/Portable/CodeRefactorings/UseExplicitOrImplicitType/AbstractUseTypeCodeRefactoringProvider.cs +++ b/src/Features/CSharp/Portable/CodeRefactorings/UseExplicitOrImplicitType/AbstractUseTypeCodeRefactoringProvider.cs @@ -15,7 +15,7 @@ using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.CSharp.Utilities; using Microsoft.CodeAnalysis.Editing; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Simplification; @@ -32,7 +32,7 @@ internal abstract class AbstractUseTypeCodeRefactoringProvider : CodeRefactoring public override async Task ComputeRefactoringsAsync(CodeRefactoringContext context) { var (document, textSpan, cancellationToken) = context; - if (document.Project.Solution.Workspace.Kind == WorkspaceKind.MiscellaneousFiles) + if (document.Project.Solution.WorkspaceKind == WorkspaceKind.MiscellaneousFiles) { return; } @@ -124,7 +124,7 @@ private static async Task GetDeclarationAsync(CodeRefactoringContext private async Task UpdateDocumentAsync(Document document, TypeSyntax type, CancellationToken cancellationToken) { var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); - var editor = new SyntaxEditor(root, document.Project.Solution.Workspace.Services); + var editor = new SyntaxEditor(root, document.Project.Solution.Services); await HandleDeclarationAsync(document, editor, type, cancellationToken).ConfigureAwait(false); diff --git a/src/Features/CSharp/Portable/CodeRefactorings/UseRecursivePatterns/UseRecursivePatternsCodeRefactoringProvider.cs b/src/Features/CSharp/Portable/CodeRefactorings/UseRecursivePatterns/UseRecursivePatternsCodeRefactoringProvider.cs index ef044753f11b7..8317863952842 100644 --- a/src/Features/CSharp/Portable/CodeRefactorings/UseRecursivePatterns/UseRecursivePatternsCodeRefactoringProvider.cs +++ b/src/Features/CSharp/Portable/CodeRefactorings/UseRecursivePatterns/UseRecursivePatternsCodeRefactoringProvider.cs @@ -47,7 +47,7 @@ public UseRecursivePatternsCodeRefactoringProvider() public override async Task ComputeRefactoringsAsync(CodeRefactoringContext context) { var (document, textSpan, cancellationToken) = context; - if (document.Project.Solution.Workspace.Kind == WorkspaceKind.MiscellaneousFiles) + if (document.Project.Solution.WorkspaceKind == WorkspaceKind.MiscellaneousFiles) return; if (textSpan.Length > 0) diff --git a/src/Features/CSharp/Portable/Completion/CSharpCompletionOptions.cs b/src/Features/CSharp/Portable/Completion/CSharpCompletionOptions.cs deleted file mode 100644 index e05db432b493a..0000000000000 --- a/src/Features/CSharp/Portable/Completion/CSharpCompletionOptions.cs +++ /dev/null @@ -1,18 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using System; -using Microsoft.CodeAnalysis.Options; - -namespace Microsoft.CodeAnalysis.CSharp.Completion -{ - internal static class CSharpCompletionOptions - { - [Obsolete("This option is superceded by CompletionOptions.Metadata.EnterKeyBehavior")] - public static readonly Option2 AddNewLineOnEnterAfterFullyTypedWord = new Option2(nameof(CSharpCompletionOptions), nameof(AddNewLineOnEnterAfterFullyTypedWord), defaultValue: false); - - [Obsolete("This option is superceded by CompletionOptions.Metadata.SnippetsBehavior")] - public static readonly Option2 IncludeSnippets = new Option2(nameof(CSharpCompletionOptions), nameof(IncludeSnippets), defaultValue: true); - } -} diff --git a/src/Features/CSharp/Portable/Completion/CSharpCompletionService.cs b/src/Features/CSharp/Portable/Completion/CSharpCompletionService.cs index e1f177289fd7c..5d7b64c6b8c97 100644 --- a/src/Features/CSharp/Portable/Completion/CSharpCompletionService.cs +++ b/src/Features/CSharp/Portable/Completion/CSharpCompletionService.cs @@ -26,13 +26,13 @@ public Factory() [Obsolete(MefConstruction.FactoryMethodMessage, error: true)] public ILanguageService CreateLanguageService(HostLanguageServices languageServices) - => new CSharpCompletionService(languageServices.WorkspaceServices.Workspace); + => new CSharpCompletionService(languageServices.LanguageServices.SolutionServices); } private CompletionRules _latestRules = CompletionRules.Default; - private CSharpCompletionService(Workspace workspace) - : base(workspace) + private CSharpCompletionService(SolutionServices services) + : base(services) { } diff --git a/src/Features/CSharp/Portable/Completion/CompletionProviders/AttributeNamedParameterCompletionProvider.cs b/src/Features/CSharp/Portable/Completion/CompletionProviders/AttributeNamedParameterCompletionProvider.cs index 71f3683a74cfc..4a09bb5064672 100644 --- a/src/Features/CSharp/Portable/Completion/CompletionProviders/AttributeNamedParameterCompletionProvider.cs +++ b/src/Features/CSharp/Portable/Completion/CompletionProviders/AttributeNamedParameterCompletionProvider.cs @@ -16,7 +16,7 @@ using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.ErrorReporting; using Microsoft.CodeAnalysis.Host.Mef; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Text; @@ -88,7 +88,6 @@ public override async Task ProvideCompletionsAsync(CompletionContext context) var existingNamedParameters = GetExistingNamedParameters(attributeArgumentList, position); - var workspace = document.Project.Solution.Workspace; var semanticModel = await document.ReuseExistingSpeculativeModelAsync(attributeSyntax, cancellationToken).ConfigureAwait(false); var nameColonItems = await GetNameColonItemsAsync(context, semanticModel, token, attributeSyntax, existingNamedParameters).ConfigureAwait(false); var nameEqualsItems = await GetNameEqualsItemsAsync(context, semanticModel, token, attributeSyntax, existingNamedParameters).ConfigureAwait(false); diff --git a/src/Features/CSharp/Portable/Completion/CompletionProviders/AwaitCompletionProvider.cs b/src/Features/CSharp/Portable/Completion/CompletionProviders/AwaitCompletionProvider.cs index c440a10617178..2350151c708b1 100644 --- a/src/Features/CSharp/Portable/Completion/CompletionProviders/AwaitCompletionProvider.cs +++ b/src/Features/CSharp/Portable/Completion/CompletionProviders/AwaitCompletionProvider.cs @@ -10,7 +10,7 @@ using Microsoft.CodeAnalysis.Completion; using Microsoft.CodeAnalysis.Completion.Providers; using Microsoft.CodeAnalysis.CSharp.Extensions; -using Microsoft.CodeAnalysis.CSharp.LanguageServices; +using Microsoft.CodeAnalysis.CSharp.LanguageService; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.Shared.Extensions; diff --git a/src/Features/CSharp/Portable/Completion/CompletionProviders/CSharpSuggestionModeCompletionProvider.cs b/src/Features/CSharp/Portable/Completion/CompletionProviders/CSharpSuggestionModeCompletionProvider.cs index 2a86bc800f6ce..ba1a551cb31d5 100644 --- a/src/Features/CSharp/Portable/Completion/CompletionProviders/CSharpSuggestionModeCompletionProvider.cs +++ b/src/Features/CSharp/Portable/Completion/CompletionProviders/CSharpSuggestionModeCompletionProvider.cs @@ -16,7 +16,7 @@ using Microsoft.CodeAnalysis.CSharp.Symbols; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Host.Mef; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Text; diff --git a/src/Features/CSharp/Portable/Completion/CompletionProviders/CompletionUtilities.cs b/src/Features/CSharp/Portable/Completion/CompletionProviders/CompletionUtilities.cs index 28f9b96544ec1..263d401c663ef 100644 --- a/src/Features/CSharp/Portable/Completion/CompletionProviders/CompletionUtilities.cs +++ b/src/Features/CSharp/Portable/Completion/CompletionProviders/CompletionUtilities.cs @@ -91,6 +91,23 @@ internal static bool IsTriggerCharacter(SourceText text, int characterPosition, return false; } + /// + /// Tells if we are in positions like this: #nullable $$ or #pragma warning $$ + /// + internal static bool IsCompilerDirectiveTriggerCharacter(SourceText text, int characterPosition) + { + while (text[characterPosition] == ' ' || + char.IsLetter(text[characterPosition])) + { + characterPosition--; + + if (characterPosition < 0) + return false; + } + + return text[characterPosition] == '#'; + } + internal static ImmutableHashSet CommonTriggerCharacters { get; } = ImmutableHashSet.Create('.', '#', '>', ':'); internal static ImmutableHashSet CommonTriggerCharactersWithArgumentList { get; } = ImmutableHashSet.Create('.', '#', '>', ':', '(', '[', ' '); diff --git a/src/Features/CSharp/Portable/Completion/CompletionProviders/DeclarationNameCompletionProvider.DeclarationInfo.cs b/src/Features/CSharp/Portable/Completion/CompletionProviders/DeclarationNameCompletionProvider.DeclarationInfo.cs index 2dd132d524299..733df9974c11d 100644 --- a/src/Features/CSharp/Portable/Completion/CompletionProviders/DeclarationNameCompletionProvider.DeclarationInfo.cs +++ b/src/Features/CSharp/Portable/Completion/CompletionProviders/DeclarationNameCompletionProvider.DeclarationInfo.cs @@ -9,7 +9,7 @@ using Microsoft.CodeAnalysis.CSharp.Extensions; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Editing; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Shared.Extensions; using static Microsoft.CodeAnalysis.Diagnostics.Analyzers.NamingStyles.SymbolSpecification; diff --git a/src/Features/CSharp/Portable/Completion/CompletionProviders/DeclarationNameCompletionProvider.cs b/src/Features/CSharp/Portable/Completion/CompletionProviders/DeclarationNameCompletionProvider.cs index 480f54224a39d..fa9e1a4aabeda 100644 --- a/src/Features/CSharp/Portable/Completion/CompletionProviders/DeclarationNameCompletionProvider.cs +++ b/src/Features/CSharp/Portable/Completion/CompletionProviders/DeclarationNameCompletionProvider.cs @@ -15,12 +15,12 @@ using Microsoft.CodeAnalysis.Completion; using Microsoft.CodeAnalysis.CSharp.Extensions; using Microsoft.CodeAnalysis.CSharp.Extensions.ContextQuery; -using Microsoft.CodeAnalysis.CSharp.LanguageServices; +using Microsoft.CodeAnalysis.CSharp.LanguageService; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Diagnostics.Analyzers.NamingStyles; using Microsoft.CodeAnalysis.ErrorReporting; using Microsoft.CodeAnalysis.Host.Mef; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Shared.Naming; diff --git a/src/Features/CSharp/Portable/Completion/CompletionProviders/EnumAndCompletionListTagCompletionProvider.cs b/src/Features/CSharp/Portable/Completion/CompletionProviders/EnumAndCompletionListTagCompletionProvider.cs index 521e7e94149fc..f5fb1814b5b46 100644 --- a/src/Features/CSharp/Portable/Completion/CompletionProviders/EnumAndCompletionListTagCompletionProvider.cs +++ b/src/Features/CSharp/Portable/Completion/CompletionProviders/EnumAndCompletionListTagCompletionProvider.cs @@ -14,7 +14,7 @@ using Microsoft.CodeAnalysis.CSharp.Extensions.ContextQuery; using Microsoft.CodeAnalysis.ErrorReporting; using Microsoft.CodeAnalysis.Host.Mef; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Shared.Utilities; using Microsoft.CodeAnalysis.Text; diff --git a/src/Features/CSharp/Portable/Completion/CompletionProviders/ExplicitInterfaceMemberCompletionProvider.cs b/src/Features/CSharp/Portable/Completion/CompletionProviders/ExplicitInterfaceMemberCompletionProvider.cs index 7f19014ce6918..7c8b28cf56dee 100644 --- a/src/Features/CSharp/Portable/Completion/CompletionProviders/ExplicitInterfaceMemberCompletionProvider.cs +++ b/src/Features/CSharp/Portable/Completion/CompletionProviders/ExplicitInterfaceMemberCompletionProvider.cs @@ -14,7 +14,7 @@ using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.ErrorReporting; using Microsoft.CodeAnalysis.Host.Mef; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Text; diff --git a/src/Features/CSharp/Portable/Completion/CompletionProviders/FunctionPointerUnmanagedCallingConventionCompletionProvider.cs b/src/Features/CSharp/Portable/Completion/CompletionProviders/FunctionPointerUnmanagedCallingConventionCompletionProvider.cs index 3a7dbf9ea04d4..7df420f481a8f 100644 --- a/src/Features/CSharp/Portable/Completion/CompletionProviders/FunctionPointerUnmanagedCallingConventionCompletionProvider.cs +++ b/src/Features/CSharp/Portable/Completion/CompletionProviders/FunctionPointerUnmanagedCallingConventionCompletionProvider.cs @@ -15,7 +15,7 @@ using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.ErrorReporting; using Microsoft.CodeAnalysis.Host.Mef; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Text; diff --git a/src/Features/CSharp/Portable/Completion/CompletionProviders/ImportCompletion/TypeImportCompletionServiceFactory.cs b/src/Features/CSharp/Portable/Completion/CompletionProviders/ImportCompletion/TypeImportCompletionServiceFactory.cs index 33480f82ebaa5..fce6aeecc715b 100644 --- a/src/Features/CSharp/Portable/Completion/CompletionProviders/ImportCompletion/TypeImportCompletionServiceFactory.cs +++ b/src/Features/CSharp/Portable/Completion/CompletionProviders/ImportCompletion/TypeImportCompletionServiceFactory.cs @@ -21,12 +21,12 @@ public TypeImportCompletionServiceFactory() } public ILanguageService CreateLanguageService(HostLanguageServices languageServices) - => new CSharpTypeImportCompletionService(languageServices.WorkspaceServices.Workspace); + => new CSharpTypeImportCompletionService(languageServices.LanguageServices.SolutionServices); private class CSharpTypeImportCompletionService : AbstractTypeImportCompletionService { - public CSharpTypeImportCompletionService(Workspace workspace) - : base(workspace) + public CSharpTypeImportCompletionService(SolutionServices services) + : base(services) { } diff --git a/src/Features/CSharp/Portable/Completion/CompletionProviders/KeywordCompletionProvider.cs b/src/Features/CSharp/Portable/Completion/CompletionProviders/KeywordCompletionProvider.cs index 2c74a4a4cc164..9e938692bab6e 100644 --- a/src/Features/CSharp/Portable/Completion/CompletionProviders/KeywordCompletionProvider.cs +++ b/src/Features/CSharp/Portable/Completion/CompletionProviders/KeywordCompletionProvider.cs @@ -68,6 +68,7 @@ public KeywordCompletionProvider() new ExternKeywordRecommender(), new FalseKeywordRecommender(), new FieldKeywordRecommender(), + new FileKeywordRecommender(), new FinallyKeywordRecommender(), new FixedKeywordRecommender(), new FloatKeywordRecommender(), @@ -173,9 +174,10 @@ public KeywordCompletionProvider() internal override string Language => LanguageNames.CSharp; public override bool IsInsertionTrigger(SourceText text, int characterPosition, CompletionOptions options) - => CompletionUtilities.IsTriggerCharacter(text, characterPosition, options); + => CompletionUtilities.IsTriggerCharacter(text, characterPosition, options) || + CompletionUtilities.IsCompilerDirectiveTriggerCharacter(text, characterPosition); - public override ImmutableHashSet TriggerCharacters { get; } = CompletionUtilities.CommonTriggerCharacters; + public override ImmutableHashSet TriggerCharacters { get; } = CompletionUtilities.CommonTriggerCharacters.Add(' '); private static readonly CompletionItemRules s_tupleRules = CompletionItemRules.Default. WithCommitCharacterRule(CharacterSetModificationRule.Create(CharacterSetModificationKind.Remove, ':')); diff --git a/src/Features/CSharp/Portable/Completion/CompletionProviders/NamedParameterCompletionProvider.cs b/src/Features/CSharp/Portable/Completion/CompletionProviders/NamedParameterCompletionProvider.cs index aff2db04346c4..93946882cea0c 100644 --- a/src/Features/CSharp/Portable/Completion/CompletionProviders/NamedParameterCompletionProvider.cs +++ b/src/Features/CSharp/Portable/Completion/CompletionProviders/NamedParameterCompletionProvider.cs @@ -18,7 +18,7 @@ using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.ErrorReporting; using Microsoft.CodeAnalysis.Host.Mef; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Text; @@ -108,8 +108,6 @@ public override async Task ProvideCompletionsAsync(CompletionContext context) var text = await document.GetTextAsync(cancellationToken).ConfigureAwait(false); - var workspace = document.Project.Solution.Workspace; - foreach (var parameter in unspecifiedParameters) { // Note: the filter text does not include the ':'. We want to ensure that if diff --git a/src/Features/CSharp/Portable/Completion/CompletionProviders/ObjectAndWithInitializerCompletionProvider.cs b/src/Features/CSharp/Portable/Completion/CompletionProviders/ObjectAndWithInitializerCompletionProvider.cs index 856c540369419..cc76626705d7d 100644 --- a/src/Features/CSharp/Portable/Completion/CompletionProviders/ObjectAndWithInitializerCompletionProvider.cs +++ b/src/Features/CSharp/Portable/Completion/CompletionProviders/ObjectAndWithInitializerCompletionProvider.cs @@ -14,7 +14,7 @@ using Microsoft.CodeAnalysis.CSharp.Extensions; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Host.Mef; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Text; diff --git a/src/Features/CSharp/Portable/Completion/CompletionProviders/OperatorsAndIndexer/UnnamedSymbolCompletionProvider.cs b/src/Features/CSharp/Portable/Completion/CompletionProviders/OperatorsAndIndexer/UnnamedSymbolCompletionProvider.cs index fe3c85da6775d..d9ffde2d938bf 100644 --- a/src/Features/CSharp/Portable/Completion/CompletionProviders/OperatorsAndIndexer/UnnamedSymbolCompletionProvider.cs +++ b/src/Features/CSharp/Portable/Completion/CompletionProviders/OperatorsAndIndexer/UnnamedSymbolCompletionProvider.cs @@ -12,7 +12,7 @@ using Microsoft.CodeAnalysis.CSharp.Extensions; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Host.Mef; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Recommendations; using Microsoft.CodeAnalysis.Shared.Extensions; diff --git a/src/Features/CSharp/Portable/Completion/CompletionProviders/OperatorsAndIndexer/UnnamedSymbolCompletionProvider_Conversions.cs b/src/Features/CSharp/Portable/Completion/CompletionProviders/OperatorsAndIndexer/UnnamedSymbolCompletionProvider_Conversions.cs index 648c4ac83db1e..5113e0940eddc 100644 --- a/src/Features/CSharp/Portable/Completion/CompletionProviders/OperatorsAndIndexer/UnnamedSymbolCompletionProvider_Conversions.cs +++ b/src/Features/CSharp/Portable/Completion/CompletionProviders/OperatorsAndIndexer/UnnamedSymbolCompletionProvider_Conversions.cs @@ -10,9 +10,9 @@ using Microsoft.CodeAnalysis.Completion; using Microsoft.CodeAnalysis.Completion.Providers; using Microsoft.CodeAnalysis.CSharp.Extensions; -using Microsoft.CodeAnalysis.CSharp.LanguageServices; +using Microsoft.CodeAnalysis.CSharp.LanguageService; using Microsoft.CodeAnalysis.CSharp.Syntax; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Text; diff --git a/src/Features/CSharp/Portable/Completion/CompletionProviders/OperatorsAndIndexer/UnnamedSymbolCompletionProvider_Indexers.cs b/src/Features/CSharp/Portable/Completion/CompletionProviders/OperatorsAndIndexer/UnnamedSymbolCompletionProvider_Indexers.cs index 86a9b45d08036..e9a14cf659eec 100644 --- a/src/Features/CSharp/Portable/Completion/CompletionProviders/OperatorsAndIndexer/UnnamedSymbolCompletionProvider_Indexers.cs +++ b/src/Features/CSharp/Portable/Completion/CompletionProviders/OperatorsAndIndexer/UnnamedSymbolCompletionProvider_Indexers.cs @@ -7,7 +7,7 @@ using System.Threading.Tasks; using Microsoft.CodeAnalysis.Completion; using Microsoft.CodeAnalysis.Completion.Providers; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; namespace Microsoft.CodeAnalysis.CSharp.Completion.Providers { diff --git a/src/Features/CSharp/Portable/Completion/CompletionProviders/OperatorsAndIndexer/UnnamedSymbolCompletionProvider_Operators.cs b/src/Features/CSharp/Portable/Completion/CompletionProviders/OperatorsAndIndexer/UnnamedSymbolCompletionProvider_Operators.cs index d2dd526a52be7..409d40d055115 100644 --- a/src/Features/CSharp/Portable/Completion/CompletionProviders/OperatorsAndIndexer/UnnamedSymbolCompletionProvider_Operators.cs +++ b/src/Features/CSharp/Portable/Completion/CompletionProviders/OperatorsAndIndexer/UnnamedSymbolCompletionProvider_Operators.cs @@ -9,7 +9,7 @@ using System.Threading.Tasks; using Microsoft.CodeAnalysis.Completion; using Microsoft.CodeAnalysis.Completion.Providers; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Text; diff --git a/src/Features/CSharp/Portable/Completion/CompletionProviders/PropertySubPatternCompletionProvider.cs b/src/Features/CSharp/Portable/Completion/CompletionProviders/PropertySubPatternCompletionProvider.cs index fdb2f82bd4818..df837a0cee9ff 100644 --- a/src/Features/CSharp/Portable/Completion/CompletionProviders/PropertySubPatternCompletionProvider.cs +++ b/src/Features/CSharp/Portable/Completion/CompletionProviders/PropertySubPatternCompletionProvider.cs @@ -15,7 +15,7 @@ using Microsoft.CodeAnalysis.CSharp.Extensions; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Host.Mef; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Text; diff --git a/src/Features/CSharp/Portable/Completion/CompletionProviders/Scripting/LoadDirectiveCompletionProvider.cs b/src/Features/CSharp/Portable/Completion/CompletionProviders/Scripting/LoadDirectiveCompletionProvider.cs index 6917a710b961f..b84329b7276f0 100644 --- a/src/Features/CSharp/Portable/Completion/CompletionProviders/Scripting/LoadDirectiveCompletionProvider.cs +++ b/src/Features/CSharp/Portable/Completion/CompletionProviders/Scripting/LoadDirectiveCompletionProvider.cs @@ -7,12 +7,13 @@ using System.Threading; using Microsoft.CodeAnalysis.Completion; using Microsoft.CodeAnalysis.Completion.Providers; +using Microsoft.CodeAnalysis.CSharp.Completion.CompletionProviders.Snippets; using Microsoft.CodeAnalysis.Host.Mef; namespace Microsoft.CodeAnalysis.CSharp.Completion.Providers { [ExportCompletionProvider(nameof(LoadDirectiveCompletionProvider), LanguageNames.CSharp)] - [ExtensionOrder(After = nameof(FunctionPointerUnmanagedCallingConventionCompletionProvider))] + [ExtensionOrder(After = nameof(CSharpSnippetCompletionProvider))] [Shared] internal sealed class LoadDirectiveCompletionProvider : AbstractLoadDirectiveCompletionProvider { diff --git a/src/Features/CSharp/Portable/Completion/CompletionProviders/SnippetCompletionProvider.cs b/src/Features/CSharp/Portable/Completion/CompletionProviders/SnippetCompletionProvider.cs index 771250f152f69..55f3bb5aa8ef1 100644 --- a/src/Features/CSharp/Portable/Completion/CompletionProviders/SnippetCompletionProvider.cs +++ b/src/Features/CSharp/Portable/Completion/CompletionProviders/SnippetCompletionProvider.cs @@ -14,9 +14,10 @@ using Microsoft.CodeAnalysis.CSharp.Extensions.ContextQuery; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.ErrorReporting; +using Microsoft.CodeAnalysis.Host; using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.Internal.Log; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Snippets; using Microsoft.CodeAnalysis.Text; @@ -55,10 +56,10 @@ public override async Task ProvideCompletionsAsync(CompletionContext context) using (Logger.LogBlock(FunctionId.Completion_SnippetCompletionProvider_GetItemsWorker_CSharp, cancellationToken)) { // TODO (https://github.com/dotnet/roslyn/issues/5107): Enable in Interactive. - var workspace = document.Project.Solution.Workspace; - if (!workspace.CanApplyChange(ApplyChangesKind.ChangeDocument) || - workspace.Kind == WorkspaceKind.Debugger || - workspace.Kind == WorkspaceKind.Interactive) + var solution = document.Project.Solution; + if (!solution.CanApplyChange(ApplyChangesKind.ChangeDocument) || + solution.WorkspaceKind == WorkspaceKind.Debugger || + solution.WorkspaceKind == WorkspaceKind.Interactive) { return; } @@ -116,7 +117,7 @@ private static async Task> GetSnippetsForDocument SyntaxKind.WarningKeyword)) { return GetSnippetCompletionItems( - document.Project.Solution.Workspace, semanticModel, isPreProcessorContext: true); + document.Project.Solution.Services, semanticModel, isPreProcessorContext: true); } } else @@ -132,7 +133,7 @@ private static async Task> GetSnippetsForDocument semanticFacts.IsLabelContext(semanticModel, position, cancellationToken)) { return GetSnippetCompletionItems( - document.Project.Solution.Workspace, semanticModel, isPreProcessorContext: false); + document.Project.Solution.Services, semanticModel, isPreProcessorContext: false); } } @@ -140,9 +141,9 @@ private static async Task> GetSnippetsForDocument } private static ImmutableArray GetSnippetCompletionItems( - Workspace workspace, SemanticModel semanticModel, bool isPreProcessorContext) + SolutionServices services, SemanticModel semanticModel, bool isPreProcessorContext) { - var service = workspace.Services.GetLanguageServices(semanticModel.Language).GetService(); + var service = services.GetLanguageServices(semanticModel.Language).GetService(); if (service == null) return ImmutableArray.Empty; @@ -157,12 +158,12 @@ private static ImmutableArray GetSnippetCompletionItems( var rules = CompletionItemRules.Default.WithFormatOnCommit(service.ShouldFormatSnippet(snippet)); return CommonCompletionItem.Create( - displayText: isPreProcessorContext ? snippet.Shortcut[1..] : snippet.Shortcut, - displayTextSuffix: "", - sortText: isPreProcessorContext ? snippet.Shortcut[1..] : snippet.Shortcut, - description: (snippet.Title + Environment.NewLine + snippet.Description).ToSymbolDisplayParts(), - glyph: Glyph.Snippet, - rules: rules); + displayText: isPreProcessorContext ? snippet.Shortcut[1..] : snippet.Shortcut, + displayTextSuffix: "", + sortText: isPreProcessorContext ? snippet.Shortcut[1..] : snippet.Shortcut, + description: (snippet.Title + Environment.NewLine + snippet.Description).ToSymbolDisplayParts(), + glyph: Glyph.Snippet, + rules: rules); }); } } diff --git a/src/Features/CSharp/Portable/Completion/CompletionProviders/Snippets/CSharpSnippetCompletionProvider.cs b/src/Features/CSharp/Portable/Completion/CompletionProviders/Snippets/CSharpSnippetCompletionProvider.cs new file mode 100644 index 0000000000000..cb1c3932f6707 --- /dev/null +++ b/src/Features/CSharp/Portable/Completion/CompletionProviders/Snippets/CSharpSnippetCompletionProvider.cs @@ -0,0 +1,26 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Composition; +using Microsoft.CodeAnalysis.Completion; +using Microsoft.CodeAnalysis.Completion.Providers.Snippets; +using Microsoft.CodeAnalysis.CSharp.Completion.Providers; +using Microsoft.CodeAnalysis.Host.Mef; +using Microsoft.CodeAnalysis.Snippets; + +namespace Microsoft.CodeAnalysis.CSharp.Completion.CompletionProviders.Snippets +{ + [ExportCompletionProvider(nameof(CSharpSnippetCompletionProvider), LanguageNames.CSharp)] + [ExtensionOrder(After = nameof(FunctionPointerUnmanagedCallingConventionCompletionProvider))] + [Shared] + internal class CSharpSnippetCompletionProvider : AbstractSnippetCompletionProvider + { + [ImportingConstructor] + [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] + public CSharpSnippetCompletionProvider() + { + } + } +} diff --git a/src/Features/CSharp/Portable/Completion/CompletionProviders/TupleNameCompletionProvider.cs b/src/Features/CSharp/Portable/Completion/CompletionProviders/TupleNameCompletionProvider.cs index ddf523d620b1a..64c8830e5336e 100644 --- a/src/Features/CSharp/Portable/Completion/CompletionProviders/TupleNameCompletionProvider.cs +++ b/src/Features/CSharp/Portable/Completion/CompletionProviders/TupleNameCompletionProvider.cs @@ -15,7 +15,7 @@ using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.ErrorReporting; using Microsoft.CodeAnalysis.Host.Mef; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Text; using Roslyn.Utilities; diff --git a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/AbstractSpecialTypePreselectingKeywordRecommender.cs b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/AbstractSpecialTypePreselectingKeywordRecommender.cs index 126e2ba18f56a..9d1768a0409a6 100644 --- a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/AbstractSpecialTypePreselectingKeywordRecommender.cs +++ b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/AbstractSpecialTypePreselectingKeywordRecommender.cs @@ -4,6 +4,7 @@ using System.Linq; using System.Threading; +using Microsoft.CodeAnalysis.Completion.Providers; using Microsoft.CodeAnalysis.CSharp.Extensions.ContextQuery; namespace Microsoft.CodeAnalysis.CSharp.Completion.KeywordRecommenders @@ -21,6 +22,11 @@ public AbstractSpecialTypePreselectingKeywordRecommender( protected abstract SpecialType SpecialType { get; } protected abstract bool IsValidContextWorker(int position, CSharpSyntaxContext context, CancellationToken cancellationToken); + // When the keyword is the inferred type in this context, we should treat it like its corresponding type symbol + // in terms of MatchPripority, so the selection can be determined by how well it matches the filter text instead, + // e.g. selecting "string" over "String" when user typed "str". + protected override int PreselectMatchPriority => SymbolMatchPriority.PreferType; + protected override bool ShouldPreselect(CSharpSyntaxContext context, CancellationToken cancellationToken) => context.InferredTypes.Any(static (t, self) => t.SpecialType == self.SpecialType, this); diff --git a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/AbstractSyntacticSingleKeywordRecommender.cs b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/AbstractSyntacticSingleKeywordRecommender.cs index 3702767d4bc7b..35544a0e56347 100644 --- a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/AbstractSyntacticSingleKeywordRecommender.cs +++ b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/AbstractSyntacticSingleKeywordRecommender.cs @@ -23,6 +23,8 @@ internal abstract partial class AbstractSyntacticSingleKeywordRecommender : IKey /// protected virtual int DefaultMatchPriority => MatchPriority.Default; + protected virtual int PreselectMatchPriority => SymbolMatchPriority.Keyword; + protected AbstractSyntacticSingleKeywordRecommender( SyntaxKind keywordKind, bool isValidInPreprocessorContext = false, @@ -34,7 +36,7 @@ protected AbstractSyntacticSingleKeywordRecommender( _keywordPriorityRecommendedKeywords = ImmutableArray.Create( new RecommendedKeyword(SyntaxFacts.GetText(keywordKind), shouldFormatOnCommit: shouldFormatOnCommit, - matchPriority: SymbolMatchPriority.Keyword)); + matchPriority: PreselectMatchPriority)); _defaultPriorityRecommendedKeywords = ImmutableArray.Create( new RecommendedKeyword(SyntaxFacts.GetText(keywordKind), shouldFormatOnCommit: shouldFormatOnCommit, diff --git a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/FileKeywordRecommender.cs b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/FileKeywordRecommender.cs new file mode 100644 index 0000000000000..73510f4b46dd1 --- /dev/null +++ b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/FileKeywordRecommender.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.Collections.Generic; +using System.Linq; +using System.Threading; +using Microsoft.CodeAnalysis.CSharp.Extensions.ContextQuery; +using Microsoft.CodeAnalysis.CSharp.Utilities; +using Roslyn.Utilities; + +namespace Microsoft.CodeAnalysis.CSharp.Completion.KeywordRecommenders; + +internal class FileKeywordRecommender : AbstractSyntacticSingleKeywordRecommender +{ + 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 + && context.IsTypeDeclarationContext(s_validModifiers, SyntaxKindSet.AllTypeDeclarations, canBePartial: true, cancellationToken); + } +} diff --git a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/NameOfKeywordRecommender.cs b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/NameOfKeywordRecommender.cs index 35616bb9637ef..a925b3f4aad22 100644 --- a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/NameOfKeywordRecommender.cs +++ b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/NameOfKeywordRecommender.cs @@ -23,15 +23,7 @@ protected override bool IsValidContext(int position, CSharpSyntaxContext context context.IsAnyExpressionContext || context.IsStatementContext || context.IsGlobalStatementContext || - IsAttributeArgumentContext(context) || context.LeftToken.IsInCastExpressionTypeWhereExpressionIsMissingOrInNextLine(); } - - private static bool IsAttributeArgumentContext(CSharpSyntaxContext context) - { - return - context.IsAnyExpressionContext && - context.LeftToken.GetAncestor() != null; - } } } diff --git a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/NullableKeywordRecommender.cs b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/NullableKeywordRecommender.cs index 654cad3d1aa06..f013ce3452831 100644 --- a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/NullableKeywordRecommender.cs +++ b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/NullableKeywordRecommender.cs @@ -2,8 +2,6 @@ // The .NET Foundation 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.CSharp.Extensions.ContextQuery; @@ -17,25 +15,6 @@ public NullableKeywordRecommender() } protected override bool IsValidContext(int position, CSharpSyntaxContext context, CancellationToken cancellationToken) - { - // #nullable - if (context.IsPreProcessorKeywordContext) - { - return true; - } - - var previousToken1 = context.TargetToken; - var previousToken2 = previousToken1.GetPreviousToken(includeSkipped: true); - var previousToken3 = previousToken2.GetPreviousToken(includeSkipped: true); - var previousToken4 = previousToken3.GetPreviousToken(includeSkipped: true); - - return - // # pragma warning | - (previousToken1.Kind() == SyntaxKind.DisableKeyword || previousToken1.Kind() == SyntaxKind.RestoreKeyword || - previousToken1.Kind() == SyntaxKind.EnableKeyword) && - previousToken2.Kind() == SyntaxKind.WarningKeyword && - previousToken3.Kind() == SyntaxKind.PragmaKeyword && - previousToken4.Kind() == SyntaxKind.HashToken; - } + => context.IsPreProcessorKeywordContext; } } diff --git a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/RequiredKeywordRecommender.cs b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/RequiredKeywordRecommender.cs index 7d8ddfabdc374..e6e4ac276dc54 100644 --- a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/RequiredKeywordRecommender.cs +++ b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/RequiredKeywordRecommender.cs @@ -15,11 +15,7 @@ internal class RequiredKeywordRecommender : AbstractSyntacticSingleKeywordRecomm { 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 = new HashSet(SyntaxFacts.EqualityComparer) - { - SyntaxKind.StructDeclaration, - SyntaxKind.ClassDeclaration, - }; + private static readonly ISet s_validTypeDeclarations = SyntaxKindSet.ClassStructRecordTypeDeclarations; public RequiredKeywordRecommender() : base(SyntaxKind.RequiredKeyword) diff --git a/src/Features/CSharp/Portable/ConflictMarkerResolution/CSharpResolveConflictMarkerCodeFixProvider.cs b/src/Features/CSharp/Portable/ConflictMarkerResolution/CSharpResolveConflictMarkerCodeFixProvider.cs index d252f44764476..8b00238d88891 100644 --- a/src/Features/CSharp/Portable/ConflictMarkerResolution/CSharpResolveConflictMarkerCodeFixProvider.cs +++ b/src/Features/CSharp/Portable/ConflictMarkerResolution/CSharpResolveConflictMarkerCodeFixProvider.cs @@ -6,7 +6,7 @@ using System.Composition; using Microsoft.CodeAnalysis.CodeFixes; using Microsoft.CodeAnalysis.ConflictMarkerResolution; -using Microsoft.CodeAnalysis.CSharp.LanguageServices; +using Microsoft.CodeAnalysis.CSharp.LanguageService; using Microsoft.CodeAnalysis.Host.Mef; namespace Microsoft.CodeAnalysis.CSharp.ConflictMarkerResolution diff --git a/src/Features/CSharp/Portable/ConvertBetweenRegularAndVerbatimString/ConvertBetweenRegularAndVerbatimStringCodeRefactoringProvider.cs b/src/Features/CSharp/Portable/ConvertBetweenRegularAndVerbatimString/ConvertBetweenRegularAndVerbatimStringCodeRefactoringProvider.cs index de3218e8b13e3..370671a15dca9 100644 --- a/src/Features/CSharp/Portable/ConvertBetweenRegularAndVerbatimString/ConvertBetweenRegularAndVerbatimStringCodeRefactoringProvider.cs +++ b/src/Features/CSharp/Portable/ConvertBetweenRegularAndVerbatimString/ConvertBetweenRegularAndVerbatimStringCodeRefactoringProvider.cs @@ -6,7 +6,7 @@ using System.Diagnostics.CodeAnalysis; using System.Text; using Microsoft.CodeAnalysis.CodeRefactorings; -using Microsoft.CodeAnalysis.CSharp.LanguageServices; +using Microsoft.CodeAnalysis.CSharp.LanguageService; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.EmbeddedLanguages.VirtualChars; using Microsoft.CodeAnalysis.PooledObjects; diff --git a/src/Features/CSharp/Portable/ConvertIfToSwitch/CSharpConvertIfToSwitchCodeRefactoringProvider.Analyzer.cs b/src/Features/CSharp/Portable/ConvertIfToSwitch/CSharpConvertIfToSwitchCodeRefactoringProvider.Analyzer.cs index 506cd4daa5625..026d54e1c700f 100644 --- a/src/Features/CSharp/Portable/ConvertIfToSwitch/CSharpConvertIfToSwitchCodeRefactoringProvider.Analyzer.cs +++ b/src/Features/CSharp/Portable/ConvertIfToSwitch/CSharpConvertIfToSwitchCodeRefactoringProvider.Analyzer.cs @@ -6,7 +6,7 @@ using System.Linq; using Microsoft.CodeAnalysis.CSharp.Syntax; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Operations; namespace Microsoft.CodeAnalysis.CSharp.ConvertIfToSwitch diff --git a/src/Features/CSharp/Portable/ConvertIfToSwitch/CSharpConvertIfToSwitchCodeRefactoringProvider.cs b/src/Features/CSharp/Portable/ConvertIfToSwitch/CSharpConvertIfToSwitchCodeRefactoringProvider.cs index 6802fe2fdf41b..8a89050d42617 100644 --- a/src/Features/CSharp/Portable/ConvertIfToSwitch/CSharpConvertIfToSwitchCodeRefactoringProvider.cs +++ b/src/Features/CSharp/Portable/ConvertIfToSwitch/CSharpConvertIfToSwitchCodeRefactoringProvider.cs @@ -11,7 +11,7 @@ using Microsoft.CodeAnalysis.CSharp.Shared.Extensions; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Host.Mef; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; namespace Microsoft.CodeAnalysis.CSharp.ConvertIfToSwitch { diff --git a/src/Features/CSharp/Portable/ConvertLinq/CSharpConvertLinqQueryToForEachProvider.cs b/src/Features/CSharp/Portable/ConvertLinq/CSharpConvertLinqQueryToForEachProvider.cs index 19f555072ebfa..8341589d99464 100644 --- a/src/Features/CSharp/Portable/ConvertLinq/CSharpConvertLinqQueryToForEachProvider.cs +++ b/src/Features/CSharp/Portable/ConvertLinq/CSharpConvertLinqQueryToForEachProvider.cs @@ -17,7 +17,7 @@ using Microsoft.CodeAnalysis.CSharp.Extensions; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Formatting; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Operations; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Simplification; diff --git a/src/Features/CSharp/Portable/ConvertProgram/ConvertProgramTransform_ProgramMain.cs b/src/Features/CSharp/Portable/ConvertProgram/ConvertProgramTransform_ProgramMain.cs index b292e2952baec..ca57eb7ae3911 100644 --- a/src/Features/CSharp/Portable/ConvertProgram/ConvertProgramTransform_ProgramMain.cs +++ b/src/Features/CSharp/Portable/ConvertProgram/ConvertProgramTransform_ProgramMain.cs @@ -39,10 +39,18 @@ public static async Task ConvertToProgramMainAsync(Document document, { if (programType.GetMembers(WellKnownMemberNames.TopLevelStatementsEntryPointMethodName).FirstOrDefault() is IMethodSymbol mainMethod) { + var oldClassDeclaration = root.Members.OfType().FirstOrDefault(IsProgramClass); + var classDeclaration = await GenerateProgramClassAsync( - document, programType, mainMethod, accessibilityModifiersRequired, cancellationToken).ConfigureAwait(false); + document, oldClassDeclaration, programType, mainMethod, accessibilityModifiersRequired, cancellationToken).ConfigureAwait(false); var newRoot = root.RemoveNodes(root.Members.OfType().Skip(1), SyntaxGenerator.DefaultRemoveOptions); + if (oldClassDeclaration is not null) + { + Contract.ThrowIfNull(newRoot); + newRoot = newRoot.RemoveNode(oldClassDeclaration, SyntaxGenerator.DefaultRemoveOptions); + } + Contract.ThrowIfNull(newRoot); var firstGlobalStatement = newRoot.Members.OfType().Single(); @@ -56,8 +64,15 @@ public static async Task ConvertToProgramMainAsync(Document document, return document; } - private static async Task GenerateProgramClassAsync( + private static bool IsProgramClass(ClassDeclarationSyntax declaration) + { + return declaration.Identifier.ValueText == WellKnownMemberNames.TopLevelStatementsEntryPointTypeName && + declaration.Modifiers.Any(SyntaxKind.PartialKeyword); + } + + private static async Task GenerateProgramClassAsync( Document document, + ClassDeclarationSyntax? oldClassDeclaration, INamedTypeSymbol programType, IMethodSymbol mainMethod, AccessibilityModifiersRequired accessibilityModifiersRequired, @@ -84,11 +99,25 @@ private static async Task GenerateProgramClassAsync( if (method.ParameterList.Parameters.Count == 1 && method.ParameterList.Parameters[0].Type is ArrayTypeSyntax arrayType) method = method.ReplaceNode(arrayType.ElementType, PredefinedType(Token(SyntaxKind.StringKeyword))); - return FixupComments(generator.ClassDeclaration( - WellKnownMemberNames.TopLevelStatementsEntryPointTypeName, - accessibility: useDeclaredAccessibity ? programType.DeclaredAccessibility : Accessibility.NotApplicable, - modifiers: hasExistingPart ? DeclarationModifiers.Partial : DeclarationModifiers.None, - members: new[] { method }).WithLeadingTrivia(leadingTrivia)); + if (oldClassDeclaration is null) + { + // If we dodn't have any suitable class declaration in the same file then generate it + return FixupComments((ClassDeclarationSyntax)generator.ClassDeclaration( + WellKnownMemberNames.TopLevelStatementsEntryPointTypeName, + accessibility: useDeclaredAccessibity ? programType.DeclaredAccessibility : Accessibility.NotApplicable, + modifiers: hasExistingPart ? DeclarationModifiers.Partial : DeclarationModifiers.None, + members: new[] { method }).WithLeadingTrivia(leadingTrivia)); + } + else + { + // Otherwise just add new member and process leading trivia + + // Old class declaration is below top-level statements and is probably separated from them with a blank line (or several ones). + // So we want to remove all leading line to make class declaration begin from the first line of the file after applying refactoring + var oldTriviaWithoutBlankLines = oldClassDeclaration.GetLeadingTrivia().WithoutLeadingBlankLines(); + return oldClassDeclaration.WithMembers(oldClassDeclaration.Members.Add(method)) + .WithLeadingTrivia(oldTriviaWithoutBlankLines.Union(leadingTrivia)); + } } private static ImmutableArray GenerateProgramMainStatements( diff --git a/src/Features/CSharp/Portable/ConvertProgram/ConvertProgramTransform_TopLevelStatements.cs b/src/Features/CSharp/Portable/ConvertProgram/ConvertProgramTransform_TopLevelStatements.cs index 384273c80dc1e..158fb8942fa59 100644 --- a/src/Features/CSharp/Portable/ConvertProgram/ConvertProgramTransform_TopLevelStatements.cs +++ b/src/Features/CSharp/Portable/ConvertProgram/ConvertProgramTransform_TopLevelStatements.cs @@ -11,7 +11,7 @@ using Microsoft.CodeAnalysis.CodeCleanup; using Microsoft.CodeAnalysis.CSharp.CodeGeneration; using Microsoft.CodeAnalysis.CSharp.ConvertNamespace; -using Microsoft.CodeAnalysis.CSharp.LanguageServices; +using Microsoft.CodeAnalysis.CSharp.LanguageService; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Editing; using Microsoft.CodeAnalysis.Formatting; diff --git a/src/Features/CSharp/Portable/ConvertToRawString/ConvertRegularStringToRawStringCodeRefactoringProvider.cs b/src/Features/CSharp/Portable/ConvertToRawString/ConvertRegularStringToRawStringCodeRefactoringProvider.cs index c409bc37868ef..9a55292210b67 100644 --- a/src/Features/CSharp/Portable/ConvertToRawString/ConvertRegularStringToRawStringCodeRefactoringProvider.cs +++ b/src/Features/CSharp/Portable/ConvertToRawString/ConvertRegularStringToRawStringCodeRefactoringProvider.cs @@ -188,7 +188,7 @@ private static async Task UpdateDocumentAsync( Contract.ThrowIfFalse(span.IntersectsWith(token.Span)); Contract.ThrowIfFalse(token.Kind() == SyntaxKind.StringLiteralToken); - var replacement = GetReplacementToken(document, token, kind, options, cancellationToken); + var replacement = await GetReplacementTokenAsync(document, token, kind, options, cancellationToken).ConfigureAwait(false); return document.WithSyntaxRoot(root.ReplaceToken(token, replacement)); } @@ -228,7 +228,7 @@ protected override async Task FixAllAsync( if (!hasMatchingKind) continue; - var replacement = GetReplacementToken(document, stringLiteral, kind, options, cancellationToken); + var replacement = await GetReplacementTokenAsync(document, stringLiteral, kind, options, cancellationToken).ConfigureAwait(false); tokenReplacementMap.Add(stringLiteral, replacement); } } @@ -237,11 +237,11 @@ protected override async Task FixAllAsync( editor.ReplaceNode(editor.OriginalRoot, newRoot); } - private static SyntaxToken GetReplacementToken( + private static async ValueTask GetReplacementTokenAsync( Document document, SyntaxToken token, ConvertToRawKind kind, - SyntaxFormattingOptions options, + SyntaxFormattingOptions formattingOptions, CancellationToken cancellationToken) { var characters = CSharpVirtualCharService.Instance.TryConvertToVirtualChars(token); @@ -251,9 +251,15 @@ private static SyntaxToken GetReplacementToken( if (kind == ConvertToRawKind.MultiLineWithoutLeadingWhitespace) characters = CleanupWhitespace(characters); - return kind == ConvertToRawKind.SingleLine - ? ConvertToSingleLineRawString(token, characters) - : ConvertToMultiLineRawIndentedString(document, token, options, characters, cancellationToken); + if (kind == ConvertToRawKind.SingleLine) + { + return ConvertToSingleLineRawString(token, characters); + } + + var indentationOptions = new IndentationOptions(formattingOptions); + var parsedDocument = await ParsedDocument.CreateAsync(document, cancellationToken).ConfigureAwait(false); + var indentation = token.GetPreferredIndentation(parsedDocument, indentationOptions, cancellationToken); + return ConvertToMultiLineRawIndentedString(indentation, token, formattingOptions, characters); } private static VirtualCharSequence CleanupWhitespace(VirtualCharSequence characters) @@ -380,20 +386,15 @@ private static bool AllWhitespace(VirtualCharSequence line) } private static SyntaxToken ConvertToMultiLineRawIndentedString( - Document document, + string indentation, SyntaxToken token, SyntaxFormattingOptions formattingOptions, - VirtualCharSequence characters, - CancellationToken cancellationToken) + VirtualCharSequence characters) { // Have to make sure we have a delimiter longer than any quote sequence in the string. var longestQuoteSequence = GetLongestQuoteSequence(characters); var quoteDelimeterCount = Math.Max(3, longestQuoteSequence + 1); - // Auto-formatting options are not relevant since they only control behavior on typing. - var indentationOptions = new IndentationOptions(formattingOptions); - var indentation = token.GetPreferredIndentation(document, indentationOptions, cancellationToken); - using var _ = PooledStringBuilder.GetInstance(out var builder); builder.Append('"', quoteDelimeterCount); diff --git a/src/Features/CSharp/Portable/Debugging/LocationInfoGetter.cs b/src/Features/CSharp/Portable/Debugging/LocationInfoGetter.cs index b78c8debe8ee4..6731b92d9e149 100644 --- a/src/Features/CSharp/Portable/Debugging/LocationInfoGetter.cs +++ b/src/Features/CSharp/Portable/Debugging/LocationInfoGetter.cs @@ -8,7 +8,7 @@ using System.Threading.Tasks; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Debugging; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Shared.Extensions; namespace Microsoft.CodeAnalysis.CSharp.Debugging @@ -50,10 +50,7 @@ internal static async Task GetInfoAsync(Document document, in } } - if (fieldDeclarator == null) - { - fieldDeclarator = variableDeclarators.Count > 0 ? variableDeclarators[0] : null; - } + fieldDeclarator ??= variableDeclarators.Count > 0 ? variableDeclarators[0] : null; } var name = syntaxFactsService.GetDisplayName(fieldDeclarator ?? memberDeclaration, diff --git a/src/Features/CSharp/Portable/Diagnostics/Analyzers/CSharpPreferFrameworkTypeDiagnosticAnalyzer.cs b/src/Features/CSharp/Portable/Diagnostics/Analyzers/CSharpPreferFrameworkTypeDiagnosticAnalyzer.cs index 95038858295f0..249bab2788e8a 100644 --- a/src/Features/CSharp/Portable/Diagnostics/Analyzers/CSharpPreferFrameworkTypeDiagnosticAnalyzer.cs +++ b/src/Features/CSharp/Portable/Diagnostics/Analyzers/CSharpPreferFrameworkTypeDiagnosticAnalyzer.cs @@ -27,8 +27,5 @@ protected override bool IsPredefinedTypeReplaceableWithFrameworkType(PredefinedT protected override bool IsInMemberAccessOrCrefReferenceContext(ExpressionSyntax node) => node.IsDirectChildOfMemberAccessExpression() || node.InsideCrefReference(); - - protected override string GetLanguageName() - => LanguageNames.CSharp; } } diff --git a/src/Features/CSharp/Portable/Diagnostics/Analyzers/CSharpSimplifyTypeNamesDiagnosticAnalyzer.cs b/src/Features/CSharp/Portable/Diagnostics/Analyzers/CSharpSimplifyTypeNamesDiagnosticAnalyzer.cs index 95d61768bb852..e9dd10120eb98 100644 --- a/src/Features/CSharp/Portable/Diagnostics/Analyzers/CSharpSimplifyTypeNamesDiagnosticAnalyzer.cs +++ b/src/Features/CSharp/Portable/Diagnostics/Analyzers/CSharpSimplifyTypeNamesDiagnosticAnalyzer.cs @@ -129,8 +129,5 @@ internal override bool CanSimplifyTypeNameExpression( return true; } - - protected override string GetLanguageName() - => LanguageNames.CSharp; } } diff --git a/src/Features/CSharp/Portable/DocumentHighlighting/CSharpDocumentHighlightsService.cs b/src/Features/CSharp/Portable/DocumentHighlighting/CSharpDocumentHighlightsService.cs index 729486de888cc..c803007ac213d 100644 --- a/src/Features/CSharp/Portable/DocumentHighlighting/CSharpDocumentHighlightsService.cs +++ b/src/Features/CSharp/Portable/DocumentHighlighting/CSharpDocumentHighlightsService.cs @@ -12,7 +12,7 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.CSharp.EmbeddedLanguages.LanguageServices; -using Microsoft.CodeAnalysis.CSharp.LanguageServices; +using Microsoft.CodeAnalysis.CSharp.LanguageService; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.DocumentHighlighting; using Microsoft.CodeAnalysis.EmbeddedLanguages; @@ -62,10 +62,7 @@ protected override async Task> GetAdditionalReferencesA if (type.IsVar) { - if (semanticModel == null) - { - semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false); - } + semanticModel ??= await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false); var boundSymbol = semanticModel.GetSymbolInfo(type, cancellationToken).Symbol; boundSymbol = boundSymbol?.OriginalDefinition; diff --git a/src/Features/CSharp/Portable/EditAndContinue/CSharpEditAndContinueAnalyzer.cs b/src/Features/CSharp/Portable/EditAndContinue/CSharpEditAndContinueAnalyzer.cs index 0a077f5112b1c..1b18c34577f69 100644 --- a/src/Features/CSharp/Portable/EditAndContinue/CSharpEditAndContinueAnalyzer.cs +++ b/src/Features/CSharp/Portable/EditAndContinue/CSharpEditAndContinueAnalyzer.cs @@ -1160,7 +1160,7 @@ internal override bool HasBackingField(SyntaxNode propertyOrIndexerDeclaration) => propertyOrIndexerDeclaration.IsKind(SyntaxKind.PropertyDeclaration, out PropertyDeclarationSyntax? propertyDecl) && SyntaxUtilities.HasBackingField(propertyDecl); - internal override bool TryGetAssociatedMemberDeclaration(SyntaxNode node, [NotNullWhen(true)] out SyntaxNode? declaration) + internal override bool TryGetAssociatedMemberDeclaration(SyntaxNode node, EditKind editKind, [NotNullWhen(true)] out SyntaxNode? declaration) { if (node.IsKind(SyntaxKind.Parameter, SyntaxKind.TypeParameter)) { @@ -1169,7 +1169,8 @@ internal override bool TryGetAssociatedMemberDeclaration(SyntaxNode node, [NotNu return true; } - if (node.Parent.IsParentKind(SyntaxKind.PropertyDeclaration, SyntaxKind.IndexerDeclaration, SyntaxKind.EventDeclaration)) + // For deletes, we don't associate accessors with their parents, as deleting accessors is allowed + if (editKind != EditKind.Delete && node.Parent.IsParentKind(SyntaxKind.PropertyDeclaration, SyntaxKind.IndexerDeclaration, SyntaxKind.EventDeclaration)) { declaration = node.Parent.Parent!; return true; diff --git a/src/Features/CSharp/Portable/EditAndContinue/SyntaxUtilities.cs b/src/Features/CSharp/Portable/EditAndContinue/SyntaxUtilities.cs index dcf9d28a2a1a1..40a83b6c98803 100644 --- a/src/Features/CSharp/Portable/EditAndContinue/SyntaxUtilities.cs +++ b/src/Features/CSharp/Portable/EditAndContinue/SyntaxUtilities.cs @@ -253,7 +253,7 @@ public static bool HasBackingField(PropertyDeclarationSyntax property) } return property.ExpressionBody == null - && property.AccessorList.Accessors.Any(e => e.Body == null); + && property.AccessorList.Accessors.Any(e => e.Body == null && e.ExpressionBody == null); } /// diff --git a/src/Features/CSharp/Portable/EmbeddedLanguages/CSharpEmbeddedLanguagesProvider.cs b/src/Features/CSharp/Portable/EmbeddedLanguages/CSharpEmbeddedLanguagesProvider.cs index 54efa4570ab44..2713f4d98446d 100644 --- a/src/Features/CSharp/Portable/EmbeddedLanguages/CSharpEmbeddedLanguagesProvider.cs +++ b/src/Features/CSharp/Portable/EmbeddedLanguages/CSharpEmbeddedLanguagesProvider.cs @@ -6,7 +6,7 @@ using System.Composition; using Microsoft.CodeAnalysis.CSharp.EmbeddedLanguages.VirtualChars; using Microsoft.CodeAnalysis.CSharp.Features.EmbeddedLanguages; -using Microsoft.CodeAnalysis.CSharp.LanguageServices; +using Microsoft.CodeAnalysis.CSharp.LanguageService; using Microsoft.CodeAnalysis.EmbeddedLanguages; using Microsoft.CodeAnalysis.Host.Mef; diff --git a/src/Features/CSharp/Portable/EmbeddedLanguages/Classification/CSharpEmbeddedLanguageClassificationServiceFactory.cs b/src/Features/CSharp/Portable/EmbeddedLanguages/Classification/CSharpEmbeddedLanguageClassificationServiceFactory.cs index e3a85a499a856..b3cf44690d6f1 100644 --- a/src/Features/CSharp/Portable/EmbeddedLanguages/Classification/CSharpEmbeddedLanguageClassificationServiceFactory.cs +++ b/src/Features/CSharp/Portable/EmbeddedLanguages/Classification/CSharpEmbeddedLanguageClassificationServiceFactory.cs @@ -7,7 +7,7 @@ using System.Composition; using Microsoft.CodeAnalysis.Classification; using Microsoft.CodeAnalysis.CSharp.EmbeddedLanguages.LanguageServices; -using Microsoft.CodeAnalysis.CSharp.LanguageServices; +using Microsoft.CodeAnalysis.CSharp.LanguageService; using Microsoft.CodeAnalysis.EmbeddedLanguages; using Microsoft.CodeAnalysis.Host.Mef; diff --git a/src/Features/CSharp/Portable/ExtractMethod/CSharpMethodExtractor.CSharpCodeGenerator.CallSiteContainerRewriter.cs b/src/Features/CSharp/Portable/ExtractMethod/CSharpMethodExtractor.CSharpCodeGenerator.CallSiteContainerRewriter.cs index 449db80b43a20..fcad217b01ceb 100644 --- a/src/Features/CSharp/Portable/ExtractMethod/CSharpMethodExtractor.CSharpCodeGenerator.CallSiteContainerRewriter.cs +++ b/src/Features/CSharp/Portable/ExtractMethod/CSharpMethodExtractor.CSharpCodeGenerator.CallSiteContainerRewriter.cs @@ -8,7 +8,7 @@ using System.Linq; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp.Extensions; -using Microsoft.CodeAnalysis.CSharp.LanguageServices; +using Microsoft.CodeAnalysis.CSharp.LanguageService; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Shared.Extensions; using Roslyn.Utilities; diff --git a/src/Features/CSharp/Portable/ExtractMethod/CSharpMethodExtractor.CSharpCodeGenerator.ExpressionCodeGenerator.cs b/src/Features/CSharp/Portable/ExtractMethod/CSharpMethodExtractor.CSharpCodeGenerator.ExpressionCodeGenerator.cs index 30d95a0663b82..730ceb2d787c0 100644 --- a/src/Features/CSharp/Portable/ExtractMethod/CSharpMethodExtractor.CSharpCodeGenerator.ExpressionCodeGenerator.cs +++ b/src/Features/CSharp/Portable/ExtractMethod/CSharpMethodExtractor.CSharpCodeGenerator.ExpressionCodeGenerator.cs @@ -170,22 +170,13 @@ container is ConstructorDeclarationSyntax || protected override SyntaxNode GetFirstStatementOrInitializerSelectedAtCallSite() { var scope = (SyntaxNode)CSharpSelectionResult.GetContainingScopeOf(); - if (scope == null) - { - scope = CSharpSelectionResult.GetContainingScopeOf(); - } + scope ??= CSharpSelectionResult.GetContainingScopeOf(); - if (scope == null) - { - scope = CSharpSelectionResult.GetContainingScopeOf(); - } + scope ??= CSharpSelectionResult.GetContainingScopeOf(); - if (scope == null) - { - // This is similar to FieldDeclaration case but we only want to do this - // if the member has an expression body. - scope = CSharpSelectionResult.GetContainingScopeOf().Parent; - } + // This is similar to FieldDeclaration case but we only want to do this + // if the member has an expression body. + scope ??= CSharpSelectionResult.GetContainingScopeOf().Parent; return scope; } diff --git a/src/Features/CSharp/Portable/ExtractMethod/CSharpMethodExtractor.CSharpCodeGenerator.MultipleStatementsCodeGenerator.cs b/src/Features/CSharp/Portable/ExtractMethod/CSharpMethodExtractor.CSharpCodeGenerator.MultipleStatementsCodeGenerator.cs index d2dd6cdbd06de..c365cd1a296f7 100644 --- a/src/Features/CSharp/Portable/ExtractMethod/CSharpMethodExtractor.CSharpCodeGenerator.MultipleStatementsCodeGenerator.cs +++ b/src/Features/CSharp/Portable/ExtractMethod/CSharpMethodExtractor.CSharpCodeGenerator.MultipleStatementsCodeGenerator.cs @@ -11,7 +11,7 @@ using System.Threading.Tasks; using Microsoft.CodeAnalysis.CSharp.CodeGeneration; using Microsoft.CodeAnalysis.CSharp.Extensions; -using Microsoft.CodeAnalysis.CSharp.LanguageServices; +using Microsoft.CodeAnalysis.CSharp.LanguageService; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.ExtractMethod; using Microsoft.CodeAnalysis.Options; diff --git a/src/Features/CSharp/Portable/ExtractMethod/CSharpMethodExtractor.CSharpCodeGenerator.cs b/src/Features/CSharp/Portable/ExtractMethod/CSharpMethodExtractor.CSharpCodeGenerator.cs index 334129da0de74..55d919e75f937 100644 --- a/src/Features/CSharp/Portable/ExtractMethod/CSharpMethodExtractor.CSharpCodeGenerator.cs +++ b/src/Features/CSharp/Portable/ExtractMethod/CSharpMethodExtractor.CSharpCodeGenerator.cs @@ -16,7 +16,7 @@ using Microsoft.CodeAnalysis.CSharp.CodeGeneration; using Microsoft.CodeAnalysis.CSharp.CodeStyle; using Microsoft.CodeAnalysis.CSharp.Extensions; -using Microsoft.CodeAnalysis.CSharp.LanguageServices; +using Microsoft.CodeAnalysis.CSharp.LanguageService; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Diagnostics.Analyzers.NamingStyles; using Microsoft.CodeAnalysis.Editing; diff --git a/src/Features/CSharp/Portable/ExtractMethod/CSharpMethodExtractor.TriviaResult.cs b/src/Features/CSharp/Portable/ExtractMethod/CSharpMethodExtractor.TriviaResult.cs index 524e9fbc20af5..a6835c9cfbcc4 100644 --- a/src/Features/CSharp/Portable/ExtractMethod/CSharpMethodExtractor.TriviaResult.cs +++ b/src/Features/CSharp/Portable/ExtractMethod/CSharpMethodExtractor.TriviaResult.cs @@ -21,7 +21,7 @@ private class CSharpTriviaResult : TriviaResult { public static async Task ProcessAsync(SelectionResult selectionResult, CancellationToken cancellationToken) { - var preservationService = selectionResult.SemanticDocument.Document.Project.LanguageServices.GetService(); + var preservationService = selectionResult.SemanticDocument.Document.Project.Services.GetService(); var root = selectionResult.SemanticDocument.Root; var result = preservationService.SaveTriviaAroundSelection(root, selectionResult.FinalSpan); return new CSharpTriviaResult( diff --git a/src/Features/CSharp/Portable/ExtractMethod/CSharpSelectionResult.ExpressionResult.cs b/src/Features/CSharp/Portable/ExtractMethod/CSharpSelectionResult.ExpressionResult.cs index 84f5d3e0a82f2..2f6c17b5e2d19 100644 --- a/src/Features/CSharp/Portable/ExtractMethod/CSharpSelectionResult.ExpressionResult.cs +++ b/src/Features/CSharp/Portable/ExtractMethod/CSharpSelectionResult.ExpressionResult.cs @@ -4,11 +4,11 @@ using System.Linq; using Microsoft.CodeAnalysis.CSharp.Extensions; -using Microsoft.CodeAnalysis.CSharp.LanguageServices; +using Microsoft.CodeAnalysis.CSharp.LanguageService; using Microsoft.CodeAnalysis.CSharp.Symbols; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.ExtractMethod; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Text; diff --git a/src/Features/CSharp/Portable/ExtractMethod/CSharpSelectionResult.cs b/src/Features/CSharp/Portable/ExtractMethod/CSharpSelectionResult.cs index 467ffcf7d04df..5ceb2f472f77c 100644 --- a/src/Features/CSharp/Portable/ExtractMethod/CSharpSelectionResult.cs +++ b/src/Features/CSharp/Portable/ExtractMethod/CSharpSelectionResult.cs @@ -10,7 +10,7 @@ using System.Threading.Tasks; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp.Extensions; -using Microsoft.CodeAnalysis.CSharp.LanguageServices; +using Microsoft.CodeAnalysis.CSharp.LanguageService; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.ExtractMethod; using Microsoft.CodeAnalysis.Shared.Extensions; diff --git a/src/Features/CSharp/Portable/ExtractMethod/CSharpSelectionValidator.cs b/src/Features/CSharp/Portable/ExtractMethod/CSharpSelectionValidator.cs index ec6be81a5d107..18a0307c69161 100644 --- a/src/Features/CSharp/Portable/ExtractMethod/CSharpSelectionValidator.cs +++ b/src/Features/CSharp/Portable/ExtractMethod/CSharpSelectionValidator.cs @@ -11,10 +11,10 @@ using System.Threading.Tasks; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp.Extensions; -using Microsoft.CodeAnalysis.CSharp.LanguageServices; +using Microsoft.CodeAnalysis.CSharp.LanguageService; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.ExtractMethod; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Text; diff --git a/src/Features/CSharp/Portable/Formatting/CSharpAccessibilityModifiersNewDocumentFormattingProvider.cs b/src/Features/CSharp/Portable/Formatting/CSharpAccessibilityModifiersNewDocumentFormattingProvider.cs index 542c08b79d270..9d5a70e6f0d4d 100644 --- a/src/Features/CSharp/Portable/Formatting/CSharpAccessibilityModifiersNewDocumentFormattingProvider.cs +++ b/src/Features/CSharp/Portable/Formatting/CSharpAccessibilityModifiersNewDocumentFormattingProvider.cs @@ -10,10 +10,10 @@ using Microsoft.CodeAnalysis.AddAccessibilityModifiers; using Microsoft.CodeAnalysis.CodeCleanup; using Microsoft.CodeAnalysis.CodeStyle; -using Microsoft.CodeAnalysis.CSharp.LanguageServices; +using Microsoft.CodeAnalysis.CSharp.LanguageService; using Microsoft.CodeAnalysis.Editing; using Microsoft.CodeAnalysis.Host.Mef; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Shared.Extensions; namespace Microsoft.CodeAnalysis.Formatting @@ -39,7 +39,7 @@ public async Task FormatNewDocumentAsync(Document document, Document? var semanticModel = await document.GetRequiredSemanticModelAsync(cancellationToken).ConfigureAwait(false); var syntaxFacts = document.GetRequiredLanguageService(); var typeDeclarations = root.DescendantNodes().Where(node => syntaxFacts.IsTypeDeclaration(node)); - var editor = new SyntaxEditor(root, document.Project.Solution.Workspace.Services); + var editor = new SyntaxEditor(root, document.Project.Solution.Services); var service = document.GetRequiredLanguageService(); diff --git a/src/Features/CSharp/Portable/Formatting/CSharpNamespaceDeclarationNewDocumentFormattingProvider.cs b/src/Features/CSharp/Portable/Formatting/CSharpNamespaceDeclarationNewDocumentFormattingProvider.cs index bd21844b93a22..53d3a290aace3 100644 --- a/src/Features/CSharp/Portable/Formatting/CSharpNamespaceDeclarationNewDocumentFormattingProvider.cs +++ b/src/Features/CSharp/Portable/Formatting/CSharpNamespaceDeclarationNewDocumentFormattingProvider.cs @@ -15,7 +15,7 @@ using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Formatting; using Microsoft.CodeAnalysis.Host.Mef; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Shared.Extensions; diff --git a/src/Features/CSharp/Portable/GenerateDefaultConstructors/CSharpGenerateDefaultConstructorsService.cs b/src/Features/CSharp/Portable/GenerateDefaultConstructors/CSharpGenerateDefaultConstructorsService.cs index 4f44ba38207c4..486d3bfae2812 100644 --- a/src/Features/CSharp/Portable/GenerateDefaultConstructors/CSharpGenerateDefaultConstructorsService.cs +++ b/src/Features/CSharp/Portable/GenerateDefaultConstructors/CSharpGenerateDefaultConstructorsService.cs @@ -11,7 +11,7 @@ using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.GenerateDefaultConstructors; using Microsoft.CodeAnalysis.Host.Mef; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Text; diff --git a/src/Features/CSharp/Portable/GenerateMember/GenerateParameterizedMember/CSharpGenerateMethodService.cs b/src/Features/CSharp/Portable/GenerateMember/GenerateParameterizedMember/CSharpGenerateMethodService.cs index cf6780ce90796..7ddf9d0f434ca 100644 --- a/src/Features/CSharp/Portable/GenerateMember/GenerateParameterizedMember/CSharpGenerateMethodService.cs +++ b/src/Features/CSharp/Portable/GenerateMember/GenerateParameterizedMember/CSharpGenerateMethodService.cs @@ -15,7 +15,7 @@ using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.GenerateMember.GenerateParameterizedMember; using Microsoft.CodeAnalysis.Host.Mef; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Shared.Extensions; namespace Microsoft.CodeAnalysis.CSharp.GenerateMember.GenerateMethod diff --git a/src/Features/CSharp/Portable/GenerateMember/GenerateParameterizedMember/CSharpGenerateParameterizedMemberService.cs b/src/Features/CSharp/Portable/GenerateMember/GenerateParameterizedMember/CSharpGenerateParameterizedMemberService.cs index 7971c75f88cd2..e7688a84623bb 100644 --- a/src/Features/CSharp/Portable/GenerateMember/GenerateParameterizedMember/CSharpGenerateParameterizedMemberService.cs +++ b/src/Features/CSharp/Portable/GenerateMember/GenerateParameterizedMember/CSharpGenerateParameterizedMemberService.cs @@ -14,7 +14,7 @@ using Microsoft.CodeAnalysis.CSharp.Extensions; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.GenerateMember.GenerateParameterizedMember; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Shared.Utilities; diff --git a/src/Features/CSharp/Portable/GenerateType/CSharpGenerateTypeService.cs b/src/Features/CSharp/Portable/GenerateType/CSharpGenerateTypeService.cs index 7e920ff11d961..04882b664226b 100644 --- a/src/Features/CSharp/Portable/GenerateType/CSharpGenerateTypeService.cs +++ b/src/Features/CSharp/Portable/GenerateType/CSharpGenerateTypeService.cs @@ -21,7 +21,7 @@ using Microsoft.CodeAnalysis.Formatting; using Microsoft.CodeAnalysis.GenerateType; using Microsoft.CodeAnalysis.Host.Mef; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Text; using Microsoft.CodeAnalysis.Utilities; @@ -687,14 +687,7 @@ internal override bool TryGetBaseList(ExpressionSyntax expression, out TypeKindO internal override bool IsPublicOnlyAccessibility(ExpressionSyntax expression, Project project) { if (expression == null) - { return false; - } - - if (GeneratedTypesMustBePublic(project)) - { - return true; - } var node = expression as SyntaxNode; SyntaxNode previousNode = null; diff --git a/src/Features/CSharp/Portable/ImplementInterface/CSharpImplementExplicitlyCodeRefactoringProvider.cs b/src/Features/CSharp/Portable/ImplementInterface/CSharpImplementExplicitlyCodeRefactoringProvider.cs index ccc0c190a5ffa..af05e90bacd86 100644 --- a/src/Features/CSharp/Portable/ImplementInterface/CSharpImplementExplicitlyCodeRefactoringProvider.cs +++ b/src/Features/CSharp/Portable/ImplementInterface/CSharpImplementExplicitlyCodeRefactoringProvider.cs @@ -13,7 +13,7 @@ using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Editing; using Microsoft.CodeAnalysis.FindSymbols; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Operations; using Microsoft.CodeAnalysis.Shared.Extensions; using Roslyn.Utilities; diff --git a/src/Features/CSharp/Portable/ImplementInterface/CSharpImplementInterfaceCodeFixProvider.cs b/src/Features/CSharp/Portable/ImplementInterface/CSharpImplementInterfaceCodeFixProvider.cs index faa2a1877ed92..95603443a1a9f 100644 --- a/src/Features/CSharp/Portable/ImplementInterface/CSharpImplementInterfaceCodeFixProvider.cs +++ b/src/Features/CSharp/Portable/ImplementInterface/CSharpImplementInterfaceCodeFixProvider.cs @@ -55,7 +55,7 @@ public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context) var actions = token.Parent.GetAncestorsOrThis() .Where(_interfaceName) - .Select(n => service.GetCodeActions(document, context.Options.GetImplementTypeGenerationOptions(document.Project.LanguageServices), model, n, cancellationToken)) + .Select(n => service.GetCodeActions(document, context.Options.GetImplementTypeGenerationOptions(document.Project.Services), model, n, cancellationToken)) .FirstOrDefault(a => !a.IsEmpty); if (actions.IsDefaultOrEmpty) diff --git a/src/Features/CSharp/Portable/InitializeParameter/CSharpAddParameterCheckCodeRefactoringProvider.cs b/src/Features/CSharp/Portable/InitializeParameter/CSharpAddParameterCheckCodeRefactoringProvider.cs index 933e298d5c1f8..060614e9dfb15 100644 --- a/src/Features/CSharp/Portable/InitializeParameter/CSharpAddParameterCheckCodeRefactoringProvider.cs +++ b/src/Features/CSharp/Portable/InitializeParameter/CSharpAddParameterCheckCodeRefactoringProvider.cs @@ -11,14 +11,14 @@ using Microsoft.CodeAnalysis.CSharp.CodeGeneration; using Microsoft.CodeAnalysis.CSharp.CodeStyle; using Microsoft.CodeAnalysis.CSharp.Extensions; -using Microsoft.CodeAnalysis.CSharp.LanguageServices; +using Microsoft.CodeAnalysis.CSharp.LanguageService; using Microsoft.CodeAnalysis.CSharp.Shared.Extensions; using Microsoft.CodeAnalysis.CSharp.Simplification; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Editing; using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.InitializeParameter; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Simplification; using static Microsoft.CodeAnalysis.CSharp.SyntaxFactory; diff --git a/src/Features/CSharp/Portable/InitializeParameter/CSharpInitializeMemberFromParameterCodeRefactoringProvider.cs b/src/Features/CSharp/Portable/InitializeParameter/CSharpInitializeMemberFromParameterCodeRefactoringProvider.cs index 5113e6cb7d356..77897bc7b65aa 100644 --- a/src/Features/CSharp/Portable/InitializeParameter/CSharpInitializeMemberFromParameterCodeRefactoringProvider.cs +++ b/src/Features/CSharp/Portable/InitializeParameter/CSharpInitializeMemberFromParameterCodeRefactoringProvider.cs @@ -5,11 +5,11 @@ using System.Composition; using System.Diagnostics.CodeAnalysis; using Microsoft.CodeAnalysis.CodeRefactorings; -using Microsoft.CodeAnalysis.CSharp.LanguageServices; +using Microsoft.CodeAnalysis.CSharp.LanguageService; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Editing; using Microsoft.CodeAnalysis.InitializeParameter; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Operations; namespace Microsoft.CodeAnalysis.CSharp.InitializeParameter diff --git a/src/Features/CSharp/Portable/InitializeParameter/InitializeParameterHelpers.cs b/src/Features/CSharp/Portable/InitializeParameter/InitializeParameterHelpers.cs index 6555c2fc0ef56..88ef3a4545535 100644 --- a/src/Features/CSharp/Portable/InitializeParameter/InitializeParameterHelpers.cs +++ b/src/Features/CSharp/Portable/InitializeParameter/InitializeParameterHelpers.cs @@ -6,11 +6,11 @@ using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp.Extensions; -using Microsoft.CodeAnalysis.CSharp.LanguageServices; +using Microsoft.CodeAnalysis.CSharp.LanguageService; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Editing; using Microsoft.CodeAnalysis.Formatting; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Operations; using Roslyn.Utilities; diff --git a/src/Features/CSharp/Portable/InlineHints/CSharpInlineParameterNameHintsService.cs b/src/Features/CSharp/Portable/InlineHints/CSharpInlineParameterNameHintsService.cs index ab01b5ad833dd..ef4642e3527f4 100644 --- a/src/Features/CSharp/Portable/InlineHints/CSharpInlineParameterNameHintsService.cs +++ b/src/Features/CSharp/Portable/InlineHints/CSharpInlineParameterNameHintsService.cs @@ -10,7 +10,7 @@ using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.InlineHints; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.PooledObjects; diff --git a/src/Features/CSharp/Portable/InlineHints/CSharpInlineTypeHintsService.cs b/src/Features/CSharp/Portable/InlineHints/CSharpInlineTypeHintsService.cs index c90655abf0378..a62064f69bebd 100644 --- a/src/Features/CSharp/Portable/InlineHints/CSharpInlineTypeHintsService.cs +++ b/src/Features/CSharp/Portable/InlineHints/CSharpInlineTypeHintsService.cs @@ -44,7 +44,10 @@ public CSharpInlineTypeHintsService() return CreateTypeHint(type, displayAllOverride, forImplicitVariableTypes, variableDeclaration.Type, variableDeclaration.Variables[0].Identifier); } - if (node is DeclarationExpressionSyntax { Type.IsVar: true } declarationExpression) + // We handle individual variables of ParenthesizedVariableDesignationSyntax separately. + // For example, in `var (x, y) = (0, "")`, we should `int` for `x` and `string` for `y`. + // It's redundant to show `(int, string)` for `var` + if (node is DeclarationExpressionSyntax { Type.IsVar: true, Designation: not ParenthesizedVariableDesignationSyntax } declarationExpression) { var type = semanticModel.GetTypeInfo(declarationExpression.Type, cancellationToken).Type; if (IsValidType(type)) diff --git a/src/Features/CSharp/Portable/LanguageServices/CSharpStructuralTypeDisplayService.cs b/src/Features/CSharp/Portable/LanguageServices/CSharpStructuralTypeDisplayService.cs index 756829e0902e3..a1c30b0342152 100644 --- a/src/Features/CSharp/Portable/LanguageServices/CSharpStructuralTypeDisplayService.cs +++ b/src/Features/CSharp/Portable/LanguageServices/CSharpStructuralTypeDisplayService.cs @@ -10,9 +10,9 @@ using System.Linq; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Extensions; -using Microsoft.CodeAnalysis.CSharp.LanguageServices; +using Microsoft.CodeAnalysis.CSharp.LanguageService; using Microsoft.CodeAnalysis.Host.Mef; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Shared.Extensions; diff --git a/src/Features/CSharp/Portable/LanguageServices/CSharpSymbolDisplayService.SymbolDescriptionBuilder.cs b/src/Features/CSharp/Portable/LanguageServices/CSharpSymbolDisplayService.SymbolDescriptionBuilder.cs index 31f2839c0402d..b336e41cf5309 100644 --- a/src/Features/CSharp/Portable/LanguageServices/CSharpSymbolDisplayService.SymbolDescriptionBuilder.cs +++ b/src/Features/CSharp/Portable/LanguageServices/CSharpSymbolDisplayService.SymbolDescriptionBuilder.cs @@ -14,7 +14,7 @@ using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Host; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Shared.Extensions; using Roslyn.Utilities; @@ -41,11 +41,11 @@ protected class SymbolDescriptionBuilder : AbstractSymbolDescriptionBuilder public SymbolDescriptionBuilder( SemanticModel semanticModel, int position, - HostWorkspaceServices workspaceServices, + SolutionServices services, IStructuralTypeDisplayService structuralTypeDisplayService, SymbolDescriptionOptions options, CancellationToken cancellationToken) - : base(semanticModel, position, workspaceServices, structuralTypeDisplayService, options, cancellationToken) + : base(semanticModel, position, services, structuralTypeDisplayService, options, cancellationToken) { } diff --git a/src/Features/CSharp/Portable/LanguageServices/CSharpSymbolDisplayService.cs b/src/Features/CSharp/Portable/LanguageServices/CSharpSymbolDisplayService.cs index 9452d3023fcf1..0a586e52be46c 100644 --- a/src/Features/CSharp/Portable/LanguageServices/CSharpSymbolDisplayService.cs +++ b/src/Features/CSharp/Portable/LanguageServices/CSharpSymbolDisplayService.cs @@ -4,18 +4,18 @@ using System.Threading; using Microsoft.CodeAnalysis.Host; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; namespace Microsoft.CodeAnalysis.Editor.CSharp.LanguageServices { internal partial class CSharpSymbolDisplayService : AbstractSymbolDisplayService { - public CSharpSymbolDisplayService(HostLanguageServices services) + public CSharpSymbolDisplayService(Host.LanguageServices services) : base(services) { } protected override AbstractSymbolDescriptionBuilder CreateDescriptionBuilder(SemanticModel semanticModel, int position, SymbolDescriptionOptions options, CancellationToken cancellationToken) - => new SymbolDescriptionBuilder(semanticModel, position, Services.WorkspaceServices, AnonymousTypeDisplayService, options, cancellationToken); + => new SymbolDescriptionBuilder(semanticModel, position, Services.SolutionServices, AnonymousTypeDisplayService, options, cancellationToken); } } diff --git a/src/Features/CSharp/Portable/LanguageServices/CSharpSymbolDisplayServiceFactory.cs b/src/Features/CSharp/Portable/LanguageServices/CSharpSymbolDisplayServiceFactory.cs index efc18ceb6d699..4b9ed95474124 100644 --- a/src/Features/CSharp/Portable/LanguageServices/CSharpSymbolDisplayServiceFactory.cs +++ b/src/Features/CSharp/Portable/LanguageServices/CSharpSymbolDisplayServiceFactory.cs @@ -8,7 +8,7 @@ using System.Composition; using Microsoft.CodeAnalysis.Host; using Microsoft.CodeAnalysis.Host.Mef; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; namespace Microsoft.CodeAnalysis.Editor.CSharp.LanguageServices { @@ -22,6 +22,6 @@ public CSharpSymbolDisplayServiceFactory() } public ILanguageService CreateLanguageService(HostLanguageServices provider) - => new CSharpSymbolDisplayService(provider); + => new CSharpSymbolDisplayService(provider.LanguageServices); } } diff --git a/src/Features/CSharp/Portable/MakeLocalFunctionStatic/MakeLocalFunctionStaticCodeFixHelper.cs b/src/Features/CSharp/Portable/MakeLocalFunctionStatic/MakeLocalFunctionStaticCodeFixHelper.cs index 1225af3e4aa6e..2a16396a0e678 100644 --- a/src/Features/CSharp/Portable/MakeLocalFunctionStatic/MakeLocalFunctionStaticCodeFixHelper.cs +++ b/src/Features/CSharp/Portable/MakeLocalFunctionStatic/MakeLocalFunctionStaticCodeFixHelper.cs @@ -29,7 +29,7 @@ public static async Task MakeLocalFunctionStaticAsync( CancellationToken cancellationToken) { var root = (await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false))!; - var syntaxEditor = new SyntaxEditor(root, document.Project.Solution.Workspace.Services); + var syntaxEditor = new SyntaxEditor(root, document.Project.Solution.Services); await MakeLocalFunctionStaticAsync(document, localFunction, captures, syntaxEditor, fallbackOptions, cancellationToken).ConfigureAwait(false); return document.WithSyntaxRoot(syntaxEditor.GetChangedRoot()); } diff --git a/src/EditorFeatures/CSharp/QuickInfo/CSharpDiagnosticAnalyzerQuickInfoProvider.cs b/src/Features/CSharp/Portable/QuickInfo/CSharpDiagnosticAnalyzerQuickInfoProvider.cs similarity index 95% rename from src/EditorFeatures/CSharp/QuickInfo/CSharpDiagnosticAnalyzerQuickInfoProvider.cs rename to src/Features/CSharp/Portable/QuickInfo/CSharpDiagnosticAnalyzerQuickInfoProvider.cs index 87d2771f7170b..7059e2de9b673 100644 --- a/src/EditorFeatures/CSharp/QuickInfo/CSharpDiagnosticAnalyzerQuickInfoProvider.cs +++ b/src/Features/CSharp/Portable/QuickInfo/CSharpDiagnosticAnalyzerQuickInfoProvider.cs @@ -27,13 +27,13 @@ namespace Microsoft.CodeAnalysis.CSharp.QuickInfo [ExtensionOrder(Before = QuickInfoProviderNames.Semantic)] internal class CSharpDiagnosticAnalyzerQuickInfoProvider : CommonQuickInfoProvider { - private readonly IDiagnosticAnalyzerService _diagnosticAnalyzerService; + private readonly DiagnosticAnalyzerInfoCache _diagnosticAnalyzerInfoCache; [ImportingConstructor] [SuppressMessage("RoslynDiagnosticsReliability", "RS0033:Importing constructor should be [Obsolete]", Justification = "Used in test code: https://github.com/dotnet/roslyn/issues/42814")] - public CSharpDiagnosticAnalyzerQuickInfoProvider(IDiagnosticAnalyzerService diagnosticAnalyzerService) + public CSharpDiagnosticAnalyzerQuickInfoProvider(DiagnosticAnalyzerInfoCache.SharedGlobalCache globalCache) { - _diagnosticAnalyzerService = diagnosticAnalyzerService; + _diagnosticAnalyzerInfoCache = globalCache.AnalyzerInfoCache; } protected override async Task BuildQuickInfoAsync( @@ -138,9 +138,8 @@ PragmaWarningDirectiveTriviaSyntax directive private QuickInfoItem? GetQuickInfoFromSupportedDiagnosticsOfProjectAnalyzers(Document document, string errorCode, TextSpan location) { - var infoCache = _diagnosticAnalyzerService.AnalyzerInfoCache; var hostAnalyzers = document.Project.Solution.State.Analyzers; - var groupedDiagnostics = hostAnalyzers.GetDiagnosticDescriptorsPerReference(infoCache, document.Project).Values; + var groupedDiagnostics = hostAnalyzers.GetDiagnosticDescriptorsPerReference(_diagnosticAnalyzerInfoCache, document.Project).Values; var supportedDiagnostics = groupedDiagnostics.SelectMany(d => d); var diagnosticDescriptor = supportedDiagnostics.FirstOrDefault(d => d.Id == errorCode); if (diagnosticDescriptor != null) diff --git a/src/EditorFeatures/CSharp/QuickInfo/CSharpDiagnosticAnalyzerQuickInfoProviderExtensions.cs b/src/Features/CSharp/Portable/QuickInfo/CSharpDiagnosticAnalyzerQuickInfoProviderExtensions.cs similarity index 100% rename from src/EditorFeatures/CSharp/QuickInfo/CSharpDiagnosticAnalyzerQuickInfoProviderExtensions.cs rename to src/Features/CSharp/Portable/QuickInfo/CSharpDiagnosticAnalyzerQuickInfoProviderExtensions.cs diff --git a/src/Features/CSharp/Portable/QuickInfo/CSharpQuickInfoSevice.cs b/src/Features/CSharp/Portable/QuickInfo/CSharpQuickInfoSevice.cs index 4cf14fcc1ae4f..4d683e6bdaba2 100644 --- a/src/Features/CSharp/Portable/QuickInfo/CSharpQuickInfoSevice.cs +++ b/src/Features/CSharp/Portable/QuickInfo/CSharpQuickInfoSevice.cs @@ -20,12 +20,12 @@ public CSharpQuickInfoServiceFactory() } public ILanguageService CreateLanguageService(HostLanguageServices languageServices) - => new CSharpQuickInfoService(languageServices); + => new CSharpQuickInfoService(languageServices.LanguageServices); } internal class CSharpQuickInfoService : QuickInfoServiceWithProviders { - internal CSharpQuickInfoService(HostLanguageServices services) + internal CSharpQuickInfoService(LanguageServices services) : base(services) { } diff --git a/src/Features/CSharp/Portable/RemoveUnusedVariable/CSharpRemoveUnusedVariableCodeFixProvider.cs b/src/Features/CSharp/Portable/RemoveUnusedVariable/CSharpRemoveUnusedVariableCodeFixProvider.cs index eadab2966da7b..bde1cde98503b 100644 --- a/src/Features/CSharp/Portable/RemoveUnusedVariable/CSharpRemoveUnusedVariableCodeFixProvider.cs +++ b/src/Features/CSharp/Portable/RemoveUnusedVariable/CSharpRemoveUnusedVariableCodeFixProvider.cs @@ -11,7 +11,7 @@ using Microsoft.CodeAnalysis.CSharp.Extensions; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Editing; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.RemoveUnusedVariable; namespace Microsoft.CodeAnalysis.CSharp.RemoveUnusedVariable diff --git a/src/Features/CSharp/Portable/ReplaceMethodWithProperty/CSharpReplaceMethodWithPropertyService.cs b/src/Features/CSharp/Portable/ReplaceMethodWithProperty/CSharpReplaceMethodWithPropertyService.cs index 473163bdb76f3..4fe69f918e412 100644 --- a/src/Features/CSharp/Portable/ReplaceMethodWithProperty/CSharpReplaceMethodWithPropertyService.cs +++ b/src/Features/CSharp/Portable/ReplaceMethodWithProperty/CSharpReplaceMethodWithPropertyService.cs @@ -12,7 +12,7 @@ using Microsoft.CodeAnalysis.CSharp.CodeGeneration; using Microsoft.CodeAnalysis.CSharp.CodeStyle; using Microsoft.CodeAnalysis.CSharp.Extensions; -using Microsoft.CodeAnalysis.CSharp.LanguageServices; +using Microsoft.CodeAnalysis.CSharp.LanguageService; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Editing; using Microsoft.CodeAnalysis.Formatting; diff --git a/src/Features/CSharp/Portable/ReverseForStatement/CSharpReverseForStatementCodeRefactoringProvider.cs b/src/Features/CSharp/Portable/ReverseForStatement/CSharpReverseForStatementCodeRefactoringProvider.cs index b8aaf6a03e895..462a7c529f8e1 100644 --- a/src/Features/CSharp/Portable/ReverseForStatement/CSharpReverseForStatementCodeRefactoringProvider.cs +++ b/src/Features/CSharp/Portable/ReverseForStatement/CSharpReverseForStatementCodeRefactoringProvider.cs @@ -267,7 +267,7 @@ private async Task ReverseForStatementAsync( var root = await document.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false); - var editor = new SyntaxEditor(root, document.Project.Solution.Workspace.Services); + var editor = new SyntaxEditor(root, document.Project.Solution.Services); var generator = editor.Generator; if (MatchesIncrementPattern( variable, condition, after, diff --git a/src/Features/CSharp/Portable/SignatureHelp/AbstractCSharpSignatureHelpProvider.LightweightOverloadResolution.cs b/src/Features/CSharp/Portable/SignatureHelp/AbstractCSharpSignatureHelpProvider.LightweightOverloadResolution.cs index b84f71bcc31f9..0d0813fe2452b 100644 --- a/src/Features/CSharp/Portable/SignatureHelp/AbstractCSharpSignatureHelpProvider.LightweightOverloadResolution.cs +++ b/src/Features/CSharp/Portable/SignatureHelp/AbstractCSharpSignatureHelpProvider.LightweightOverloadResolution.cs @@ -8,7 +8,7 @@ using System.Diagnostics.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp.Extensions; using Microsoft.CodeAnalysis.CSharp.Syntax; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Shared.Extensions; using Roslyn.Utilities; diff --git a/src/Features/CSharp/Portable/SignatureHelp/AbstractCSharpSignatureHelpProvider.cs b/src/Features/CSharp/Portable/SignatureHelp/AbstractCSharpSignatureHelpProvider.cs index bc9112ce2f57a..ca9d91b826798 100644 --- a/src/Features/CSharp/Portable/SignatureHelp/AbstractCSharpSignatureHelpProvider.cs +++ b/src/Features/CSharp/Portable/SignatureHelp/AbstractCSharpSignatureHelpProvider.cs @@ -13,7 +13,7 @@ using Microsoft.CodeAnalysis.CSharp.Extensions; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.DocumentationComments; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.SignatureHelp; diff --git a/src/Features/CSharp/Portable/SignatureHelp/AbstractOrdinaryMethodSignatureHelpProvider.cs b/src/Features/CSharp/Portable/SignatureHelp/AbstractOrdinaryMethodSignatureHelpProvider.cs index 686dedcde4fe7..4e46bdc7a29f1 100644 --- a/src/Features/CSharp/Portable/SignatureHelp/AbstractOrdinaryMethodSignatureHelpProvider.cs +++ b/src/Features/CSharp/Portable/SignatureHelp/AbstractOrdinaryMethodSignatureHelpProvider.cs @@ -5,7 +5,7 @@ using System.Collections.Generic; using System.Linq; using Microsoft.CodeAnalysis.DocumentationComments; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.SignatureHelp; using Roslyn.Utilities; diff --git a/src/Features/CSharp/Portable/SignatureHelp/AttributeSignatureHelpProvider.cs b/src/Features/CSharp/Portable/SignatureHelp/AttributeSignatureHelpProvider.cs index 11ef37b89d8c4..3f567fdc7cc67 100644 --- a/src/Features/CSharp/Portable/SignatureHelp/AttributeSignatureHelpProvider.cs +++ b/src/Features/CSharp/Portable/SignatureHelp/AttributeSignatureHelpProvider.cs @@ -13,7 +13,7 @@ using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.DocumentationComments; using Microsoft.CodeAnalysis.Host.Mef; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.SignatureHelp; using Microsoft.CodeAnalysis.Text; diff --git a/src/Features/CSharp/Portable/SignatureHelp/ConstructorInitializerSignatureHelpProvider.cs b/src/Features/CSharp/Portable/SignatureHelp/ConstructorInitializerSignatureHelpProvider.cs index 351c434432433..365222cd8b9c6 100644 --- a/src/Features/CSharp/Portable/SignatureHelp/ConstructorInitializerSignatureHelpProvider.cs +++ b/src/Features/CSharp/Portable/SignatureHelp/ConstructorInitializerSignatureHelpProvider.cs @@ -15,7 +15,7 @@ using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.DocumentationComments; using Microsoft.CodeAnalysis.Host.Mef; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; 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 2e2cf111ffece..01b76a10461a4 100644 --- a/src/Features/CSharp/Portable/SignatureHelp/ElementAccessExpressionSignatureHelpProvider.cs +++ b/src/Features/CSharp/Portable/SignatureHelp/ElementAccessExpressionSignatureHelpProvider.cs @@ -16,7 +16,7 @@ using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.DocumentationComments; using Microsoft.CodeAnalysis.Host.Mef; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.SignatureHelp; using Microsoft.CodeAnalysis.Text; diff --git a/src/Features/CSharp/Portable/SignatureHelp/GenericNamePartiallyWrittenSignatureHelpProvider.cs b/src/Features/CSharp/Portable/SignatureHelp/GenericNamePartiallyWrittenSignatureHelpProvider.cs index 8a0b656535016..2ed09039c368f 100644 --- a/src/Features/CSharp/Portable/SignatureHelp/GenericNamePartiallyWrittenSignatureHelpProvider.cs +++ b/src/Features/CSharp/Portable/SignatureHelp/GenericNamePartiallyWrittenSignatureHelpProvider.cs @@ -7,7 +7,7 @@ using System.Threading; using Microsoft.CodeAnalysis.CSharp.Extensions; using Microsoft.CodeAnalysis.Host.Mef; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.SignatureHelp; using Microsoft.CodeAnalysis.Text; using Roslyn.Utilities; diff --git a/src/Features/CSharp/Portable/SignatureHelp/GenericNameSignatureHelpProvider.cs b/src/Features/CSharp/Portable/SignatureHelp/GenericNameSignatureHelpProvider.cs index c5c0b0f8a25a2..965f3f35de759 100644 --- a/src/Features/CSharp/Portable/SignatureHelp/GenericNameSignatureHelpProvider.cs +++ b/src/Features/CSharp/Portable/SignatureHelp/GenericNameSignatureHelpProvider.cs @@ -14,7 +14,7 @@ using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.DocumentationComments; using Microsoft.CodeAnalysis.Host.Mef; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.SignatureHelp; using Microsoft.CodeAnalysis.Text; diff --git a/src/Features/CSharp/Portable/SignatureHelp/InitializerExpressionSignatureHelpProvider.cs b/src/Features/CSharp/Portable/SignatureHelp/InitializerExpressionSignatureHelpProvider.cs index c4ed12f2fd9f9..f3d5ea0c0d675 100644 --- a/src/Features/CSharp/Portable/SignatureHelp/InitializerExpressionSignatureHelpProvider.cs +++ b/src/Features/CSharp/Portable/SignatureHelp/InitializerExpressionSignatureHelpProvider.cs @@ -9,7 +9,7 @@ using System.Threading.Tasks; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Host.Mef; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.SignatureHelp; using Microsoft.CodeAnalysis.Text; diff --git a/src/Features/CSharp/Portable/SignatureHelp/InvocationExpressionSignatureHelpProvider.cs b/src/Features/CSharp/Portable/SignatureHelp/InvocationExpressionSignatureHelpProvider.cs index 1a52894137f65..aa81d7f827a6f 100644 --- a/src/Features/CSharp/Portable/SignatureHelp/InvocationExpressionSignatureHelpProvider.cs +++ b/src/Features/CSharp/Portable/SignatureHelp/InvocationExpressionSignatureHelpProvider.cs @@ -15,7 +15,7 @@ using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.DocumentationComments; using Microsoft.CodeAnalysis.Host.Mef; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.SignatureHelp; using Microsoft.CodeAnalysis.Text; @@ -150,7 +150,7 @@ private static bool IsArgumentListToken(InvocationExpressionSyntax expression, S LightweightOverloadResolution.FindParameterIndexIfCompatibleMethod(arguments, currentSymbol, position, semanticModel, semanticFactsService, out var parameterIndex); // present item and select - var structuralTypeDisplayService = document.Project.LanguageServices.GetRequiredService(); + var structuralTypeDisplayService = document.Project.Services.GetRequiredService(); var documentationCommentFormattingService = document.GetRequiredLanguageService(); var items = GetDelegateOrFunctionPointerInvokeItems(invocationExpression, currentSymbol, diff --git a/src/Features/CSharp/Portable/SignatureHelp/InvocationExpressionSignatureHelpProviderBase_DelegateAndFunctionPointerInvoke.cs b/src/Features/CSharp/Portable/SignatureHelp/InvocationExpressionSignatureHelpProviderBase_DelegateAndFunctionPointerInvoke.cs index e6d79c993d753..d802315bce837 100644 --- a/src/Features/CSharp/Portable/SignatureHelp/InvocationExpressionSignatureHelpProviderBase_DelegateAndFunctionPointerInvoke.cs +++ b/src/Features/CSharp/Portable/SignatureHelp/InvocationExpressionSignatureHelpProviderBase_DelegateAndFunctionPointerInvoke.cs @@ -7,7 +7,7 @@ using Microsoft.CodeAnalysis.CSharp.Extensions; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.DocumentationComments; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.SignatureHelp; using Roslyn.Utilities; diff --git a/src/Features/CSharp/Portable/SignatureHelp/ObjectCreationExpressionSignatureHelpProvider.cs b/src/Features/CSharp/Portable/SignatureHelp/ObjectCreationExpressionSignatureHelpProvider.cs index 828a490ecd9ee..63eec7c1976ea 100644 --- a/src/Features/CSharp/Portable/SignatureHelp/ObjectCreationExpressionSignatureHelpProvider.cs +++ b/src/Features/CSharp/Portable/SignatureHelp/ObjectCreationExpressionSignatureHelpProvider.cs @@ -12,7 +12,7 @@ using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.DocumentationComments; using Microsoft.CodeAnalysis.Host.Mef; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.SignatureHelp; using Microsoft.CodeAnalysis.Text; @@ -101,7 +101,7 @@ private static bool IsArgumentListToken(BaseObjectCreationExpressionSyntax expre LightweightOverloadResolution.RefineOverloadAndPickParameter(document, position, semanticModel, methods, arguments, out var currentSymbol, out var parameterIndex); // present items and select - var structuralTypeDisplayService = document.Project.LanguageServices.GetRequiredService(); + var structuralTypeDisplayService = document.Project.Services.GetRequiredService(); var documentationCommentFormattingService = document.GetRequiredLanguageService(); var items = methods.SelectAsArray(c => @@ -133,7 +133,7 @@ private static bool IsArgumentListToken(BaseObjectCreationExpressionSyntax expre LightweightOverloadResolution.FindParameterIndexIfCompatibleMethod(arguments, invokeMethod, position, semanticModel, semanticFactsService, out var parameterIndex); // present item and select - var structuralTypeDisplayService = document.Project.LanguageServices.GetRequiredService(); + var structuralTypeDisplayService = document.Project.Services.GetRequiredService(); var items = ConvertDelegateTypeConstructor(objectCreationExpression, invokeMethod, semanticModel, structuralTypeDisplayService, position); var textSpan = SignatureHelpUtilities.GetSignatureHelpSpan(objectCreationExpression.ArgumentList); var syntaxFacts = document.GetRequiredLanguageService(); diff --git a/src/Features/CSharp/Portable/SignatureHelp/ObjectCreationExpressionSignatureHelpProvider_DelegateType.cs b/src/Features/CSharp/Portable/SignatureHelp/ObjectCreationExpressionSignatureHelpProvider_DelegateType.cs index 4ed27b88307ff..85105efa9457a 100644 --- a/src/Features/CSharp/Portable/SignatureHelp/ObjectCreationExpressionSignatureHelpProvider_DelegateType.cs +++ b/src/Features/CSharp/Portable/SignatureHelp/ObjectCreationExpressionSignatureHelpProvider_DelegateType.cs @@ -5,7 +5,7 @@ using System.Collections.Generic; using System.Collections.Immutable; using Microsoft.CodeAnalysis.CSharp.Syntax; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.SignatureHelp; using Roslyn.Utilities; diff --git a/src/Features/CSharp/Portable/SignatureHelp/ObjectCreationExpressionSignatureHelpProvider_NormalType.cs b/src/Features/CSharp/Portable/SignatureHelp/ObjectCreationExpressionSignatureHelpProvider_NormalType.cs index 73052e9cdcb6b..4ca70cfc8df3b 100644 --- a/src/Features/CSharp/Portable/SignatureHelp/ObjectCreationExpressionSignatureHelpProvider_NormalType.cs +++ b/src/Features/CSharp/Portable/SignatureHelp/ObjectCreationExpressionSignatureHelpProvider_NormalType.cs @@ -7,7 +7,7 @@ using Microsoft.CodeAnalysis.CSharp.Symbols; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.DocumentationComments; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.SignatureHelp; using Roslyn.Utilities; diff --git a/src/Features/CSharp/Portable/SignatureHelp/PrimaryConstructorBaseTypeSignatureHelpProvider.cs b/src/Features/CSharp/Portable/SignatureHelp/PrimaryConstructorBaseTypeSignatureHelpProvider.cs index 72723f599349a..f7ca9cca0faea 100644 --- a/src/Features/CSharp/Portable/SignatureHelp/PrimaryConstructorBaseTypeSignatureHelpProvider.cs +++ b/src/Features/CSharp/Portable/SignatureHelp/PrimaryConstructorBaseTypeSignatureHelpProvider.cs @@ -14,7 +14,7 @@ using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.DocumentationComments; using Microsoft.CodeAnalysis.Host.Mef; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.SignatureHelp; using Microsoft.CodeAnalysis.Text; diff --git a/src/Features/CSharp/Portable/SignatureHelp/TupleConstructionSignatureHelpProvider.cs b/src/Features/CSharp/Portable/SignatureHelp/TupleConstructionSignatureHelpProvider.cs index 30074faa069b9..b57920e60219e 100644 --- a/src/Features/CSharp/Portable/SignatureHelp/TupleConstructionSignatureHelpProvider.cs +++ b/src/Features/CSharp/Portable/SignatureHelp/TupleConstructionSignatureHelpProvider.cs @@ -12,7 +12,7 @@ using System.Threading.Tasks; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Host.Mef; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.SignatureHelp; using Microsoft.CodeAnalysis.Text; diff --git a/src/Features/CSharp/Portable/SimplifyThisOrMe/CSharpSimplifyThisOrMeDiagnosticAnalyzer.cs b/src/Features/CSharp/Portable/SimplifyThisOrMe/CSharpSimplifyThisOrMeDiagnosticAnalyzer.cs index 006f3bdf70f9c..c7eb7fe8d2ae5 100644 --- a/src/Features/CSharp/Portable/SimplifyThisOrMe/CSharpSimplifyThisOrMeDiagnosticAnalyzer.cs +++ b/src/Features/CSharp/Portable/SimplifyThisOrMe/CSharpSimplifyThisOrMeDiagnosticAnalyzer.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 Microsoft.CodeAnalysis.CSharp.LanguageServices; +using Microsoft.CodeAnalysis.CSharp.LanguageService; using Microsoft.CodeAnalysis.CSharp.Simplification; using Microsoft.CodeAnalysis.CSharp.Simplification.Simplifiers; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Diagnostics; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Simplification; using Microsoft.CodeAnalysis.Simplification.Simplifiers; using Microsoft.CodeAnalysis.SimplifyThisOrMe; diff --git a/src/Features/CSharp/Portable/Snippets/CSharpConsoleSnippetProvider.cs b/src/Features/CSharp/Portable/Snippets/CSharpConsoleSnippetProvider.cs new file mode 100644 index 0000000000000..1ac7d20c24337 --- /dev/null +++ b/src/Features/CSharp/Portable/Snippets/CSharpConsoleSnippetProvider.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.Collections.Immutable; +using System.Composition; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.CSharp.Extensions; +using Microsoft.CodeAnalysis.CSharp.Extensions.ContextQuery; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using Microsoft.CodeAnalysis.Editing; +using Microsoft.CodeAnalysis.Formatting; +using Microsoft.CodeAnalysis.Host.Mef; +using Microsoft.CodeAnalysis.PooledObjects; +using Microsoft.CodeAnalysis.Shared.Extensions; +using Microsoft.CodeAnalysis.Shared.Extensions.ContextQuery; +using Microsoft.CodeAnalysis.Simplification; +using Microsoft.CodeAnalysis.Snippets; +using Microsoft.CodeAnalysis.Snippets.SnippetProviders; +using Microsoft.CodeAnalysis.Text; +using Roslyn.Utilities; + +namespace Microsoft.CodeAnalysis.CSharp.Snippets +{ + [ExportSnippetProvider(nameof(ISnippetProvider), LanguageNames.CSharp), Shared] + internal class CSharpConsoleSnippetProvider : AbstractConsoleSnippetProvider + { + [ImportingConstructor] + [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] + public CSharpConsoleSnippetProvider() + { + } + + protected override SyntaxNode? GetAsyncSupportingDeclaration(SyntaxToken token) + { + var node = token.GetAncestor(node => node.IsAsyncSupportingFunctionSyntax()); + return node; + } + } +} diff --git a/src/Features/CSharp/Portable/Snippets/CSharpIfSnippetProvider.cs b/src/Features/CSharp/Portable/Snippets/CSharpIfSnippetProvider.cs new file mode 100644 index 0000000000000..ca1154aa7c506 --- /dev/null +++ b/src/Features/CSharp/Portable/Snippets/CSharpIfSnippetProvider.cs @@ -0,0 +1,87 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Composition; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using Microsoft.CodeAnalysis.Editing; +using Microsoft.CodeAnalysis.Formatting; +using Microsoft.CodeAnalysis.Host.Mef; +using Microsoft.CodeAnalysis.Indentation; +using Microsoft.CodeAnalysis.LanguageService; +using Microsoft.CodeAnalysis.Shared.Extensions; +using Microsoft.CodeAnalysis.Snippets; +using Microsoft.CodeAnalysis.Snippets.SnippetProviders; +using Microsoft.CodeAnalysis.Text; + +namespace Microsoft.CodeAnalysis.CSharp.Snippets +{ + [ExportSnippetProvider(nameof(ISnippetProvider), LanguageNames.CSharp), Shared] + internal class CSharpIfSnippetProvider : AbstractIfSnippetProvider + { + [ImportingConstructor] + [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] + public CSharpIfSnippetProvider() + { + } + + protected override void GetIfStatementCursorPosition(SourceText sourceText, SyntaxNode node, out int cursorPosition) + { + var ifStatement = (IfStatementSyntax)node; + var blockStatement = (BlockSyntax)ifStatement.Statement; + + var triviaSpan = blockStatement.CloseBraceToken.LeadingTrivia.Span; + var line = sourceText.Lines.GetLineFromPosition(triviaSpan.Start); + // Getting the location at the end of the line before the newline. + cursorPosition = line.Span.End; + } + + protected override void GetIfStatementCondition(SyntaxNode node, out SyntaxNode condition) + { + var ifStatement = (IfStatementSyntax)node; + condition = ifStatement.Condition; + } + + private static string GetIndentation(Document document, SyntaxNode node, SyntaxFormattingOptions syntaxFormattingOptions, CancellationToken cancellationToken) + { + var parsedDocument = ParsedDocument.CreateSynchronously(document, cancellationToken); + var ifStatementSyntax = (IfStatementSyntax)node; + var openBraceLine = parsedDocument.Text.Lines.GetLineFromPosition(ifStatementSyntax.Statement.SpanStart).LineNumber; + + var indentationOptions = new IndentationOptions(syntaxFormattingOptions); + var newLine = indentationOptions.FormattingOptions.NewLine; + + var indentationService = parsedDocument.LanguageServices.GetRequiredService(); + var indentation = indentationService.GetIndentation(parsedDocument, openBraceLine + 1, indentationOptions, cancellationToken); + + // Adding the offset calculated with one tab so that it is indented once past the line containing the opening brace + var newIndentation = new IndentationResult(indentation.BasePosition, indentation.Offset + syntaxFormattingOptions.TabSize); + return newIndentation.GetIndentationString(parsedDocument.Text, syntaxFormattingOptions.UseTabs, syntaxFormattingOptions.TabSize) + newLine; + } + + protected override async Task AddIndentationToDocumentAsync(Document document, int position, ISyntaxFacts syntaxFacts, CancellationToken cancellationToken) + { + var root = await document.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false); + var nearestStatement = FindAddedSnippetSyntaxNode(root, position, syntaxFacts); + + if (nearestStatement is null) + { + return document; + } + + var syntaxFormattingOptions = await document.GetSyntaxFormattingOptionsAsync(fallbackOptions: null, cancellationToken).ConfigureAwait(false); + var indentationString = GetIndentation(document, nearestStatement, syntaxFormattingOptions, cancellationToken); + + var ifStatementSyntax = (IfStatementSyntax)nearestStatement; + var blockStatement = (BlockSyntax)ifStatementSyntax.Statement; + blockStatement = blockStatement.WithCloseBraceToken(blockStatement.CloseBraceToken.WithPrependedLeadingTrivia(SyntaxFactory.SyntaxTrivia(SyntaxKind.WhitespaceTrivia, indentationString))); + var newIfStatementSyntax = ifStatementSyntax.ReplaceNode(ifStatementSyntax.Statement, blockStatement); + + var newRoot = root.ReplaceNode(ifStatementSyntax, newIfStatementSyntax); + return document.WithSyntaxRoot(newRoot); + } + } +} diff --git a/src/Features/CSharp/Portable/Snippets/CSharpSnippetService.cs b/src/Features/CSharp/Portable/Snippets/CSharpSnippetService.cs new file mode 100644 index 0000000000000..6f4f796207d72 --- /dev/null +++ b/src/Features/CSharp/Portable/Snippets/CSharpSnippetService.cs @@ -0,0 +1,34 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Composition; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.CSharp.Extensions.ContextQuery; +using Microsoft.CodeAnalysis.Host.Mef; +using Microsoft.CodeAnalysis.PooledObjects; +using Microsoft.CodeAnalysis.Shared.Extensions; +using Microsoft.CodeAnalysis.Shared.Extensions.ContextQuery; +using Microsoft.CodeAnalysis.Snippets; +using Microsoft.CodeAnalysis.Snippets.SnippetProviders; +using Microsoft.CodeAnalysis.Text; +using Roslyn.Utilities; + +namespace Microsoft.CodeAnalysis.CSharp.Snippets +{ + [ExportLanguageService(typeof(ISnippetService), LanguageNames.CSharp), Shared] + internal class CSharpSnippetService : AbstractSnippetService + { + [ImportingConstructor] + [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] + public CSharpSnippetService([ImportMany] IEnumerable> snippetProviders) + : base(snippetProviders) + { + } + } +} diff --git a/src/Features/CSharp/Portable/SplitStringLiteral/InterpolatedStringSplitter.cs b/src/Features/CSharp/Portable/SplitStringLiteral/InterpolatedStringSplitter.cs index c6e2382ac162a..fc6a837234578 100644 --- a/src/Features/CSharp/Portable/SplitStringLiteral/InterpolatedStringSplitter.cs +++ b/src/Features/CSharp/Portable/SplitStringLiteral/InterpolatedStringSplitter.cs @@ -21,16 +21,12 @@ private sealed class InterpolatedStringSplitter : StringSplitter private readonly InterpolatedStringExpressionSyntax _interpolatedStringExpression; public InterpolatedStringSplitter( - Document document, + ParsedDocument document, int position, - SyntaxNode root, - SourceText sourceText, InterpolatedStringExpressionSyntax interpolatedStringExpression, IndentationOptions options, - bool useTabs, - int tabSize, CancellationToken cancellationToken) - : base(document, position, root, sourceText, options, useTabs, tabSize, cancellationToken) + : base(document, position, options, cancellationToken) { _interpolatedStringExpression = interpolatedStringExpression; } @@ -88,7 +84,7 @@ protected override BinaryExpressionSyntax CreateSplitString() private InterpolatedStringTextSyntax CreateInterpolatedStringText(int start, int end) { - var content = SourceText.ToString(TextSpan.FromBounds(start, end)); + var content = Document.Text.ToString(TextSpan.FromBounds(start, end)); return SyntaxFactory.InterpolatedStringText( SyntaxFactory.Token( leading: default, diff --git a/src/Features/CSharp/Portable/SplitStringLiteral/SimpleStringSplitter.cs b/src/Features/CSharp/Portable/SplitStringLiteral/SimpleStringSplitter.cs index d3a6e8307afe3..26355e115e175 100644 --- a/src/Features/CSharp/Portable/SplitStringLiteral/SimpleStringSplitter.cs +++ b/src/Features/CSharp/Portable/SplitStringLiteral/SimpleStringSplitter.cs @@ -20,10 +20,12 @@ private sealed class SimpleStringSplitter : StringSplitter private readonly SyntaxToken _token; public SimpleStringSplitter( - Document document, int position, - SyntaxNode root, SourceText sourceText, SyntaxToken token, - in IndentationOptions options, bool useTabs, int tabSize, CancellationToken cancellationToken) - : base(document, position, root, sourceText, options, useTabs, tabSize, cancellationToken) + ParsedDocument document, + int position, + SyntaxToken token, + in IndentationOptions options, + CancellationToken cancellationToken) + : base(document, position, options, cancellationToken) { _token = token; } @@ -43,13 +45,13 @@ private bool CursorIsAfterQuotesInUtf8String() protected override BinaryExpressionSyntax CreateSplitString() { // TODO(cyrusn): Deal with the positoin being after a \ character - var prefix = SourceText.GetSubText(TextSpan.FromBounds(_token.SpanStart, CursorPosition)).ToString(); - var suffix = SourceText.GetSubText(TextSpan.FromBounds(CursorPosition, _token.Span.End)).ToString(); + var prefix = Document.Text.GetSubText(TextSpan.FromBounds(_token.SpanStart, CursorPosition)).ToString(); + var suffix = Document.Text.GetSubText(TextSpan.FromBounds(CursorPosition, _token.Span.End)).ToString(); // If we're spliting a UTF-8 string we need to keep the u8 suffix on the first part. We copy whatever // the user had on the second part, for consistency. var firstTokenSuffix = _token.Kind() == SyntaxKind.Utf8StringLiteralToken - ? SourceText.GetSubText(TextSpan.FromBounds(_token.Span.End - "u8".Length, _token.Span.End)).ToString() + ? Document.Text.GetSubText(TextSpan.FromBounds(_token.Span.End - "u8".Length, _token.Span.End)).ToString() : ""; var firstToken = SyntaxFactory.Token( diff --git a/src/Features/CSharp/Portable/SplitStringLiteral/StringSplitter.cs b/src/Features/CSharp/Portable/SplitStringLiteral/StringSplitter.cs index bde21447daf39..d2c6f1bbb94c8 100644 --- a/src/Features/CSharp/Portable/SplitStringLiteral/StringSplitter.cs +++ b/src/Features/CSharp/Portable/SplitStringLiteral/StringSplitter.cs @@ -2,8 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - +using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Threading; using Microsoft.CodeAnalysis.CSharp.Syntax; @@ -23,47 +22,38 @@ internal abstract partial class StringSplitter SyntaxKind.PlusToken, SyntaxFactory.TriviaList(SyntaxFactory.ElasticCarriageReturnLineFeed)); - protected readonly Document Document; + protected readonly ParsedDocument Document; protected readonly int CursorPosition; - protected readonly SourceText SourceText; - protected readonly SyntaxNode Root; protected readonly IndentationOptions Options; - protected readonly int TabSize; - protected readonly bool UseTabs; protected readonly CancellationToken CancellationToken; public StringSplitter( - Document document, int position, - SyntaxNode root, SourceText sourceText, - in IndentationOptions options, bool useTabs, int tabSize, + ParsedDocument document, int position, + in IndentationOptions options, CancellationToken cancellationToken) { Document = document; CursorPosition = position; - Root = root; - SourceText = sourceText; - UseTabs = useTabs; - TabSize = tabSize; Options = options; CancellationToken = cancellationToken; } - public static StringSplitter TryCreate( - Document document, int position, - in IndentationOptions options, bool useTabs, int tabSize, + protected int TabSize => Options.FormattingOptions.TabSize; + protected bool UseTabs => Options.FormattingOptions.UseTabs; + + public static StringSplitter? TryCreate( + ParsedDocument document, int position, + in IndentationOptions options, CancellationToken cancellationToken) { - var root = document.GetSyntaxRootSynchronously(cancellationToken); - var sourceText = root.SyntaxTree.GetText(cancellationToken); - - var token = root.FindToken(position); + var token = document.Root.FindToken(position); if (token.IsKind(SyntaxKind.StringLiteralToken) || token.IsKind(SyntaxKind.Utf8StringLiteralToken)) { return new SimpleStringSplitter( - document, position, root, - sourceText, token, options, useTabs, tabSize, + document, position, + token, options, cancellationToken); } @@ -71,15 +61,15 @@ public static StringSplitter TryCreate( if (interpolatedStringExpression != null) { return new InterpolatedStringSplitter( - document, position, root, - sourceText, interpolatedStringExpression, - options, useTabs, tabSize, cancellationToken); + document, position, + interpolatedStringExpression, + options, cancellationToken); } return null; } - private static InterpolatedStringExpressionSyntax TryGetInterpolatedStringExpression( + private static InterpolatedStringExpressionSyntax? TryGetInterpolatedStringExpression( SyntaxToken token, int position) { if (token.IsKind(SyntaxKind.InterpolatedStringTextToken) || @@ -107,55 +97,53 @@ private static bool IsInterpolationOpenBrace(SyntaxToken token, int position) protected abstract BinaryExpressionSyntax CreateSplitString(); - public bool TrySplit(out Document newDocument, out int newPosition) + public bool TrySplit([NotNullWhen(true)] out SyntaxNode? newRoot, out int newPosition) { var nodeToReplace = GetNodeToReplace(); if (CursorPosition <= nodeToReplace.SpanStart || CursorPosition >= nodeToReplace.Span.End) { - newDocument = null; + newRoot = null; newPosition = 0; return false; } if (!CheckToken()) { - newDocument = null; + newRoot = null; newPosition = 0; return false; } - (newDocument, newPosition) = SplitString(); + (newRoot, newPosition) = SplitString(); return true; } - private (Document document, int caretPosition) SplitString() + private (SyntaxNode root, int caretPosition) SplitString() { var splitString = CreateSplitString(); var nodeToReplace = GetNodeToReplace(); - var newRoot = Root.ReplaceNode(nodeToReplace, splitString); + var newRoot = Document.Root.ReplaceNode(nodeToReplace, splitString); var rightExpression = newRoot.GetAnnotatedNodes(RightNodeAnnotation).Single(); var indentString = GetIndentString(newRoot); var newRightExpression = rightExpression.WithLeadingTrivia(SyntaxFactory.ElasticWhitespace(indentString)); var newRoot2 = newRoot.ReplaceNode(rightExpression, newRightExpression); - var newDocument2 = Document.WithSyntaxRoot(newRoot2); - return (newDocument2, rightExpression.Span.Start + indentString.Length + StringOpenQuoteLength()); + return (newRoot2, rightExpression.Span.Start + indentString.Length + StringOpenQuoteLength()); } private string GetIndentString(SyntaxNode newRoot) { - var newDocument = Document.WithSyntaxRoot(newRoot); - - var indentationService = newDocument.GetLanguageService(); - var originalLineNumber = SourceText.Lines.GetLineFromPosition(CursorPosition).LineNumber; + var indentationService = Document.LanguageServices.GetRequiredService(); + var originalLineNumber = Document.Text.Lines.GetLineFromPosition(CursorPosition).LineNumber; + var newDocument = Document.WithChangedRoot(newRoot, CancellationToken); var desiredIndentation = indentationService.GetIndentation( newDocument, originalLineNumber + 1, Options, CancellationToken); - var newSourceText = newDocument.GetSyntaxRootSynchronously(CancellationToken).SyntaxTree.GetText(CancellationToken); + var newSourceText = newDocument.Text; var baseLine = newSourceText.Lines.GetLineFromPosition(desiredIndentation.BasePosition); var baseOffsetInLineInPositions = desiredIndentation.BasePosition - baseLine.Start; diff --git a/src/Features/CSharp/Portable/StringIndentation/CSharpStringIndentationService.cs b/src/Features/CSharp/Portable/StringIndentation/CSharpStringIndentationService.cs index 80f08897de9f4..02b153ad3a006 100644 --- a/src/Features/CSharp/Portable/StringIndentation/CSharpStringIndentationService.cs +++ b/src/Features/CSharp/Portable/StringIndentation/CSharpStringIndentationService.cs @@ -82,7 +82,8 @@ private static void Recurse( // Break out of the 'for' loop, which effectively continues the containing 'while' loop break; } - else if (child.IsKind(SyntaxKind.MultiLineRawStringLiteralToken)) + else if (child.IsKind(SyntaxKind.MultiLineRawStringLiteralToken) || + child.IsKind(SyntaxKind.Utf8MultiLineRawStringLiteralToken)) { ProcessMultiLineRawStringLiteralToken(text, child.AsToken(), result, cancellationToken); } diff --git a/src/Features/CSharp/Portable/Structure/CSharpBlockStructureService.cs b/src/Features/CSharp/Portable/Structure/CSharpBlockStructureService.cs index ced4f38eebbe8..45bd077c3f35d 100644 --- a/src/Features/CSharp/Portable/Structure/CSharpBlockStructureService.cs +++ b/src/Features/CSharp/Portable/Structure/CSharpBlockStructureService.cs @@ -23,12 +23,13 @@ public CSharpBlockStructureServiceFactory() } public ILanguageService CreateLanguageService(HostLanguageServices languageServices) - => new CSharpBlockStructureService(languageServices.WorkspaceServices.Workspace); + => new CSharpBlockStructureService(languageServices.LanguageServices.SolutionServices); } internal class CSharpBlockStructureService : BlockStructureServiceWithProviders { - public CSharpBlockStructureService(Workspace workspace) : base(workspace) + public CSharpBlockStructureService(SolutionServices services) + : base(services) { } diff --git a/src/Features/CSharp/Portable/Structure/Providers/DocumentationCommentStructureProvider.cs b/src/Features/CSharp/Portable/Structure/Providers/DocumentationCommentStructureProvider.cs index 29918c067da97..03358b2fe44cf 100644 --- a/src/Features/CSharp/Portable/Structure/Providers/DocumentationCommentStructureProvider.cs +++ b/src/Features/CSharp/Portable/Structure/Providers/DocumentationCommentStructureProvider.cs @@ -3,7 +3,7 @@ // See the LICENSE file in the project root for more information. using System.Threading; -using Microsoft.CodeAnalysis.CSharp.LanguageServices; +using Microsoft.CodeAnalysis.CSharp.LanguageService; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Shared.Collections; using Microsoft.CodeAnalysis.Structure; diff --git a/src/Features/CSharp/Portable/UpgradeProject/CSharpUpgradeProjectCodeFixProvider.cs b/src/Features/CSharp/Portable/UpgradeProject/CSharpUpgradeProjectCodeFixProvider.cs index 3d601ff8ab2bf..0b4a3c4e8d711 100644 --- a/src/Features/CSharp/Portable/UpgradeProject/CSharpUpgradeProjectCodeFixProvider.cs +++ b/src/Features/CSharp/Portable/UpgradeProject/CSharpUpgradeProjectCodeFixProvider.cs @@ -58,6 +58,7 @@ public CSharpUpgradeProjectCodeFixProvider() "CS8880", // warning CS8880: Auto-implemented property 'S.Test1' must be fully assigned before control is returned to the caller. Consider updating to language version 'preview' to auto-default the property. "CS8881", // warning CS8881: Field 'S.Test1' must be fully assigned before control is returned to the caller. Consider updating to language version 'preview' to auto-default the field. "CS8885", // warning CS8885: The 'this' object cannot be used before all of its fields have been assigned. Consider updating to language version 'preview' to auto-default the unassigned fields. + "CS9058", // error CS9058: Feature '{0}' is not available in C# 11.0. Please use language version {1} or greater. }); public override string UpgradeThisProjectResource => CSharpFeaturesResources.Upgrade_this_project_to_csharp_language_version_0; diff --git a/src/Features/CSharp/Portable/UseExpressionBody/UseExpressionBodyCodeRefactoringProvider.cs b/src/Features/CSharp/Portable/UseExpressionBody/UseExpressionBodyCodeRefactoringProvider.cs index acb42ecd773e4..c3516bcb11376 100644 --- a/src/Features/CSharp/Portable/UseExpressionBody/UseExpressionBodyCodeRefactoringProvider.cs +++ b/src/Features/CSharp/Portable/UseExpressionBody/UseExpressionBodyCodeRefactoringProvider.cs @@ -20,7 +20,6 @@ using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Editing; using Microsoft.CodeAnalysis.Formatting; -using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Text; using Roslyn.Utilities; @@ -33,8 +32,8 @@ internal class UseExpressionBodyCodeRefactoringProvider : SyntaxEditorBasedCodeR { private static readonly ImmutableArray _helpers = UseExpressionBodyHelper.Helpers; - private static readonly BidirectionalMap<(UseExpressionBodyHelper helper, bool useExpressionBody), string> s_helperToTitleMap - = CreateHelperToTitleMap(UseExpressionBodyHelper.Helpers); + private static readonly BidirectionalMap<(UseExpressionBodyHelper helper, bool useExpressionBody), string> s_equivalenceKeyMap + = CreateEquivalanceKeyMap(UseExpressionBodyHelper.Helpers); [ImportingConstructor] [SuppressMessage("RoslynDiagnosticsReliability", "RS0033:Importing constructor should be [Obsolete]", Justification = "Used in test code: https://github.com/dotnet/roslyn/issues/42814")] @@ -42,7 +41,7 @@ public UseExpressionBodyCodeRefactoringProvider() { } - private static BidirectionalMap<(UseExpressionBodyHelper helper, bool useExpressionBody), string> CreateHelperToTitleMap( + private static BidirectionalMap<(UseExpressionBodyHelper helper, bool useExpressionBody), string> CreateEquivalanceKeyMap( ImmutableArray helpers) { return new BidirectionalMap<(UseExpressionBodyHelper helper, bool useExpressionBody), string>(GetKeyValuePairs(helpers)); @@ -52,8 +51,8 @@ public UseExpressionBodyCodeRefactoringProvider() { foreach (var helper in helpers) { - yield return KeyValuePairUtil.Create((helper, useExpressionBody: true), helper.UseExpressionBodyTitle.ToString()); - yield return KeyValuePairUtil.Create((helper, useExpressionBody: false), helper.UseBlockBodyTitle.ToString()); + yield return KeyValuePairUtil.Create((helper, useExpressionBody: true), helper.GetType().Name + "_UseExpressionBody"); + yield return KeyValuePairUtil.Create((helper, useExpressionBody: false), helper.GetType().Name + "_UseBlockBody"); } } } @@ -125,28 +124,26 @@ private static bool TryComputeRefactoring( var succeeded = false; if (helper.CanOfferUseExpressionBody(preference, declaration, forAnalyzer: false)) { - var title = s_helperToTitleMap[(helper, useExpressionBody: true)]; context.RegisterRefactoring( CodeAction.Create( - title, + helper.UseExpressionBodyTitle.ToString(), c => UpdateDocumentAsync( document, root, declaration, helper, useExpressionBody: true, cancellationToken: c), - title), + s_equivalenceKeyMap[(helper, useExpressionBody: true)]), declaration.Span); succeeded = true; } if (helper.CanOfferUseBlockBody(preference, declaration, forAnalyzer: false, out _, out _)) { - var title = s_helperToTitleMap[(helper, useExpressionBody: false)]; context.RegisterRefactoring( CodeAction.Create( - title, + helper.UseBlockBodyTitle.ToString(), c => UpdateDocumentAsync( document, root, declaration, helper, useExpressionBody: false, cancellationToken: c), - title), + s_equivalenceKeyMap[(helper, useExpressionBody: false)]), declaration.Span); succeeded = true; } @@ -200,7 +197,7 @@ protected override async Task FixAllAsync( CancellationToken cancellationToken) { Debug.Assert(equivalenceKey != null); - var (helper, useExpressionBody) = s_helperToTitleMap[equivalenceKey]; + var (helper, useExpressionBody) = s_equivalenceKeyMap[equivalenceKey]; var root = await document.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false); var options = (CSharpCodeGenerationOptions)await document.GetCodeGenerationOptionsAsync(optionsProvider, cancellationToken).ConfigureAwait(false); diff --git a/src/Features/CSharp/Portable/UseExpressionBodyForLambda/UseExpressionBodyForLambdaCodeStyleProvider_Refactoring.cs b/src/Features/CSharp/Portable/UseExpressionBodyForLambda/UseExpressionBodyForLambdaCodeRefactoringProvider.cs similarity index 53% rename from src/Features/CSharp/Portable/UseExpressionBodyForLambda/UseExpressionBodyForLambdaCodeStyleProvider_Refactoring.cs rename to src/Features/CSharp/Portable/UseExpressionBodyForLambda/UseExpressionBodyForLambdaCodeRefactoringProvider.cs index 1e0aabb93d3b1..ae7b13ce435b2 100644 --- a/src/Features/CSharp/Portable/UseExpressionBodyForLambda/UseExpressionBodyForLambdaCodeStyleProvider_Refactoring.cs +++ b/src/Features/CSharp/Portable/UseExpressionBodyForLambda/UseExpressionBodyForLambdaCodeRefactoringProvider.cs @@ -2,27 +2,95 @@ // The .NET Foundation 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.Composition; +using System.Diagnostics.CodeAnalysis; using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeRefactorings; using Microsoft.CodeAnalysis.CodeStyle; -using Microsoft.CodeAnalysis.CSharp.Extensions; +using Microsoft.CodeAnalysis.CSharp.CodeFixes.UseExpressionBodyForLambda; using Microsoft.CodeAnalysis.CSharp.Syntax; +using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.PooledObjects; +using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Text; using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.CSharp.UseExpressionBodyForLambda { - // Code for the CodeRefactoringProvider ("Refactoring") portion of the feature. - - internal partial class UseExpressionBodyForLambdaCodeStyleProvider + [ExportCodeRefactoringProvider(LanguageNames.CSharp, Name = PredefinedCodeRefactoringProviderNames.UseExpressionBodyForLambda), Shared] + internal sealed class UseExpressionBodyForLambdaCodeRefactoringProvider : CodeRefactoringProvider { - protected override async Task> ComputeOpposingRefactoringsWhenAnalyzerActiveAsync( + [ImportingConstructor] + [SuppressMessage("RoslynDiagnosticsReliability", "RS0033:Importing constructor should be [Obsolete]", Justification = "Used in test code: https://github.com/dotnet/roslyn/issues/42814")] + public UseExpressionBodyForLambdaCodeRefactoringProvider() + { + } + + public override async Task ComputeRefactoringsAsync(CodeRefactoringContext context) + { + var document = context.Document; + var cancellationToken = context.CancellationToken; + + var optionProvider = await document.GetAnalyzerOptionsProviderAsync(cancellationToken).ConfigureAwait(false); + var optionValue = UseExpressionBodyForLambdaHelpers.GetCodeStyleOption(optionProvider); + + var severity = UseExpressionBodyForLambdaHelpers.GetOptionSeverity(optionValue); + switch (severity) + { + case ReportDiagnostic.Suppress: + case ReportDiagnostic.Hidden: + // if the severity is Hidden that's equivalent to 'refactoring only', so we want + // to try to compute the refactoring here. + // + // If the severity is 'suppress', that means the user doesn't want the actual + // analyzer to run here. However, we can still check to see if we could offer + // the feature here as a refactoring. + await ComputeRefactoringsAsync(context, optionValue.Value, analyzerActive: false).ConfigureAwait(false); + return; + + case ReportDiagnostic.Error: + case ReportDiagnostic.Warn: + case ReportDiagnostic.Info: + // User has this option set at a level where we want it checked by the + // DiagnosticAnalyser and not the CodeRefactoringProvider. However, we still + // want to check if we want to offer the *reverse* refactoring here in this + // single location. + // + // For example, say this is the "use expression body" feature. If the user says + // they always prefer expression-bodies (with warning level), then we want the + // analyzer to always be checking for that. However, we still want to offer the + // refactoring to flip their code to use a block body here, just in case that + // was something they wanted to do as a one off (i.e. before adding new + // statements. + // + // TODO(cyrusn): Should we only do this for warn/info? Argument could be made + // that we shouldn't even offer to refactor in the reverse direction if it will + // just cause an error. That said, maybe this is just an intermediary step, and + // we shouldn't really be blocking the user from making it. + await ComputeRefactoringsAsync(context, optionValue.Value, analyzerActive: true).ConfigureAwait(false); + return; + } + } + + private static async Task ComputeRefactoringsAsync( + CodeRefactoringContext context, ExpressionBodyPreference option, bool analyzerActive) + { + var document = context.Document; + var span = context.Span; + var cancellationToken = context.CancellationToken; + + var computationTask = analyzerActive + ? ComputeOpposingRefactoringsWhenAnalyzerActiveAsync(document, span, option, cancellationToken) + : ComputeAllRefactoringsWhenAnalyzerInactiveAsync(document, span, cancellationToken); + + var codeActions = await computationTask.ConfigureAwait(false); + context.RegisterRefactorings(codeActions); + } + + private static async Task> ComputeOpposingRefactoringsWhenAnalyzerActiveAsync( Document document, TextSpan span, ExpressionBodyPreference option, CancellationToken cancellationToken) { if (option == ExpressionBodyPreference.Never) @@ -78,7 +146,7 @@ protected override async Task> ComputeOpposingRefacto } } - protected override async Task> ComputeAllRefactoringsWhenAnalyzerInactiveAsync( + private static async Task> ComputeAllRefactoringsWhenAnalyzerInactiveAsync( Document document, TextSpan span, CancellationToken cancellationToken) { // If the analyzer is inactive, then we want to offer refactorings in any viable @@ -103,12 +171,12 @@ private static async Task> ComputeRefactoringsAsync( return ImmutableArray.Empty; } - var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); + var root = await document.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false); using var resultDisposer = ArrayBuilder.GetInstance(out var result); - if (CanOfferUseExpressionBody(option, lambdaNode, root.GetLanguageVersion())) + if (UseExpressionBodyForLambdaHelpers.CanOfferUseExpressionBody(option, lambdaNode, root.GetLanguageVersion())) { - var title = UseExpressionBodyTitle.ToString(); + var title = UseExpressionBodyForLambdaHelpers.UseExpressionBodyTitle.ToString(); result.Add(CodeAction.Create( title, c => UpdateDocumentAsync( @@ -116,10 +184,10 @@ private static async Task> ComputeRefactoringsAsync( title)); } - var semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false); - if (CanOfferUseBlockBody(semanticModel, option, lambdaNode, cancellationToken)) + var semanticModel = await document.GetRequiredSemanticModelAsync(cancellationToken).ConfigureAwait(false); + if (UseExpressionBodyForLambdaHelpers.CanOfferUseBlockBody(semanticModel, option, lambdaNode, cancellationToken)) { - var title = UseBlockBodyTitle.ToString(); + var title = UseExpressionBodyForLambdaHelpers.UseBlockBodyTitle.ToString(); result.Add(CodeAction.Create( title, c => UpdateDocumentAsync( @@ -133,11 +201,11 @@ private static async Task> ComputeRefactoringsAsync( private static async Task UpdateDocumentAsync( Document document, SyntaxNode root, LambdaExpressionSyntax declaration, CancellationToken cancellationToken) { - var semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false); + var semanticModel = await document.GetRequiredSemanticModelAsync(cancellationToken).ConfigureAwait(false); // We're only replacing a single declaration in the refactoring. So pass 'declaration' // as both the 'original' and 'current' declaration. - var updatedDeclaration = Update(semanticModel, declaration, declaration); + var updatedDeclaration = UseExpressionBodyForLambdaCodeActionHelpers.Update(semanticModel, declaration, declaration); var newRoot = root.ReplaceNode(declaration, updatedDeclaration); return document.WithSyntaxRoot(newRoot); diff --git a/src/Features/CSharp/Portable/UseExpressionBodyForLambda/UseExpressionBodyForLambdaCodeStyleProvider.cs b/src/Features/CSharp/Portable/UseExpressionBodyForLambda/UseExpressionBodyForLambdaCodeStyleProvider.cs deleted file mode 100644 index ac7591f83de49..0000000000000 --- a/src/Features/CSharp/Portable/UseExpressionBodyForLambda/UseExpressionBodyForLambdaCodeStyleProvider.cs +++ /dev/null @@ -1,248 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -#nullable disable - -using System; -using System.Composition; -using System.Diagnostics.CodeAnalysis; -using System.Linq; -using System.Threading; -using System.Threading.Tasks; -using Microsoft.CodeAnalysis.CodeActions; -using Microsoft.CodeAnalysis.CodeFixes; -using Microsoft.CodeAnalysis.CodeRefactorings; -using Microsoft.CodeAnalysis.CodeStyle; -using Microsoft.CodeAnalysis.CSharp.CodeStyle; -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; - -namespace Microsoft.CodeAnalysis.CSharp.UseExpressionBodyForLambda -{ - internal partial class UseExpressionBodyForLambdaCodeStyleProvider - : AbstractCodeStyleProvider - { - private static readonly LocalizableString UseExpressionBodyTitle = new LocalizableResourceString(nameof(FeaturesResources.Use_expression_body_for_lambda_expressions), FeaturesResources.ResourceManager, typeof(FeaturesResources)); - private static readonly LocalizableString UseBlockBodyTitle = new LocalizableResourceString(nameof(FeaturesResources.Use_block_body_for_lambda_expressions), FeaturesResources.ResourceManager, typeof(FeaturesResources)); - - public UseExpressionBodyForLambdaCodeStyleProvider() - : base(CSharpCodeStyleOptions.PreferExpressionBodiedLambdas, - LanguageNames.CSharp, - IDEDiagnosticIds.UseExpressionBodyForLambdaExpressionsDiagnosticId, - EnforceOnBuildValues.UseExpressionBodyForLambdaExpressions, - UseExpressionBodyTitle, - UseExpressionBodyTitle) - { - } - - // Shared code needed by all parts of the style provider for this feature. - - protected override CodeStyleOption2 GetCodeStyleOption(AnalyzerOptionsProvider provider) - => ((CSharpAnalyzerOptionsProvider)provider).PreferExpressionBodiedLambdas; - - private static ExpressionSyntax GetBodyAsExpression(LambdaExpressionSyntax declaration) - => declaration.Body as ExpressionSyntax; - - private static bool CanOfferUseExpressionBody( - ExpressionBodyPreference preference, LambdaExpressionSyntax declaration, LanguageVersion languageVersion) - { - var userPrefersExpressionBodies = preference != ExpressionBodyPreference.Never; - if (!userPrefersExpressionBodies) - { - // If the user doesn't even want expression bodies, then certainly do not offer. - return false; - } - - var expressionBody = GetBodyAsExpression(declaration); - if (expressionBody != null) - { - // they already have an expression body. so nothing to do here. - return false; - } - - // They don't have an expression body. See if we could convert the block they - // have into one. - return TryConvertToExpressionBody(declaration, languageVersion, preference, out _, out _); - } - - private static bool TryConvertToExpressionBody( - LambdaExpressionSyntax declaration, - LanguageVersion languageVersion, - ExpressionBodyPreference conversionPreference, - out ExpressionSyntax expression, - out SyntaxToken semicolon) - { - var body = declaration.Body as BlockSyntax; - - return body.TryConvertToExpressionBody(languageVersion, conversionPreference, out expression, out semicolon); - } - - private static bool CanOfferUseBlockBody( - SemanticModel semanticModel, ExpressionBodyPreference preference, - LambdaExpressionSyntax declaration, CancellationToken cancellationToken) - { - var userPrefersBlockBodies = preference == ExpressionBodyPreference.Never; - if (!userPrefersBlockBodies) - { - // If the user doesn't even want block bodies, then certainly do not offer. - return false; - } - - var expressionBodyOpt = GetBodyAsExpression(declaration); - if (expressionBodyOpt == null) - { - // they already have a block body. - return false; - } - - // We need to know what sort of lambda this is (void returning or not) in order to be - // able to create the right sort of block body (i.e. with a return-statement or - // expr-statement). So, if we can't figure out what lambda type this is, we should not - // proceed. - if (semanticModel.GetTypeInfo(declaration, cancellationToken).ConvertedType is not INamedTypeSymbol lambdaType || lambdaType.DelegateInvokeMethod == null) - { - return false; - } - - var canOffer = expressionBodyOpt.TryConvertToStatement( - semicolonTokenOpt: null, createReturnStatementForExpression: false, out _); - if (!canOffer) - { - // Couldn't even convert the expression into statement form. - return false; - } - - var languageVersion = declaration.SyntaxTree.Options.LanguageVersion(); - if (expressionBodyOpt.IsKind(SyntaxKind.ThrowExpression) && - languageVersion < LanguageVersion.CSharp7) - { - // Can't convert this prior to C# 7 because ```a => throw ...``` isn't allowed. - return false; - } - - return true; - } - - private static LambdaExpressionSyntax Update(SemanticModel semanticModel, LambdaExpressionSyntax originalDeclaration, LambdaExpressionSyntax currentDeclaration) - => UpdateWorker(semanticModel, originalDeclaration, currentDeclaration).WithAdditionalAnnotations(Formatter.Annotation); - - private static LambdaExpressionSyntax UpdateWorker( - SemanticModel semanticModel, LambdaExpressionSyntax originalDeclaration, LambdaExpressionSyntax currentDeclaration) - { - var expressionBody = GetBodyAsExpression(currentDeclaration); - return expressionBody == null - ? WithExpressionBody(currentDeclaration, originalDeclaration.GetLanguageVersion()) - : WithBlockBody(semanticModel, originalDeclaration, currentDeclaration); - } - - private static LambdaExpressionSyntax WithExpressionBody(LambdaExpressionSyntax declaration, LanguageVersion languageVersion) - { - if (!TryConvertToExpressionBody(declaration, languageVersion, ExpressionBodyPreference.WhenPossible, out var expressionBody, out _)) - { - return declaration; - } - - var updatedDecl = declaration.WithBody(expressionBody); - - // If there will only be whitespace between the arrow and the body, then replace that - // with a single space so that the lambda doesn't have superfluous newlines in it. - if (declaration.ArrowToken.TrailingTrivia.All(t => t.IsWhitespaceOrEndOfLine()) && - expressionBody.GetLeadingTrivia().All(t => t.IsWhitespaceOrEndOfLine())) - { - updatedDecl = updatedDecl.WithArrowToken(updatedDecl.ArrowToken.WithTrailingTrivia(SyntaxFactory.ElasticSpace)); - } - - return updatedDecl; - } - - private static LambdaExpressionSyntax WithBlockBody( - SemanticModel semanticModel, LambdaExpressionSyntax originalDeclaration, LambdaExpressionSyntax currentDeclaration) - { - var expressionBody = GetBodyAsExpression(currentDeclaration); - var createReturnStatementForExpression = CreateReturnStatementForExpression( - semanticModel, originalDeclaration); - - if (!expressionBody.TryConvertToStatement( - semicolonTokenOpt: null, - createReturnStatementForExpression, - out var statement)) - { - return currentDeclaration; - } - - // If the user is converting to a block, it's likely they intend to add multiple - // statements to it. So make a multi-line block so that things are formatted properly - // for them to do so. - return currentDeclaration.WithBody(SyntaxFactory.Block( - SyntaxFactory.Token(SyntaxKind.OpenBraceToken).WithAppendedTrailingTrivia(SyntaxFactory.ElasticCarriageReturnLineFeed), - SyntaxFactory.SingletonList(statement), - SyntaxFactory.Token(SyntaxKind.CloseBraceToken))); - } - - private static bool CreateReturnStatementForExpression( - SemanticModel semanticModel, LambdaExpressionSyntax declaration) - { - var lambdaType = (INamedTypeSymbol)semanticModel.GetTypeInfo(declaration).ConvertedType; - if (lambdaType.DelegateInvokeMethod.ReturnsVoid) - { - return false; - } - - // 'async Task' is effectively a void-returning lambda. we do not want to create - // 'return statements' when converting. - if (declaration.AsyncKeyword != default) - { - var returnType = lambdaType.DelegateInvokeMethod.ReturnType; - if (returnType.IsErrorType()) - { - // "async Goo" where 'Goo' failed to bind. If 'Goo' is 'Task' then it's - // reasonable to assume this is just a missing 'using' and that this is a true - // "async Task" lambda. If the name isn't 'Task', then this looks like a - // real return type, and we should use return statements. - return returnType.Name != nameof(Task); - } - - var taskType = semanticModel.Compilation.GetTypeByMetadataName(typeof(Task).FullName); - if (returnType.Equals(taskType)) - { - // 'async Task'. definitely do not create a 'return' statement; - return false; - } - } - - return true; - } - } - - // Stub classes needed only for exporting purposes. - - [ExportCodeFixProvider(LanguageNames.CSharp, Name = PredefinedCodeFixProviderNames.UseExpressionBodyForLambda), Shared] - internal sealed class UseExpressionBodyForLambdaCodeFixProvider : UseExpressionBodyForLambdaCodeStyleProvider.CodeFixProvider - { - [ImportingConstructor] - [SuppressMessage("RoslynDiagnosticsReliability", "RS0033:Importing constructor should be [Obsolete]", Justification = "Used in test code: https://github.com/dotnet/roslyn/issues/42814")] - public UseExpressionBodyForLambdaCodeFixProvider() - { - } - } - - [ExportCodeRefactoringProvider(LanguageNames.CSharp, Name = PredefinedCodeRefactoringProviderNames.UseExpressionBodyForLambda), Shared] - internal sealed class UseExpressionBodyForLambdaCodeRefactoringProvider : UseExpressionBodyForLambdaCodeStyleProvider.CodeRefactoringProvider - { - [ImportingConstructor] - [SuppressMessage("RoslynDiagnosticsReliability", "RS0033:Importing constructor should be [Obsolete]", Justification = "Used in test code: https://github.com/dotnet/roslyn/issues/42814")] - public UseExpressionBodyForLambdaCodeRefactoringProvider() - { - } - } - - [DiagnosticAnalyzer(LanguageNames.CSharp)] - internal sealed class UseExpressionBodyForLambdaDiagnosticAnalyzer : UseExpressionBodyForLambdaCodeStyleProvider.DiagnosticAnalyzer - { - } -} diff --git a/src/Features/CSharp/Portable/UseExpressionBodyForLambda/UseExpressionBodyForLambdaCodeStyleProvider_Analysis.cs b/src/Features/CSharp/Portable/UseExpressionBodyForLambda/UseExpressionBodyForLambdaCodeStyleProvider_Analysis.cs deleted file mode 100644 index bb21394dadfff..0000000000000 --- a/src/Features/CSharp/Portable/UseExpressionBodyForLambda/UseExpressionBodyForLambdaCodeStyleProvider_Analysis.cs +++ /dev/null @@ -1,73 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -#nullable disable - -using System.Collections.Immutable; -using System.Threading; -using Microsoft.CodeAnalysis.CodeStyle; -using Microsoft.CodeAnalysis.CSharp.Extensions; -using Microsoft.CodeAnalysis.CSharp.Syntax; -using Microsoft.CodeAnalysis.Diagnostics; -using Microsoft.CodeAnalysis.Text; - -namespace Microsoft.CodeAnalysis.CSharp.UseExpressionBodyForLambda -{ - // Code for the DiagnosticAnalyzer ("Analysis") portion of the feature. - - internal partial class UseExpressionBodyForLambdaCodeStyleProvider - { - protected override void DiagnosticAnalyzerInitialize(AnalysisContext context) - => context.RegisterSyntaxNodeAction(AnalyzeSyntax, - SyntaxKind.SimpleLambdaExpression, SyntaxKind.ParenthesizedLambdaExpression); - - protected override DiagnosticAnalyzerCategory GetAnalyzerCategory() - => DiagnosticAnalyzerCategory.SemanticSpanAnalysis; - - private void AnalyzeSyntax(SyntaxNodeAnalysisContext context, CodeStyleOption2 option) - { - var declaration = (LambdaExpressionSyntax)context.Node; - var diagnostic = AnalyzeSyntax(context.SemanticModel, option, declaration, context.CancellationToken); - if (diagnostic != null) - { - context.ReportDiagnostic(diagnostic); - } - } - - private Diagnostic AnalyzeSyntax( - SemanticModel semanticModel, CodeStyleOption2 option, - LambdaExpressionSyntax declaration, CancellationToken cancellationToken) - { - if (CanOfferUseExpressionBody(option.Value, declaration, declaration.GetLanguageVersion())) - { - var location = GetDiagnosticLocation(declaration); - - var additionalLocations = ImmutableArray.Create(declaration.GetLocation()); - var properties = ImmutableDictionary.Empty; - return DiagnosticHelper.Create( - CreateDescriptorWithId(UseExpressionBodyTitle, UseExpressionBodyTitle), - location, option.Notification.Severity, additionalLocations, properties); - } - - if (CanOfferUseBlockBody(semanticModel, option.Value, declaration, cancellationToken)) - { - // They have an expression body. Create a diagnostic to convert it to a block - // if they don't want expression bodies for this member. - var location = GetDiagnosticLocation(declaration); - - var properties = ImmutableDictionary.Empty; - var additionalLocations = ImmutableArray.Create(declaration.GetLocation()); - return DiagnosticHelper.Create( - CreateDescriptorWithId(UseBlockBodyTitle, UseBlockBodyTitle), - location, option.Notification.Severity, additionalLocations, properties); - } - - return null; - } - - private static Location GetDiagnosticLocation(LambdaExpressionSyntax declaration) - => Location.Create(declaration.SyntaxTree, - TextSpan.FromBounds(declaration.SpanStart, declaration.ArrowToken.Span.End)); - } -} diff --git a/src/Features/CSharp/Portable/UseExpressionBodyForLambda/UseExpressionBodyForLambdaCodeStyleProvider_Fixing.cs b/src/Features/CSharp/Portable/UseExpressionBodyForLambda/UseExpressionBodyForLambdaCodeStyleProvider_Fixing.cs deleted file mode 100644 index 9f451b3cb3d49..0000000000000 --- a/src/Features/CSharp/Portable/UseExpressionBodyForLambda/UseExpressionBodyForLambdaCodeStyleProvider_Fixing.cs +++ /dev/null @@ -1,56 +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.Collections.Immutable; -using System.Threading; -using System.Threading.Tasks; -using Microsoft.CodeAnalysis.CodeActions; -using Microsoft.CodeAnalysis.CSharp.Syntax; -using Microsoft.CodeAnalysis.Editing; -using Microsoft.CodeAnalysis.Shared.Extensions; - -namespace Microsoft.CodeAnalysis.CSharp.UseExpressionBodyForLambda -{ - // Code for the CodeFixProvider ("Fixing") portion of the feature. - - internal partial class UseExpressionBodyForLambdaCodeStyleProvider - { - protected override Task> ComputeCodeActionsAsync(Document document, Diagnostic diagnostic, CancellationToken cancellationToken) - { - var title = diagnostic.GetMessage(); - var codeAction = CodeAction.Create( - title, - c => FixWithSyntaxEditorAsync(document, diagnostic, c), - title); - - return Task.FromResult(ImmutableArray.Create(codeAction)); - } - - protected override async Task FixAllAsync( - Document document, ImmutableArray diagnostics, - SyntaxEditor editor, CancellationToken cancellationToken) - { - var semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false); - foreach (var diagnostic in diagnostics) - { - cancellationToken.ThrowIfCancellationRequested(); - AddEdits(editor, semanticModel, diagnostic, cancellationToken); - } - } - - private static void AddEdits( - SyntaxEditor editor, SemanticModel semanticModel, - Diagnostic diagnostic, CancellationToken cancellationToken) - { - var declarationLocation = diagnostic.AdditionalLocations[0]; - var originalDeclaration = (LambdaExpressionSyntax)declarationLocation.FindNode(getInnermostNodeForTie: true, cancellationToken); - - editor.ReplaceNode( - originalDeclaration, - (current, _) => Update(semanticModel, originalDeclaration, (LambdaExpressionSyntax)current)); - } - } -} diff --git a/src/Features/CSharp/Portable/UseLocalFunction/CSharpUseLocalFunctionCodeFixProvider.cs b/src/Features/CSharp/Portable/UseLocalFunction/CSharpUseLocalFunctionCodeFixProvider.cs index 3001b9e3aecfc..0e819685621d4 100644 --- a/src/Features/CSharp/Portable/UseLocalFunction/CSharpUseLocalFunctionCodeFixProvider.cs +++ b/src/Features/CSharp/Portable/UseLocalFunction/CSharpUseLocalFunctionCodeFixProvider.cs @@ -111,7 +111,7 @@ protected override async Task FixAllAsync( var currentAnonymousFunction = currentRoot.GetCurrentNode(anonymousFunction); currentRoot = ReplaceAnonymousWithLocalFunction( - document.Project.Solution.Workspace.Services, currentRoot, + document.Project.Solution.Services, currentRoot, currentLocalDeclaration, currentAnonymousFunction, delegateType.DelegateInvokeMethod, parameterList, makeStatic); @@ -155,7 +155,7 @@ private static bool MakeStatic( } private static SyntaxNode ReplaceAnonymousWithLocalFunction( - HostWorkspaceServices services, SyntaxNode currentRoot, + SolutionServices services, SyntaxNode currentRoot, LocalDeclarationStatementSyntax localDeclaration, AnonymousFunctionExpressionSyntax anonymousFunction, IMethodSymbol delegateMethod, ParameterListSyntax parameterList, bool makeStatic) { diff --git a/src/Features/CSharp/Portable/UsePatternMatching/CSharpIsAndCastCheckWithoutNameDiagnosticAnalyzer.cs b/src/Features/CSharp/Portable/UsePatternMatching/CSharpIsAndCastCheckWithoutNameDiagnosticAnalyzer.cs index 80b25c4018b50..f08d57a546ac3 100644 --- a/src/Features/CSharp/Portable/UsePatternMatching/CSharpIsAndCastCheckWithoutNameDiagnosticAnalyzer.cs +++ b/src/Features/CSharp/Portable/UsePatternMatching/CSharpIsAndCastCheckWithoutNameDiagnosticAnalyzer.cs @@ -15,7 +15,7 @@ using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.Editing; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Shared.Utilities; using Roslyn.Utilities; @@ -44,7 +44,6 @@ public CSharpIsAndCastCheckWithoutNameDiagnosticAnalyzer() : base(IDEDiagnosticIds.InlineIsTypeWithoutNameCheckDiagnosticsId, EnforceOnBuildValues.InlineIsTypeWithoutName, CSharpCodeStyleOptions.PreferPatternMatchingOverIsWithCastCheck, - LanguageNames.CSharp, new LocalizableResourceString( nameof(CSharpAnalyzersResources.Use_pattern_matching), CSharpAnalyzersResources.ResourceManager, typeof(CSharpAnalyzersResources))) { diff --git a/src/Features/CSharp/Portable/Wrapping/BinaryExpression/CSharpBinaryExpressionWrapper.cs b/src/Features/CSharp/Portable/Wrapping/BinaryExpression/CSharpBinaryExpressionWrapper.cs index 0326e15104a2e..c8c321d4b6400 100644 --- a/src/Features/CSharp/Portable/Wrapping/BinaryExpression/CSharpBinaryExpressionWrapper.cs +++ b/src/Features/CSharp/Portable/Wrapping/BinaryExpression/CSharpBinaryExpressionWrapper.cs @@ -5,7 +5,7 @@ #nullable disable using Microsoft.CodeAnalysis.CSharp.Indentation; -using Microsoft.CodeAnalysis.CSharp.LanguageServices; +using Microsoft.CodeAnalysis.CSharp.LanguageService; using Microsoft.CodeAnalysis.CSharp.Precedence; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Wrapping.BinaryExpression; diff --git a/src/Features/CSharp/Portable/Wrapping/ChainedExpression/CSharpChainedExpressionWrapper.cs b/src/Features/CSharp/Portable/Wrapping/ChainedExpression/CSharpChainedExpressionWrapper.cs index 0e442533fc274..15f4b854f774f 100644 --- a/src/Features/CSharp/Portable/Wrapping/ChainedExpression/CSharpChainedExpressionWrapper.cs +++ b/src/Features/CSharp/Portable/Wrapping/ChainedExpression/CSharpChainedExpressionWrapper.cs @@ -5,7 +5,7 @@ #nullable disable using Microsoft.CodeAnalysis.CSharp.Indentation; -using Microsoft.CodeAnalysis.CSharp.LanguageServices; +using Microsoft.CodeAnalysis.CSharp.LanguageService; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Wrapping.ChainedExpression; diff --git a/src/Features/CSharp/Portable/Wrapping/SeparatedSyntaxList/CSharpArgumentWrapper.cs b/src/Features/CSharp/Portable/Wrapping/SeparatedSyntaxList/CSharpArgumentWrapper.cs index bd3dd28d03636..2401cb1decb3d 100644 --- a/src/Features/CSharp/Portable/Wrapping/SeparatedSyntaxList/CSharpArgumentWrapper.cs +++ b/src/Features/CSharp/Portable/Wrapping/SeparatedSyntaxList/CSharpArgumentWrapper.cs @@ -3,7 +3,7 @@ // See the LICENSE file in the project root for more information. using System.Linq; -using Microsoft.CodeAnalysis.CSharp.LanguageServices; +using Microsoft.CodeAnalysis.CSharp.LanguageService; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Shared.Extensions; diff --git a/src/Features/Core/Portable/AddAnonymousTypeMemberName/AbstractAddAnonymousTypeMemberNameCodeFixProvider.cs b/src/Features/Core/Portable/AddAnonymousTypeMemberName/AbstractAddAnonymousTypeMemberNameCodeFixProvider.cs index bb4a326124f06..9ae543b0f0ff2 100644 --- a/src/Features/Core/Portable/AddAnonymousTypeMemberName/AbstractAddAnonymousTypeMemberNameCodeFixProvider.cs +++ b/src/Features/Core/Portable/AddAnonymousTypeMemberName/AbstractAddAnonymousTypeMemberNameCodeFixProvider.cs @@ -10,7 +10,7 @@ using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeFixes; using Microsoft.CodeAnalysis.Editing; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Shared.Utilities; diff --git a/src/Features/Core/Portable/AddConstructorParametersFromMembers/AddConstructorParametersFromMembersCodeRefactoringProvider.AddConstructorParametersCodeAction.cs b/src/Features/Core/Portable/AddConstructorParametersFromMembers/AddConstructorParametersFromMembersCodeRefactoringProvider.AddConstructorParametersCodeAction.cs index 156832a8177f0..0db954a1bf30e 100644 --- a/src/Features/Core/Portable/AddConstructorParametersFromMembers/AddConstructorParametersFromMembersCodeRefactoringProvider.AddConstructorParametersCodeAction.cs +++ b/src/Features/Core/Portable/AddConstructorParametersFromMembers/AddConstructorParametersFromMembersCodeRefactoringProvider.AddConstructorParametersCodeAction.cs @@ -11,7 +11,7 @@ using Microsoft.CodeAnalysis.CodeGeneration; using Microsoft.CodeAnalysis.Editing; using Microsoft.CodeAnalysis.Formatting; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Shared.Extensions; using Roslyn.Utilities; @@ -52,7 +52,7 @@ public AddConstructorParametersCodeAction( protected override Task GetChangedSolutionAsync(CancellationToken cancellationToken) { - var services = _document.Project.Solution.Workspace.Services; + var services = _document.Project.Solution.Services; var declarationService = _document.GetRequiredLanguageService(); var constructor = declarationService.GetDeclarations( _constructorCandidate.Constructor).Select(r => r.GetSyntax(cancellationToken)).First(); diff --git a/src/Features/Core/Portable/AddConstructorParametersFromMembers/AddConstructorParametersFromMembersCodeRefactoringProvider.cs b/src/Features/Core/Portable/AddConstructorParametersFromMembers/AddConstructorParametersFromMembersCodeRefactoringProvider.cs index fdca6a31fbaf6..7a4838110c5b1 100644 --- a/src/Features/Core/Portable/AddConstructorParametersFromMembers/AddConstructorParametersFromMembersCodeRefactoringProvider.cs +++ b/src/Features/Core/Portable/AddConstructorParametersFromMembers/AddConstructorParametersFromMembersCodeRefactoringProvider.cs @@ -39,7 +39,7 @@ public AddConstructorParametersFromMembersCodeRefactoringProvider() public override async Task ComputeRefactoringsAsync(CodeRefactoringContext context) { var (document, textSpan, cancellationToken) = context; - if (document.Project.Solution.Workspace.Kind == WorkspaceKind.MiscellaneousFiles) + if (document.Project.Solution.WorkspaceKind == WorkspaceKind.MiscellaneousFiles) { return; } diff --git a/src/Features/Core/Portable/AddDebuggerDisplay/AbstractAddDebuggerDisplayCodeRefactoringProvider.cs b/src/Features/Core/Portable/AddDebuggerDisplay/AbstractAddDebuggerDisplayCodeRefactoringProvider.cs index e1b5b97caebf4..9a34c26ca8164 100644 --- a/src/Features/Core/Portable/AddDebuggerDisplay/AbstractAddDebuggerDisplayCodeRefactoringProvider.cs +++ b/src/Features/Core/Portable/AddDebuggerDisplay/AbstractAddDebuggerDisplayCodeRefactoringProvider.cs @@ -115,7 +115,7 @@ private async Task ApplyAsync(Document document, TTypeDeclarationSynta var syntaxRoot = await document.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false); var semanticModel = await document.GetRequiredSemanticModelAsync(cancellationToken).ConfigureAwait(false); - var editor = new SyntaxEditor(syntaxRoot, document.Project.Solution.Workspace.Services); + var editor = new SyntaxEditor(syntaxRoot, document.Project.Solution.Services); var generator = editor.Generator; SyntaxNode attributeArgument; diff --git a/src/Features/Core/Portable/AddFileBanner/AbstractAddFileBannerCodeRefactoringProvider.cs b/src/Features/Core/Portable/AddFileBanner/AbstractAddFileBannerCodeRefactoringProvider.cs index 1698a948c4ff0..6bb222cd0e377 100644 --- a/src/Features/Core/Portable/AddFileBanner/AbstractAddFileBannerCodeRefactoringProvider.cs +++ b/src/Features/Core/Portable/AddFileBanner/AbstractAddFileBannerCodeRefactoringProvider.cs @@ -15,7 +15,7 @@ using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.Editing; using Microsoft.CodeAnalysis.Formatting; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Shared.Utilities; diff --git a/src/Features/Core/Portable/AddFileBanner/AbstractAddFileBannerNewDocumentFormattingProvider.cs b/src/Features/Core/Portable/AddFileBanner/AbstractAddFileBannerNewDocumentFormattingProvider.cs index f431af511fc40..5780caf049b2f 100644 --- a/src/Features/Core/Portable/AddFileBanner/AbstractAddFileBannerNewDocumentFormattingProvider.cs +++ b/src/Features/Core/Portable/AddFileBanner/AbstractAddFileBannerNewDocumentFormattingProvider.cs @@ -9,7 +9,7 @@ using Microsoft.CodeAnalysis.Editing; using Microsoft.CodeAnalysis.FileHeaders; using Microsoft.CodeAnalysis.Formatting; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Shared.Extensions; namespace Microsoft.CodeAnalysis.AddFileBanner diff --git a/src/Features/Core/Portable/AddImport/AbstractAddImportCodeFixProvider.cs b/src/Features/Core/Portable/AddImport/AbstractAddImportCodeFixProvider.cs index 50387d3554821..0a1c7bdd01077 100644 --- a/src/Features/Core/Portable/AddImport/AbstractAddImportCodeFixProvider.cs +++ b/src/Features/Core/Portable/AddImport/AbstractAddImportCodeFixProvider.cs @@ -54,9 +54,9 @@ public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context) var diagnostics = context.Diagnostics; var addImportService = document.GetRequiredLanguageService(); - var services = document.Project.Solution.Workspace.Services; + var services = document.Project.Solution.Services; - var codeActionOptions = context.Options.GetOptions(document.Project.LanguageServices); + var codeActionOptions = context.Options.GetOptions(document.Project.Services); var searchOptions = codeActionOptions.SearchOptions; var symbolSearchService = _symbolSearchService ?? services.GetRequiredService(); diff --git a/src/Features/Core/Portable/AddImport/AbstractAddImportFeatureService.cs b/src/Features/Core/Portable/AddImport/AbstractAddImportFeatureService.cs index 9da0f2eff27c9..607e86618fe63 100644 --- a/src/Features/Core/Portable/AddImport/AbstractAddImportFeatureService.cs +++ b/src/Features/Core/Portable/AddImport/AbstractAddImportFeatureService.cs @@ -13,7 +13,7 @@ using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.Host; using Microsoft.CodeAnalysis.Internal.Log; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Packaging; using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Options; @@ -154,7 +154,7 @@ private async Task> FindResultsAsync( } private static bool IsHostOrRemoteWorkspace(Project project) - => project.Solution.Workspace.Kind is WorkspaceKind.Host or WorkspaceKind.RemoteWorkspace; + => project.Solution.WorkspaceKind is WorkspaceKind.Host or WorkspaceKind.RemoteWorkspace; private async Task> FindResultsAsync( ConcurrentDictionary> projectToAssembly, @@ -395,7 +395,7 @@ static bool ContainsPathComponent(PortableExecutableReference reference, string /// private static Compilation CreateCompilation(Project project, PortableExecutableReference reference) { - var compilationService = project.LanguageServices.GetRequiredService(); + var compilationService = project.Services.GetRequiredService(); var compilation = compilationService.CreateCompilation("TempAssembly", compilationService.GetDefaultCompilationOptions()); return compilation.WithReferences(reference); } @@ -595,7 +595,7 @@ public ImmutableArray GetCodeActionsForFixes( AddImportFixKind.ProjectSymbol => new ProjectSymbolReferenceCodeAction(document, fixData), AddImportFixKind.MetadataSymbol => new MetadataSymbolReferenceCodeAction(document, fixData), AddImportFixKind.ReferenceAssemblySymbol => new AssemblyReferenceCodeAction(document, fixData), - AddImportFixKind.PackageSymbol => installerService?.IsInstalled(document.Project.Solution.Workspace, document.Project.Id, fixData.PackageName) == false + AddImportFixKind.PackageSymbol => installerService?.IsInstalled(document.Project.Id, fixData.PackageName) == false ? new ParentInstallPackageCodeAction(document, fixData, installerService) : null, _ => throw ExceptionUtilities.Unreachable, diff --git a/src/Features/Core/Portable/AddImport/CodeActions/AssemblyReferenceCodeAction.cs b/src/Features/Core/Portable/AddImport/CodeActions/AssemblyReferenceCodeAction.cs index a31b78f31ccbc..ca2b0f94a064c 100644 --- a/src/Features/Core/Portable/AddImport/CodeActions/AssemblyReferenceCodeAction.cs +++ b/src/Features/Core/Portable/AddImport/CodeActions/AssemblyReferenceCodeAction.cs @@ -79,13 +79,14 @@ public override void Apply(Workspace workspace, CancellationToken cancellationTo operation.Apply(workspace, cancellationToken); } - internal override Task TryApplyAsync(Workspace workspace, IProgressTracker progressTracker, CancellationToken cancellationToken) + internal override Task TryApplyAsync( + Workspace workspace, Solution originalSolution, IProgressTracker progressTracker, CancellationToken cancellationToken) { var operation = GetApplyChangesOperation(workspace); if (operation is null) return SpecializedTasks.False; - return operation.TryApplyAsync(workspace, progressTracker, cancellationToken); + return operation.TryApplyAsync(workspace, originalSolution, progressTracker, cancellationToken); } private ApplyChangesOperation? GetApplyChangesOperation(Workspace workspace) diff --git a/src/Features/Core/Portable/AddImport/CodeActions/InstallPackageAndAddImportCodeAction.cs b/src/Features/Core/Portable/AddImport/CodeActions/InstallPackageAndAddImportCodeAction.cs index b87c15ce4b770..4ba21c98e321a 100644 --- a/src/Features/Core/Portable/AddImport/CodeActions/InstallPackageAndAddImportCodeAction.cs +++ b/src/Features/Core/Portable/AddImport/CodeActions/InstallPackageAndAddImportCodeAction.cs @@ -113,7 +113,8 @@ public InstallPackageAndAddImportOperation( internal override bool ApplyDuringTests => _installPackageOperation.ApplyDuringTests; public override string Title => _installPackageOperation.Title; - internal override async Task TryApplyAsync(Workspace workspace, IProgressTracker progressTracker, CancellationToken cancellationToken) + internal override async Task TryApplyAsync( + Workspace workspace, Solution originalSolution, IProgressTracker progressTracker, CancellationToken cancellationToken) { var newSolution = workspace.CurrentSolution.WithDocumentText( _changedDocumentId, _newText); @@ -121,7 +122,7 @@ internal override async Task TryApplyAsync(Workspace workspace, IProgressT // First make the changes to add the import to the document. if (workspace.TryApplyChanges(newSolution, progressTracker)) { - if (await _installPackageOperation.TryApplyAsync(workspace, progressTracker, cancellationToken).ConfigureAwait(true)) + if (await _installPackageOperation.TryApplyAsync(workspace, originalSolution, progressTracker, cancellationToken).ConfigureAwait(true)) { return true; } diff --git a/src/Features/Core/Portable/AddImport/CodeActions/ProjectSymbolReferenceCodeAction.cs b/src/Features/Core/Portable/AddImport/CodeActions/ProjectSymbolReferenceCodeAction.cs index bd97d46177c1b..05f98f38e3083 100644 --- a/src/Features/Core/Portable/AddImport/CodeActions/ProjectSymbolReferenceCodeAction.cs +++ b/src/Features/Core/Portable/AddImport/CodeActions/ProjectSymbolReferenceCodeAction.cs @@ -71,12 +71,13 @@ public override void Apply(Workspace workspace, CancellationToken cancellationTo _applyOperation.Apply(workspace, cancellationToken); } - internal override Task TryApplyAsync(Workspace workspace, IProgressTracker progressTracker, CancellationToken cancellationToken) + internal override Task TryApplyAsync( + Workspace workspace, Solution originalSolution, IProgressTracker progressTracker, CancellationToken cancellationToken) { if (!CanApply(workspace)) return SpecializedTasks.False; - return _applyOperation.TryApplyAsync(workspace, progressTracker, cancellationToken); + return _applyOperation.TryApplyAsync(workspace, originalSolution, progressTracker, cancellationToken); } private bool CanApply(Workspace workspace) diff --git a/src/Features/Core/Portable/AddImport/SearchScopes/MetadataSymbolsSearchScope.cs b/src/Features/Core/Portable/AddImport/SearchScopes/MetadataSymbolsSearchScope.cs index 828729c699553..06a3385c7b41f 100644 --- a/src/Features/Core/Portable/AddImport/SearchScopes/MetadataSymbolsSearchScope.cs +++ b/src/Features/Core/Portable/AddImport/SearchScopes/MetadataSymbolsSearchScope.cs @@ -49,16 +49,13 @@ public override SymbolReference CreateReference(SymbolResult searchResult) protected override async Task> FindDeclarationsAsync( SymbolFilter filter, SearchQuery searchQuery) { - var service = _solution.Workspace.Services.GetService(); - var info = await service.TryGetMetadataSymbolTreeInfoAsync(_solution, _metadataReference, CancellationToken).ConfigureAwait(false); + var service = _solution.Services.GetService(); + var info = await service.TryGetPotentiallyStaleMetadataSymbolTreeInfoAsync(_solution, _metadataReference, CancellationToken).ConfigureAwait(false); if (info == null) - { return ImmutableArray.Empty; - } var declarations = await info.FindAsync( - searchQuery, _assembly, - filter, CancellationToken).ConfigureAwait(false); + searchQuery, _assembly, filter, CancellationToken).ConfigureAwait(false); return declarations; } diff --git a/src/Features/Core/Portable/AddImport/SearchScopes/SourceSymbolsProjectSearchScope.cs b/src/Features/Core/Portable/AddImport/SearchScopes/SourceSymbolsProjectSearchScope.cs index d7f47683067cc..defb7b473b427 100644 --- a/src/Features/Core/Portable/AddImport/SearchScopes/SourceSymbolsProjectSearchScope.cs +++ b/src/Features/Core/Portable/AddImport/SearchScopes/SourceSymbolsProjectSearchScope.cs @@ -36,8 +36,8 @@ public SourceSymbolsProjectSearchScope( protected override async Task> FindDeclarationsAsync( SymbolFilter filter, SearchQuery searchQuery) { - var service = _project.Solution.Workspace.Services.GetService(); - var info = await service.TryGetSourceSymbolTreeInfoAsync(_project, CancellationToken).ConfigureAwait(false); + var service = _project.Solution.Services.GetService(); + var info = await service.TryGetPotentiallyStaleSourceSymbolTreeInfoAsync(_project, CancellationToken).ConfigureAwait(false); if (info == null) { // Looks like there was nothing in the cache. Return no results for now. diff --git a/src/Features/Core/Portable/AddImport/SymbolReferenceFinder.cs b/src/Features/Core/Portable/AddImport/SymbolReferenceFinder.cs index a4e5a6bcae3ae..33aba1ead62cf 100644 --- a/src/Features/Core/Portable/AddImport/SymbolReferenceFinder.cs +++ b/src/Features/Core/Portable/AddImport/SymbolReferenceFinder.cs @@ -13,7 +13,7 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.Completion; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Packaging; using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Shared.Extensions; diff --git a/src/Features/Core/Portable/AddImport/SymbolResult.cs b/src/Features/Core/Portable/AddImport/SymbolResult.cs index 0d61a8eae8298..f7b717b2833aa 100644 --- a/src/Features/Core/Portable/AddImport/SymbolResult.cs +++ b/src/Features/Core/Portable/AddImport/SymbolResult.cs @@ -5,7 +5,7 @@ using System; using System.Collections.Generic; using System.Diagnostics; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Shared.Extensions; namespace Microsoft.CodeAnalysis.AddImport diff --git a/src/Features/Core/Portable/AddMissingReference/AddMissingReferenceCodeAction.cs b/src/Features/Core/Portable/AddMissingReference/AddMissingReferenceCodeAction.cs index 713d11a80103f..c5c56dc004e12 100644 --- a/src/Features/Core/Portable/AddMissingReference/AddMissingReferenceCodeAction.cs +++ b/src/Features/Core/Portable/AddMissingReference/AddMissingReferenceCodeAction.cs @@ -85,7 +85,7 @@ protected override Task> ComputeOperationsAsync else { // We didn't have any project, so we need to try adding a metadata reference - var factoryService = _project.Solution.Workspace.Services.GetRequiredService(); + var factoryService = _project.Solution.Services.GetRequiredService(); var operation = factoryService.CreateAddMetadataReferenceOperation(_project.Id, _missingAssemblyIdentity); return Task.FromResult(SpecializedCollections.SingletonEnumerable(operation)); } diff --git a/src/Features/Core/Portable/AddPackage/AbstractAddPackageCodeFixProvider.cs b/src/Features/Core/Portable/AddPackage/AbstractAddPackageCodeFixProvider.cs index 25151d245702f..ea89224f80892 100644 --- a/src/Features/Core/Portable/AddPackage/AbstractAddPackageCodeFixProvider.cs +++ b/src/Features/Core/Portable/AddPackage/AbstractAddPackageCodeFixProvider.cs @@ -44,7 +44,7 @@ protected async Task> GetAddPackagesCodeActionsAsync( var document = context.Document; var cancellationToken = context.CancellationToken; - var workspaceServices = document.Project.Solution.Workspace.Services; + var workspaceServices = document.Project.Solution.Services; var symbolSearchService = _symbolSearchService ?? workspaceServices.GetService(); var installerService = _packageInstallerService ?? workspaceServices.GetService(); @@ -52,7 +52,7 @@ protected async Task> GetAddPackagesCodeActionsAsync( var codeActions = ArrayBuilder.GetInstance(); if (symbolSearchService != null && installerService != null && - context.Options.GetOptions(document.Project.LanguageServices).SearchOptions.SearchNuGetPackages && + context.Options.GetOptions(document.Project.Services).SearchOptions.SearchNuGetPackages && installerService.IsEnabled(document.Project.Id)) { var packageSources = PackageSourceHelper.GetPackageSources(installerService.TryGetPackageSources()); diff --git a/src/Features/Core/Portable/AddPackage/InstallPackageDirectlyCodeActionOperation.cs b/src/Features/Core/Portable/AddPackage/InstallPackageDirectlyCodeActionOperation.cs index b801a1082739b..a0df4193efe6d 100644 --- a/src/Features/Core/Portable/AddPackage/InstallPackageDirectlyCodeActionOperation.cs +++ b/src/Features/Core/Portable/AddPackage/InstallPackageDirectlyCodeActionOperation.cs @@ -70,7 +70,7 @@ public InstallPackageDirectlyCodeActionOperation( internal override bool ApplyDuringTests => true; internal override Task TryApplyAsync( - Workspace workspace, IProgressTracker progressTracker, CancellationToken cancellationToken) + Workspace workspace, Solution originalSolution, IProgressTracker progressTracker, CancellationToken cancellationToken) { return _installerService.TryInstallPackageAsync( workspace, _document.Id, _source, _packageName, diff --git a/src/Features/Core/Portable/AddParameter/AbstractAddParameterCodeFixProvider.cs b/src/Features/Core/Portable/AddParameter/AbstractAddParameterCodeFixProvider.cs index 9226a4b53d9b9..e8ad08e461af2 100644 --- a/src/Features/Core/Portable/AddParameter/AbstractAddParameterCodeFixProvider.cs +++ b/src/Features/Core/Portable/AddParameter/AbstractAddParameterCodeFixProvider.cs @@ -11,7 +11,7 @@ using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeFixes; using Microsoft.CodeAnalysis.Formatting; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Shared.Extensions; using Roslyn.Utilities; @@ -244,7 +244,7 @@ private void RegisterFixForMethodOverloads( ImmutableArray NestByOverload() { - using var builderDisposer = ArrayBuilder.GetInstance(codeFixData.Length, out var builder); + using var _ = ArrayBuilder.GetInstance(codeFixData.Length, out var builder); foreach (var data in codeFixData) { // We create the mandatory data.CreateChangedSolutionNonCascading fix first. @@ -275,12 +275,12 @@ ImmutableArray NestByOverload() builder.Add(codeAction); } - return builder.ToImmutable(); + return builder.ToImmutableAndClear(); } ImmutableArray NestByCascading() { - using var builderDisposer = ArrayBuilder.GetInstance(capacity: 2, out var builder); + using var _ = ArrayBuilder.GetInstance(capacity: 2, out var builder); var nonCascadingActions = codeFixData.SelectAsArray(data => { @@ -320,7 +320,7 @@ private ImmutableArray PrepareCreationOfCodeActions( SeparatedSyntaxList arguments, ImmutableArray> methodsAndArgumentsToAdd) { - using var builderDisposer = ArrayBuilder.GetInstance(methodsAndArgumentsToAdd.Length, out var builder); + using var _ = ArrayBuilder.GetInstance(methodsAndArgumentsToAdd.Length, out var builder); // Order by the furthest argument index to the nearest argument index. The ones with // larger argument indexes mean that we matched more earlier arguments (and thus are diff --git a/src/Features/Core/Portable/AddParameter/AddParameterService.cs b/src/Features/Core/Portable/AddParameter/AddParameterService.cs index cf8d27937fb09..450a2dddd07cf 100644 --- a/src/Features/Core/Portable/AddParameter/AddParameterService.cs +++ b/src/Features/Core/Portable/AddParameter/AddParameterService.cs @@ -11,7 +11,7 @@ using Microsoft.CodeAnalysis.Editing; using Microsoft.CodeAnalysis.FindSymbols; using Microsoft.CodeAnalysis.Formatting; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Shared.Utilities; @@ -99,7 +99,7 @@ public static async Task AddParameterAsync( var document = documentLookup.Key; var syntaxFacts = document.GetRequiredLanguageService(); var syntaxRoot = await document.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false); - var editor = new SyntaxEditor(syntaxRoot, solution.Workspace.Services); + var editor = new SyntaxEditor(syntaxRoot, solution.Services); var generator = editor.Generator; foreach (var methodDeclaration in documentLookup) { diff --git a/src/Features/Core/Portable/BraceCompletion/AbstractBraceCompletionService.cs b/src/Features/Core/Portable/BraceCompletion/AbstractBraceCompletionService.cs index bbc3470a36615..4ff9f3082fad9 100644 --- a/src/Features/Core/Portable/BraceCompletion/AbstractBraceCompletionService.cs +++ b/src/Features/Core/Portable/BraceCompletion/AbstractBraceCompletionService.cs @@ -3,10 +3,11 @@ // 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.Indentation; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Text; using Roslyn.Utilities; @@ -35,55 +36,46 @@ internal abstract class AbstractBraceCompletionService : IBraceCompletionService /// protected abstract bool IsValidClosingBraceToken(SyntaxToken token); - public abstract Task AllowOverTypeAsync(BraceCompletionContext braceCompletionContext, CancellationToken cancellationToken); + public abstract bool AllowOverType(BraceCompletionContext braceCompletionContext, CancellationToken cancellationToken); - public async Task GetBraceCompletionAsync(BraceCompletionContext braceCompletionContext, CancellationToken cancellationToken) + public Task HasBraceCompletionAsync(BraceCompletionContext context, Document document, CancellationToken cancellationToken) { - var closingPoint = braceCompletionContext.ClosingPoint; - if (closingPoint < 1) - return null; - - var openingPoint = braceCompletionContext.OpeningPoint; - var document = braceCompletionContext.Document; - - var sourceText = await document.GetTextAsync(cancellationToken).ConfigureAwait(false); - if (sourceText[openingPoint] != OpeningBrace) - return null; - - var root = await document.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false); - var token = root.FindToken(openingPoint, findInsideTrivia: true); - - if (NeedsSemantics) + if (!context.HasCompletionForOpeningBrace(OpeningBrace)) { - // Pass along a document with frozen partial semantics. Brace completion is a highly latency sensitive - // operation. We don't want to wait on things like source generators to figure things out. - var validOpeningPoint = await IsValidOpenBraceTokenAtPositionAsync( - document.WithFrozenPartialSemantics(cancellationToken), token, openingPoint, cancellationToken).ConfigureAwait(false); - if (!validOpeningPoint) - return null; + return Task.FromResult(false); } - else + + var openingToken = context.GetOpeningToken(); + if (!NeedsSemantics) { - var validOpeningPoint = IsValidOpenBraceTokenAtPosition(sourceText, token, openingPoint); - if (!validOpeningPoint) - return null; + return Task.FromResult(IsValidOpenBraceTokenAtPosition(context.Document.Text, openingToken, context.OpeningPoint)); } + // Pass along a document with frozen partial semantics. Brace completion is a highly latency sensitive + // operation. We don't want to wait on things like source generators to figure things out. + return IsValidOpenBraceTokenAtPositionAsync(document.WithFrozenPartialSemantics(cancellationToken), openingToken, context.OpeningPoint, cancellationToken); + } + + public BraceCompletionResult GetBraceCompletion(BraceCompletionContext context) + { + Debug.Assert(context.HasCompletionForOpeningBrace(OpeningBrace)); + + var closingPoint = context.ClosingPoint; var braceTextEdit = new TextChange(TextSpan.FromBounds(closingPoint, closingPoint), ClosingBrace.ToString()); // The caret location should be in between the braces. - var originalOpeningLinePosition = sourceText.Lines.GetLinePosition(openingPoint); + var originalOpeningLinePosition = context.Document.Text.Lines.GetLinePosition(context.OpeningPoint); var caretLocation = new LinePosition(originalOpeningLinePosition.Line, originalOpeningLinePosition.Character + 1); return new BraceCompletionResult(ImmutableArray.Create(braceTextEdit), caretLocation); } - public virtual Task GetTextChangesAfterCompletionAsync(BraceCompletionContext braceCompletionContext, IndentationOptions options, CancellationToken cancellationToken) - => SpecializedTasks.Default(); + public virtual BraceCompletionResult? GetTextChangesAfterCompletion(BraceCompletionContext braceCompletionContext, IndentationOptions options, CancellationToken cancellationToken) + => null; - public virtual Task GetTextChangeAfterReturnAsync(BraceCompletionContext braceCompletionContext, IndentationOptions options, CancellationToken cancellationToken) - => SpecializedTasks.Default(); + public virtual BraceCompletionResult? GetTextChangeAfterReturn(BraceCompletionContext braceCompletionContext, IndentationOptions options, CancellationToken cancellationToken) + => null; - public virtual async Task CanProvideBraceCompletionAsync(char brace, int openingPosition, Document document, CancellationToken cancellationToken) + public virtual bool CanProvideBraceCompletion(char brace, int openingPosition, ParsedDocument document, CancellationToken cancellationToken) { if (OpeningBrace != brace) { @@ -91,17 +83,15 @@ public virtual async Task CanProvideBraceCompletionAsync(char brace, int o } // check that the user is not typing in a string literal or comment - var tree = await document.GetRequiredSyntaxTreeAsync(cancellationToken).ConfigureAwait(false); - var syntaxFactsService = document.GetRequiredLanguageService(); + var syntaxFactsService = document.LanguageServices.GetRequiredService(); - return !syntaxFactsService.IsInNonUserCode(tree, openingPosition, cancellationToken); + return !syntaxFactsService.IsInNonUserCode(document.SyntaxTree, openingPosition, cancellationToken); } - public async Task GetCompletedBraceContextAsync(Document document, int caretLocation, CancellationToken cancellationToken) + public BraceCompletionContext? GetCompletedBraceContext(ParsedDocument document, int caretLocation) { - var root = await document.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false); - var leftToken = root.FindTokenOnLeftOfPosition(caretLocation); - var rightToken = root.FindTokenOnRightOfPosition(caretLocation); + var leftToken = document.Root.FindTokenOnLeftOfPosition(caretLocation); + var rightToken = document.Root.FindTokenOnRightOfPosition(caretLocation); if (IsValidOpeningBraceToken(leftToken) && IsValidClosingBraceToken(rightToken)) { @@ -114,7 +104,7 @@ public virtual async Task CanProvideBraceCompletionAsync(char brace, int o /// /// Only called if returns true; /// - protected virtual ValueTask IsValidOpenBraceTokenAtPositionAsync(Document document, SyntaxToken token, int position, CancellationToken cancellationToken) + protected virtual Task IsValidOpenBraceTokenAtPositionAsync(Document document, SyntaxToken token, int position, CancellationToken cancellationToken) { // Subclass should have overridden this. throw ExceptionUtilities.Unreachable; @@ -130,25 +120,25 @@ protected virtual bool IsValidOpenBraceTokenAtPosition(SourceText text, SyntaxTo /// /// Returns true when the current position is inside user code (e.g. not strings) and the closing token /// matches the expected closing token for this brace completion service. - /// Helper method used by implementations. + /// Helper method used by implementations. /// - protected async Task AllowOverTypeInUserCodeWithValidClosingTokenAsync(BraceCompletionContext context, CancellationToken cancellationToken) + protected bool AllowOverTypeInUserCodeWithValidClosingToken(BraceCompletionContext context, CancellationToken cancellationToken) { - var tree = await context.Document.GetRequiredSyntaxTreeAsync(cancellationToken).ConfigureAwait(false); - var syntaxFactsService = context.Document.GetRequiredLanguageService(); + var tree = context.Document.SyntaxTree; + var syntaxFactsService = context.Document.LanguageServices.GetRequiredService(); return !syntaxFactsService.IsInNonUserCode(tree, context.CaretLocation, cancellationToken) - && await CheckClosingTokenKindAsync(context.Document, context.ClosingPoint, cancellationToken).ConfigureAwait(false); + && CheckClosingTokenKind(context.Document, context.ClosingPoint); } /// /// Returns true when the closing token matches the expected closing token for this brace completion service. - /// Used by implementations + /// Used by implementations /// when the over type could be triggered from outside of user code (e.g. overtyping end quotes in a string). /// - protected Task AllowOverTypeWithValidClosingTokenAsync(BraceCompletionContext context, CancellationToken cancellationToken) + protected bool AllowOverTypeWithValidClosingToken(BraceCompletionContext context) { - return CheckClosingTokenKindAsync(context.Document, context.ClosingPoint, cancellationToken); + return CheckClosingTokenKind(context.Document, context.ClosingPoint); } protected static bool ParentIsSkippedTokensTriviaOrNull(ISyntaxFacts syntaxFacts, SyntaxToken token) @@ -157,10 +147,9 @@ protected static bool ParentIsSkippedTokensTriviaOrNull(ISyntaxFacts syntaxFacts /// /// Checks that the token at the closing position is a valid closing token. /// - private async Task CheckClosingTokenKindAsync(Document document, int closingPosition, CancellationToken cancellationToken) + private bool CheckClosingTokenKind(ParsedDocument document, int closingPosition) { - var root = await document.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false); - var closingToken = root.FindTokenFromEnd(closingPosition, includeZeroWidth: false, findInsideTrivia: true); + var closingToken = document.Root.FindTokenFromEnd(closingPosition, includeZeroWidth: false, findInsideTrivia: true); return IsValidClosingBraceToken(closingToken); } @@ -205,9 +194,8 @@ public static class SingleQuote /// escape a previously inserted opening brace. /// E.g. they are trying to type $"{{" /// - protected static async Task CouldEscapePreviousOpenBraceAsync(char openingBrace, int position, Document document, CancellationToken cancellationToken) + protected static bool CouldEscapePreviousOpenBrace(char openingBrace, int position, SourceText text) { - var text = await document.GetTextAsync(cancellationToken).ConfigureAwait(false); var index = position - 1; var openBraceCount = 0; while (index >= 0) diff --git a/src/Features/Core/Portable/BraceCompletion/IBraceCompletionService.cs b/src/Features/Core/Portable/BraceCompletion/IBraceCompletionService.cs index 0da69a7acabd7..8828c20ac76df 100644 --- a/src/Features/Core/Portable/BraceCompletion/IBraceCompletionService.cs +++ b/src/Features/Core/Portable/BraceCompletion/IBraceCompletionService.cs @@ -12,7 +12,7 @@ namespace Microsoft.CodeAnalysis.BraceCompletion { - internal interface IBraceCompletionService : ILanguageService + internal interface IBraceCompletionService { /// /// Checks if this brace completion service should be the service used to provide brace completions at @@ -30,40 +30,46 @@ internal interface IBraceCompletionService : ILanguageService /// /// The document to insert the brace at the position. /// A cancellation token. - Task CanProvideBraceCompletionAsync(char brace, int openingPosition, Document document, CancellationToken cancellationToken); + bool CanProvideBraceCompletion(char brace, int openingPosition, ParsedDocument document, CancellationToken cancellationToken); + + /// + /// True if is available in the given . + /// Completes synchronously unless the service needs Semantic Model to determine the brace completion result. + /// + Task HasBraceCompletionAsync(BraceCompletionContext context, Document document, CancellationToken cancellationToken); /// /// Returns the text change to add the closing brace given the context. /// - Task GetBraceCompletionAsync(BraceCompletionContext braceCompletionContext, CancellationToken cancellationToken); + BraceCompletionResult GetBraceCompletion(BraceCompletionContext braceCompletionContext); /// /// Returns any text changes that need to be made after adding the closing brace. /// /// - /// This cannot be merged with + /// This cannot be merged with /// as we need to swap the editor tracking mode of the closing point from positive to negative /// in BraceCompletionSessionProvider.BraceCompletionSession.Start after completing the brace and before /// doing any kind of formatting on it. So these must be two distinct steps until we fully move to LSP. /// - Task GetTextChangesAfterCompletionAsync(BraceCompletionContext braceCompletionContext, IndentationOptions options, CancellationToken cancellationToken); + BraceCompletionResult? GetTextChangesAfterCompletion(BraceCompletionContext braceCompletionContext, IndentationOptions options, CancellationToken cancellationToken); /// /// Get any text changes that should be applied after the enter key is typed inside a brace completion context. /// - Task GetTextChangeAfterReturnAsync(BraceCompletionContext braceCompletionContext, IndentationOptions options, CancellationToken cancellationToken); + BraceCompletionResult? GetTextChangeAfterReturn(BraceCompletionContext braceCompletionContext, IndentationOptions options, CancellationToken cancellationToken); /// /// Returns the brace completion context if the caret is located between an already completed /// set of braces with only whitespace in between. /// - Task GetCompletedBraceContextAsync(Document document, int caretLocation, CancellationToken cancellationToken); + BraceCompletionContext? GetCompletedBraceContext(ParsedDocument document, int caretLocation); /// /// Returns true if over typing should be allowed given the caret location and completed pair of braces. /// For example some providers allow over typing in non-user code and others do not. /// - Task AllowOverTypeAsync(BraceCompletionContext braceCompletionContext, CancellationToken cancellationToken); + bool AllowOverType(BraceCompletionContext braceCompletionContext, CancellationToken cancellationToken); } internal readonly struct BraceCompletionResult @@ -93,7 +99,7 @@ public BraceCompletionResult(ImmutableArray textChanges, LinePositio internal readonly struct BraceCompletionContext { - public Document Document { get; } + public ParsedDocument Document { get; } public int OpeningPoint { get; } @@ -101,12 +107,18 @@ internal readonly struct BraceCompletionContext public int CaretLocation { get; } - public BraceCompletionContext(Document document, int openingPoint, int closingPoint, int caretLocation) + public BraceCompletionContext(ParsedDocument document, int openingPoint, int closingPoint, int caretLocation) { Document = document; OpeningPoint = openingPoint; ClosingPoint = closingPoint; CaretLocation = caretLocation; } + + public bool HasCompletionForOpeningBrace(char openingBrace) + => ClosingPoint >= 1 && Document.Text[OpeningPoint] == openingBrace; + + public SyntaxToken GetOpeningToken() + => Document.Root.FindToken(OpeningPoint, findInsideTrivia: true); } } diff --git a/src/EditorFeatures/Core/BraceMatching/AbstractBraceMatcher.cs b/src/Features/Core/Portable/BraceMatching/AbstractBraceMatcher.cs similarity index 98% rename from src/EditorFeatures/Core/BraceMatching/AbstractBraceMatcher.cs rename to src/Features/Core/Portable/BraceMatching/AbstractBraceMatcher.cs index bc772f929b8dd..e56d1036d55b1 100644 --- a/src/EditorFeatures/Core/BraceMatching/AbstractBraceMatcher.cs +++ b/src/Features/Core/Portable/BraceMatching/AbstractBraceMatcher.cs @@ -8,7 +8,6 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.Editor; namespace Microsoft.CodeAnalysis.BraceMatching { diff --git a/src/EditorFeatures/Core/Extensibility/BraceMatching/AbstractDirectiveTriviaBraceMatcher.cs b/src/Features/Core/Portable/BraceMatching/AbstractDirectiveTriviaBraceMatcher.cs similarity index 98% rename from src/EditorFeatures/Core/Extensibility/BraceMatching/AbstractDirectiveTriviaBraceMatcher.cs rename to src/Features/Core/Portable/BraceMatching/AbstractDirectiveTriviaBraceMatcher.cs index 3cbbc7115f29c..f4aaf1e8d0f89 100644 --- a/src/EditorFeatures/Core/Extensibility/BraceMatching/AbstractDirectiveTriviaBraceMatcher.cs +++ b/src/Features/Core/Portable/BraceMatching/AbstractDirectiveTriviaBraceMatcher.cs @@ -9,7 +9,7 @@ using System.Threading.Tasks; using Microsoft.CodeAnalysis.Text; -namespace Microsoft.CodeAnalysis.Editor +namespace Microsoft.CodeAnalysis.BraceMatching { internal abstract class AbstractDirectiveTriviaBraceMatcher> _braceMatchers; diff --git a/src/EditorFeatures/Core/Extensibility/BraceMatching/ExportBraceMatcherAttribute.cs b/src/Features/Core/Portable/BraceMatching/ExportBraceMatcherAttribute.cs similarity index 79% rename from src/EditorFeatures/Core/Extensibility/BraceMatching/ExportBraceMatcherAttribute.cs rename to src/Features/Core/Portable/BraceMatching/ExportBraceMatcherAttribute.cs index a366f21a272fa..929f252ecca38 100644 --- a/src/EditorFeatures/Core/Extensibility/BraceMatching/ExportBraceMatcherAttribute.cs +++ b/src/Features/Core/Portable/BraceMatching/ExportBraceMatcherAttribute.cs @@ -5,13 +5,13 @@ #nullable disable using System; -using System.ComponentModel.Composition; +using System.Composition; -namespace Microsoft.CodeAnalysis.Editor +namespace Microsoft.CodeAnalysis.BraceMatching { [MetadataAttribute] [AttributeUsage(AttributeTargets.Class)] - internal class ExportBraceMatcherAttribute : ExportAttribute + internal sealed class ExportBraceMatcherAttribute : ExportAttribute { public string Language { get; } diff --git a/src/EditorFeatures/Core/BraceMatching/ExportEmbeddedLanguageBraceMatcherAttribute.cs b/src/Features/Core/Portable/BraceMatching/ExportEmbeddedLanguageBraceMatcherAttribute.cs similarity index 100% rename from src/EditorFeatures/Core/BraceMatching/ExportEmbeddedLanguageBraceMatcherAttribute.cs rename to src/Features/Core/Portable/BraceMatching/ExportEmbeddedLanguageBraceMatcherAttribute.cs diff --git a/src/EditorFeatures/Core/Extensibility/BraceMatching/IBraceMatcher.cs b/src/Features/Core/Portable/BraceMatching/IBraceMatcher.cs similarity index 97% rename from src/EditorFeatures/Core/Extensibility/BraceMatching/IBraceMatcher.cs rename to src/Features/Core/Portable/BraceMatching/IBraceMatcher.cs index 02d4e75a62db4..12342548bb04a 100644 --- a/src/EditorFeatures/Core/Extensibility/BraceMatching/IBraceMatcher.cs +++ b/src/Features/Core/Portable/BraceMatching/IBraceMatcher.cs @@ -5,7 +5,7 @@ using System.Threading; using System.Threading.Tasks; -namespace Microsoft.CodeAnalysis.Editor +namespace Microsoft.CodeAnalysis.BraceMatching { internal interface IBraceMatcher { diff --git a/src/EditorFeatures/Core/IBraceMatchingService.cs b/src/Features/Core/Portable/BraceMatching/IBraceMatchingService.cs similarity index 94% rename from src/EditorFeatures/Core/IBraceMatchingService.cs rename to src/Features/Core/Portable/BraceMatching/IBraceMatchingService.cs index 2098011c8b070..7008e97f1eade 100644 --- a/src/EditorFeatures/Core/IBraceMatchingService.cs +++ b/src/Features/Core/Portable/BraceMatching/IBraceMatchingService.cs @@ -7,7 +7,7 @@ using System.Threading.Tasks; using Microsoft.CodeAnalysis.Text; -namespace Microsoft.CodeAnalysis.Editor +namespace Microsoft.CodeAnalysis.BraceMatching { internal interface IBraceMatchingService { diff --git a/src/EditorFeatures/Core/Shared/Extensions/IBraceMatchingServiceExtensions.cs b/src/Features/Core/Portable/BraceMatching/IBraceMatchingServiceExtensions.cs similarity index 97% rename from src/EditorFeatures/Core/Shared/Extensions/IBraceMatchingServiceExtensions.cs rename to src/Features/Core/Portable/BraceMatching/IBraceMatchingServiceExtensions.cs index 752216cd48f85..12e991a789003 100644 --- a/src/EditorFeatures/Core/Shared/Extensions/IBraceMatchingServiceExtensions.cs +++ b/src/Features/Core/Portable/BraceMatching/IBraceMatchingServiceExtensions.cs @@ -6,7 +6,7 @@ using System.Threading.Tasks; using Microsoft.CodeAnalysis.Text; -namespace Microsoft.CodeAnalysis.Editor.Shared.Extensions +namespace Microsoft.CodeAnalysis.BraceMatching { internal static class IBraceMatchingServiceExtensions { diff --git a/src/EditorFeatures/Core/BraceMatching/IEmbeddedLanguageBraceMatcher.cs b/src/Features/Core/Portable/BraceMatching/IEmbeddedLanguageBraceMatcher.cs similarity index 94% rename from src/EditorFeatures/Core/BraceMatching/IEmbeddedLanguageBraceMatcher.cs rename to src/Features/Core/Portable/BraceMatching/IEmbeddedLanguageBraceMatcher.cs index 80d3b6bd74596..af52cbaa0c080 100644 --- a/src/EditorFeatures/Core/BraceMatching/IEmbeddedLanguageBraceMatcher.cs +++ b/src/Features/Core/Portable/BraceMatching/IEmbeddedLanguageBraceMatcher.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.EmbeddedLanguages; namespace Microsoft.CodeAnalysis.BraceMatching diff --git a/src/Features/Core/Portable/ChangeSignature/AbstractChangeSignatureService.cs b/src/Features/Core/Portable/ChangeSignature/AbstractChangeSignatureService.cs index 9f23f66e57ba0..7c0f511cb1d20 100644 --- a/src/Features/Core/Portable/ChangeSignature/AbstractChangeSignatureService.cs +++ b/src/Features/Core/Portable/ChangeSignature/AbstractChangeSignatureService.cs @@ -20,7 +20,7 @@ using Microsoft.CodeAnalysis.Formatting.Rules; using Microsoft.CodeAnalysis.Host; using Microsoft.CodeAnalysis.Internal.Log; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Recommendations; using Microsoft.CodeAnalysis.Shared.Extensions; @@ -215,7 +215,7 @@ async Task GetChangeSignatureResultAsync(ChangeSignatureA return null; } - var changeSignatureOptionsService = succeededContext.Solution.Workspace.Services.GetRequiredService(); + var changeSignatureOptionsService = succeededContext.Solution.Services.GetRequiredService(); return changeSignatureOptionsService.GetChangeSignatureOptions( succeededContext.Document, succeededContext.PositionForTypeBinding, succeededContext.Symbol, succeededContext.ParameterConfiguration); @@ -379,7 +379,7 @@ private static async Task> FindChangeSignatureR foreach (var docId in nodesToUpdate.Keys) { var doc = currentSolution.GetRequiredDocument(docId); - var updater = doc.Project.LanguageServices.GetRequiredService(); + var updater = doc.Project.Services.GetRequiredService(); var root = await doc.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); if (root is null) { @@ -405,7 +405,7 @@ private static async Task> FindChangeSignatureR var formattedRoot = Formatter.Format( newRoot, changeSignatureFormattingAnnotation, - doc.Project.Solution.Workspace.Services, + doc.Project.Solution.Services, options: formattingOptions, rules: GetFormattingRules(doc), cancellationToken: CancellationToken.None); @@ -427,7 +427,7 @@ private static async Task> FindChangeSignatureR } telemetryTimer.Stop(); - ChangeSignatureLogger.LogCommitInformation(telemetryNumberOfDeclarationsToUpdate, telemetryNumberOfReferencesToUpdate, (int)telemetryTimer.ElapsedMilliseconds); + ChangeSignatureLogger.LogCommitInformation(telemetryNumberOfDeclarationsToUpdate, telemetryNumberOfReferencesToUpdate, telemetryTimer.Elapsed); return (currentSolution, confirmationMessage); } diff --git a/src/Features/Core/Portable/ChangeSignature/ChangeSignatureCodeActionOperation.cs b/src/Features/Core/Portable/ChangeSignature/ChangeSignatureCodeActionOperation.cs index 56dd2cf72a0ba..7735857a43d9e 100644 --- a/src/Features/Core/Portable/ChangeSignature/ChangeSignatureCodeActionOperation.cs +++ b/src/Features/Core/Portable/ChangeSignature/ChangeSignatureCodeActionOperation.cs @@ -31,19 +31,16 @@ public ChangeSignatureCodeActionOperation(Solution changedSolution, string? conf internal override bool ApplyDuringTests => true; - public sealed override void Apply(Workspace workspace, CancellationToken cancellationToken) - => ApplyWorker(workspace, new ProgressTracker()); - /// /// Show the confirmation message, if available, before attempting to apply the changes. /// internal sealed override Task TryApplyAsync( - Workspace workspace, IProgressTracker progressTracker, CancellationToken cancellationToken) + Workspace workspace, Solution originalSolution, IProgressTracker progressTracker, CancellationToken cancellationToken) { - return ApplyWorker(workspace, progressTracker) ? SpecializedTasks.True : SpecializedTasks.False; + return ApplyWorker(workspace, originalSolution, progressTracker, cancellationToken) ? SpecializedTasks.True : SpecializedTasks.False; } - private bool ApplyWorker(Workspace workspace, IProgressTracker progressTracker) + private bool ApplyWorker(Workspace workspace, Solution originalSolution, IProgressTracker progressTracker, CancellationToken cancellationToken) { if (ConfirmationMessage != null) { @@ -54,7 +51,7 @@ private bool ApplyWorker(Workspace workspace, IProgressTracker progressTracker) } } - return workspace.TryApplyChanges(ChangedSolution, progressTracker); + return ApplyChangesOperation.ApplyOrMergeChanges(workspace, originalSolution, ChangedSolution, progressTracker, cancellationToken); } } } diff --git a/src/Features/Core/Portable/ChangeSignature/ChangeSignatureTelemetryLogger.cs b/src/Features/Core/Portable/ChangeSignature/ChangeSignatureTelemetryLogger.cs index 58c09b0537c93..b11f23925c330 100644 --- a/src/Features/Core/Portable/ChangeSignature/ChangeSignatureTelemetryLogger.cs +++ b/src/Features/Core/Portable/ChangeSignature/ChangeSignatureTelemetryLogger.cs @@ -4,6 +4,7 @@ #nullable disable +using System; using Microsoft.CodeAnalysis.Internal.Log; namespace Microsoft.CodeAnalysis.ChangeSignature @@ -14,9 +15,9 @@ internal class ChangeSignatureLogger private const string Minimum = nameof(Minimum); private const string Mean = nameof(Mean); - private static readonly LogAggregator s_logAggregator = new(); - private static readonly StatisticLogAggregator s_statisticLogAggregator = new(); - private static readonly HistogramLogAggregator s_histogramLogAggregator = new(bucketSize: 1000, maxBucketValue: 30000); + private static readonly CountLogAggregator s_countLogAggregator = new(); + private static readonly StatisticLogAggregator s_statisticLogAggregator = new(); + private static readonly HistogramLogAggregator s_histogramLogAggregator = new(bucketSize: 1000, maxBucketValue: 30000); internal enum ActionInfo { @@ -62,31 +63,31 @@ internal enum ActionInfo } internal static void LogChangeSignatureDialogLaunched() => - s_logAggregator.IncreaseCount((int)ActionInfo.ChangeSignatureDialogLaunched); + s_countLogAggregator.IncreaseCount(ActionInfo.ChangeSignatureDialogLaunched); internal static void LogChangeSignatureDialogCommitted() => - s_logAggregator.IncreaseCount((int)ActionInfo.ChangeSignatureDialogCommitted); + s_countLogAggregator.IncreaseCount(ActionInfo.ChangeSignatureDialogCommitted); internal static void LogAddParameterDialogLaunched() => - s_logAggregator.IncreaseCount((int)ActionInfo.AddParameterDialogLaunched); + s_countLogAggregator.IncreaseCount(ActionInfo.AddParameterDialogLaunched); internal static void LogAddParameterDialogCommitted() => - s_logAggregator.IncreaseCount((int)ActionInfo.AddParameterDialogCommitted); + s_countLogAggregator.IncreaseCount(ActionInfo.AddParameterDialogCommitted); internal static void LogTransformationInformation(int numOriginalParameters, int numParametersAdded, int numParametersRemoved, bool anyParametersReordered) { LogTransformationCombination(numParametersAdded > 0, numParametersRemoved > 0, anyParametersReordered); - s_logAggregator.IncreaseCountBy((int)ActionInfo.CommittedSession_OriginalParameterCount, numOriginalParameters); + s_countLogAggregator.IncreaseCountBy(ActionInfo.CommittedSession_OriginalParameterCount, numOriginalParameters); if (numParametersAdded > 0) { - s_logAggregator.IncreaseCountBy((int)ActionInfo.CommittedSessionWithAdded_NumberAdded, numParametersAdded); + s_countLogAggregator.IncreaseCountBy(ActionInfo.CommittedSessionWithAdded_NumberAdded, numParametersAdded); } if (numParametersRemoved > 0) { - s_logAggregator.IncreaseCountBy((int)ActionInfo.CommittedSessionWithRemoved_NumberRemoved, numParametersRemoved); + s_countLogAggregator.IncreaseCountBy(ActionInfo.CommittedSessionWithRemoved_NumberRemoved, numParametersRemoved); } } @@ -95,121 +96,110 @@ private static void LogTransformationCombination(bool parametersAdded, bool para // All three transformations if (parametersAdded && parametersRemoved && parametersReordered) { - s_logAggregator.IncreaseCount((int)ActionInfo.CommittedSessionAddedRemovedReordered); + s_countLogAggregator.IncreaseCount(ActionInfo.CommittedSessionAddedRemovedReordered); return; } // Two transformations if (parametersAdded && parametersRemoved) { - s_logAggregator.IncreaseCount((int)ActionInfo.CommittedSessionAddedRemovedOnly); + s_countLogAggregator.IncreaseCount(ActionInfo.CommittedSessionAddedRemovedOnly); return; } if (parametersAdded && parametersReordered) { - s_logAggregator.IncreaseCount((int)ActionInfo.CommittedSessionAddedReorderedOnly); + s_countLogAggregator.IncreaseCount(ActionInfo.CommittedSessionAddedReorderedOnly); return; } if (parametersRemoved && parametersReordered) { - s_logAggregator.IncreaseCount((int)ActionInfo.CommittedSessionRemovedReorderedOnly); + s_countLogAggregator.IncreaseCount(ActionInfo.CommittedSessionRemovedReorderedOnly); return; } // One transformation if (parametersAdded) { - s_logAggregator.IncreaseCount((int)ActionInfo.CommittedSessionAddedOnly); + s_countLogAggregator.IncreaseCount(ActionInfo.CommittedSessionAddedOnly); return; } if (parametersRemoved) { - s_logAggregator.IncreaseCount((int)ActionInfo.CommittedSessionRemovedOnly); + s_countLogAggregator.IncreaseCount(ActionInfo.CommittedSessionRemovedOnly); return; } if (parametersReordered) { - s_logAggregator.IncreaseCount((int)ActionInfo.CommittedSessionReorderedOnly); + s_countLogAggregator.IncreaseCount(ActionInfo.CommittedSessionReorderedOnly); return; } } - internal static void LogCommitInformation(int numDeclarationsUpdated, int numCallSitesUpdated, int elapsedMS) + internal static void LogCommitInformation(int numDeclarationsUpdated, int numCallSitesUpdated, TimeSpan elapsedTime) { - s_logAggregator.IncreaseCount((int)ActionInfo.ChangeSignatureCommitCompleted); + s_countLogAggregator.IncreaseCount(ActionInfo.ChangeSignatureCommitCompleted); - s_logAggregator.IncreaseCountBy((int)ActionInfo.CommittedSessionNumberOfDeclarationsUpdated, numDeclarationsUpdated); - s_logAggregator.IncreaseCountBy((int)ActionInfo.CommittedSessionNumberOfCallSitesUpdated, numCallSitesUpdated); + s_countLogAggregator.IncreaseCountBy(ActionInfo.CommittedSessionNumberOfDeclarationsUpdated, numDeclarationsUpdated); + s_countLogAggregator.IncreaseCountBy(ActionInfo.CommittedSessionNumberOfCallSitesUpdated, numCallSitesUpdated); - s_statisticLogAggregator.AddDataPoint((int)ActionInfo.CommittedSessionCommitElapsedMS, elapsedMS); - s_histogramLogAggregator.IncreaseCount((int)ActionInfo.CommittedSessionCommitElapsedMS, elapsedMS); + s_statisticLogAggregator.AddDataPoint(ActionInfo.CommittedSessionCommitElapsedMS, (int)elapsedTime.TotalMilliseconds); + s_histogramLogAggregator.LogTime(ActionInfo.CommittedSessionCommitElapsedMS, elapsedTime); } internal static void LogAddedParameterTypeBinds() { - s_logAggregator.IncreaseCount((int)ActionInfo.AddedParameterTypeBinds); + s_countLogAggregator.IncreaseCount(ActionInfo.AddedParameterTypeBinds); } internal static void LogAddedParameterRequired() { - s_logAggregator.IncreaseCount((int)ActionInfo.AddedParameterRequired); + s_countLogAggregator.IncreaseCount(ActionInfo.AddedParameterRequired); } internal static void LogAddedParameter_ValueExplicit() { - s_logAggregator.IncreaseCount((int)ActionInfo.AddedParameterValueExplicit); + s_countLogAggregator.IncreaseCount(ActionInfo.AddedParameterValueExplicit); } internal static void LogAddedParameter_ValueExplicitNamed() { - s_logAggregator.IncreaseCount((int)ActionInfo.AddedParameterValueExplicitNamed); + s_countLogAggregator.IncreaseCount(ActionInfo.AddedParameterValueExplicitNamed); } internal static void LogAddedParameter_ValueTODO() { - s_logAggregator.IncreaseCount((int)ActionInfo.AddedParameterValueTODO); + s_countLogAggregator.IncreaseCount(ActionInfo.AddedParameterValueTODO); } internal static void LogAddedParameter_ValueOmitted() { - s_logAggregator.IncreaseCount((int)ActionInfo.AddedParameterValueOmitted); + s_countLogAggregator.IncreaseCount(ActionInfo.AddedParameterValueOmitted); } internal static void ReportTelemetry() { Logger.Log(FunctionId.ChangeSignature_Data, KeyValueLogMessage.Create(m => { - foreach (var kv in s_logAggregator) + foreach (var kv in s_countLogAggregator) { - var info = ((ActionInfo)kv.Key).ToString("f"); - m[info] = kv.Value.GetCount(); + m[kv.Key.ToString()] = kv.Value.GetCount(); } foreach (var kv in s_statisticLogAggregator) { - var info = ((ActionInfo)kv.Key).ToString("f"); var statistics = kv.Value.GetStatisticResult(); - - m[CreateProperty(info, Maximum)] = statistics.Maximum; - m[CreateProperty(info, Minimum)] = statistics.Minimum; - m[CreateProperty(info, Mean)] = statistics.Mean; + statistics.WriteTelemetryPropertiesTo(m, prefix: kv.Key.ToString()); } foreach (var kv in s_histogramLogAggregator) { - var info = ((ActionInfo)kv.Key).ToString("f"); - m[$"{info}.BucketSize"] = kv.Value.BucketSize; - m[$"{info}.MaxBucketValue"] = kv.Value.MaxBucketValue; - m[$"{info}.Buckets"] = kv.Value.GetBucketsAsString(); + kv.Value.WriteTelemetryPropertiesTo(m, prefix: kv.Key.ToString()); } })); } - - private static string CreateProperty(string parent, string child) - => parent + "." + child; } } diff --git a/src/Features/Core/Portable/ChangeSignature/DelegateInvokeMethodReferenceFinder.cs b/src/Features/Core/Portable/ChangeSignature/DelegateInvokeMethodReferenceFinder.cs index 3f63b26ad6340..8260327e07d14 100644 --- a/src/Features/Core/Portable/ChangeSignature/DelegateInvokeMethodReferenceFinder.cs +++ b/src/Features/Core/Portable/ChangeSignature/DelegateInvokeMethodReferenceFinder.cs @@ -9,7 +9,7 @@ using System.Threading.Tasks; using Microsoft.CodeAnalysis.FindSymbols; using Microsoft.CodeAnalysis.FindSymbols.Finders; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Shared.Extensions; using Roslyn.Utilities; diff --git a/src/Features/Core/Portable/CodeFixes/Configuration/ConfigurationUpdater.cs b/src/Features/Core/Portable/CodeFixes/Configuration/ConfigurationUpdater.cs index 4d56475ff006d..51d3074f6ef49 100644 --- a/src/Features/Core/Portable/CodeFixes/Configuration/ConfigurationUpdater.cs +++ b/src/Features/Core/Portable/CodeFixes/Configuration/ConfigurationUpdater.cs @@ -285,7 +285,7 @@ private async Task ConfigureAsync() // Add the newly added analyzer config document as a solution item. // The analyzer config document is not yet created, so we just mark the file // path for tracking and add it as a solution item whenever the file gets created by the code fix application. - var service = _project.Solution.Workspace.Services.GetService(); + var service = _project.Solution.Services.GetService(); service?.TrackFilePathAndAddSolutionItemWhenFileCreated(editorConfigDocument.FilePath); return solution.WithAnalyzerConfigDocumentText(editorConfigDocument.Id, newText); @@ -341,7 +341,7 @@ private async Task ConfigureAsync() var codeStyleOptions = GetCodeStyleOptionsForDiagnostic(diagnostic, project); if (!codeStyleOptions.IsEmpty) { - var optionSet = project.Solution.Workspace.Options; + var optionSet = project.Solution.Options; var builder = ArrayBuilder<(string optionName, string currentOptionValue, bool isPerLanguage)>.GetInstance(); try @@ -396,7 +396,7 @@ internal static bool TryGetEditorConfigStringParts( { if (IDEDiagnosticIdToOptionMappingHelper.TryGetMappedOptions(diagnostic.Id, project.Language, out var options)) { - var optionSet = project.Solution.Workspace.Options; + var optionSet = project.Solution.Options; using var _ = ArrayBuilder<(OptionKey, ICodeStyleOption, IEditorConfigStorageLocation2, bool)>.GetInstance(out var builder); foreach (var option in options.OrderBy(option => option.Name)) diff --git a/src/Features/Core/Portable/CodeFixes/Configuration/ConfigureCodeStyle/ConfigureCodeStyleOptionCodeFixProvider.cs b/src/Features/Core/Portable/CodeFixes/Configuration/ConfigureCodeStyle/ConfigureCodeStyleOptionCodeFixProvider.cs index 8ef7a660e7411..3b8db9e0356bb 100644 --- a/src/Features/Core/Portable/CodeFixes/Configuration/ConfigureCodeStyle/ConfigureCodeStyleOptionCodeFixProvider.cs +++ b/src/Features/Core/Portable/CodeFixes/Configuration/ConfigureCodeStyle/ConfigureCodeStyleOptionCodeFixProvider.cs @@ -79,7 +79,7 @@ private static ImmutableArray GetConfigurations(Project project, IEnume // For example, if the option value is CodeStyleOption, we will have two nested actions, one for 'true' setting and one // for 'false' setting. If the option value is CodeStyleOption, we will have a nested action for each enum field. using var _ = ArrayBuilder.GetInstance(out var nestedActions); - var optionSet = project.Solution.Workspace.Options; + var optionSet = project.Solution.Options; var hasMultipleOptions = codeStyleOptions.Length > 1; foreach (var (optionKey, codeStyleOption, editorConfigLocation, perLanguageOption) in codeStyleOptions.OrderBy(t => t.optionKey.Option.Name)) { diff --git a/src/Features/Core/Portable/CodeFixes/GenerateMember/AbstractGenerateMemberCodeFixProvider.cs b/src/Features/Core/Portable/CodeFixes/GenerateMember/AbstractGenerateMemberCodeFixProvider.cs index 8ac8abfbba279..319b231b8f15f 100644 --- a/src/Features/Core/Portable/CodeFixes/GenerateMember/AbstractGenerateMemberCodeFixProvider.cs +++ b/src/Features/Core/Portable/CodeFixes/GenerateMember/AbstractGenerateMemberCodeFixProvider.cs @@ -9,7 +9,7 @@ using System.Threading.Tasks; using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeGeneration; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Text; using Roslyn.Utilities; diff --git a/src/Features/Core/Portable/CodeFixes/Suppression/AbstractSuppressionCodeFixProvider.AbstractGlobalSuppressMessageCodeAction.cs b/src/Features/Core/Portable/CodeFixes/Suppression/AbstractSuppressionCodeFixProvider.AbstractGlobalSuppressMessageCodeAction.cs index 947dafd9e1280..68c056d4a9cbc 100644 --- a/src/Features/Core/Portable/CodeFixes/Suppression/AbstractSuppressionCodeFixProvider.AbstractGlobalSuppressMessageCodeAction.cs +++ b/src/Features/Core/Portable/CodeFixes/Suppression/AbstractSuppressionCodeFixProvider.AbstractGlobalSuppressMessageCodeAction.cs @@ -10,7 +10,7 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.CodeActions; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.CodeFixes.Suppression @@ -81,7 +81,7 @@ protected async Task GetOrCreateSuppressionsDocumentAsync(Cancellation var t = await document.GetSyntaxTreeAsync(c).ConfigureAwait(false); var r = await t.GetRootAsync(c).ConfigureAwait(false); - var syntaxFacts = _project.LanguageServices.GetRequiredService(); + var syntaxFacts = _project.Services.GetRequiredService(); if (r.ChildNodes().All(n => syntaxFacts.IsUsingOrExternOrImport(n) || Fixer.IsAttributeListWithAssemblyAttributes(n))) { diff --git a/src/Features/Core/Portable/CodeFixes/Suppression/AbstractSuppressionCodeFixProvider.GlobalSuppressMessageCodeAction.cs b/src/Features/Core/Portable/CodeFixes/Suppression/AbstractSuppressionCodeFixProvider.GlobalSuppressMessageCodeAction.cs index 69691538eaf06..44b8c7acc9d2b 100644 --- a/src/Features/Core/Portable/CodeFixes/Suppression/AbstractSuppressionCodeFixProvider.GlobalSuppressMessageCodeAction.cs +++ b/src/Features/Core/Portable/CodeFixes/Suppression/AbstractSuppressionCodeFixProvider.GlobalSuppressMessageCodeAction.cs @@ -38,7 +38,7 @@ public GlobalSuppressMessageCodeAction( protected override async Task GetChangedSuppressionDocumentAsync(CancellationToken cancellationToken) { var suppressionsDoc = await GetOrCreateSuppressionsDocumentAsync(cancellationToken).ConfigureAwait(false); - var services = suppressionsDoc.Project.Solution.Workspace.Services; + var services = suppressionsDoc.Project.Solution.Services; var suppressionsRoot = await suppressionsDoc.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); var addImportsService = suppressionsDoc.GetRequiredLanguageService(); var options = await suppressionsDoc.GetSyntaxFormattingOptionsAsync(_fallbackOptions, cancellationToken).ConfigureAwait(false); diff --git a/src/Features/Core/Portable/CodeFixes/Suppression/AbstractSuppressionCodeFixProvider.GlobalSuppressMessageFixAllCodeAction.cs b/src/Features/Core/Portable/CodeFixes/Suppression/AbstractSuppressionCodeFixProvider.GlobalSuppressMessageFixAllCodeAction.cs index 3f44b93b4f3dd..e08dd1d3b114e 100644 --- a/src/Features/Core/Portable/CodeFixes/Suppression/AbstractSuppressionCodeFixProvider.GlobalSuppressMessageFixAllCodeAction.cs +++ b/src/Features/Core/Portable/CodeFixes/Suppression/AbstractSuppressionCodeFixProvider.GlobalSuppressMessageFixAllCodeAction.cs @@ -136,7 +136,7 @@ private static async Task CreateChangedSolutionAsync( protected override async Task GetChangedSuppressionDocumentAsync(CancellationToken cancellationToken) { var suppressionsDoc = await GetOrCreateSuppressionsDocumentAsync(cancellationToken).ConfigureAwait(false); - var services = suppressionsDoc.Project.Solution.Workspace.Services; + var services = suppressionsDoc.Project.Solution.Services; var suppressionsRoot = await suppressionsDoc.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); var addImportsService = suppressionsDoc.GetRequiredLanguageService(); var cleanupOptions = await suppressionsDoc.GetCodeCleanupOptionsAsync(_fallbackOptions, cancellationToken).ConfigureAwait(false); diff --git a/src/Features/Core/Portable/CodeFixes/Suppression/AbstractSuppressionCodeFixProvider.PragmaWarningCodeAction.cs b/src/Features/Core/Portable/CodeFixes/Suppression/AbstractSuppressionCodeFixProvider.PragmaWarningCodeAction.cs index bb2f8de920e15..091b9c65fba52 100644 --- a/src/Features/Core/Portable/CodeFixes/Suppression/AbstractSuppressionCodeFixProvider.PragmaWarningCodeAction.cs +++ b/src/Features/Core/Portable/CodeFixes/Suppression/AbstractSuppressionCodeFixProvider.PragmaWarningCodeAction.cs @@ -84,7 +84,7 @@ public async Task GetChangedDocumentAsync(bool includeStartTokenChange public SyntaxToken EndToken_TestOnly => _suppressionTargetInfo.EndToken; private SyntaxNode FormatNode(SyntaxNode node, CancellationToken cancellationToken) - => Formatter.Format(node, _document.Project.Solution.Workspace.Services, _options, cancellationToken); + => Formatter.Format(node, _document.Project.Solution.Services, _options, cancellationToken); } } } diff --git a/src/Features/Core/Portable/CodeFixes/Suppression/AbstractSuppressionCodeFixProvider.RemoveSuppressionCodeAction.BatchFixer.cs b/src/Features/Core/Portable/CodeFixes/Suppression/AbstractSuppressionCodeFixProvider.RemoveSuppressionCodeAction.BatchFixer.cs index a64eef67218b1..4380686b45715 100644 --- a/src/Features/Core/Portable/CodeFixes/Suppression/AbstractSuppressionCodeFixProvider.RemoveSuppressionCodeAction.BatchFixer.cs +++ b/src/Features/Core/Portable/CodeFixes/Suppression/AbstractSuppressionCodeFixProvider.RemoveSuppressionCodeAction.BatchFixer.cs @@ -159,14 +159,14 @@ public override async Task TryGetMergedFixAsync( private static async Task> GetAttributeNodesToFixAsync(ImmutableArray attributeRemoveFixes, CancellationToken cancellationToken) { - using var builderDisposer = ArrayBuilder.GetInstance(attributeRemoveFixes.Length, out var builder); + using var _ = ArrayBuilder.GetInstance(attributeRemoveFixes.Length, out var builder); foreach (var attributeRemoveFix in attributeRemoveFixes) { var attributeToRemove = await attributeRemoveFix.GetAttributeToRemoveAsync(cancellationToken).ConfigureAwait(false); builder.Add(attributeToRemove); } - return builder.ToImmutable(); + return builder.ToImmutableAndClear(); } } } diff --git a/src/Features/Core/Portable/CodeFixes/Suppression/AbstractSuppressionCodeFixProvider.RemoveSuppressionCodeAction_Pragma.cs b/src/Features/Core/Portable/CodeFixes/Suppression/AbstractSuppressionCodeFixProvider.RemoveSuppressionCodeAction_Pragma.cs index 856de08fb5619..bdf1aa58dcb6a 100644 --- a/src/Features/Core/Portable/CodeFixes/Suppression/AbstractSuppressionCodeFixProvider.RemoveSuppressionCodeAction_Pragma.cs +++ b/src/Features/Core/Portable/CodeFixes/Suppression/AbstractSuppressionCodeFixProvider.RemoveSuppressionCodeAction_Pragma.cs @@ -218,7 +218,7 @@ private async Task IsDiagnosticSuppressedBeforeLeadingPragmaAsync(int inde public SyntaxToken EndToken_TestOnly => _suppressionTargetInfo.EndToken; private SyntaxNode FormatNode(SyntaxNode node, CancellationToken cancellationToken) - => Formatter.Format(node, _document.Project.Solution.Workspace.Services, _options, cancellationToken); + => Formatter.Format(node, _document.Project.Solution.Services, _options, cancellationToken); } } } diff --git a/src/Features/Core/Portable/CodeFixes/Suppression/AbstractSuppressionCodeFixProvider.cs b/src/Features/Core/Portable/CodeFixes/Suppression/AbstractSuppressionCodeFixProvider.cs index 9a8a50f732428..4a892c9dfa17f 100644 --- a/src/Features/Core/Portable/CodeFixes/Suppression/AbstractSuppressionCodeFixProvider.cs +++ b/src/Features/Core/Portable/CodeFixes/Suppression/AbstractSuppressionCodeFixProvider.cs @@ -15,7 +15,7 @@ using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.Formatting; using Microsoft.CodeAnalysis.Host; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Text; @@ -52,7 +52,7 @@ protected abstract SyntaxNode AddGlobalSuppressMessageAttribute( ISymbol targetSymbol, INamedTypeSymbol suppressMessageAttribute, Diagnostic diagnostic, - HostWorkspaceServices services, + SolutionServices services, SyntaxFormattingOptions options, IAddImportsService addImportsService, CancellationToken cancellationToken); @@ -332,11 +332,8 @@ private async Task GetSuppressionTargetInfoAsync(Document } } - if (targetSymbol == null) - { - // Outside of a member declaration, suppress diagnostic for the entire assembly. - targetSymbol = semanticModel.Compilation.Assembly; - } + // Outside of a member declaration, suppress diagnostic for the entire assembly. + targetSymbol ??= semanticModel.Compilation.Assembly; return new SuppressionTargetInfo() { TargetSymbol = targetSymbol, NodeWithTokens = nodeWithTokens, StartToken = startToken, EndToken = endToken, TargetMemberNode = targetMemberNode }; } diff --git a/src/Features/Core/Portable/CodeFixesAndRefactorings/AbstractFixAllCodeAction.cs b/src/Features/Core/Portable/CodeFixesAndRefactorings/AbstractFixAllCodeAction.cs index a38945733651b..f2a950048a633 100644 --- a/src/Features/Core/Portable/CodeFixesAndRefactorings/AbstractFixAllCodeAction.cs +++ b/src/Features/Core/Portable/CodeFixesAndRefactorings/AbstractFixAllCodeAction.cs @@ -62,7 +62,7 @@ internal sealed override Task> ComputeOperat cancellationToken.ThrowIfCancellationRequested(); FixAllLogger.LogState(FixAllState, IsInternalProvider(FixAllState)); - var service = FixAllState.Project.Solution.Workspace.Services.GetRequiredService(); + var service = FixAllState.Project.Solution.Services.GetRequiredService(); var fixAllContext = CreateFixAllContext(FixAllState, progressTracker, cancellationToken); progressTracker.Description = fixAllContext.GetDefaultFixAllTitle(); @@ -76,7 +76,7 @@ internal sealed override Task> ComputeOperat cancellationToken.ThrowIfCancellationRequested(); FixAllLogger.LogState(FixAllState, IsInternalProvider(FixAllState)); - var service = FixAllState.Project.Solution.Workspace.Services.GetRequiredService(); + var service = FixAllState.Project.Solution.Services.GetRequiredService(); var fixAllContext = CreateFixAllContext(FixAllState, progressTracker, cancellationToken); progressTracker.Description = fixAllContext.GetDefaultFixAllTitle(); diff --git a/src/Features/Core/Portable/CodeLens/CodeLensReferencesService.cs b/src/Features/Core/Portable/CodeLens/CodeLensReferencesService.cs index fe5e464a41d8b..1c0dd7ff0c29d 100644 --- a/src/Features/Core/Portable/CodeLens/CodeLensReferencesService.cs +++ b/src/Features/Core/Portable/CodeLens/CodeLensReferencesService.cs @@ -12,7 +12,8 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.FindSymbols; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.Host; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Text; @@ -194,10 +195,7 @@ private static SyntaxNode GetEnclosingCodeElementNode(Document document, SyntaxT } } - if (node == null) - { - node = token.Parent; - } + node ??= token.Parent; return langServices.GetDisplayNode(node); } @@ -279,8 +277,8 @@ public async Task GetFullyQualifiedNameAsync(Solution solution, Document CancellationToken cancellationToken) { var document = solution.GetDocument(syntaxNode.GetLocation().SourceTree); - - using (solution.Services.CacheService?.EnableCaching(document.Project.Id)) + var cacheService = solution.Services.GetService(); + using (cacheService?.EnableCaching(document.Project.Id)) { var semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false); var declaredSymbol = semanticModel.GetDeclaredSymbol(syntaxNode, cancellationToken); diff --git a/src/Features/Core/Portable/CodeRefactorings/AbstractRefactoringHelpersService.cs b/src/Features/Core/Portable/CodeRefactorings/AbstractRefactoringHelpersService.cs index 63e32dbb7ac74..3e42467ae7720 100644 --- a/src/Features/Core/Portable/CodeRefactorings/AbstractRefactoringHelpersService.cs +++ b/src/Features/Core/Portable/CodeRefactorings/AbstractRefactoringHelpersService.cs @@ -9,7 +9,7 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Text; diff --git a/src/Features/Core/Portable/CodeRefactorings/AddAwait/AbstractAddAwaitCodeRefactoringProvider.cs b/src/Features/Core/Portable/CodeRefactorings/AddAwait/AbstractAddAwaitCodeRefactoringProvider.cs index 6e9620343eaaf..488fb6dd8edf4 100644 --- a/src/Features/Core/Portable/CodeRefactorings/AddAwait/AbstractAddAwaitCodeRefactoringProvider.cs +++ b/src/Features/Core/Portable/CodeRefactorings/AddAwait/AbstractAddAwaitCodeRefactoringProvider.cs @@ -7,7 +7,7 @@ using System.Threading.Tasks; using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.Editing; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Shared.Extensions; namespace Microsoft.CodeAnalysis.CodeRefactorings.AddAwait diff --git a/src/Features/Core/Portable/CodeRefactorings/AddMissingImports/AbstractAddMissingImportsFeatureService.cs b/src/Features/Core/Portable/CodeRefactorings/AddMissingImports/AbstractAddMissingImportsFeatureService.cs index a535cfb0ce7bc..efcac8af3b855 100644 --- a/src/Features/Core/Portable/CodeRefactorings/AddMissingImports/AbstractAddMissingImportsFeatureService.cs +++ b/src/Features/Core/Portable/CodeRefactorings/AddMissingImports/AbstractAddMissingImportsFeatureService.cs @@ -58,7 +58,7 @@ public async Task AnalyzeAsync(Document documen var addImportFeatureService = document.GetRequiredLanguageService(); var solution = document.Project.Solution; - var symbolSearchService = solution.Workspace.Services.GetRequiredService(); + var symbolSearchService = solution.Services.GetRequiredService(); // Since we are not currently considering NuGet packages, pass an empty array var packageSources = ImmutableArray.Empty; @@ -94,8 +94,8 @@ private async Task ApplyFixesAsync(Document document, ImmutableArray(); - var packageInstallerService = solution.Workspace.Services.GetService(); + var textDiffingService = solution.Services.GetRequiredService(); + var packageInstallerService = solution.Services.GetService(); var addImportService = document.GetRequiredLanguageService(); // Do not limit the results since we plan to fix all the reported issues. @@ -166,7 +166,7 @@ private async Task CleanUpNewLinesAsync(Document document, TextSpan in { var root = await document.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false); var text = await document.GetTextAsync(cancellationToken).ConfigureAwait(false); - var services = document.Project.Solution.Workspace.Services; + var services = document.Project.Solution.Services; var textChanges = Formatter.GetFormattedTextChanges( root, diff --git a/src/Features/Core/Portable/CodeRefactorings/AddMissingImports/AbstractAddMissingImportsRefactoringProvider.cs b/src/Features/Core/Portable/CodeRefactorings/AddMissingImports/AbstractAddMissingImportsRefactoringProvider.cs index 59e2c084904e8..71c13dc2d173b 100644 --- a/src/Features/Core/Portable/CodeRefactorings/AddMissingImports/AbstractAddMissingImportsRefactoringProvider.cs +++ b/src/Features/Core/Portable/CodeRefactorings/AddMissingImports/AbstractAddMissingImportsRefactoringProvider.cs @@ -40,7 +40,7 @@ public override async Task ComputeRefactoringsAsync(CodeRefactoringContext conte var cleanupOptions = await document.GetCodeCleanupOptionsAsync(context.Options, cancellationToken).ConfigureAwait(false); var options = new AddMissingImportsOptions( cleanupOptions, - context.Options.GetOptions(document.Project.LanguageServices).HideAdvancedMembers); + context.Options.GetOptions(document.Project.Services).HideAdvancedMembers); var analysis = await addMissingImportsService.AnalyzeAsync(document, textSpan, options, cancellationToken).ConfigureAwait(false); if (!analysis.CanAddMissingImports) diff --git a/src/Features/Core/Portable/CodeRefactorings/CodeRefactoringService.cs b/src/Features/Core/Portable/CodeRefactorings/CodeRefactoringService.cs index c5289a8576273..885f6c9e1c887 100644 --- a/src/Features/Core/Portable/CodeRefactorings/CodeRefactoringService.cs +++ b/src/Features/Core/Portable/CodeRefactorings/CodeRefactoringService.cs @@ -85,7 +85,7 @@ public async Task HasRefactoringsAsync( CodeActionOptionsProvider options, CancellationToken cancellationToken) { - var extensionManager = document.Project.Solution.Workspace.Services.GetRequiredService(); + var extensionManager = document.Project.Solution.Services.GetRequiredService(); foreach (var provider in GetProviders(document)) { @@ -115,7 +115,7 @@ public async Task> GetRefactoringsAsync( { using (Logger.LogBlock(FunctionId.Refactoring_CodeRefactoringService_GetRefactoringsAsync, cancellationToken)) { - var extensionManager = document.Project.Solution.Workspace.Services.GetRequiredService(); + var extensionManager = document.Project.Solution.Services.GetRequiredService(); using var _ = ArrayBuilder>.GetInstance(out var tasks); foreach (var provider in GetProviders(document)) @@ -211,7 +211,7 @@ public async Task> GetRefactoringsAsync( private static ImmutableArray GetProjectRefactorings(Project project) { // TODO (https://github.com/dotnet/roslyn/issues/4932): Don't restrict refactorings in Interactive - if (project.Solution.Workspace.Kind == WorkspaceKind.Interactive) + if (project.Solution.WorkspaceKind == WorkspaceKind.Interactive) return ImmutableArray.Empty; return ProjectCodeRefactoringProvider.GetExtensions(project); diff --git a/src/Features/Core/Portable/CodeRefactorings/ExtractMethod/AbstractExtractMethodCodeRefactoringProvider.cs b/src/Features/Core/Portable/CodeRefactorings/ExtractMethod/AbstractExtractMethodCodeRefactoringProvider.cs index 33c78be068002..f443bf7d98712 100644 --- a/src/Features/Core/Portable/CodeRefactorings/ExtractMethod/AbstractExtractMethodCodeRefactoringProvider.cs +++ b/src/Features/Core/Portable/CodeRefactorings/ExtractMethod/AbstractExtractMethodCodeRefactoringProvider.cs @@ -13,7 +13,7 @@ using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeCleanup; using Microsoft.CodeAnalysis.ExtractMethod; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Text; @@ -40,13 +40,13 @@ public override async Task ComputeRefactoringsAsync(CodeRefactoringContext conte return; } - var workspace = document.Project.Solution.Workspace; - if (workspace.Kind == WorkspaceKind.MiscellaneousFiles) + var solution = document.Project.Solution; + if (solution.WorkspaceKind == WorkspaceKind.MiscellaneousFiles) { return; } - var activeInlineRenameSession = workspace.Services.GetService().ActiveInlineRenameSession; + var activeInlineRenameSession = solution.Services.GetService().ActiveInlineRenameSession; if (activeInlineRenameSession) { return; diff --git a/src/Features/Core/Portable/CodeRefactorings/IRefactoringHelpersService.cs b/src/Features/Core/Portable/CodeRefactorings/IRefactoringHelpersService.cs index d9317ebd1a832..5c56249dc1ba0 100644 --- a/src/Features/Core/Portable/CodeRefactorings/IRefactoringHelpersService.cs +++ b/src/Features/Core/Portable/CodeRefactorings/IRefactoringHelpersService.cs @@ -7,7 +7,7 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.Host; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Text; namespace Microsoft.CodeAnalysis.CodeRefactorings diff --git a/src/Features/Core/Portable/CodeRefactorings/MoveType/AbstractMoveTypeService.MoveTypeEditor.cs b/src/Features/Core/Portable/CodeRefactorings/MoveType/AbstractMoveTypeService.MoveTypeEditor.cs index 08954a69402b0..38bf8226debdc 100644 --- a/src/Features/Core/Portable/CodeRefactorings/MoveType/AbstractMoveTypeService.MoveTypeEditor.cs +++ b/src/Features/Core/Portable/CodeRefactorings/MoveType/AbstractMoveTypeService.MoveTypeEditor.cs @@ -13,7 +13,7 @@ using Microsoft.CodeAnalysis.CodeCleanup; using Microsoft.CodeAnalysis.Editing; using Microsoft.CodeAnalysis.Formatting; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.RemoveUnnecessaryImports; using Microsoft.CodeAnalysis.Shared.Extensions; using Roslyn.Utilities; diff --git a/src/Features/Core/Portable/CodeRefactorings/MoveType/AbstractMoveTypeService.MoveTypeNamespaceScopeEditor.cs b/src/Features/Core/Portable/CodeRefactorings/MoveType/AbstractMoveTypeService.MoveTypeNamespaceScopeEditor.cs index dc2e73dfaac04..866be72439e10 100644 --- a/src/Features/Core/Portable/CodeRefactorings/MoveType/AbstractMoveTypeService.MoveTypeNamespaceScopeEditor.cs +++ b/src/Features/Core/Portable/CodeRefactorings/MoveType/AbstractMoveTypeService.MoveTypeNamespaceScopeEditor.cs @@ -9,7 +9,7 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.Editing; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Shared.Extensions; namespace Microsoft.CodeAnalysis.CodeRefactorings.MoveType diff --git a/src/Features/Core/Portable/CodeRefactorings/MoveType/AbstractMoveTypeService.State.cs b/src/Features/Core/Portable/CodeRefactorings/MoveType/AbstractMoveTypeService.State.cs index 986e1e9b0fdaa..2cec51e4d8aee 100644 --- a/src/Features/Core/Portable/CodeRefactorings/MoveType/AbstractMoveTypeService.State.cs +++ b/src/Features/Core/Portable/CodeRefactorings/MoveType/AbstractMoveTypeService.State.cs @@ -9,7 +9,7 @@ using System.Threading; using Microsoft.CodeAnalysis.CodeCleanup; using Microsoft.CodeAnalysis.Formatting; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Shared.Extensions; namespace Microsoft.CodeAnalysis.CodeRefactorings.MoveType diff --git a/src/Features/Core/Portable/CodeRefactorings/MoveType/AbstractMoveTypeService.cs b/src/Features/Core/Portable/CodeRefactorings/MoveType/AbstractMoveTypeService.cs index 51e12825a3ad7..f5e9030019180 100644 --- a/src/Features/Core/Portable/CodeRefactorings/MoveType/AbstractMoveTypeService.cs +++ b/src/Features/Core/Portable/CodeRefactorings/MoveType/AbstractMoveTypeService.cs @@ -15,7 +15,7 @@ using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeCleanup; using Microsoft.CodeAnalysis.Formatting; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Text; diff --git a/src/Features/Core/Portable/CodeRefactorings/SyncNamespace/AbstractChangeNamespaceService.cs b/src/Features/Core/Portable/CodeRefactorings/SyncNamespace/AbstractChangeNamespaceService.cs index e67d6bc37020a..232fc988d9804 100644 --- a/src/Features/Core/Portable/CodeRefactorings/SyncNamespace/AbstractChangeNamespaceService.cs +++ b/src/Features/Core/Portable/CodeRefactorings/SyncNamespace/AbstractChangeNamespaceService.cs @@ -18,7 +18,7 @@ using Microsoft.CodeAnalysis.FindSymbols; using Microsoft.CodeAnalysis.Formatting; using Microsoft.CodeAnalysis.Host; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.RemoveUnnecessaryImports; using Microsoft.CodeAnalysis.Shared.Extensions; @@ -277,8 +277,8 @@ await ChangeNamespaceInSingleDocumentAsync(solutionAfterNamespaceChange, documen // will return false. We use span of namespace declaration found in each document to decide if they are identical. var documents = ids.SelectAsArray(solution.GetRequiredDocument); - using var containersDisposer = ArrayBuilder<(DocumentId, SyntaxNode)>.GetInstance(ids.Length, out var containers); - using var spanForContainersDisposer = PooledHashSet.GetInstance(out var spanForContainers); + using var _1 = ArrayBuilder<(DocumentId, SyntaxNode)>.GetInstance(ids.Length, out var containers); + using var _2 = PooledHashSet.GetInstance(out var spanForContainers); foreach (var document in documents) { @@ -401,13 +401,11 @@ private static ImmutableArray GetAllNamespaceImportsForDeclaringDocument private static ImmutableArray CreateImports(Document document, ImmutableArray names, bool withFormatterAnnotation) { var generator = SyntaxGenerator.GetGenerator(document); - using var builderDisposer = ArrayBuilder.GetInstance(names.Length, out var builder); + using var _ = ArrayBuilder.GetInstance(names.Length, out var builder); for (var i = 0; i < names.Length; ++i) - { builder.Add(CreateImport(generator, names[i], withFormatterAnnotation)); - } - return builder.ToImmutable(); + return builder.ToImmutableAndClear(); } private static SyntaxNode CreateImport(SyntaxGenerator syntaxGenerator, string name, bool withFormatterAnnotation) @@ -630,7 +628,7 @@ private async Task FixDeclarationDocumentAsync( .WithAdditionalAnnotations(Formatter.Annotation); // Need to invoke formatter explicitly since we are doing the diff merge ourselves. - var services = documentWithAddedImports.Project.Solution.Workspace.Services; + var services = documentWithAddedImports.Project.Solution.Services; root = Formatter.Format(root, Formatter.Annotation, services, documentOptions.FormattingOptions, cancellationToken); root = root.WithAdditionalAnnotations(Simplifier.Annotation); diff --git a/src/Features/Core/Portable/CodeRefactorings/SyncNamespace/AbstractSyncNamespaceCodeRefactoringProvider.State.cs b/src/Features/Core/Portable/CodeRefactorings/SyncNamespace/AbstractSyncNamespaceCodeRefactoringProvider.State.cs index 65a0dae04e5a8..5182ccf34e6d2 100644 --- a/src/Features/Core/Portable/CodeRefactorings/SyncNamespace/AbstractSyncNamespaceCodeRefactoringProvider.State.cs +++ b/src/Features/Core/Portable/CodeRefactorings/SyncNamespace/AbstractSyncNamespaceCodeRefactoringProvider.State.cs @@ -10,7 +10,7 @@ using System.Threading.Tasks; using Microsoft.CodeAnalysis.ChangeNamespace; using Microsoft.CodeAnalysis.Editing; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Shared.Utilities; using Microsoft.CodeAnalysis.Text; @@ -150,8 +150,8 @@ private State( /// private static bool IsDocumentPathRootedInProjectFolder(Document document) { - var absoluteDircetoryPath = PathUtilities.GetDirectoryName(document.FilePath); - if (absoluteDircetoryPath is null) + var absoluteDirectoryPath = PathUtilities.GetDirectoryName(document.FilePath); + if (absoluteDirectoryPath is null) return false; var projectRoot = PathUtilities.GetDirectoryName(document.Project.FilePath); @@ -163,7 +163,7 @@ private static bool IsDocumentPathRootedInProjectFolder(Document document) if (logicalDirectoryPath is null) return false; - return PathUtilities.PathsEqual(absoluteDircetoryPath, logicalDirectoryPath); + return PathUtilities.PathsEqual(absoluteDirectoryPath, logicalDirectoryPath); } private static string? GetDefaultNamespace(Document document, ISyntaxFactsService syntaxFacts) diff --git a/src/Features/Core/Portable/CodeRefactorings/SyncNamespace/AbstractSyncNamespaceCodeRefactoringProvider.cs b/src/Features/Core/Portable/CodeRefactorings/SyncNamespace/AbstractSyncNamespaceCodeRefactoringProvider.cs index 4123d170d3ec5..f0dc9eac7ccf2 100644 --- a/src/Features/Core/Portable/CodeRefactorings/SyncNamespace/AbstractSyncNamespaceCodeRefactoringProvider.cs +++ b/src/Features/Core/Portable/CodeRefactorings/SyncNamespace/AbstractSyncNamespaceCodeRefactoringProvider.cs @@ -23,7 +23,7 @@ internal abstract partial class AbstractSyncNamespaceCodeRefactoringProvider - { - public abstract class DiagnosticAnalyzer : AbstractBuiltInCodeStyleDiagnosticAnalyzer - { - public readonly TCodeStyleProvider _codeStyleProvider; - - protected DiagnosticAnalyzer(bool isUnnecessary = true, bool configurable = true) - : this(new TCodeStyleProvider(), isUnnecessary, configurable) - { - } - - private DiagnosticAnalyzer(TCodeStyleProvider codeStyleProvider, bool isUnnecessary, bool configurable) - : base(codeStyleProvider._descriptorId, - codeStyleProvider._enforceOnBuild, - codeStyleProvider._option, - codeStyleProvider._language, - codeStyleProvider._title, - codeStyleProvider._message, - isUnnecessary, - configurable) - { - _codeStyleProvider = codeStyleProvider; - } - - protected sealed override void InitializeWorker(Diagnostics.AnalysisContext context) - => _codeStyleProvider.DiagnosticAnalyzerInitialize(new AnalysisContext(_codeStyleProvider, context)); - - public sealed override DiagnosticAnalyzerCategory GetAnalyzerCategory() - => _codeStyleProvider.GetAnalyzerCategory(); - } - - /// - /// Critically, we want to consolidate the logic about checking if the analyzer should run - /// at all. i.e. if the user has their option set to 'none' or 'refactoring only' then we - /// do not want the analyzer to run at all. - /// - /// To that end, we don't let the subclass have direct access to the real . Instead, we pass this type to the subclass for it - /// register with. We then check if the registration should proceed given the - /// and the current being processed. If not, we don't do the - /// actual registration. - /// - protected struct AnalysisContext - { - private readonly TCodeStyleProvider _codeStyleProvider; - private readonly Diagnostics.AnalysisContext _context; - - public AnalysisContext(TCodeStyleProvider codeStyleProvider, Diagnostics.AnalysisContext context) - { - _codeStyleProvider = codeStyleProvider; - _context = context; - } - - public void RegisterCompilationStartAction(Action analyze) - { - var _this = this; - _context.RegisterCompilationStartAction( - c => analyze(c.Compilation, _this)); - } - - public void RegisterCodeBlockAction(Action> analyze) - { - var provider = _codeStyleProvider; - _context.RegisterCodeBlockAction( - c => AnalyzeIfEnabled(provider, c, analyze, c.Options, c.SemanticModel.SyntaxTree)); - } - - public void RegisterSemanticModelAction(Action> analyze) - { - var provider = _codeStyleProvider; - _context.RegisterSemanticModelAction( - c => AnalyzeIfEnabled(provider, c, analyze, c.Options, c.SemanticModel.SyntaxTree)); - } - - public void RegisterSyntaxTreeAction(Action> analyze) - { - var provider = _codeStyleProvider; - _context.RegisterSyntaxTreeAction( - c => AnalyzeIfEnabled(provider, c, analyze, c.Options, c.Tree)); - } - - public void RegisterOperationAction( - Action> analyze, - params OperationKind[] operationKinds) - { - var provider = _codeStyleProvider; - _context.RegisterOperationAction( - c => AnalyzeIfEnabled(provider, c, analyze, c.Options, c.Operation.SemanticModel.SyntaxTree), - operationKinds); - } - - public void RegisterSyntaxNodeAction( - Action> analyze, - params TSyntaxKind[] syntaxKinds) where TSyntaxKind : struct - { - var provider = _codeStyleProvider; - _context.RegisterSyntaxNodeAction( - c => AnalyzeIfEnabled(provider, c, analyze, c.Options, c.SemanticModel.SyntaxTree), - syntaxKinds); - } - - private static void AnalyzeIfEnabled( - TCodeStyleProvider provider, TContext context, Action> analyze, - AnalyzerOptions analyzerOptions, SyntaxTree syntaxTree) - { - var optionValue = provider.GetCodeStyleOption(analyzerOptions.GetAnalyzerOptions(syntaxTree)); - var severity = GetOptionSeverity(optionValue); - switch (severity) - { - case ReportDiagnostic.Error: - case ReportDiagnostic.Warn: - case ReportDiagnostic.Info: - break; - default: - // don't analyze if it's any other value. - return; - } - - analyze(context, optionValue); - } - } - } -} diff --git a/src/Features/Core/Portable/CodeStyle/AbstractCodeStyleProvider.Fixing.cs b/src/Features/Core/Portable/CodeStyle/AbstractCodeStyleProvider.Fixing.cs deleted file mode 100644 index 6481f90b5f7bb..0000000000000 --- a/src/Features/Core/Portable/CodeStyle/AbstractCodeStyleProvider.Fixing.cs +++ /dev/null @@ -1,52 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -#nullable disable - -using System.Collections.Immutable; -using System.Threading; -using System.Threading.Tasks; -using Microsoft.CodeAnalysis.CodeActions; -using Microsoft.CodeAnalysis.CodeFixes; -using Microsoft.CodeAnalysis.Editing; - -namespace Microsoft.CodeAnalysis.CodeStyle -{ - // This part contains all the logic for hooking up the CodeFixProvider to the CodeStyleProvider. - // All the code in this part is an implementation detail and is intentionally private so that - // subclasses cannot change anything. All code relevant to subclasses relating to fixing is - // contained in AbstractCodeStyleProvider.cs - - internal abstract partial class AbstractCodeStyleProvider - { - private async Task RegisterCodeFixesAsync(CodeFixContext context) - { - var document = context.Document; - var diagnostic = context.Diagnostics[0]; - var cancellationToken = context.CancellationToken; - - var codeFixes = await ComputeCodeActionsAsync( - document, diagnostic, cancellationToken).ConfigureAwait(false); - context.RegisterFixes(codeFixes, context.Diagnostics); - } - - public abstract class CodeFixProvider : SyntaxEditorBasedCodeFixProvider - { - public readonly TCodeStyleProvider _codeStyleProvider = new(); - - protected CodeFixProvider() - { - FixableDiagnosticIds = ImmutableArray.Create(_codeStyleProvider._descriptorId); - } - - public sealed override ImmutableArray FixableDiagnosticIds { get; } - - public sealed override Task RegisterCodeFixesAsync(CodeFixContext context) - => _codeStyleProvider.RegisterCodeFixesAsync(context); - - protected sealed override Task FixAllAsync(Document document, ImmutableArray diagnostics, SyntaxEditor editor, CodeActionOptionsProvider fallbackOptions, CancellationToken cancellationToken) - => _codeStyleProvider.FixAllAsync(document, diagnostics, editor, cancellationToken); - } - } -} diff --git a/src/Features/Core/Portable/CodeStyle/AbstractCodeStyleProvider.Refactoring.cs b/src/Features/Core/Portable/CodeStyle/AbstractCodeStyleProvider.Refactoring.cs deleted file mode 100644 index fe2711b81fe16..0000000000000 --- a/src/Features/Core/Portable/CodeStyle/AbstractCodeStyleProvider.Refactoring.cs +++ /dev/null @@ -1,89 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -#nullable disable - -using System.Threading.Tasks; -using Microsoft.CodeAnalysis.CodeRefactorings; -using Microsoft.CodeAnalysis.Diagnostics; - -namespace Microsoft.CodeAnalysis.CodeStyle -{ - // This part contains all the logic for hooking up the CodeRefactoring to the CodeStyleProvider. - // All the code in this part is an implementation detail and is intentionally private so that - // subclasses cannot change anything. All code relevant to subclasses relating to refactorings - // is contained in AbstractCodeStyleProvider.cs - - internal abstract partial class AbstractCodeStyleProvider - { - private async Task ComputeRefactoringsAsync(CodeRefactoringContext context) - { - var (document, _, cancellationToken) = context; - - var optionProvider = await document.GetAnalyzerOptionsProviderAsync(cancellationToken).ConfigureAwait(false); - var optionValue = GetCodeStyleOption(optionProvider); - - var severity = GetOptionSeverity(optionValue); - switch (severity) - { - case ReportDiagnostic.Suppress: - case ReportDiagnostic.Hidden: - // if the severity is Hidden that's equivalent to 'refactoring only', so we want - // to try to compute the refactoring here. - // - // If the severity is 'suppress', that means the user doesn't want the actual - // analyzer to run here. However, we can still check to see if we could offer - // the feature here as a refactoring. - await ComputeRefactoringsAsync(context, optionValue.Value, analyzerActive: false).ConfigureAwait(false); - return; - - case ReportDiagnostic.Error: - case ReportDiagnostic.Warn: - case ReportDiagnostic.Info: - // User has this option set at a level where we want it checked by the - // DiagnosticAnalyser and not the CodeRefactoringProvider. However, we still - // want to check if we want to offer the *reverse* refactoring here in this - // single location. - // - // For example, say this is the "use expression body" feature. If the user says - // they always prefer expression-bodies (with warning level), then we want the - // analyzer to always be checking for that. However, we still want to offer the - // refactoring to flip their code to use a block body here, just in case that - // was something they wanted to do as a one off (i.e. before adding new - // statements. - // - // TODO(cyrusn): Should we only do this for warn/info? Argument could be made - // that we shouldn't even offer to refactor in the reverse direction if it will - // just cause an error. That said, maybe this is just an intermediary step, and - // we shouldn't really be blocking the user from making it. - await ComputeRefactoringsAsync(context, optionValue.Value, analyzerActive: true).ConfigureAwait(false); - return; - } - } - - private async Task ComputeRefactoringsAsync( - CodeRefactoringContext context, TOptionValue option, bool analyzerActive) - { - var (document, span, cancellationToken) = context; - - var computationTask = analyzerActive - ? ComputeOpposingRefactoringsWhenAnalyzerActiveAsync(document, span, option, cancellationToken) - : ComputeAllRefactoringsWhenAnalyzerInactiveAsync(document, span, cancellationToken); - - var codeActions = await computationTask.ConfigureAwait(false); - context.RegisterRefactorings(codeActions); - } - - public class CodeRefactoringProvider : CodeRefactorings.CodeRefactoringProvider - { - public readonly TCodeStyleProvider _codeStyleProvider; - - protected CodeRefactoringProvider() - => _codeStyleProvider = new TCodeStyleProvider(); - - public sealed override Task ComputeRefactoringsAsync(CodeRefactoringContext context) - => _codeStyleProvider.ComputeRefactoringsAsync(context); - } - } -} diff --git a/src/Features/Core/Portable/CodeStyle/AbstractCodeStyleProvider.cs b/src/Features/Core/Portable/CodeStyle/AbstractCodeStyleProvider.cs deleted file mode 100644 index 2b1722f568b48..0000000000000 --- a/src/Features/Core/Portable/CodeStyle/AbstractCodeStyleProvider.cs +++ /dev/null @@ -1,149 +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.Collections.Immutable; -using System.Threading; -using System.Threading.Tasks; -using Microsoft.CodeAnalysis.CodeActions; -using Microsoft.CodeAnalysis.CodeFixes; -using Microsoft.CodeAnalysis.Diagnostics; -using Microsoft.CodeAnalysis.Editing; -using Microsoft.CodeAnalysis.Options; -using Microsoft.CodeAnalysis.Text; - -namespace Microsoft.CodeAnalysis.CodeStyle -{ - // This file contains the "protected" surface area of the AbstractCodeStyleProvider. - // It specifically is all the extensibility surface that a subclass needs to fill in - // in order to properly expose a code style analyzer/fixer/refactoring. - - /// - /// This is the core class a code-style feature needs to derive from. All logic related to the - /// feature will then be contained in this class. This class will take care of many bit of - /// common logic that all code style providers would have to care about and can thus do that - /// logic in a consistent fashion without all providers having to do the same. For example, - /// this class will check the current value of the code style option. If it is 'refactoring - /// only', it will not bother running any of the DiagnosticAnalyzer codepaths, and will only run - /// the CodeRefactoringProvider codepaths. - /// - internal abstract partial class AbstractCodeStyleProvider - where TCodeStyleProvider : AbstractCodeStyleProvider, new() - { - private readonly Option2> _option; - private readonly string _language; - private readonly string _descriptorId; - private readonly EnforceOnBuild _enforceOnBuild; - private readonly LocalizableString _title; - private readonly LocalizableString _message; - - protected AbstractCodeStyleProvider( - Option2> option, - string language, - string descriptorId, - EnforceOnBuild enforceOnBuild, - LocalizableString title, - LocalizableString message) - { - _option = option; - _language = language; - _descriptorId = descriptorId; - _enforceOnBuild = enforceOnBuild; - _title = title; - _message = message; - } - - /// - /// Helper to get the true ReportDiagnostic severity for a given option. Importantly, this - /// handle ReportDiagnostic.Default and will map that back to the appropriate value in that - /// case. - /// - protected static ReportDiagnostic GetOptionSeverity(CodeStyleOption2 optionValue) - { - var severity = optionValue.Notification.Severity; - return severity == ReportDiagnostic.Default - ? severity.WithDefaultSeverity(DiagnosticSeverity.Hidden) - : severity; - } - - protected abstract CodeStyleOption2 GetCodeStyleOption(AnalyzerOptionsProvider provider); - - #region analysis - - protected abstract void DiagnosticAnalyzerInitialize(AnalysisContext context); - protected abstract DiagnosticAnalyzerCategory GetAnalyzerCategory(); - - protected DiagnosticDescriptor CreateDescriptorWithId( - LocalizableString title, LocalizableString message) - { - return new DiagnosticDescriptor( - _descriptorId, title, message, - DiagnosticCategory.Style, - DiagnosticSeverity.Hidden, - isEnabledByDefault: true); - } - - #endregion - - #region fixing - - /// - /// Subclasses must implement this method to provide fixes for any diagnostics that this - /// type has registered. If this subclass wants the same code to run for this single - /// diagnostic as well as for when running fix-all, then it should call - /// from its code action. This will end up calling - /// , with that single in the - /// passed to that method. - /// - protected abstract Task> ComputeCodeActionsAsync( - Document document, Diagnostic diagnostic, CancellationToken cancellationToken); - - /// - /// Subclasses should implement this to support fixing all given diagnostics efficiently. - /// - protected abstract Task FixAllAsync( - Document document, ImmutableArray diagnostics, SyntaxEditor editor, CancellationToken cancellationToken); - - protected Task FixWithSyntaxEditorAsync(Document document, Diagnostic diagnostic, CancellationToken cancellationToken) - => SyntaxEditorBasedCodeFixProvider.FixAllWithEditorAsync( - document, editor => FixAllAsync(document, ImmutableArray.Create(diagnostic), editor, cancellationToken), cancellationToken); - - #endregion - - #region refactoring - - /// - /// Subclasses should implement this to provide their feature as a refactoring. This will - /// be called when the user has the code style set to 'refactoring only' (or if the - /// diagnostic is suppressed). - /// - /// The implementation of this should offer all refactorings it can that are relevant at the - /// provided . Specifically, because these are just refactorings, - /// they should be offered when they would make the code match the desired user preference, - /// or even for allowing the user to quickly switch their code to *not* follow their desired - /// preference. - /// - protected abstract Task> ComputeAllRefactoringsWhenAnalyzerInactiveAsync( - Document document, TextSpan span, CancellationToken cancellationToken); - - /// - /// Subclasses should implement this to provide the refactoring that works in the opposing - /// direction of what the option preference is. This is only called if the user has the - /// code style enabled, and has it set to 'info/warning/error'. In this case it is the - /// *analyzer* responsible for making code compliant with the option. - /// - /// The refactoring then exists to allow the user to update their code to go against that - /// option on an individual case by case basis. - /// - /// For example, if the user had set that they want expression-bodies for methods (at - /// warning level), then this would offer 'use block body' on a method that had an - /// expression body already. - /// - protected abstract Task> ComputeOpposingRefactoringsWhenAnalyzerActiveAsync( - Document document, TextSpan span, TOptionValue option, CancellationToken cancellationToken); - - #endregion - } -} diff --git a/src/Features/Core/Portable/CommentSelection/AbstractCommentSelectionService.cs b/src/Features/Core/Portable/CommentSelection/AbstractCommentSelectionService.cs index 9d779836ebe77..644ae654ab0fd 100644 --- a/src/Features/Core/Portable/CommentSelection/AbstractCommentSelectionService.cs +++ b/src/Features/Core/Portable/CommentSelection/AbstractCommentSelectionService.cs @@ -20,17 +20,9 @@ internal abstract class AbstractCommentSelectionService : ICommentSelectionServi public abstract string SingleLineCommentString { get; } public abstract bool SupportsBlockComment { get; } - public Task FormatAsync(Document document, ImmutableArray changes, SyntaxFormattingOptions formattingOptions, CancellationToken cancellationToken) - { - var root = document.GetRequiredSyntaxRootSynchronously(cancellationToken); - var formattingSpans = changes.Select(s => CommonFormattingHelpers.GetFormattingSpan(root, s)); - - return Formatter.FormatAsync(document, formattingSpans, formattingOptions, rules: null, cancellationToken); - } - - public Task GetInfoAsync(Document document, TextSpan textSpan, CancellationToken cancellationToken) - => Task.FromResult(SupportsBlockComment - ? new CommentSelectionInfo(true, SupportsBlockComment, SingleLineCommentString, BlockCommentStartString, BlockCommentEndString) - : new CommentSelectionInfo(true, SupportsBlockComment, SingleLineCommentString, "", "")); + public CommentSelectionInfo GetInfo() + => SupportsBlockComment + ? new(supportsSingleLineComment: true, SupportsBlockComment, SingleLineCommentString, BlockCommentStartString, BlockCommentEndString) + : new(supportsSingleLineComment: true, SupportsBlockComment, SingleLineCommentString, blockCommentStartString: "", blockCommentEndString: ""); } } diff --git a/src/Features/Core/Portable/CommentSelection/ICommentSelectionService.cs b/src/Features/Core/Portable/CommentSelection/ICommentSelectionService.cs index 49858bbf8a298..8e259cc0b4ff0 100644 --- a/src/Features/Core/Portable/CommentSelection/ICommentSelectionService.cs +++ b/src/Features/Core/Portable/CommentSelection/ICommentSelectionService.cs @@ -13,8 +13,6 @@ namespace Microsoft.CodeAnalysis.CommentSelection { internal interface ICommentSelectionService : ILanguageService { - Task GetInfoAsync(Document document, TextSpan textSpan, CancellationToken cancellationToken); - - Task FormatAsync(Document document, ImmutableArray changes, SyntaxFormattingOptions formattingOptions, CancellationToken cancellationToken); + CommentSelectionInfo GetInfo(); } } diff --git a/src/Features/Core/Portable/Completion/CommonCompletionProvider.cs b/src/Features/Core/Portable/Completion/CommonCompletionProvider.cs index ad83b030f2978..63d44ce375327 100644 --- a/src/Features/Core/Portable/Completion/CommonCompletionProvider.cs +++ b/src/Features/Core/Portable/Completion/CommonCompletionProvider.cs @@ -9,7 +9,7 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.Host; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Snippets; @@ -39,7 +39,7 @@ public sealed override bool ShouldTriggerCompletion(SourceText text, int caretPo return ShouldTriggerCompletionImpl(text, caretPosition, trigger, CompletionOptions.Default); } - internal override bool ShouldTriggerCompletion(HostLanguageServices languageServices, SourceText text, int caretPosition, CompletionTrigger trigger, CompletionOptions options, OptionSet passThroughOptions) + internal override bool ShouldTriggerCompletion(LanguageServices languageServices, SourceText text, int caretPosition, CompletionTrigger trigger, CompletionOptions options, OptionSet passThroughOptions) => ShouldTriggerCompletionImpl(text, caretPosition, trigger, options); private bool ShouldTriggerCompletionImpl(SourceText text, int caretPosition, CompletionTrigger trigger, in CompletionOptions options) @@ -76,8 +76,7 @@ private async Task> TryAddSnippetInvocationPartAsync( Document document, CompletionItem item, ImmutableArray parts, CancellationToken cancellationToken) { - var languageServices = document.Project.LanguageServices; - var snippetService = languageServices.GetService(); + var snippetService = document.Project.Services.GetService(); if (snippetService != null) { var change = await GetTextChangeAsync(document, item, ch: '\t', cancellationToken: cancellationToken).ConfigureAwait(false) ?? diff --git a/src/Features/Core/Portable/Completion/CommonCompletionService.cs b/src/Features/Core/Portable/Completion/CommonCompletionService.cs index b93d1e2918aa4..a377f94ef6da4 100644 --- a/src/Features/Core/Portable/Completion/CommonCompletionService.cs +++ b/src/Features/Core/Portable/Completion/CommonCompletionService.cs @@ -4,6 +4,7 @@ using System.Collections.Generic; using System.Collections.Immutable; +using Microsoft.CodeAnalysis.Host; using Microsoft.CodeAnalysis.PatternMatching; using Microsoft.CodeAnalysis.Tags; @@ -11,8 +12,8 @@ namespace Microsoft.CodeAnalysis.Completion { internal abstract partial class CommonCompletionService : CompletionService { - protected CommonCompletionService(Workspace workspace) - : base(workspace) + protected CommonCompletionService(SolutionServices services) + : base(services) { } diff --git a/src/Features/Core/Portable/Completion/CommonCompletionUtilities.cs b/src/Features/Core/Portable/Completion/CommonCompletionUtilities.cs index 33ef4c7c177e6..0fc8cf2356e43 100644 --- a/src/Features/Core/Portable/Completion/CommonCompletionUtilities.cs +++ b/src/Features/Core/Portable/Completion/CommonCompletionUtilities.cs @@ -13,7 +13,7 @@ using Microsoft.CodeAnalysis.Classification.Classifiers; using Microsoft.CodeAnalysis.DocumentationComments; using Microsoft.CodeAnalysis.Host; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Shared.Extensions.ContextQuery; using Microsoft.CodeAnalysis.Shared.Utilities; @@ -85,7 +85,7 @@ public static bool IsStartingNewWord(SourceText text, int characterPosition, Fun } public static Func> CreateDescriptionFactory( - HostWorkspaceServices workspaceServices, + SolutionServices workspaceServices, SemanticModel semanticModel, int position, ISymbol symbol, @@ -95,22 +95,22 @@ public static Func> CreateDescrip } public static Func> CreateDescriptionFactory( - HostWorkspaceServices workspaceServices, SemanticModel semanticModel, int position, SymbolDescriptionOptions options, IReadOnlyList symbols) + SolutionServices workspaceServices, SemanticModel semanticModel, int position, SymbolDescriptionOptions options, IReadOnlyList symbols) { return c => CreateDescriptionAsync(workspaceServices, semanticModel, position, symbols, options, supportedPlatforms: null, cancellationToken: c); } public static Func> CreateDescriptionFactory( - HostWorkspaceServices workspaceServices, SemanticModel semanticModel, int position, IReadOnlyList symbols, SymbolDescriptionOptions options, SupportedPlatformData supportedPlatforms) + SolutionServices workspaceServices, SemanticModel semanticModel, int position, IReadOnlyList symbols, SymbolDescriptionOptions options, SupportedPlatformData supportedPlatforms) { return c => CreateDescriptionAsync(workspaceServices, semanticModel, position, symbols, options, supportedPlatforms: supportedPlatforms, cancellationToken: c); } public static async Task CreateDescriptionAsync( - HostWorkspaceServices workspaceServices, SemanticModel semanticModel, int position, ISymbol symbol, int overloadCount, SymbolDescriptionOptions options, SupportedPlatformData? supportedPlatforms, CancellationToken cancellationToken) + SolutionServices workspaceServices, SemanticModel semanticModel, int position, ISymbol symbol, int overloadCount, SymbolDescriptionOptions options, SupportedPlatformData? supportedPlatforms, CancellationToken cancellationToken) { - var symbolDisplayService = workspaceServices.GetLanguageServices(semanticModel.Language).GetRequiredService(); - var formatter = workspaceServices.GetLanguageServices(semanticModel.Language).GetRequiredService(); + var symbolDisplayService = workspaceServices.GetRequiredLanguageService(semanticModel.Language); + var formatter = workspaceServices.GetRequiredLanguageService(semanticModel.Language); // TODO(cyrusn): Figure out a way to cancel this. var sections = await symbolDisplayService.ToDescriptionGroupsAsync(semanticModel, position, ImmutableArray.Create(symbol), options, cancellationToken).ConfigureAwait(false); @@ -172,7 +172,7 @@ public static async Task CreateDescriptionAsync( } public static Task CreateDescriptionAsync( - HostWorkspaceServices workspaceServices, SemanticModel semanticModel, int position, IReadOnlyList symbols, SymbolDescriptionOptions options, SupportedPlatformData? supportedPlatforms, CancellationToken cancellationToken) + SolutionServices workspaceServices, SemanticModel semanticModel, int position, IReadOnlyList symbols, SymbolDescriptionOptions options, SupportedPlatformData? supportedPlatforms, CancellationToken cancellationToken) { // Lets try to find the first non-obsolete symbol (overload) and fall-back // to the first symbol if all are obsolete. diff --git a/src/Features/Core/Portable/Completion/CompletionChange.cs b/src/Features/Core/Portable/Completion/CompletionChange.cs index 4c7f456992d04..1e59751452d00 100644 --- a/src/Features/Core/Portable/Completion/CompletionChange.cs +++ b/src/Features/Core/Portable/Completion/CompletionChange.cs @@ -3,6 +3,7 @@ // See the LICENSE file in the project root for more information. using System; +using System.Collections.Generic; using System.Collections.Immutable; using System.Linq; using Microsoft.CodeAnalysis.Text; @@ -40,8 +41,16 @@ public sealed class CompletionChange /// public bool IncludesCommitCharacter { get; } + internal ImmutableDictionary Properties { get; } + private CompletionChange( TextChange textChange, ImmutableArray textChanges, int? newPosition, bool includesCommitCharacter) + : this(textChange, textChanges, newPosition, includesCommitCharacter, ImmutableDictionary.Empty) + { + } + + private CompletionChange( + TextChange textChange, ImmutableArray textChanges, int? newPosition, bool includesCommitCharacter, ImmutableDictionary properties) { TextChange = textChange; NewPosition = newPosition; @@ -49,6 +58,7 @@ private CompletionChange( TextChanges = textChanges.NullToEmpty(); if (TextChanges.IsEmpty) TextChanges = ImmutableArray.Create(textChange); + Properties = properties; } /// @@ -97,6 +107,16 @@ public static CompletionChange Create( return new CompletionChange(textChange, textChanges, newPosition, includesCommitCharacter); } + internal static CompletionChange Create( + TextChange textChange, + ImmutableArray textChanges, + ImmutableDictionary properties, + int? newPosition, + bool includesCommitCharacter) + { + return new CompletionChange(textChange, textChanges, newPosition, includesCommitCharacter, properties); + } + /// /// Creates a copy of this with the property changed. /// diff --git a/src/Features/Core/Portable/Completion/CompletionHelper.cs b/src/Features/Core/Portable/Completion/CompletionHelper.cs index 7b87af061de72..b0952056014e1 100644 --- a/src/Features/Core/Portable/Completion/CompletionHelper.cs +++ b/src/Features/Core/Portable/Completion/CompletionHelper.cs @@ -32,14 +32,14 @@ public CompletionHelper(bool isCaseSensitive) public static CompletionHelper GetHelper(Document document) { - return document.Project.Solution.Workspace.Services.GetRequiredService() + return document.Project.Solution.Services.GetRequiredService() .GetCompletionHelper(document); } public ImmutableArray GetHighlightedSpans( - string text, string pattern, CultureInfo culture) + CompletionItem item, string pattern, CultureInfo culture) { - var match = GetMatch(text, pattern, includeMatchSpans: true, culture: culture); + var match = GetMatch(item.GetEntireDisplayText(), pattern, includeMatchSpans: true, culture: culture); return match == null ? ImmutableArray.Empty : match.Value.MatchedSpans; } @@ -48,11 +48,31 @@ public ImmutableArray GetHighlightedSpans( /// if and only if the completion item matches and should be included in the filtered completion /// results, or false if it should not be. /// - public bool MatchesPattern(string text, string pattern, CultureInfo culture) - => GetMatch(text, pattern, includeMatchSpans: false, culture) != null; + public bool MatchesPattern(CompletionItem item, string pattern, CultureInfo culture) + => GetMatch(item, pattern, includeMatchSpans: false, culture) != null; public PatternMatch? GetMatch( - string completionItemText, + CompletionItem item, + string pattern, + bool includeMatchSpans, + CultureInfo culture) + { + var match = GetMatch(item.FilterText, pattern, includeMatchSpans, culture); + if (item.HasAdditionalFilterTexts) + { + foreach (var additionalFilterText in item.AdditionalFilterTexts) + { + var additionalMatch = GetMatch(additionalFilterText, pattern, includeMatchSpans, culture); + if (additionalMatch.HasValue && additionalMatch.Value.CompareTo(match, ignoreCase: false) < 0) + match = additionalMatch; + } + } + + return match; + } + + private PatternMatch? GetMatch( + string text, string pattern, bool includeMatchSpans, CultureInfo culture) @@ -63,11 +83,11 @@ public bool MatchesPattern(string text, string pattern, CultureInfo culture) // better match as they'll both be prefix matches, and the latter will have a higher // priority. - var lastDotIndex = completionItemText.LastIndexOf('.'); + var lastDotIndex = text.LastIndexOf('.'); if (lastDotIndex >= 0) { var afterDotPosition = lastDotIndex + 1; - var textAfterLastDot = completionItemText[afterDotPosition..]; + var textAfterLastDot = text[afterDotPosition..]; var match = GetMatchWorker(textAfterLastDot, pattern, culture, includeMatchSpans); if (match != null) @@ -78,7 +98,7 @@ public bool MatchesPattern(string text, string pattern, CultureInfo culture) // Didn't have a dot, or the user text didn't match the portion after the dot. // Just do a normal check against the entire completion item. - return GetMatchWorker(completionItemText, pattern, culture, includeMatchSpans); + return GetMatchWorker(text, pattern, culture, includeMatchSpans); } private static PatternMatch? AdjustMatchedSpans(PatternMatch value, int offset) @@ -87,11 +107,11 @@ public bool MatchesPattern(string text, string pattern, CultureInfo culture) : value.WithMatchedSpans(value.MatchedSpans.SelectAsArray(s => new TextSpan(s.Start + offset, s.Length))); private PatternMatch? GetMatchWorker( - string completionItemText, string pattern, + string text, string pattern, CultureInfo culture, bool includeMatchSpans) { var patternMatcher = GetPatternMatcher(pattern, culture, includeMatchSpans); - var match = patternMatcher.GetFirstMatch(completionItemText); + var match = patternMatcher.GetFirstMatch(text); // We still have making checks for language having different to English capitalization, // for example, for Turkish with dotted and dotless i capitalization totally diferent from English. @@ -106,7 +126,7 @@ public bool MatchesPattern(string text, string pattern, CultureInfo culture) // Identifiers can be in user language. // Try to get matches for both and return the best of them. patternMatcher = GetPatternMatcher(pattern, EnUSCultureInfo, includeMatchSpans); - var enUSCultureMatch = patternMatcher.GetFirstMatch(completionItemText); + var enUSCultureMatch = patternMatcher.GetFirstMatch(text); if (match == null) { @@ -143,18 +163,6 @@ private PatternMatcher GetPatternMatcher( private PatternMatcher GetPatternMatcher(string pattern, CultureInfo culture, bool includeMatchedSpans) => GetPatternMatcher(pattern, culture, includeMatchedSpans, _patternMatcherMap); - /// - /// Returns true if item1 is a better completion item than item2 given the provided filter - /// text, or false if it is not better. - /// - public int CompareItems(CompletionItem item1, CompletionItem item2, string pattern, CultureInfo culture) - { - var match1 = GetMatch(item1.FilterText, pattern, includeMatchSpans: false, culture); - var match2 = GetMatch(item2.FilterText, pattern, includeMatchSpans: false, culture); - - return CompareItems(item1, match1, item2, match2, out _); - } - public int CompareItems(CompletionItem item1, PatternMatch? match1, CompletionItem item2, PatternMatch? match2, out bool onlyDifferInCaseSensitivity) { onlyDifferInCaseSensitivity = false; @@ -382,10 +390,10 @@ internal static bool TryCreateMatchResult( CompletionHelper completionHelper, CompletionItem item, T editorCompletionItem, - string filterText, + string pattern, CompletionTriggerKind initialTriggerKind, CompletionFilterReason filterReason, - ImmutableArray recentItems, + bool isRecentItem, bool includeMatchSpans, int currentIndex, out MatchResult matchResult) @@ -396,23 +404,49 @@ internal static bool TryCreateMatchResult( // against terms like "IList" and not IList<>. // Note that the check on filter text length is purely for efficiency, we should // get the same result with or without it. - var patternMatch = filterText.Length > 0 - ? completionHelper.GetMatch(item.FilterText, filterText, includeMatchSpans, CultureInfo.CurrentCulture) + var patternMatch = pattern.Length > 0 + ? completionHelper.GetMatch(item.FilterText, pattern, includeMatchSpans, CultureInfo.CurrentCulture) : null; - var matchedFilterText = MatchesFilterText( - item, - filterText, + string? matchedAdditionalFilterText = null; + var shouldBeConsideredMatchingFilterText = ShouldBeConsideredMatchingFilterText( + item.FilterText, + pattern, + item.Rules.MatchPriority, initialTriggerKind, filterReason, - recentItems, + isRecentItem, patternMatch); - if (matchedFilterText || KeepAllItemsInTheList(initialTriggerKind, filterText)) + if (pattern.Length > 0 && item.HasAdditionalFilterTexts) + { + foreach (var additionalFilterText in item.AdditionalFilterTexts) + { + var additionalMatch = completionHelper.GetMatch(additionalFilterText, pattern, includeMatchSpans, CultureInfo.CurrentCulture); + var additionalFlag = ShouldBeConsideredMatchingFilterText( + additionalFilterText, + pattern, + item.Rules.MatchPriority, + initialTriggerKind, + filterReason, + isRecentItem, + additionalMatch); + + if (!shouldBeConsideredMatchingFilterText || + additionalFlag && additionalMatch.HasValue && additionalMatch.Value.CompareTo(patternMatch, ignoreCase: false) < 0) + { + matchedAdditionalFilterText = additionalFilterText; + shouldBeConsideredMatchingFilterText = additionalFlag; + patternMatch = additionalMatch; + } + } + } + + if (shouldBeConsideredMatchingFilterText || KeepAllItemsInTheList(initialTriggerKind, pattern)) { matchResult = new MatchResult( - item, editorCompletionItem, matchedFilterText: matchedFilterText, - patternMatch: patternMatch, currentIndex); + item, editorCompletionItem, shouldBeConsideredMatchingFilterText, + patternMatch, currentIndex, matchedAdditionalFilterText); return true; } @@ -420,12 +454,13 @@ internal static bool TryCreateMatchResult( matchResult = default; return false; - static bool MatchesFilterText( - CompletionItem item, + static bool ShouldBeConsideredMatchingFilterText( string filterText, + string pattern, + int matchPriority, CompletionTriggerKind initialTriggerKind, CompletionFilterReason filterReason, - ImmutableArray recentItems, + bool isRecentItem, PatternMatch? patternMatch) { // For the deletion we bake in the core logic for how matching should work. @@ -438,34 +473,21 @@ static bool MatchesFilterText( if (filterReason == CompletionFilterReason.Deletion && initialTriggerKind == CompletionTriggerKind.Deletion) { - return item.FilterText.GetCaseInsensitivePrefixLength(filterText) > 0; + return filterText.GetCaseInsensitivePrefixLength(pattern) > 0; } // If the user hasn't typed anything, and this item was preselected, or was in the // MRU list, then we definitely want to include it. - if (filterText.Length == 0) + if (pattern.Length == 0) { - if (item.Rules.MatchPriority > MatchPriority.Default) - { + if (isRecentItem || matchPriority > MatchPriority.Default) return true; - } - - if (!recentItems.IsDefault && GetRecentItemIndex(recentItems, item) <= 0) - { - return true; - } } // Otherwise, the item matches filter text if a pattern match is returned. return patternMatch != null; } - static int GetRecentItemIndex(ImmutableArray recentItems, CompletionItem item) - { - var index = recentItems.IndexOf(item.FilterText); - return -index; - } - // If the item didn't match the filter text, we still keep it in the list // if one of two things is true: // 1. The user has typed nothing or only typed a single character. In this case they might diff --git a/src/Features/Core/Portable/Completion/CompletionHelperServiceFactory.cs b/src/Features/Core/Portable/Completion/CompletionHelperServiceFactory.cs index cca71708559ce..1a2f95d7d37e6 100644 --- a/src/Features/Core/Portable/Completion/CompletionHelperServiceFactory.cs +++ b/src/Features/Core/Portable/Completion/CompletionHelperServiceFactory.cs @@ -6,7 +6,7 @@ using System.Composition; using Microsoft.CodeAnalysis.Host; using Microsoft.CodeAnalysis.Host.Mef; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Shared.Extensions; using Roslyn.Utilities; diff --git a/src/Features/Core/Portable/Completion/CompletionItem.cs b/src/Features/Core/Portable/Completion/CompletionItem.cs index ee534d541c98d..4230632eabba5 100644 --- a/src/Features/Core/Portable/Completion/CompletionItem.cs +++ b/src/Features/Core/Portable/Completion/CompletionItem.cs @@ -8,6 +8,7 @@ using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using Microsoft.CodeAnalysis.Text; +using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Completion { @@ -45,8 +46,23 @@ public sealed class CompletionItem : IComparable /// public string FilterText => _filterText ?? DisplayText; + /// + /// If provided, each additional string would be used in the same way as for item matching. + /// However, there's a key difference: matches of is considered inferior than matches + /// of when they have identical pattern matching result. + /// + internal ImmutableArray AdditionalFilterTexts { get; init; } = ImmutableArray.Empty; + + /// + /// Returns if is identical to . + /// Otherwise returns . + /// Be aware that this value is independent from and could return + /// even if is . + /// internal bool HasDifferentFilterText => _filterText != null; + internal bool HasAdditionalFilterTexts => !AdditionalFilterTexts.IsEmpty; + /// /// The text used to determine the order that the item appears in the list. /// This is often the same as the but may be different in certain circumstances. @@ -261,7 +277,8 @@ private CompletionItem With( Optional displayTextPrefix = default, Optional displayTextSuffix = default, Optional inlineDescription = default, - Optional isComplexTextEdit = default) + Optional isComplexTextEdit = default, + Optional> additionalFilterTexts = default) { var newSpan = span.HasValue ? span.Value : Span; var newDisplayText = displayText.HasValue ? displayText.Value : DisplayText; @@ -274,6 +291,7 @@ private CompletionItem With( var newDisplayTextPrefix = displayTextPrefix.HasValue ? displayTextPrefix.Value : DisplayTextPrefix; var newDisplayTextSuffix = displayTextSuffix.HasValue ? displayTextSuffix.Value : DisplayTextSuffix; var newIsComplexTextEdit = isComplexTextEdit.HasValue ? isComplexTextEdit.Value : IsComplexTextEdit; + var newAdditionalFilterTexts = additionalFilterTexts.HasValue ? additionalFilterTexts.Value.NullToEmpty() : AdditionalFilterTexts; if (newSpan == Span && newDisplayText == DisplayText && @@ -285,7 +303,8 @@ private CompletionItem With( newDisplayTextPrefix == DisplayTextPrefix && newDisplayTextSuffix == DisplayTextSuffix && newInlineDescription == InlineDescription && - newIsComplexTextEdit == IsComplexTextEdit) + newIsComplexTextEdit == IsComplexTextEdit && + newAdditionalFilterTexts == AdditionalFilterTexts) { return this; } @@ -306,6 +325,7 @@ private CompletionItem With( AutomationText = AutomationText, ProviderName = ProviderName, Flags = Flags, + AdditionalFilterTexts = newAdditionalFilterTexts }; } @@ -397,6 +417,12 @@ public CompletionItem WithRules(CompletionItemRules rules) public CompletionItem WithIsComplexTextEdit(bool isComplexTextEdit) => With(isComplexTextEdit: isComplexTextEdit); + /// + /// Creates a copy of this with the property changed. + /// + internal CompletionItem WithAdditionalFilterTexts(ImmutableArray additionalFilterTexts) + => With(additionalFilterTexts: additionalFilterTexts); + int IComparable.CompareTo([AllowNull] CompletionItem other) { if (other == null) diff --git a/src/Features/Core/Portable/Completion/CompletionList.cs b/src/Features/Core/Portable/Completion/CompletionList.cs index 9de387eb48a68..b43b63d566e6e 100644 --- a/src/Features/Core/Portable/Completion/CompletionList.cs +++ b/src/Features/Core/Portable/Completion/CompletionList.cs @@ -5,6 +5,7 @@ using System; using System.Collections.Generic; using System.Collections.Immutable; +using System.ComponentModel; using Microsoft.CodeAnalysis.Text; using Roslyn.Utilities; @@ -15,12 +16,13 @@ namespace Microsoft.CodeAnalysis.Completion /// public sealed class CompletionList { - private readonly bool _isExclusive; private readonly Lazy> _lazyItems; /// /// The completion items to present to the user. /// + [Obsolete($"This property is obsolete. Use {nameof(ItemsList)} instead", error: false)] + [EditorBrowsable(EditorBrowsableState.Never)] public ImmutableArray Items => _lazyItems.Value; /// @@ -28,7 +30,7 @@ public sealed class CompletionList /// This property is preferred over `Items` because of the flexibility it provides. /// For example, the list can be backed by types like SegmentedList to avoid LOH allocations. /// - internal IReadOnlyList ItemsList { get; } + public IReadOnlyList ItemsList { get; } /// /// The span of the syntax element at the caret position when the was created. @@ -61,6 +63,11 @@ public sealed class CompletionList /// public CompletionItem? SuggestionModeItem { get; } + /// + /// Whether the items in this list should be the only items presented to the user. + /// + internal bool IsExclusive { get; } + private CompletionList( TextSpan defaultSpan, IReadOnlyList itemsList, @@ -74,7 +81,7 @@ private CompletionList( Rules = rules ?? CompletionRules.Default; SuggestionModeItem = suggestionModeItem; - _isExclusive = isExclusive; + IsExclusive = isExclusive; foreach (var item in ItemsList) { @@ -129,7 +136,7 @@ private CompletionList With( } else { - return Create(newSpan, newItemsList, newRules, newSuggestionModeItem, isExclusive: false); + return Create(newSpan, newItemsList, newRules, newSuggestionModeItem, IsExclusive); } } @@ -177,18 +184,5 @@ public CompletionList WithSuggestionModeItem(CompletionItem suggestionModeItem) suggestionModeItem: null, isExclusive: false); internal bool IsEmpty => ItemsList.Count == 0 && SuggestionModeItem is null; - - internal TestAccessor GetTestAccessor() - => new(this); - - internal readonly struct TestAccessor - { - private readonly CompletionList _completionList; - - public TestAccessor(CompletionList completionList) - => _completionList = completionList; - - internal bool IsExclusive => _completionList._isExclusive; - } } } diff --git a/src/Features/Core/Portable/Completion/CompletionOptions.cs b/src/Features/Core/Portable/Completion/CompletionOptions.cs index 7642ccd08faa0..9d4cf0ea06ede 100644 --- a/src/Features/Core/Portable/Completion/CompletionOptions.cs +++ b/src/Features/Core/Portable/Completion/CompletionOptions.cs @@ -27,6 +27,8 @@ internal sealed record class CompletionOptions public bool UpdateImportCompletionCacheInBackground { get; init; } = false; public bool FilterOutOfScopeLocals { get; init; } = true; public bool ShowXmlDocCommentCompletion { get; init; } = true; + public bool? ShowNewSnippetExperience { get; init; } = null; + public bool SnippetCompletion { get; init; } = false; public ExpandedCompletionMode ExpandedCompletionBehavior { get; init; } = ExpandedCompletionMode.AllItems; public NamingStylePreferences? NamingStyleFallbackOptions { get; init; } = null; @@ -42,10 +44,21 @@ public RecommendationServiceOptions ToRecommendationServiceOptions() /// This takes into consideration the experiment we are running in addition to the value /// from user facing options. /// - public bool ShouldShowItemsFromUnimportNamspaces() + public bool ShouldShowItemsFromUnimportedNamespaces() { // Don't trigger import completion if the option value is "default" and the experiment is disabled for the user. return ShowItemsFromUnimportedNamespaces ?? TypeImportCompletion; } + + /// + /// Whether items from new snippet experience should be included in the completion list. + /// This takes into consideration the experiment we are running in addition to the value + /// from user facing options. + /// + public bool ShouldShowNewSnippetExperience() + { + // Don't trigger snippet completion if the option value is "default" and the experiment is disabled for the user. + return ShowNewSnippetExperience ?? SnippetCompletion; + } } } diff --git a/src/Features/Core/Portable/Completion/CompletionProvider.cs b/src/Features/Core/Portable/Completion/CompletionProvider.cs index e23688c70c16f..d52072b0378d6 100644 --- a/src/Features/Core/Portable/Completion/CompletionProvider.cs +++ b/src/Features/Core/Portable/Completion/CompletionProvider.cs @@ -5,7 +5,7 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.Host; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Text; @@ -44,7 +44,7 @@ public virtual bool ShouldTriggerCompletion(SourceText text, int caretPosition, /// The position of the caret after the triggering action. /// The triggering action. /// The set of options in effect. - internal virtual bool ShouldTriggerCompletion(HostLanguageServices languageServices, SourceText text, int caretPosition, CompletionTrigger trigger, CompletionOptions options, OptionSet passThroughOptions) + internal virtual bool ShouldTriggerCompletion(LanguageServices languageServices, SourceText text, int caretPosition, CompletionTrigger trigger, CompletionOptions options, OptionSet passThroughOptions) #pragma warning disable RS0030, CS0618 // Do not used banned/obsolete APIs => ShouldTriggerCompletion(text, caretPosition, trigger, passThroughOptions); #pragma warning restore @@ -55,7 +55,7 @@ internal virtual bool ShouldTriggerCompletion(HostLanguageServices languageServi /// an augmenting provider instead. /// internal virtual async Task IsSyntacticTriggerCharacterAsync(Document document, int caretPosition, CompletionTrigger trigger, CompletionOptions options, CancellationToken cancellationToken) - => ShouldTriggerCompletion(document.Project.LanguageServices, await document.GetTextAsync(cancellationToken).ConfigureAwait(false), caretPosition, trigger, options, document.Project.Solution.Options); + => ShouldTriggerCompletion(document.Project.Services, await document.GetTextAsync(cancellationToken).ConfigureAwait(false), caretPosition, trigger, options, document.Project.Solution.Options); /// /// Gets the description of the specified item. diff --git a/src/Features/Core/Portable/Completion/CompletionService.ProviderManager.cs b/src/Features/Core/Portable/Completion/CompletionService.ProviderManager.cs index 8bc7bf282f1b1..f4f3ad3df4816 100644 --- a/src/Features/Core/Portable/Completion/CompletionService.ProviderManager.cs +++ b/src/Features/Core/Portable/Completion/CompletionService.ProviderManager.cs @@ -12,6 +12,7 @@ using Microsoft.CodeAnalysis.Completion.Providers; using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.Host.Mef; +using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Shared.Utilities; using Roslyn.Utilities; @@ -25,26 +26,21 @@ private sealed class ProviderManager : IEqualityComparer _nameToProvider = new(); private readonly Dictionary, ImmutableArray> _rolesToProviders; - private readonly Func, ImmutableArray> _createRoleProviders; - private readonly Func _getProviderByName; - - private IEnumerable>? _lazyImportedProviders; + private IReadOnlyList>? _lazyImportedProviders; private readonly CompletionService _service; public ProviderManager(CompletionService service) { _service = service; _rolesToProviders = new Dictionary, ImmutableArray>(this); - _createRoleProviders = CreateRoleProviders; - _getProviderByName = GetProviderByName; } - public IEnumerable> GetImportedProviders() + public IReadOnlyList> GetLazyImportedProviders() { if (_lazyImportedProviders == null) { var language = _service.Language; - var mefExporter = (IMefHostExportProvider)_service._workspace.Services.HostServices; + var mefExporter = _service._services.ExportProvider; var providers = ExtensionOrderer.Order( mefExporter.GetExports() @@ -57,65 +53,77 @@ public IEnumerable> GetImpo return _lazyImportedProviders; } - public ImmutableArray GetAllProviders(ImmutableHashSet roles) + public static ImmutableArray GetProjectCompletionProviders(Project? project) { - var imported = GetImportedProviders() - .Where(lz => lz.Metadata.Roles == null || lz.Metadata.Roles.Length == 0 || roles.Overlaps(lz.Metadata.Roles)) - .Select(lz => lz.Value); - -#pragma warning disable 0618 - // We need to keep supporting built-in providers for a while longer since this is a public API. - // https://github.com/dotnet/roslyn/issues/42367 - var builtin = _service.GetBuiltInProviders(); -#pragma warning restore 0618 + if (project is null || project.Solution.WorkspaceKind == WorkspaceKind.Interactive) + { + // TODO (https://github.com/dotnet/roslyn/issues/4932): Don't restrict completions in Interactive + return ImmutableArray.Empty; + } - return imported.Concat(builtin).ToImmutableArray(); + return ProjectCompletionProvider.GetExtensions(project); } - public ImmutableArray GetProviders(ImmutableHashSet? roles) + private ImmutableArray GetImportedAndBuiltInProviders(ImmutableHashSet? roles) { roles ??= ImmutableHashSet.Empty; lock (_gate) { - return _rolesToProviders.GetOrAdd(roles, _createRoleProviders); + if (!_rolesToProviders.TryGetValue(roles, out var providers)) + { + providers = GetImportedAndBuiltInProvidersWorker(roles); + _rolesToProviders.Add(roles, providers); + } + + return providers; + } + + ImmutableArray GetImportedAndBuiltInProvidersWorker(ImmutableHashSet roles) + { + using var _ = ArrayBuilder.GetInstance(out var providers); + providers.AddRange(GetLazyImportedProviders() + .Where(lz => lz.Metadata.Roles == null || lz.Metadata.Roles.Length == 0 || roles.Overlaps(lz.Metadata.Roles)) + .Select(lz => lz.Value)); + +#pragma warning disable 0618 + // We need to keep supporting built-in providers for a while longer since this is a public API. + // https://github.com/dotnet/roslyn/issues/42367 + providers.AddRange(_service.GetBuiltInProviders()); +#pragma warning restore 0618 + + return providers.ToImmutable(); } } - public CompletionProvider? GetProvider(CompletionItem item) + public CompletionProvider? GetProvider(CompletionItem item, Project? project) { + if (item.ProviderName == null) + return null; + CompletionProvider? provider = null; + using var _ = PooledDelegates.GetPooledFunction(static (p, n) => p.Name == n, item.ProviderName, out Func isNameMatchingProviderPredicate); - if (item.ProviderName != null) + lock (_gate) { - lock (_gate) + if (!_nameToProvider.TryGetValue(item.ProviderName, out provider)) { - provider = _nameToProvider.GetOrAdd(item.ProviderName, _getProviderByName); + provider = GetImportedAndBuiltInProviders(roles: ImmutableHashSet.Empty).FirstOrDefault(isNameMatchingProviderPredicate); + _nameToProvider.Add(item.ProviderName, provider); } } - return provider; + return provider ?? GetProjectCompletionProviders(project).FirstOrDefault(isNameMatchingProviderPredicate); } public ConcatImmutableArray GetFilteredProviders( Project? project, ImmutableHashSet? roles, CompletionTrigger trigger, in CompletionOptions options) { - var allCompletionProviders = FilterProviders(GetProviders(roles), trigger, options); + var allCompletionProviders = FilterProviders(GetImportedAndBuiltInProviders(roles), trigger, options); var projectCompletionProviders = FilterProviders(GetProjectCompletionProviders(project), trigger, options); return allCompletionProviders.ConcatFast(projectCompletionProviders); } - public static ImmutableArray GetProjectCompletionProviders(Project? project) - { - if (project?.Solution.Workspace.Kind == WorkspaceKind.Interactive) - { - // TODO (https://github.com/dotnet/roslyn/issues/4932): Don't restrict completions in Interactive - return ImmutableArray.Empty; - } - - return ProjectCompletionProvider.GetExtensions(project); - } - private ImmutableArray FilterProviders( ImmutableArray providers, CompletionTrigger trigger, @@ -159,24 +167,6 @@ private ImmutableArray FilterProviders( return ImmutableArray.Empty; } - private CompletionProvider? GetProviderByName(string providerName) - { - var providers = GetAllProviders(roles: ImmutableHashSet.Empty); - return providers.FirstOrDefault(p => p.Name == providerName); - } - - private ImmutableArray CreateRoleProviders(ImmutableHashSet roles) - { - var providers = GetAllProviders(roles); - - foreach (var provider in providers) - { - _nameToProvider[provider.Name] = provider; - } - - return providers; - } - bool IEqualityComparer>.Equals([AllowNull] ImmutableHashSet x, [AllowNull] ImmutableHashSet y) { if (x == y) @@ -230,6 +220,27 @@ protected override bool TryGetExtensionsFromReference(AnalyzerReference referenc return false; } } + + internal TestAccessor GetTestAccessor() + => new(this); + + internal readonly struct TestAccessor + { + private readonly ProviderManager _providerManager; + + public TestAccessor(ProviderManager providerManager) + { + _providerManager = providerManager; + } + + public ImmutableArray GetProviders(ImmutableHashSet roles, Project? project) + { + using var _ = ArrayBuilder.GetInstance(out var providers); + providers.AddRange(_providerManager.GetImportedAndBuiltInProviders(roles)); + providers.AddRange(GetProjectCompletionProviders(project)); + return providers.ToImmutable(); + } + } } } } diff --git a/src/Features/Core/Portable/Completion/CompletionService.cs b/src/Features/Core/Portable/Completion/CompletionService.cs index 9228bdff74be0..dacae8c6f8044 100644 --- a/src/Features/Core/Portable/Completion/CompletionService.cs +++ b/src/Features/Core/Portable/Completion/CompletionService.cs @@ -13,7 +13,7 @@ using Microsoft.CodeAnalysis.Collections; using Microsoft.CodeAnalysis.Completion.Providers; using Microsoft.CodeAnalysis.Host; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.PatternMatching; using Microsoft.CodeAnalysis.PooledObjects; @@ -30,7 +30,7 @@ namespace Microsoft.CodeAnalysis.Completion /// public abstract partial class CompletionService : ILanguageService { - private readonly Workspace _workspace; + private readonly SolutionServices _services; private readonly ProviderManager _providerManager; /// @@ -39,9 +39,9 @@ public abstract partial class CompletionService : ILanguageService private bool _suppressPartialSemantics; // Prevent inheritance outside of Roslyn. - internal CompletionService(Workspace workspace) + internal CompletionService(SolutionServices services) { - _workspace = workspace; + _services = services; _providerManager = new(this); } @@ -99,7 +99,7 @@ public bool ShouldTriggerCompletion( OptionSet? options = null) { var document = text.GetOpenDocumentInCurrentContextWithChanges(); - var languageServices = document?.Project.LanguageServices ?? _workspace.Services.GetLanguageServices(Language); + var languageServices = document?.Project.Services ?? _services.GetLanguageServices(Language); // Publicly available options do not affect this API. var completionOptions = CompletionOptions.Default; @@ -129,7 +129,7 @@ internal virtual bool SupportsTriggerOnDeletion(CompletionOptions options) /// internal virtual bool ShouldTriggerCompletion( Project? project, - HostLanguageServices languageServices, + LanguageServices languageServices, SourceText text, int caretPosition, CompletionTrigger trigger, @@ -194,7 +194,7 @@ public virtual TextSpan GetDefaultCompletionListSpan(SourceText text, int caretP /// internal virtual async Task GetDescriptionAsync(Document document, CompletionItem item, CompletionOptions options, SymbolDescriptionOptions displayOptions, CancellationToken cancellationToken = default) { - var provider = GetProvider(item); + var provider = GetProvider(item, document.Project); if (provider is null) return CompletionDescription.Empty; @@ -220,7 +220,7 @@ public virtual async Task GetChangeAsync( char? commitCharacter = null, CancellationToken cancellationToken = default) { - var provider = GetProvider(item); + var provider = GetProvider(item, document.Project); if (provider != null) { // We don't need SemanticModel here, just want to make sure it won't get GC'd before CompletionProviders are able to get it. @@ -250,7 +250,7 @@ public virtual ImmutableArray FilterItems( { var helper = CompletionHelper.GetHelper(document); var itemsWithPatternMatch = new SegmentedList<(CompletionItem, PatternMatch?)>(items.Select( - item => (item, helper.GetMatch(item.FilterText, filterText, includeMatchSpans: false, CultureInfo.CurrentCulture)))); + item => (item, helper.GetMatch(item, filterText, includeMatchSpans: false, CultureInfo.CurrentCulture)))); var builder = ImmutableArray.CreateBuilder(); FilterItems(helper, itemsWithPatternMatch, filterText, builder); @@ -392,17 +392,17 @@ internal static void FilterItems( /// /// Don't call. Used for pre-populating MEF providers only. /// - internal IEnumerable> GetImportedProviders() - => _providerManager.GetImportedProviders(); + internal IReadOnlyList> GetLazyImportedProviders() + => _providerManager.GetLazyImportedProviders(); /// /// Don't call. Used for pre-populating NuGet providers only. /// - internal static ImmutableArray GetProjectCompletionProviders(Project? project) + internal static ImmutableArray GetProjectCompletionProviders(Project project) => ProviderManager.GetProjectCompletionProviders(project); - internal CompletionProvider? GetProvider(CompletionItem item) - => _providerManager.GetProvider(item); + internal CompletionProvider? GetProvider(CompletionItem item, Project? project) + => _providerManager.GetProvider(item, project); internal TestAccessor GetTestAccessor() => new(this); @@ -414,8 +414,8 @@ internal readonly struct TestAccessor public TestAccessor(CompletionService completionServiceWithProviders) => _completionServiceWithProviders = completionServiceWithProviders; - internal ImmutableArray GetAllProviders(ImmutableHashSet roles) - => _completionServiceWithProviders._providerManager.GetAllProviders(roles); + internal ImmutableArray GetAllProviders(ImmutableHashSet roles, Project? project = null) + => _completionServiceWithProviders._providerManager.GetTestAccessor().GetProviders(roles, project); internal async Task GetContextAsync( CompletionProvider provider, diff --git a/src/Features/Core/Portable/Completion/CompletionService_GetCompletions.cs b/src/Features/Core/Portable/Completion/CompletionService_GetCompletions.cs index a59b64fecc45a..4991e4bcb0b78 100644 --- a/src/Features/Core/Portable/Completion/CompletionService_GetCompletions.cs +++ b/src/Features/Core/Portable/Completion/CompletionService_GetCompletions.cs @@ -12,7 +12,7 @@ using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Collections; using Microsoft.CodeAnalysis.Host; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Shared.Extensions; @@ -158,9 +158,9 @@ ImmutableArray GetTriggeredProviders( case CompletionTriggerKind.Insertion: case CompletionTriggerKind.Deletion: - if (ShouldTriggerCompletion(document.Project, document.Project.LanguageServices, text, caretPosition, trigger, options, passThroughOptions, roles)) + if (ShouldTriggerCompletion(document.Project, document.Project.Services, text, caretPosition, trigger, options, passThroughOptions, roles)) { - var triggeredProviders = providers.Where(p => p.ShouldTriggerCompletion(document.Project.LanguageServices, text, caretPosition, trigger, options, passThroughOptions)).ToImmutableArrayOrEmpty(); + var triggeredProviders = providers.Where(p => p.ShouldTriggerCompletion(document.Project.Services, text, caretPosition, trigger, options, passThroughOptions)).ToImmutableArrayOrEmpty(); Debug.Assert(ValidatePossibleTriggerCharacterSet(trigger.Kind, triggeredProviders, document, text, caretPosition, options)); return triggeredProviders.IsEmpty ? providers.ToImmutableArray() : triggeredProviders; @@ -297,7 +297,7 @@ private CompletionList MergeAndPruneCompletionLists( protected virtual bool ItemsMatch(CompletionItem item, CompletionItem existingItem) { return item.Span == existingItem.Span - && item.SortText == existingItem.SortText; + && item.SortText == existingItem.SortText && item.InlineDescription == existingItem.InlineDescription; } /// diff --git a/src/Features/Core/Portable/Completion/Log/CompletionProvidersLogger.cs b/src/Features/Core/Portable/Completion/Log/CompletionProvidersLogger.cs index f0f0030f34b4e..11fcfaeca6e46 100644 --- a/src/Features/Core/Portable/Completion/Log/CompletionProvidersLogger.cs +++ b/src/Features/Core/Portable/Completion/Log/CompletionProvidersLogger.cs @@ -2,16 +2,17 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +using System; using Microsoft.CodeAnalysis.Internal.Log; namespace Microsoft.CodeAnalysis.Completion.Log { internal static class CompletionProvidersLogger { - private static readonly StatisticLogAggregator s_statisticLogAggregator = new(); - private static readonly LogAggregator s_logAggregator = new(); + private static readonly StatisticLogAggregator s_statisticLogAggregator = new(); + private static readonly CountLogAggregator s_countLogAggregator = new(); - private static readonly HistogramLogAggregator s_histogramLogAggregator = new(bucketSize: 50, maxBucketValue: 1000); + private static readonly HistogramLogAggregator s_histogramLogAggregator = new(bucketSize: 50, maxBucketValue: 1000); internal enum ActionInfo { @@ -33,52 +34,52 @@ internal enum ActionInfo CommitUsingDotToAddParenthesis } - internal static void LogTypeImportCompletionTicksDataPoint(int count) + internal static void LogTypeImportCompletionTicksDataPoint(TimeSpan elapsed) { - s_histogramLogAggregator.IncreaseCount((int)ActionInfo.TypeImportCompletionTicks, count); - s_statisticLogAggregator.AddDataPoint((int)ActionInfo.TypeImportCompletionTicks, count); + s_histogramLogAggregator.LogTime(ActionInfo.TypeImportCompletionTicks, elapsed); + s_statisticLogAggregator.AddDataPoint(ActionInfo.TypeImportCompletionTicks, elapsed); } internal static void LogTypeImportCompletionItemCountDataPoint(int count) => - s_statisticLogAggregator.AddDataPoint((int)ActionInfo.TypeImportCompletionItemCount, count); + s_statisticLogAggregator.AddDataPoint(ActionInfo.TypeImportCompletionItemCount, count); internal static void LogTypeImportCompletionReferenceCountDataPoint(int count) => - s_statisticLogAggregator.AddDataPoint((int)ActionInfo.TypeImportCompletionReferenceCount, count); + s_statisticLogAggregator.AddDataPoint(ActionInfo.TypeImportCompletionReferenceCount, count); internal static void LogTypeImportCompletionCacheMiss() => - s_logAggregator.IncreaseCount((int)ActionInfo.TypeImportCompletionCacheMissCount); + s_countLogAggregator.IncreaseCount(ActionInfo.TypeImportCompletionCacheMissCount); internal static void LogCommitOfTypeImportCompletionItem() => - s_logAggregator.IncreaseCount((int)ActionInfo.CommitsOfTypeImportCompletionItem); + s_countLogAggregator.IncreaseCount(ActionInfo.CommitsOfTypeImportCompletionItem); - internal static void LogExtensionMethodCompletionTicksDataPoint(int total, int getSymbols, int createItems, bool isRemote) + internal static void LogExtensionMethodCompletionTicksDataPoint(TimeSpan total, TimeSpan getSymbols, TimeSpan createItems, bool isRemote) { - s_histogramLogAggregator.IncreaseCount((int)ActionInfo.ExtensionMethodCompletionTicks, total); - s_statisticLogAggregator.AddDataPoint((int)ActionInfo.ExtensionMethodCompletionTicks, total); + s_histogramLogAggregator.LogTime(ActionInfo.ExtensionMethodCompletionTicks, total); + s_statisticLogAggregator.AddDataPoint(ActionInfo.ExtensionMethodCompletionTicks, total); if (isRemote) { - s_statisticLogAggregator.AddDataPoint((int)ActionInfo.ExtensionMethodCompletionRemoteTicks, (total - getSymbols - createItems)); + s_statisticLogAggregator.AddDataPoint(ActionInfo.ExtensionMethodCompletionRemoteTicks, total - getSymbols - createItems); } - s_statisticLogAggregator.AddDataPoint((int)ActionInfo.ExtensionMethodCompletionGetSymbolsTicks, getSymbols); - s_statisticLogAggregator.AddDataPoint((int)ActionInfo.ExtensionMethodCompletionCreateItemsTicks, createItems); + s_statisticLogAggregator.AddDataPoint(ActionInfo.ExtensionMethodCompletionGetSymbolsTicks, getSymbols); + s_statisticLogAggregator.AddDataPoint(ActionInfo.ExtensionMethodCompletionCreateItemsTicks, createItems); } internal static void LogExtensionMethodCompletionMethodsProvidedDataPoint(int count) => - s_statisticLogAggregator.AddDataPoint((int)ActionInfo.ExtensionMethodCompletionMethodsProvided, count); + s_statisticLogAggregator.AddDataPoint(ActionInfo.ExtensionMethodCompletionMethodsProvided, count); internal static void LogCommitOfExtensionMethodImportCompletionItem() => - s_logAggregator.IncreaseCount((int)ActionInfo.CommitsOfExtensionMethodImportCompletionItem); + s_countLogAggregator.IncreaseCount(ActionInfo.CommitsOfExtensionMethodImportCompletionItem); internal static void LogExtensionMethodCompletionPartialResultCount() => - s_logAggregator.IncreaseCount((int)ActionInfo.ExtensionMethodCompletionPartialResultCount); + s_countLogAggregator.IncreaseCount(ActionInfo.ExtensionMethodCompletionPartialResultCount); internal static void LogCommitUsingSemicolonToAddParenthesis() => - s_logAggregator.IncreaseCount((int)ActionInfo.CommitUsingSemicolonToAddParenthesis); + s_countLogAggregator.IncreaseCount(ActionInfo.CommitUsingSemicolonToAddParenthesis); internal static void LogCommitUsingDotToAddParenthesis() => - s_logAggregator.IncreaseCount((int)ActionInfo.CommitUsingDotToAddParenthesis); + s_countLogAggregator.IncreaseCount(ActionInfo.CommitUsingDotToAddParenthesis); internal static void LogCustomizedCommitToAddParenthesis(char? commitChar) { @@ -99,33 +100,20 @@ internal static void ReportTelemetry() { foreach (var kv in s_statisticLogAggregator) { - var info = ((ActionInfo)kv.Key).ToString("f"); var statistics = kv.Value.GetStatisticResult(); - - m[CreateProperty(info, nameof(statistics.Maximum))] = statistics.Maximum; - m[CreateProperty(info, nameof(statistics.Minimum))] = statistics.Minimum; - m[CreateProperty(info, nameof(statistics.Mean))] = statistics.Mean; - m[CreateProperty(info, nameof(statistics.Range))] = statistics.Range; - m[CreateProperty(info, nameof(statistics.Count))] = statistics.Count; + statistics.WriteTelemetryPropertiesTo(m, prefix: kv.Key.ToString()); } - foreach (var kv in s_logAggregator) + foreach (var kv in s_countLogAggregator) { - var info = ((ActionInfo)kv.Key).ToString("f"); - m[info] = kv.Value.GetCount(); + m[kv.Key.ToString()] = kv.Value.GetCount(); } foreach (var kv in s_histogramLogAggregator) { - var info = ((ActionInfo)kv.Key).ToString("f"); - m[$"{info}.BucketSize"] = kv.Value.BucketSize; - m[$"{info}.MaxBucketValue"] = kv.Value.MaxBucketValue; - m[$"{info}.Buckets"] = kv.Value.GetBucketsAsString(); + kv.Value.WriteTelemetryPropertiesTo(m, prefix: kv.Key.ToString()); } })); } - - private static string CreateProperty(string parent, string child) - => parent + "." + child; } } diff --git a/src/Features/Core/Portable/Completion/MatchResult.cs b/src/Features/Core/Portable/Completion/MatchResult.cs index 0b39061bb28b9..f41bc801b2ed5 100644 --- a/src/Features/Core/Portable/Completion/MatchResult.cs +++ b/src/Features/Core/Portable/Completion/MatchResult.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.Generic; -using System.Collections.Immutable; using Microsoft.CodeAnalysis.PatternMatching; using Roslyn.Utilities; using RoslynCompletionItem = Microsoft.CodeAnalysis.Completion.CompletionItem; @@ -14,11 +12,20 @@ namespace Microsoft.CodeAnalysis.Completion internal readonly struct MatchResult { public readonly RoslynCompletionItem RoslynCompletionItem; - public readonly bool MatchedFilterText; - // In certain cases, there'd be no match but we'd still set `MatchedFilterText` to true, - // e.g. when the item is in MRU list. Therefore making this nullable. + // The value of `ShouldBeConsideredMatchingFilterText` doesn't 100% refect the actual PatternMatch result. + // In certain cases, there'd be no match but we'd still want to consider it a match (e.g. when the item is in MRU list,) + // and this is why PatternMatch can be null. There's also cases it's a match but we want to consider it a non-match + // (e.g. when not a prefix match in deleteion sceanrio). public readonly PatternMatch? PatternMatch; + public readonly bool ShouldBeConsideredMatchingFilterText; + + // Text used to create this match if it's one of the CompletionItem.AdditionalFilterTexts. null if it's FilterText. + public readonly string? MatchedAddtionalFilterText; + + public string FilterTextUsed => MatchedAddtionalFilterText ?? RoslynCompletionItem.FilterText; + + public bool MatchedWithAdditionalFilterTexts => MatchedAddtionalFilterText is not null; /// /// The actual editor completion item associated with this @@ -34,15 +41,17 @@ internal readonly struct MatchResult public MatchResult( RoslynCompletionItem roslynCompletionItem, TEditorCompletionItem editorCompletionItem, - bool matchedFilterText, + bool shouldBeConsideredMatchingFilterText, PatternMatch? patternMatch, - int index) + int index, + string? matchedAdditionalFilterText) { RoslynCompletionItem = roslynCompletionItem; EditorCompletionItem = editorCompletionItem; - MatchedFilterText = matchedFilterText; + ShouldBeConsideredMatchingFilterText = shouldBeConsideredMatchingFilterText; PatternMatch = patternMatch; _indexInOriginalSortedOrder = index; + MatchedAddtionalFilterText = matchedAdditionalFilterText; } public static IComparer> SortingComparer => FilterResultSortingComparer.Instance; @@ -62,10 +71,13 @@ public int Compare(MatchResult x, MatchResult x, MatchResult other, string filterText) + public int CompareTo(MatchResult other, string pattern) { - var thisItem = this.RoslynCompletionItem; + var thisItem = RoslynCompletionItem; var otherItem = other.RoslynCompletionItem; // Prefer the item that matches a longer prefix of the filter text. - var comparison = thisItem.FilterText.GetCaseInsensitivePrefixLength(filterText).CompareTo(otherItem.FilterText.GetCaseInsensitivePrefixLength(filterText)); + var comparison = FilterTextUsed.GetCaseInsensitivePrefixLength(pattern).CompareTo(other.FilterTextUsed.GetCaseInsensitivePrefixLength(pattern)); if (comparison != 0) return comparison; // If there are "Abc" vs "abc", we should prefer the case typed by user. - comparison = thisItem.FilterText.GetCaseSensitivePrefixLength(filterText).CompareTo(otherItem.FilterText.GetCaseSensitivePrefixLength(filterText)); + comparison = FilterTextUsed.GetCaseSensitivePrefixLength(pattern).CompareTo(other.FilterTextUsed.GetCaseSensitivePrefixLength(pattern)); if (comparison != 0) return comparison; diff --git a/src/Features/Core/Portable/Completion/Providers/AbstractAggregateEmbeddedLanguageCompletionProvider.cs b/src/Features/Core/Portable/Completion/Providers/AbstractAggregateEmbeddedLanguageCompletionProvider.cs index 281621ffe9bff..eebce9b7f1d25 100644 --- a/src/Features/Core/Portable/Completion/Providers/AbstractAggregateEmbeddedLanguageCompletionProvider.cs +++ b/src/Features/Core/Portable/Completion/Providers/AbstractAggregateEmbeddedLanguageCompletionProvider.cs @@ -11,7 +11,7 @@ using Microsoft.CodeAnalysis.EmbeddedLanguages; using Microsoft.CodeAnalysis.Host; using Microsoft.CodeAnalysis.Host.Mef; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Text; using Roslyn.Utilities; @@ -57,7 +57,7 @@ private static bool IsEmbeddedLanguageProvider(Lazy GetLanguageProviders(HostLanguageServices? languageServices) + protected ImmutableArray GetLanguageProviders(Host.LanguageServices? languageServices) { if (_languageProviders.IsDefault) { @@ -70,7 +70,7 @@ protected ImmutableArray GetLanguageProviders(HostLanguageSer public override ImmutableHashSet TriggerCharacters { get; } - internal sealed override bool ShouldTriggerCompletion(HostLanguageServices languageServices, SourceText text, int caretPosition, CompletionTrigger trigger, CompletionOptions options, OptionSet passThroughOptions) + internal sealed override bool ShouldTriggerCompletion(LanguageServices languageServices, SourceText text, int caretPosition, CompletionTrigger trigger, CompletionOptions options, OptionSet passThroughOptions) { foreach (var language in GetLanguageProviders(languageServices)) { @@ -89,7 +89,7 @@ internal sealed override bool ShouldTriggerCompletion(HostLanguageServices langu public override async Task ProvideCompletionsAsync(CompletionContext context) { - foreach (var language in GetLanguageProviders(context.Document.Project.LanguageServices)) + foreach (var language in GetLanguageProviders(context.Document.Project.Services)) { var completionProvider = language.CompletionProvider; if (completionProvider != null) diff --git a/src/Features/Core/Portable/Completion/Providers/AbstractAwaitCompletionProvider.cs b/src/Features/Core/Portable/Completion/Providers/AbstractAwaitCompletionProvider.cs index e72f3b6b18ee5..be6f981d649b7 100644 --- a/src/Features/Core/Portable/Completion/Providers/AbstractAwaitCompletionProvider.cs +++ b/src/Features/Core/Portable/Completion/Providers/AbstractAwaitCompletionProvider.cs @@ -9,7 +9,7 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.Editing; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Shared.Extensions.ContextQuery; diff --git a/src/Features/Core/Portable/Completion/Providers/AbstractCrefCompletionProvider.cs b/src/Features/Core/Portable/Completion/Providers/AbstractCrefCompletionProvider.cs index fc6fbf2445dde..3140fe54bc1c5 100644 --- a/src/Features/Core/Portable/Completion/Providers/AbstractCrefCompletionProvider.cs +++ b/src/Features/Core/Portable/Completion/Providers/AbstractCrefCompletionProvider.cs @@ -5,7 +5,7 @@ using System.Collections.Immutable; using System.Threading; using System.Threading.Tasks; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Options; using Roslyn.Utilities; diff --git a/src/Features/Core/Portable/Completion/Providers/AbstractInternalsVisibleToCompletionProvider.cs b/src/Features/Core/Portable/Completion/Providers/AbstractInternalsVisibleToCompletionProvider.cs index badd89e5735e5..bfb574a038abc 100644 --- a/src/Features/Core/Portable/Completion/Providers/AbstractInternalsVisibleToCompletionProvider.cs +++ b/src/Features/Core/Portable/Completion/Providers/AbstractInternalsVisibleToCompletionProvider.cs @@ -8,7 +8,7 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.ErrorReporting; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Shared.Extensions; @@ -274,7 +274,7 @@ public override async Task GetChangeAsync(Document document, C var publicKey = await GetPublicKeyOfProjectAsync(project, cancellationToken).ConfigureAwait(false); if (!string.IsNullOrEmpty(publicKey)) { - assemblyName += $", PublicKey={ publicKey }"; + assemblyName += $", PublicKey={publicKey}"; } var textChange = new TextChange(item.Span, assemblyName); diff --git a/src/Features/Core/Portable/Completion/Providers/AbstractKeywordCompletionProvider.cs b/src/Features/Core/Portable/Completion/Providers/AbstractKeywordCompletionProvider.cs index 7caf809dfa7c3..d0415ee4a5c9e 100644 --- a/src/Features/Core/Portable/Completion/Providers/AbstractKeywordCompletionProvider.cs +++ b/src/Features/Core/Portable/Completion/Providers/AbstractKeywordCompletionProvider.cs @@ -7,7 +7,7 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.Internal.Log; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Shared.Extensions.ContextQuery; diff --git a/src/Features/Core/Portable/Completion/Providers/AbstractMemberInsertingCompletionProvider.cs b/src/Features/Core/Portable/Completion/Providers/AbstractMemberInsertingCompletionProvider.cs index aa5ab7753f104..2577e277ac63a 100644 --- a/src/Features/Core/Portable/Completion/Providers/AbstractMemberInsertingCompletionProvider.cs +++ b/src/Features/Core/Portable/Completion/Providers/AbstractMemberInsertingCompletionProvider.cs @@ -11,7 +11,7 @@ using Microsoft.CodeAnalysis.CodeCleanup; using Microsoft.CodeAnalysis.CodeGeneration; using Microsoft.CodeAnalysis.Formatting; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Simplification; @@ -38,7 +38,7 @@ public AbstractMemberInsertingCompletionProvider() public override async Task GetChangeAsync(Document document, CompletionItem item, char? commitKey = null, CancellationToken cancellationToken = default) { // TODO: pass fallback options: https://github.com/dotnet/roslyn/issues/60786 - var globalOptions = document.Project.Solution.Workspace.Services.GetService(); + var globalOptions = document.Project.Solution.Services.GetService(); var fallbackOptions = globalOptions?.CleanCodeGenerationOptionsProvider ?? CodeActionOptions.DefaultProvider; var newDocument = await DetermineNewDocumentAsync(document, item, fallbackOptions, cancellationToken).ConfigureAwait(false); diff --git a/src/Features/Core/Portable/Completion/Providers/AbstractObjectCreationCompletionProvider.cs b/src/Features/Core/Portable/Completion/Providers/AbstractObjectCreationCompletionProvider.cs index f6b9fa726161f..0f30eea195975 100644 --- a/src/Features/Core/Portable/Completion/Providers/AbstractObjectCreationCompletionProvider.cs +++ b/src/Features/Core/Portable/Completion/Providers/AbstractObjectCreationCompletionProvider.cs @@ -6,7 +6,7 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Recommendations; using Microsoft.CodeAnalysis.Shared.Extensions; diff --git a/src/Features/Core/Portable/Completion/Providers/AbstractObjectInitializerCompletionProvider.cs b/src/Features/Core/Portable/Completion/Providers/AbstractObjectInitializerCompletionProvider.cs index a85146f816dc9..ce4c99d5a4242 100644 --- a/src/Features/Core/Portable/Completion/Providers/AbstractObjectInitializerCompletionProvider.cs +++ b/src/Features/Core/Portable/Completion/Providers/AbstractObjectInitializerCompletionProvider.cs @@ -9,7 +9,7 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Shared.Extensions; using Roslyn.Utilities; @@ -62,17 +62,32 @@ public override async Task ProvideCompletionsAsync(CompletionContext context) var alreadyTypedMembers = GetInitializedMembers(semanticModel.SyntaxTree, position, cancellationToken); var uninitializedMembers = members.Where(m => !alreadyTypedMembers.Contains(m.Name)); - uninitializedMembers = uninitializedMembers.Where(m => m.IsEditorBrowsable(context.CompletionOptions.HideAdvancedMembers, semanticModel.Compilation)); + // Sort the members by name so if we preselect one, it'll be stable + uninitializedMembers = uninitializedMembers.Where(m => m.IsEditorBrowsable(context.CompletionOptions.HideAdvancedMembers, semanticModel.Compilation)) + .OrderBy(m => m.Name); + + var firstUnitializedRequiredMember = true; foreach (var uninitializedMember in uninitializedMembers) { + var rules = s_rules; + + // We'll hard select the first required member to make it a bit easier to type out an object initializer + // with a bunch of members. + if (firstUnitializedRequiredMember && uninitializedMember.IsRequired()) + { + rules = rules.WithSelectionBehavior(CompletionItemSelectionBehavior.HardSelection).WithMatchPriority(MatchPriority.Preselect); + firstUnitializedRequiredMember = false; + } + context.AddItem(SymbolCompletionItem.CreateWithSymbolId( displayText: EscapeIdentifier(uninitializedMember), displayTextSuffix: "", insertionText: null, symbols: ImmutableArray.Create(uninitializedMember), contextPosition: initializerLocation.SourceSpan.Start, - rules: s_rules)); + inlineDescription: uninitializedMember.IsRequired() ? FeaturesResources.Required : null, + rules: rules)); } } diff --git a/src/Features/Core/Portable/Completion/Providers/AbstractPartialTypeCompletionProvider.cs b/src/Features/Core/Portable/Completion/Providers/AbstractPartialTypeCompletionProvider.cs index e90b06ad1f282..d0956b67fb568 100644 --- a/src/Features/Core/Portable/Completion/Providers/AbstractPartialTypeCompletionProvider.cs +++ b/src/Features/Core/Portable/Completion/Providers/AbstractPartialTypeCompletionProvider.cs @@ -9,7 +9,7 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.ErrorReporting; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Shared.Extensions.ContextQuery; using Microsoft.CodeAnalysis.Text; diff --git a/src/Features/Core/Portable/Completion/Providers/AbstractPreprocessorCompletionProvider.cs b/src/Features/Core/Portable/Completion/Providers/AbstractPreprocessorCompletionProvider.cs index f039c9496605a..219444c585205 100644 --- a/src/Features/Core/Portable/Completion/Providers/AbstractPreprocessorCompletionProvider.cs +++ b/src/Features/Core/Portable/Completion/Providers/AbstractPreprocessorCompletionProvider.cs @@ -6,7 +6,7 @@ using System.Collections.Immutable; using System.Linq; using System.Threading.Tasks; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Shared.Extensions.ContextQuery; using Roslyn.Utilities; diff --git a/src/Features/Core/Portable/Completion/Providers/AbstractRecommendationServiceBasedCompletionProvider.cs b/src/Features/Core/Portable/Completion/Providers/AbstractRecommendationServiceBasedCompletionProvider.cs index 29f67ce539802..7a4a340228e49 100644 --- a/src/Features/Core/Portable/Completion/Providers/AbstractRecommendationServiceBasedCompletionProvider.cs +++ b/src/Features/Core/Portable/Completion/Providers/AbstractRecommendationServiceBasedCompletionProvider.cs @@ -8,7 +8,7 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Recommendations; using Microsoft.CodeAnalysis.Shared.Extensions; diff --git a/src/Features/Core/Portable/Completion/Providers/AbstractSymbolCompletionProvider.cs b/src/Features/Core/Portable/Completion/Providers/AbstractSymbolCompletionProvider.cs index cbdc1f1dd0d6c..0a716e684b27a 100644 --- a/src/Features/Core/Portable/Completion/Providers/AbstractSymbolCompletionProvider.cs +++ b/src/Features/Core/Portable/Completion/Providers/AbstractSymbolCompletionProvider.cs @@ -10,7 +10,7 @@ using System.Threading.Tasks; using Microsoft.CodeAnalysis.ErrorReporting; using Microsoft.CodeAnalysis.Internal.Log; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Shared.Extensions.ContextQuery; diff --git a/src/Features/Core/Portable/Completion/Providers/EmbeddedLanguageCompletionProvider.cs b/src/Features/Core/Portable/Completion/Providers/EmbeddedLanguageCompletionProvider.cs index 69eae4c26bcf6..612efdc2b906c 100644 --- a/src/Features/Core/Portable/Completion/Providers/EmbeddedLanguageCompletionProvider.cs +++ b/src/Features/Core/Portable/Completion/Providers/EmbeddedLanguageCompletionProvider.cs @@ -5,7 +5,7 @@ using System.Collections.Immutable; using System.Threading; using System.Threading.Tasks; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Text; namespace Microsoft.CodeAnalysis.Completion.Providers diff --git a/src/Features/Core/Portable/Completion/Providers/ImportCompletionProvider/AbstractExtensionMethodImportCompletionProvider.cs b/src/Features/Core/Portable/Completion/Providers/ImportCompletionProvider/AbstractExtensionMethodImportCompletionProvider.cs index d052732ea2cde..03b9ba23a13b8 100644 --- a/src/Features/Core/Portable/Completion/Providers/ImportCompletionProvider/AbstractExtensionMethodImportCompletionProvider.cs +++ b/src/Features/Core/Portable/Completion/Providers/ImportCompletionProvider/AbstractExtensionMethodImportCompletionProvider.cs @@ -11,9 +11,10 @@ using System.Threading.Tasks; using Microsoft.CodeAnalysis.Completion.Log; using Microsoft.CodeAnalysis.Internal.Log; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Shared.Extensions.ContextQuery; +using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Completion.Providers { @@ -43,7 +44,8 @@ protected override async Task AddCompletionItemsAsync( var syntaxFacts = completionContext.Document.GetRequiredLanguageService(); if (TryGetReceiverTypeSymbol(syntaxContext, syntaxFacts, cancellationToken, out var receiverTypeSymbol)) { - var ticks = Environment.TickCount; + var totalTime = SharedStopwatch.StartNew(); + var inferredTypes = completionContext.CompletionOptions.TargetTypedCompletionFilter ? syntaxContext.InferredTypes : ImmutableArray.Empty; @@ -65,9 +67,8 @@ protected override async Task AddCompletionItemsAsync( completionContext.AddItems(result.CompletionItems.Select(i => Convert(i, receiverTypeKey))); // report telemetry: - var totalTicks = Environment.TickCount - ticks; CompletionProvidersLogger.LogExtensionMethodCompletionTicksDataPoint( - totalTicks, result.GetSymbolsTicks, result.CreateItemsTicks, result.IsRemote); + totalTime.Elapsed, result.GetSymbolsTime, result.CreateItemsTime, result.IsRemote); if (result.IsPartialResult) CompletionProvidersLogger.LogExtensionMethodCompletionPartialResultCount(); diff --git a/src/Features/Core/Portable/Completion/Providers/ImportCompletionProvider/AbstractImportCompletionProvider.cs b/src/Features/Core/Portable/Completion/Providers/ImportCompletionProvider/AbstractImportCompletionProvider.cs index 649dcf21f7199..aaef287c70e5a 100644 --- a/src/Features/Core/Portable/Completion/Providers/ImportCompletionProvider/AbstractImportCompletionProvider.cs +++ b/src/Features/Core/Portable/Completion/Providers/ImportCompletionProvider/AbstractImportCompletionProvider.cs @@ -11,7 +11,7 @@ using Microsoft.CodeAnalysis.Completion.Log; using Microsoft.CodeAnalysis.Editing; using Microsoft.CodeAnalysis.Formatting; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Shared; @@ -41,7 +41,7 @@ public Task NotifyCommittingItemAsync(Document document, CompletionItem item, ch public override async Task ProvideCompletionsAsync(CompletionContext completionContext) { - if (!completionContext.CompletionOptions.ShouldShowItemsFromUnimportNamspaces()) + if (!completionContext.CompletionOptions.ShouldShowItemsFromUnimportedNamespaces()) return; var cancellationToken = completionContext.CancellationToken; @@ -130,7 +130,7 @@ public override async Task GetChangeAsync( var generator = document.GetRequiredLanguageService(); // TODO: fallback options https://github.com/dotnet/roslyn/issues/60786 - var globalOptions = document.Project.Solution.Workspace.Services.GetService(); + var globalOptions = document.Project.Solution.Services.GetService(); var fallbackOptions = globalOptions?.CleanCodeGenerationOptionsProvider ?? CodeActionOptions.DefaultProvider; var addImportsOptions = await document.GetAddImportPlacementOptionsAsync(fallbackOptions, cancellationToken).ConfigureAwait(false); @@ -215,16 +215,16 @@ private async Task IsInImportsDirectiveAsync(Document document, int positi protected static bool IsAddingImportsSupported(Document document) { - var workspace = document.Project.Solution.Workspace; + var solution = document.Project.Solution; // Certain types of workspace don't support document change, e.g. DebuggerIntelliSenseWorkspace - if (!workspace.CanApplyChange(ApplyChangesKind.ChangeDocument)) + if (!solution.CanApplyChange(ApplyChangesKind.ChangeDocument)) { return false; } // Certain documents, e.g. Razor document, don't support adding imports - var documentSupportsFeatureService = workspace.Services.GetRequiredService(); + var documentSupportsFeatureService = solution.Services.GetRequiredService(); if (!documentSupportsFeatureService.SupportsRefactorings(document)) { return false; diff --git a/src/Features/Core/Portable/Completion/Providers/ImportCompletionProvider/AbstractTypeImportCompletionProvider.cs b/src/Features/Core/Portable/Completion/Providers/ImportCompletionProvider/AbstractTypeImportCompletionProvider.cs index 2e39c11984bcf..985ca57c7a4f4 100644 --- a/src/Features/Core/Portable/Completion/Providers/ImportCompletionProvider/AbstractTypeImportCompletionProvider.cs +++ b/src/Features/Core/Portable/Completion/Providers/ImportCompletionProvider/AbstractTypeImportCompletionProvider.cs @@ -9,7 +9,7 @@ using System.Threading.Tasks; using Microsoft.CodeAnalysis.Completion.Log; using Microsoft.CodeAnalysis.Internal.Log; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Shared.Extensions.ContextQuery; using Roslyn.Utilities; @@ -163,7 +163,7 @@ static bool ShouldAddItem( private class TelemetryCounter { - private readonly int _tick; + private readonly SharedStopwatch _elapsedTime; public int ItemsCount { get; set; } public int ReferenceCount { get; set; } @@ -171,7 +171,7 @@ private class TelemetryCounter public TelemetryCounter() { - _tick = Environment.TickCount; + _elapsedTime = SharedStopwatch.StartNew(); } public void Report() @@ -182,8 +182,7 @@ public void Report() } // cache miss still count towards the cost of completion, so we need to log regardless of it. - var delta = Environment.TickCount - _tick; - CompletionProvidersLogger.LogTypeImportCompletionTicksDataPoint(delta); + CompletionProvidersLogger.LogTypeImportCompletionTicksDataPoint(_elapsedTime.Elapsed); CompletionProvidersLogger.LogTypeImportCompletionItemCountDataPoint(ItemsCount); CompletionProvidersLogger.LogTypeImportCompletionReferenceCountDataPoint(ReferenceCount); } diff --git a/src/Features/Core/Portable/Completion/Providers/ImportCompletionProvider/AbstractTypeImportCompletionService.cs b/src/Features/Core/Portable/Completion/Providers/ImportCompletionProvider/AbstractTypeImportCompletionService.cs index 5c06487303d72..45eef1a97647b 100644 --- a/src/Features/Core/Portable/Completion/Providers/ImportCompletionProvider/AbstractTypeImportCompletionService.cs +++ b/src/Features/Core/Portable/Completion/Providers/ImportCompletionProvider/AbstractTypeImportCompletionService.cs @@ -11,6 +11,7 @@ using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Collections; using Microsoft.CodeAnalysis.FindSymbols; +using Microsoft.CodeAnalysis.Host; using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Shared.Extensions.ContextQuery; @@ -31,9 +32,9 @@ internal abstract partial class AbstractTypeImportCompletionService : ITypeImpor protected abstract string Language { get; } - internal AbstractTypeImportCompletionService(Workspace workspace) + internal AbstractTypeImportCompletionService(SolutionServices services) { - CacheService = workspace.Services.GetRequiredService>(); + CacheService = services.GetRequiredService>(); } public void QueueCacheWarmUpTask(Project project) @@ -196,7 +197,7 @@ private bool TryGetUpToDateCacheForPEReference( cacheEntry = CreateCacheWorker( GetPEReferenceCacheKey(peReference)!, assemblySymbol, - checksum: SymbolTreeInfo.GetMetadataChecksum(solution, peReference, cancellationToken), + checksum: SymbolTreeInfo.GetMetadataChecksum(solution.Services, peReference, cancellationToken), CacheService.PEItemsCache, editorBrowsableInfo, cancellationToken); diff --git a/src/Features/Core/Portable/Completion/Providers/ImportCompletionProvider/ExtensionMethodImportCompletionHelper.SymbolComputer.cs b/src/Features/Core/Portable/Completion/Providers/ImportCompletionProvider/ExtensionMethodImportCompletionHelper.SymbolComputer.cs index 0160dbd8b5442..8bf4a98ae6c67 100644 --- a/src/Features/Core/Portable/Completion/Providers/ImportCompletionProvider/ExtensionMethodImportCompletionHelper.SymbolComputer.cs +++ b/src/Features/Core/Portable/Completion/Providers/ImportCompletionProvider/ExtensionMethodImportCompletionHelper.SymbolComputer.cs @@ -64,7 +64,7 @@ public static async Task CreateAsync( } private static IImportCompletionCacheService GetCacheService(Project project) - => project.Solution.Workspace.Services.GetRequiredService>(); + => project.Solution.Services.GetRequiredService>(); private static string? GetPEReferenceCacheKey(PortableExecutableReference peReference) => peReference.FilePath ?? peReference.Display; @@ -86,7 +86,7 @@ public static async ValueTask UpdateCacheAsync(Project project, CancellationToke await GetUpToDateCacheEntryAsync(relevantProject, cacheService, cancellationToken).ConfigureAwait(false); foreach (var peReference in GetAllRelevantPeReferences(project)) - await SymbolTreeInfo.GetInfoForMetadataReferenceAsync(project.Solution, peReference, loadOnly: false, cancellationToken).ConfigureAwait(false); + await SymbolTreeInfo.GetInfoForMetadataReferenceAsync(project.Solution, peReference, cancellationToken).ConfigureAwait(false); } public async Task<(ImmutableArray symbols, bool isPartialResult)> GetExtensionMethodSymbolsAsync(bool forceCacheCreation, bool hideAdvancedMembers, CancellationToken cancellationToken) @@ -199,7 +199,7 @@ private static ImmutableArray GetAllRelevantPeRefer if (forceCacheCreation) { symbolInfo = await SymbolTreeInfo.GetInfoForMetadataReferenceAsync( - _originatingDocument.Project.Solution, peReference, loadOnly: false, cancellationToken).ConfigureAwait(false); + _originatingDocument.Project.Solution, peReference, cancellationToken).ConfigureAwait(false); } else { @@ -521,7 +521,7 @@ private static ImmutableArray AddComplexTypes(ImmutableArray rec receiverTypeNamesBuilder.Add(FindSymbols.Extensions.ComplexReceiverTypeName); receiverTypeNamesBuilder.Add(FindSymbols.Extensions.ComplexArrayReceiverTypeName); - return receiverTypeNamesBuilder.ToImmutable(); + return receiverTypeNamesBuilder.ToImmutableAndClear(); } private static string GetReceiverTypeName(ITypeSymbol typeSymbol) diff --git a/src/Features/Core/Portable/Completion/Providers/ImportCompletionProvider/ExtensionMethodImportCompletionHelper.cs b/src/Features/Core/Portable/Completion/Providers/ImportCompletionProvider/ExtensionMethodImportCompletionHelper.cs index 7eeb953a45410..bd4b515d55de9 100644 --- a/src/Features/Core/Portable/Completion/Providers/ImportCompletionProvider/ExtensionMethodImportCompletionHelper.cs +++ b/src/Features/Core/Portable/Completion/Providers/ImportCompletionProvider/ExtensionMethodImportCompletionHelper.cs @@ -9,7 +9,7 @@ using System.Threading.Tasks; using Microsoft.CodeAnalysis.Collections; using Microsoft.CodeAnalysis.FindSymbols; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Remote; using Microsoft.CodeAnalysis.Shared.Extensions; @@ -90,7 +90,7 @@ public static async Task GetUnimportedEx bool isRemote, CancellationToken cancellationToken) { - var ticks = Environment.TickCount; + var stopwatch = SharedStopwatch.StartNew(); // First find symbols of all applicable extension methods. // Workspace's syntax/symbol index is used to avoid iterating every method symbols in the solution. @@ -98,15 +98,15 @@ public static async Task GetUnimportedEx document, position, receiverTypeSymbol, namespaceInScope, cancellationToken).ConfigureAwait(false); var (extentsionMethodSymbols, isPartialResult) = await symbolComputer.GetExtensionMethodSymbolsAsync(forceCacheCreation, hideAdvancedMembers, cancellationToken).ConfigureAwait(false); - var getSymbolsTicks = Environment.TickCount - ticks; - ticks = Environment.TickCount; + var getSymbolsTime = stopwatch.Elapsed; + stopwatch = SharedStopwatch.StartNew(); var compilation = await document.Project.GetRequiredCompilationAsync(cancellationToken).ConfigureAwait(false); var items = ConvertSymbolsToCompletionItems(compilation, extentsionMethodSymbols, targetTypes, cancellationToken); - var createItemsTicks = Environment.TickCount - ticks; + var createItemsTime = stopwatch.Elapsed; - return new SerializableUnimportedExtensionMethods(items, isPartialResult, getSymbolsTicks, createItemsTicks, isRemote); + return new SerializableUnimportedExtensionMethods(items, isPartialResult, getSymbolsTime, createItemsTime, isRemote); } public static async ValueTask BatchUpdateCacheAsync(ImmutableSegmentedList projects, CancellationToken cancellationToken) @@ -238,7 +238,7 @@ private static async Task GetUpToDate cacheEntry.Checksum != checksum || cacheEntry.Language != project.Language) { - var syntaxFacts = project.LanguageServices.GetRequiredService(); + var syntaxFacts = project.Services.GetRequiredService(); var builder = new ExtensionMethodImportCompletionCacheEntry.Builder(checksum, project.Language, syntaxFacts.StringComparer); foreach (var document in project.Documents) diff --git a/src/Features/Core/Portable/Completion/Providers/ImportCompletionProvider/ImportCompletionItem.cs b/src/Features/Core/Portable/Completion/Providers/ImportCompletionProvider/ImportCompletionItem.cs index 14b9f6cdd2ef5..9d33ba1509196 100644 --- a/src/Features/Core/Portable/Completion/Providers/ImportCompletionProvider/ImportCompletionItem.cs +++ b/src/Features/Core/Portable/Completion/Providers/ImportCompletionProvider/ImportCompletionItem.cs @@ -6,7 +6,7 @@ using System.Diagnostics; using System.Threading; using System.Threading.Tasks; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Tags; @@ -126,7 +126,7 @@ public static async Task GetCompletionDescriptionAsync(Do var semanticModel = await document.GetRequiredSemanticModelAsync(cancellationToken).ConfigureAwait(false); return await CommonCompletionUtilities.CreateDescriptionAsync( - document.Project.Solution.Workspace.Services, + document.Project.Solution.Services, semanticModel, position: 0, symbol, diff --git a/src/Features/Core/Portable/Completion/Providers/ImportCompletionProvider/SerializableUnimportedExtensionMethods.cs b/src/Features/Core/Portable/Completion/Providers/ImportCompletionProvider/SerializableUnimportedExtensionMethods.cs index b8eee20c00241..b7dc7a3362067 100644 --- a/src/Features/Core/Portable/Completion/Providers/ImportCompletionProvider/SerializableUnimportedExtensionMethods.cs +++ b/src/Features/Core/Portable/Completion/Providers/ImportCompletionProvider/SerializableUnimportedExtensionMethods.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +using System; using System.Collections.Immutable; using System.Runtime.Serialization; @@ -17,10 +18,10 @@ internal sealed class SerializableUnimportedExtensionMethods public readonly bool IsPartialResult; [DataMember(Order = 2)] - public readonly int GetSymbolsTicks; + public readonly TimeSpan GetSymbolsTime; [DataMember(Order = 3)] - public readonly int CreateItemsTicks; + public readonly TimeSpan CreateItemsTime; [DataMember(Order = 4)] public readonly bool IsRemote; @@ -28,14 +29,14 @@ internal sealed class SerializableUnimportedExtensionMethods public SerializableUnimportedExtensionMethods( ImmutableArray completionItems, bool isPartialResult, - int getSymbolsTicks, - int createItemsTicks, + TimeSpan getSymbolsTime, + TimeSpan createItemsTime, bool isRemote) { CompletionItems = completionItems; IsPartialResult = isPartialResult; - GetSymbolsTicks = getSymbolsTicks; - CreateItemsTicks = createItemsTicks; + GetSymbolsTime = getSymbolsTime; + CreateItemsTime = createItemsTime; IsRemote = isRemote; } } diff --git a/src/Features/Core/Portable/Completion/Providers/MemberInsertingCompletionItem.cs b/src/Features/Core/Portable/Completion/Providers/MemberInsertingCompletionItem.cs index 93dbda173474e..0ca872a46bbc5 100644 --- a/src/Features/Core/Portable/Completion/Providers/MemberInsertingCompletionItem.cs +++ b/src/Features/Core/Portable/Completion/Providers/MemberInsertingCompletionItem.cs @@ -6,7 +6,7 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.Editing; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; namespace Microsoft.CodeAnalysis.Completion.Providers { diff --git a/src/Features/Core/Portable/Completion/Providers/Snippets/AbstractSnippetCompletionProvider.cs b/src/Features/Core/Portable/Completion/Providers/Snippets/AbstractSnippetCompletionProvider.cs new file mode 100644 index 0000000000000..3c14970d44892 --- /dev/null +++ b/src/Features/Core/Portable/Completion/Providers/Snippets/AbstractSnippetCompletionProvider.cs @@ -0,0 +1,129 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation 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.ConvertToInterpolatedString; +using Microsoft.CodeAnalysis.Internal.Log; +using Microsoft.CodeAnalysis.Shared.Extensions; +using Microsoft.CodeAnalysis.Snippets; +using Microsoft.CodeAnalysis.Text; +using Roslyn.Utilities; + +namespace Microsoft.CodeAnalysis.Completion.Providers.Snippets +{ + internal abstract class AbstractSnippetCompletionProvider : CompletionProvider + { + public override async Task GetChangeAsync(Document document, CompletionItem item, char? commitKey = null, CancellationToken cancellationToken = default) + { + // This retrieves the document without the text used to invoke completion + // as well as the new cursor position after that has been removed. + var (strippedDocument, position) = await GetDocumentWithoutInvokingTextAsync(document, SnippetCompletionItem.GetInvocationPosition(item), cancellationToken).ConfigureAwait(false); + var service = strippedDocument.GetRequiredLanguageService(); + var snippetIdentifier = SnippetCompletionItem.GetSnippetIdentifier(item); + var snippetProvider = service.GetSnippetProvider(snippetIdentifier); + + // Logging for telemetry. + Logger.Log(FunctionId.Completion_SemanticSnippets, $"Name: {snippetIdentifier}"); + + // This retrieves the generated Snippet + var snippet = await snippetProvider.GetSnippetAsync(strippedDocument, position, cancellationToken).ConfigureAwait(false); + var strippedText = await strippedDocument.GetTextAsync(cancellationToken).ConfigureAwait(false); + + // This introduces the text changes of the snippet into the document with the completion invoking text + var allChangesText = strippedText.WithChanges(snippet.TextChanges); + + // This retrieves ALL text changes from the original document which includes the TextChanges from the snippet + // as well as the clean up. + var allChangesDocument = document.WithText(allChangesText); + var allTextChanges = await allChangesDocument.GetTextChangesAsync(document, cancellationToken).ConfigureAwait(false); + + var change = Utilities.Collapse(allChangesText, allTextChanges.AsImmutable()); + + // Converts the snippet to an LSP formatted snippet string. + var lspSnippet = await RoslynLSPSnippetConverter.GenerateLSPSnippetAsync(allChangesDocument, snippet.CursorPosition, snippet.Placeholders, change, item.Span.Start, cancellationToken).ConfigureAwait(false); + + // If the TextChanges retrieved starts after the trigger point of the CompletionItem, + // then we need to move the bounds backwards and encapsulate the trigger point. + if (change.Span.Start > item.Span.Start) + { + var textSpan = TextSpan.FromBounds(item.Span.Start, change.Span.End); + var snippetText = change.NewText; + Contract.ThrowIfNull(snippetText); + change = new TextChange(textSpan, snippetText); + } + + var props = ImmutableDictionary.Empty + .Add(SnippetCompletionItem.LSPSnippetKey, lspSnippet); + + return CompletionChange.Create(change, allTextChanges.AsImmutable(), properties: props, snippet.CursorPosition, includesCommitCharacter: true); + } + + public override async Task ProvideCompletionsAsync(CompletionContext context) + { + if (!context.CompletionOptions.ShouldShowNewSnippetExperience()) + { + return; + } + + var document = context.Document; + var cancellationToken = context.CancellationToken; + var position = context.Position; + var service = document.GetLanguageService(); + + if (service == null) + { + return; + } + + var (strippedDocument, newPosition) = await GetDocumentWithoutInvokingTextAsync(document, position, cancellationToken).ConfigureAwait(false); + + var snippets = await service.GetSnippetsAsync(strippedDocument, newPosition, cancellationToken).ConfigureAwait(false); + + foreach (var snippetData in snippets) + { + var completionItem = SnippetCompletionItem.Create( + displayText: snippetData.SnippetIdentifier, + displayTextSuffix: "", + position: position, + snippetIdentifier: snippetData.SnippetIdentifier, + glyph: Glyph.Snippet, + inlineDescription: snippetData.Description, + additionalFilterTexts: snippetData.AdditionalFilterTexts); + context.AddItem(completionItem); + } + } + + /// Gets the document without whatever text was used to invoke the completion. + /// Also gets the new position the cursor will be on. + /// Returns the original document and position if completion was invoked using Ctrl-Space. + /// + /// public void Method() + /// { + /// $$ //invoked by typing Ctrl-Space + /// } + /// Example invoking when span is not empty: + /// public void Method() + /// { + /// Wr$$ //invoked by typing out the completion + /// } + private static async Task<(Document, int)> GetDocumentWithoutInvokingTextAsync(Document document, int position, CancellationToken cancellationToken) + { + var originalText = await document.GetTextAsync(cancellationToken).ConfigureAwait(false); + + // Uses the existing CompletionService logic to find the TextSpan we want to use for the document sans invoking text + var completionService = document.GetRequiredLanguageService(); + var span = completionService.GetDefaultCompletionListSpan(originalText, position); + + var textChange = new TextChange(span, string.Empty); + originalText = originalText.WithChanges(textChange); + var newDocument = document.WithText(originalText); + return (newDocument, span.Start); + } + } +} diff --git a/src/Features/Core/Portable/Completion/Providers/Snippets/SnippetCompletionItem.cs b/src/Features/Core/Portable/Completion/Providers/Snippets/SnippetCompletionItem.cs new file mode 100644 index 0000000000000..b055442febc40 --- /dev/null +++ b/src/Features/Core/Portable/Completion/Providers/Snippets/SnippetCompletionItem.cs @@ -0,0 +1,61 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Collections.Immutable; +using Microsoft.CodeAnalysis.Text; +using Roslyn.Utilities; + +namespace Microsoft.CodeAnalysis.Completion.Providers.Snippets +{ + internal class SnippetCompletionItem + { + public static string LSPSnippetKey = "LSPSnippet"; + public static string SnippetIdentifierKey = "SnippetIdentifier"; + + public static CompletionItem Create( + string displayText, + string displayTextSuffix, + int position, + string snippetIdentifier, + Glyph glyph, + string inlineDescription, + ImmutableArray additionalFilterTexts) + { + var props = ImmutableDictionary.Empty + .Add("Position", position.ToString()) + .Add(SnippetIdentifierKey, snippetIdentifier); + + return CommonCompletionItem.Create( + displayText: displayText, + displayTextSuffix: displayTextSuffix, + glyph: glyph, + // Adding a space after the identifier string that way it will always be sorted after the original snippet. + sortText: snippetIdentifier + " ", + filterText: snippetIdentifier, + properties: props, + isComplexTextEdit: true, + inlineDescription: inlineDescription, + rules: CompletionItemRules.Default) + .WithAdditionalFilterTexts(additionalFilterTexts); + } + + public static string GetSnippetIdentifier(CompletionItem item) + { + Contract.ThrowIfFalse(item.Properties.TryGetValue(SnippetIdentifierKey, out var text)); + return text; + } + + public static int GetInvocationPosition(CompletionItem item) + { + Contract.ThrowIfFalse(item.Properties.TryGetValue("Position", out var text)); + Contract.ThrowIfFalse(int.TryParse(text, out var num)); + return num; + } + + public static bool IsSnippet(CompletionItem item) + { + return item.Properties.TryGetValue(SnippetIdentifierKey, out var _); + } + } +} diff --git a/src/Features/Core/Portable/Completion/Providers/SymbolCompletionItem.cs b/src/Features/Core/Portable/Completion/Providers/SymbolCompletionItem.cs index ec30f46ee82d7..ca88ab8bfacf9 100644 --- a/src/Features/Core/Portable/Completion/Providers/SymbolCompletionItem.cs +++ b/src/Features/Core/Portable/Completion/Providers/SymbolCompletionItem.cs @@ -9,14 +9,14 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Shared.Utilities; namespace Microsoft.CodeAnalysis.Completion.Providers { - internal static partial class SymbolCompletionItem + internal static class SymbolCompletionItem { private const string InsertionTextProperty = "InsertionText"; @@ -194,7 +194,7 @@ public static async Task GetDescriptionForSymbolsAsync( var contextDocument = FindAppropriateDocumentForDescriptionContext(document, supportedPlatforms); var semanticModel = await contextDocument.GetRequiredSemanticModelAsync(cancellationToken).ConfigureAwait(false); - var services = document.Project.Solution.Workspace.Services; + var services = document.Project.Solution.Services; return await CommonCompletionUtilities.CreateDescriptionAsync(services, semanticModel, position, symbols, options, supportedPlatforms, cancellationToken).ConfigureAwait(false); } @@ -359,7 +359,7 @@ public static async Task GetDescriptionAsync( if (symbols.Count != 0) { - return await CommonCompletionUtilities.CreateDescriptionAsync(document.Project.Solution.Workspace.Services, semanticModel, position, symbols, options, supportedPlatforms, cancellationToken).ConfigureAwait(false); + return await CommonCompletionUtilities.CreateDescriptionAsync(document.Project.Solution.Services, semanticModel, position, symbols, options, supportedPlatforms, cancellationToken).ConfigureAwait(false); } else { diff --git a/src/Features/Core/Portable/ConflictMarkerResolution/AbstractConflictMarkerCodeFixProvider.cs b/src/Features/Core/Portable/ConflictMarkerResolution/AbstractConflictMarkerCodeFixProvider.cs index cb645fd163608..f4a13fa41953e 100644 --- a/src/Features/Core/Portable/ConflictMarkerResolution/AbstractConflictMarkerCodeFixProvider.cs +++ b/src/Features/Core/Portable/ConflictMarkerResolution/AbstractConflictMarkerCodeFixProvider.cs @@ -9,7 +9,7 @@ using System.Threading.Tasks; using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeFixes; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Text; @@ -17,6 +17,19 @@ namespace Microsoft.CodeAnalysis.ConflictMarkerResolution { + /// + /// This code fixer helps remove version conflict markers in code by offering the choice + /// of which version to keep and which version to discard. + /// + /// Conflict markers come in two flavors, diff3 and diff formats. + /// + /// diff3 has a start marker, followed by a first middle markers and a second middle marker, and terminate with an end marker. + /// The disabled text between the first and second middle markers is the baseline for the three-way diff. + /// The fixer always discards this baseline text. + /// + /// diff has a start marker, followed by a middle marker, and terminates with an end marker. + /// We treat the middle marker as both the first and second middle markers (degenerate case with no baseline). + /// internal abstract partial class AbstractResolveConflictMarkerCodeFixProvider : CodeFixProvider { internal const string TakeTopEquivalenceKey = nameof(TakeTopEquivalenceKey); @@ -56,18 +69,19 @@ public override async Task RegisterCodeFixesAsync(CodeFixContext context) var text = await document.GetTextAsync(cancellationToken).ConfigureAwait(false); var position = context.Span.Start; - if (!ShouldFix(root, text, position, out var startLine, out var middleLine, out var endLine)) + if (!ShouldFix(root, text, position, out var startLine, out var firstMiddleLine, out var secondMiddleLine, out var endLine)) return; - RegisterCodeFixes(context, startLine, middleLine, endLine); + RegisterCodeFixes(context, startLine, firstMiddleLine, secondMiddleLine, endLine); } private bool ShouldFix( SyntaxNode root, SourceText text, int position, - out TextLine startLine, out TextLine middleLine, out TextLine endLine) + out TextLine startLine, out TextLine firstMiddleLine, out TextLine secondMiddleLine, out TextLine endLine) { startLine = default; - middleLine = default; + firstMiddleLine = default; + secondMiddleLine = default; endLine = default; var lines = text.Lines; @@ -78,30 +92,45 @@ private bool ShouldFix( return false; } - if (!TryGetConflictLines(text, position, out startLine, out middleLine, out endLine)) + if (!TryGetConflictLines(text, position, out startLine, out firstMiddleLine, out secondMiddleLine, out endLine)) return false; var startTrivia = root.FindTrivia(startLine.Start); - var middleTrivia = root.FindTrivia(middleLine.Start); + var firstMiddleTrivia = root.FindTrivia(firstMiddleLine.Start); + var secondMiddleTrivia = root.FindTrivia(secondMiddleLine.Start); - if (position == middleLine.Start) + if (position == firstMiddleLine.Start) { - // we were on the ======= lines. We only want to report here if there was no - // conflict trivia on the <<<<<<< line (since we would have already reported the - // issue there. + // We were on the ||||||| line. + // We don't want to report here if there was conflict trivia on the <<<<<<< line (since we would have already reported the issue there). if (startTrivia.RawKind == _syntaxKinds.ConflictMarkerTrivia) return false; } + else if (position == secondMiddleLine.Start) + { + // We were on the ======= line. + // We don't want to report here if there was conflict trivia on the <<<<<<< line (since we would have already reported the issue there). + if (startTrivia.RawKind == _syntaxKinds.ConflictMarkerTrivia) + return false; + + // We don't want to report here if there was conflict trivia on the ||||||| line (since we would have already reported the issue there). + if (firstMiddleLine != secondMiddleLine && firstMiddleTrivia.RawKind == _syntaxKinds.ConflictMarkerTrivia) + return false; + } else if (position == endLine.Start) { - // we were on the >>>>>>> lines. We only want to report here if there was no - // conflict trivia on the ======= or <<<<<<< line (since we would have already reported the - // issue there. - if (startTrivia.RawKind == _syntaxKinds.ConflictMarkerTrivia || - middleTrivia.RawKind == _syntaxKinds.ConflictMarkerTrivia) - { + // We were on the >>>>>>> line. + // We don't want to report here if there was conflict trivia on the <<<<<<< line (since we would have already reported the issue there). + if (startTrivia.RawKind == _syntaxKinds.ConflictMarkerTrivia) + return false; + + // We don't want to report here if there was conflict trivia on the ||||||| line (since we would have already reported the issue there). + if (firstMiddleLine != secondMiddleLine && firstMiddleTrivia.RawKind == _syntaxKinds.ConflictMarkerTrivia) + return false; + + // We don't want to report here if there was conflict trivia on the ======= line (since we would have already reported the issue there). + if (secondMiddleTrivia.RawKind == _syntaxKinds.ConflictMarkerTrivia) return false; - } } return true; @@ -109,30 +138,65 @@ private bool ShouldFix( private static bool TryGetConflictLines( SourceText text, int position, - out TextLine startLine, out TextLine middleLine, out TextLine endLine) + out TextLine startLine, out TextLine firstMiddleLine, out TextLine secondMiddleLine, out TextLine endLine) { startLine = default; - middleLine = default; + firstMiddleLine = default; + secondMiddleLine = default; endLine = default; var lines = text.Lines; + bool foundBarLine; switch (text[position]) { case '<': startLine = lines.GetLineFromPosition(position); - return TryFindLineForwards(startLine, '=', out middleLine) && - TryFindLineForwards(middleLine, '>', out endLine); + foundBarLine = TryFindLineForwards(startLine, '|', out firstMiddleLine); + + if (!TryFindLineForwards(foundBarLine ? firstMiddleLine : startLine, '=', out secondMiddleLine) || + !TryFindLineForwards(secondMiddleLine, '>', out endLine)) + { + return false; + } + + break; + case '|': + firstMiddleLine = lines.GetLineFromPosition(position); + return TryFindLineBackwards(firstMiddleLine, '<', out startLine) && + TryFindLineForwards(firstMiddleLine, '=', out secondMiddleLine) && + TryFindLineForwards(secondMiddleLine, '>', out endLine); case '=': - middleLine = lines.GetLineFromPosition(position); - return TryFindLineBackwards(middleLine, '<', out startLine) && - TryFindLineForwards(middleLine, '>', out endLine); + secondMiddleLine = lines.GetLineFromPosition(position); + foundBarLine = TryFindLineBackwards(secondMiddleLine, '|', out firstMiddleLine); + + if (!TryFindLineBackwards(foundBarLine ? firstMiddleLine : secondMiddleLine, '<', out startLine) || + !TryFindLineForwards(secondMiddleLine, '>', out endLine)) + { + return false; + } + + break; case '>': endLine = lines.GetLineFromPosition(position); - return TryFindLineBackwards(endLine, '=', out middleLine) && - TryFindLineBackwards(middleLine, '<', out startLine); + if (!TryFindLineBackwards(endLine, '=', out secondMiddleLine)) + { + return false; + } + + foundBarLine = TryFindLineBackwards(secondMiddleLine, '|', out firstMiddleLine); + + if (!TryFindLineBackwards(foundBarLine ? firstMiddleLine : secondMiddleLine, '<', out startLine)) + return false; + + break; default: throw ExceptionUtilities.UnexpectedValue(text[position]); } + + if (!foundBarLine) + firstMiddleLine = secondMiddleLine; + + return true; } private static bool TryFindLineForwards(TextLine startLine, char ch, out TextLine foundLine) @@ -193,7 +257,7 @@ private static bool IsConflictMarker(TextLine currentLine, char ch) } private static void RegisterCodeFixes( - CodeFixContext context, TextLine startLine, TextLine middleLine, TextLine endLine) + CodeFixContext context, TextLine startLine, TextLine firstMiddleLine, TextLine secondMiddleLine, TextLine endLine) { var document = context.Document; @@ -208,35 +272,36 @@ private static void RegisterCodeFixes( : string.Format(FeaturesResources.Take_0, bottomText); var startPos = startLine.Start; - var equalsPos = middleLine.Start; + var firstMiddlePos = firstMiddleLine.Start; + var secondMiddlePos = secondMiddleLine.Start; var endPos = endLine.Start; context.RegisterCodeFix( CodeAction.Create(takeTopText, - c => TakeTopAsync(document, startPos, equalsPos, endPos, c), + c => TakeTopAsync(document, startPos, firstMiddlePos, secondMiddlePos, endPos, c), TakeTopEquivalenceKey), context.Diagnostics); context.RegisterCodeFix( CodeAction.Create(takeBottomText, - c => TakeBottomAsync(document, startPos, equalsPos, endPos, c), + c => TakeBottomAsync(document, startPos, firstMiddlePos, secondMiddlePos, endPos, c), TakeBottomEquivalenceKey), context.Diagnostics); context.RegisterCodeFix( CodeAction.Create(FeaturesResources.Take_both, - c => TakeBothAsync(document, startPos, equalsPos, endPos, c), + c => TakeBothAsync(document, startPos, firstMiddlePos, secondMiddlePos, endPos, c), TakeBothEquivalenceKey), context.Diagnostics); } private static async Task AddEditsAsync( - Document document, int startPos, int equalsPos, int endPos, - Action, int, int, int> addEdits, + Document document, int startPos, int firstMiddlePos, int secondMiddlePos, int endPos, + Action, int, int, int, int> addEdits, CancellationToken cancellationToken) { var text = await document.GetTextAsync(cancellationToken).ConfigureAwait(false); using var _ = ArrayBuilder.GetInstance(out var edits); - addEdits(text, edits, startPos, equalsPos, endPos); + addEdits(text, edits, startPos, firstMiddlePos, secondMiddlePos, endPos); var finalText = text.WithChanges(edits); return document.WithText(finalText); @@ -244,55 +309,64 @@ private static async Task AddEditsAsync( private static void AddTopEdits( SourceText text, ArrayBuilder edits, - int startPos, int equalsPos, int endPos) + int startPos, int firstMiddlePos, int secondMiddlePos, int endPos) { // Delete the line containing <<<<<<< var startEnd = GetEndIncludingLineBreak(text, startPos); edits.Add(new TextChange(TextSpan.FromBounds(startPos, startEnd), "")); - // Remove the chunk of text (inclusive) from ======= through >>>>>>> + // Remove the chunk of text (inclusive) from ||||||| or ======= through >>>>>>> var bottomEnd = GetEndIncludingLineBreak(text, endPos); - edits.Add(new TextChange(TextSpan.FromBounds(equalsPos, bottomEnd), "")); + edits.Add(new TextChange(TextSpan.FromBounds(firstMiddlePos, bottomEnd), "")); } private static void AddBottomEdits( SourceText text, ArrayBuilder edits, - int startPos, int equalsPos, int endPos) + int startPos, int firstMiddlePos, int secondMiddlePos, int endPos) { // Remove the chunk of text (inclusive) from <<<<<<< through ======= - var equalsEnd = GetEndIncludingLineBreak(text, equalsPos); + var equalsEnd = GetEndIncludingLineBreak(text, secondMiddlePos); edits.Add(new TextChange(TextSpan.FromBounds(startPos, equalsEnd), "")); - // Delete the line containing >>>>>>> + // Delete the line containing >>>>>>> var bottomEnd = GetEndIncludingLineBreak(text, endPos); edits.Add(new TextChange(TextSpan.FromBounds(endPos, bottomEnd), "")); } private static void AddBothEdits( SourceText text, ArrayBuilder edits, - int startPos, int equalsPos, int endPos) + int startPos, int firstMiddlePos, int secondMiddlePos, int endPos) { // Delete the line containing <<<<<<< var startEnd = GetEndIncludingLineBreak(text, startPos); edits.Add(new TextChange(TextSpan.FromBounds(startPos, startEnd), "")); - // Delete the line containing ======= - var equalsEnd = GetEndIncludingLineBreak(text, equalsPos); - edits.Add(new TextChange(TextSpan.FromBounds(equalsPos, equalsEnd), "")); + if (firstMiddlePos == secondMiddlePos) + { + // Delete the line containing ======= + var equalsEnd = GetEndIncludingLineBreak(text, secondMiddlePos); + edits.Add(new TextChange(TextSpan.FromBounds(secondMiddlePos, equalsEnd), "")); + } + else + { + // Remove the chunk of text (inclusive) from ||||||| through ======= + var equalsEnd = GetEndIncludingLineBreak(text, secondMiddlePos); + edits.Add(new TextChange(TextSpan.FromBounds(firstMiddlePos, equalsEnd), "")); + } // Delete the line containing >>>>>>> var bottomEnd = GetEndIncludingLineBreak(text, endPos); edits.Add(new TextChange(TextSpan.FromBounds(endPos, bottomEnd), "")); } - private static Task TakeTopAsync(Document document, int startPos, int equalsPos, int endPos, CancellationToken cancellationToken) - => AddEditsAsync(document, startPos, equalsPos, endPos, AddTopEdits, cancellationToken); + private static Task TakeTopAsync(Document document, int startPos, int firstMiddlePos, int secondMiddlePos, int endPos, CancellationToken cancellationToken) + => AddEditsAsync(document, startPos, firstMiddlePos, secondMiddlePos, endPos, AddTopEdits, cancellationToken); - private static Task TakeBottomAsync(Document document, int startPos, int equalsPos, int endPos, CancellationToken cancellationToken) - => AddEditsAsync(document, startPos, equalsPos, endPos, AddBottomEdits, cancellationToken); + private static Task TakeBottomAsync(Document document, int startPos, int firstMiddlePos, int secondMiddlePos, int endPos, CancellationToken cancellationToken) + => AddEditsAsync(document, startPos, firstMiddlePos, secondMiddlePos, endPos, AddBottomEdits, cancellationToken); - private static Task TakeBothAsync(Document document, int startPos, int equalsPos, int endPos, CancellationToken cancellationToken) - => AddEditsAsync(document, startPos, equalsPos, endPos, AddBothEdits, cancellationToken); + private static Task TakeBothAsync(Document document, int startPos, int firstMiddlePos, int secondMiddlePos, int endPos, CancellationToken cancellationToken) + => AddEditsAsync(document, startPos, firstMiddlePos, secondMiddlePos, endPos, AddBothEdits, cancellationToken); private static int GetEndIncludingLineBreak(SourceText text, int position) => text.Lines.GetLineFromPosition(position).SpanIncludingLineBreak.End; @@ -322,25 +396,26 @@ TakeBottomEquivalenceKey or foreach (var diagnostic in diagnostics) { var position = diagnostic.Location.SourceSpan.Start; - if (!ShouldFix(root, text, position, out var startLine, out var middleLine, out var endLine)) + if (!ShouldFix(root, text, position, out var startLine, out var firstMiddleLine, out var secondMiddleLine, out var endLine)) continue; var startPos = startLine.Start; - var equalsPos = middleLine.Start; + var firstMiddlePos = firstMiddleLine.Start; + var secondMiddlePos = secondMiddleLine.Start; var endPos = endLine.Start; switch (equivalenceKey) { case TakeTopEquivalenceKey: - AddTopEdits(text, edits, startPos, equalsPos, endPos); + AddTopEdits(text, edits, startPos, firstMiddlePos, secondMiddlePos, endPos); continue; case TakeBottomEquivalenceKey: - AddBottomEdits(text, edits, startPos, equalsPos, endPos); + AddBottomEdits(text, edits, startPos, firstMiddlePos, secondMiddlePos, endPos); continue; case TakeBothEquivalenceKey: - AddBothEdits(text, edits, startPos, equalsPos, endPos); + AddBothEdits(text, edits, startPos, firstMiddlePos, secondMiddlePos, endPos); continue; default: diff --git a/src/Features/Core/Portable/ConvertAnonymousType/AbstractConvertAnonymousTypeToClassCodeRefactoringProvider.cs b/src/Features/Core/Portable/ConvertAnonymousType/AbstractConvertAnonymousTypeToClassCodeRefactoringProvider.cs index 420a64550ab7c..392d743239627 100644 --- a/src/Features/Core/Portable/ConvertAnonymousType/AbstractConvertAnonymousTypeToClassCodeRefactoringProvider.cs +++ b/src/Features/Core/Portable/ConvertAnonymousType/AbstractConvertAnonymousTypeToClassCodeRefactoringProvider.cs @@ -16,7 +16,7 @@ using Microsoft.CodeAnalysis.Editing; using Microsoft.CodeAnalysis.Formatting; using Microsoft.CodeAnalysis.GenerateEqualsAndGetHashCodeFromMembers; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Shared.Utilities; diff --git a/src/Features/Core/Portable/ConvertAnonymousType/AbstractConvertAnonymousTypeToTupleCodeRefactoringProvider.cs b/src/Features/Core/Portable/ConvertAnonymousType/AbstractConvertAnonymousTypeToTupleCodeRefactoringProvider.cs index 2dded37589372..311df92689483 100644 --- a/src/Features/Core/Portable/ConvertAnonymousType/AbstractConvertAnonymousTypeToTupleCodeRefactoringProvider.cs +++ b/src/Features/Core/Portable/ConvertAnonymousType/AbstractConvertAnonymousTypeToTupleCodeRefactoringProvider.cs @@ -13,7 +13,7 @@ using Microsoft.CodeAnalysis.CodeRefactorings; using Microsoft.CodeAnalysis.Editing; using Microsoft.CodeAnalysis.Formatting; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Shared.Extensions; namespace Microsoft.CodeAnalysis.ConvertAnonymousType diff --git a/src/Features/Core/Portable/ConvertAutoPropertyToFullProperty/AbstractConvertAutoPropertyToFullPropertyCodeRefactoringProvider.cs b/src/Features/Core/Portable/ConvertAutoPropertyToFullProperty/AbstractConvertAutoPropertyToFullPropertyCodeRefactoringProvider.cs index 6f62db9b11fc8..337fa85dd64b2 100644 --- a/src/Features/Core/Portable/ConvertAutoPropertyToFullProperty/AbstractConvertAutoPropertyToFullPropertyCodeRefactoringProvider.cs +++ b/src/Features/Core/Portable/ConvertAutoPropertyToFullProperty/AbstractConvertAutoPropertyToFullPropertyCodeRefactoringProvider.cs @@ -92,7 +92,7 @@ private async Task ExpandToFullPropertyAsync( var generator = SyntaxGenerator.GetGenerator(document); var codeGenerator = document.GetRequiredLanguageService(); - var services = document.Project.Solution.Workspace.Services; + var services = document.Project.Solution.Services; var options = await document.GetCodeGenerationOptionsAsync(fallbackOptions, cancellationToken).ConfigureAwait(false); var info = (TCodeGenerationContextInfo)options.GetInfo(CodeGenerationContext.Default, document.Project); @@ -109,7 +109,8 @@ private async Task ExpandToFullPropertyAsync( : new SyntaxNode[] { newGetAccessor, newSetAccessor }) .WithLeadingTrivia(property.GetLeadingTrivia()); fullProperty = ConvertPropertyToExpressionBodyIfDesired(info, fullProperty); - var editor = new SyntaxEditor(root, services); + + var editor = new SyntaxEditor(root, document.Project.Solution.Services); editor.ReplaceNode(property, fullProperty.WithAdditionalAnnotations(Formatter.Annotation)); // add backing field, plus initializer if it exists diff --git a/src/Features/Core/Portable/ConvertForEachToFor/AbstractConvertForEachToForCodeRefactoringProvider.cs b/src/Features/Core/Portable/ConvertForEachToFor/AbstractConvertForEachToForCodeRefactoringProvider.cs index 7b5b738955b4b..2fe80df6ac889 100644 --- a/src/Features/Core/Portable/ConvertForEachToFor/AbstractConvertForEachToForCodeRefactoringProvider.cs +++ b/src/Features/Core/Portable/ConvertForEachToFor/AbstractConvertForEachToForCodeRefactoringProvider.cs @@ -14,7 +14,7 @@ using Microsoft.CodeAnalysis.CodeRefactorings; using Microsoft.CodeAnalysis.Editing; using Microsoft.CodeAnalysis.Formatting; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Operations; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Simplification; @@ -325,10 +325,7 @@ private static void GetInterfaceInfo( return; } - if (explicitInterface == null) - { - explicitInterface = current; - } + explicitInterface ??= current; } // okay, we don't have implicitly implemented one, but we do have explicitly implemented one @@ -421,7 +418,7 @@ private async Task ConvertForeachToForAsync( CancellationToken cancellationToken) { var model = await document.GetRequiredSemanticModelAsync(cancellationToken).ConfigureAwait(false); - var services = document.Project.Solution.Workspace.Services; + var services = document.Project.Solution.Services; var editor = new SyntaxEditor(model.SyntaxTree.GetRoot(cancellationToken), services); ConvertToForStatement(model, foreachInfo, editor, cancellationToken); diff --git a/src/Features/Core/Portable/ConvertForToForEach/AbstractConvertForToForEachCodeRefactoringProvider.cs b/src/Features/Core/Portable/ConvertForToForEach/AbstractConvertForToForEachCodeRefactoringProvider.cs index f59820b18acb4..7951bf3dc8084 100644 --- a/src/Features/Core/Portable/ConvertForToForEach/AbstractConvertForToForEachCodeRefactoringProvider.cs +++ b/src/Features/Core/Portable/ConvertForToForEach/AbstractConvertForToForEachCodeRefactoringProvider.cs @@ -12,7 +12,7 @@ using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeRefactorings; using Microsoft.CodeAnalysis.Editing; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Operations; using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Shared.Extensions; diff --git a/src/Features/Core/Portable/ConvertIfToSwitch/AbstractConvertIfToSwitchCodeRefactoringProvider.Analyzer.cs b/src/Features/Core/Portable/ConvertIfToSwitch/AbstractConvertIfToSwitchCodeRefactoringProvider.Analyzer.cs index 3893f453351b3..0f1290daf51d2 100644 --- a/src/Features/Core/Portable/ConvertIfToSwitch/AbstractConvertIfToSwitchCodeRefactoringProvider.Analyzer.cs +++ b/src/Features/Core/Portable/ConvertIfToSwitch/AbstractConvertIfToSwitchCodeRefactoringProvider.Analyzer.cs @@ -5,7 +5,7 @@ using System; using System.Collections.Immutable; using System.Diagnostics; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Operations; using Microsoft.CodeAnalysis.PooledObjects; using Roslyn.Utilities; diff --git a/src/Features/Core/Portable/ConvertIfToSwitch/AbstractConvertIfToSwitchCodeRefactoringProvider.cs b/src/Features/Core/Portable/ConvertIfToSwitch/AbstractConvertIfToSwitchCodeRefactoringProvider.cs index 68820b82540b1..6e3653d0a5d80 100644 --- a/src/Features/Core/Portable/ConvertIfToSwitch/AbstractConvertIfToSwitchCodeRefactoringProvider.cs +++ b/src/Features/Core/Portable/ConvertIfToSwitch/AbstractConvertIfToSwitchCodeRefactoringProvider.cs @@ -13,7 +13,7 @@ using Microsoft.CodeAnalysis.CodeFixes; using Microsoft.CodeAnalysis.CodeRefactorings; using Microsoft.CodeAnalysis.Editing; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Operations; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Text; @@ -35,7 +35,7 @@ internal abstract partial class AbstractConvertIfToSwitchCodeRefactoringProvider public sealed override async Task ComputeRefactoringsAsync(CodeRefactoringContext context) { var (document, _, cancellationToken) = context; - if (document.Project.Solution.Workspace.Kind == WorkspaceKind.MiscellaneousFiles) + if (document.Project.Solution.WorkspaceKind == WorkspaceKind.MiscellaneousFiles) { return; } diff --git a/src/Features/Core/Portable/ConvertLinq/AbstractConvertLinqQueryToForEachProvider.cs b/src/Features/Core/Portable/ConvertLinq/AbstractConvertLinqQueryToForEachProvider.cs index 4f7868ccc3cd2..75deaf88d0ce4 100644 --- a/src/Features/Core/Portable/ConvertLinq/AbstractConvertLinqQueryToForEachProvider.cs +++ b/src/Features/Core/Portable/ConvertLinq/AbstractConvertLinqQueryToForEachProvider.cs @@ -9,7 +9,7 @@ using System.Threading.Tasks; using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeRefactorings; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Shared.Extensions; namespace Microsoft.CodeAnalysis.ConvertLinq diff --git a/src/Features/Core/Portable/ConvertLinq/ConvertForEachToLinqQuery/AbstractConvertForEachToLinqQueryProvider.cs b/src/Features/Core/Portable/ConvertLinq/ConvertForEachToLinqQuery/AbstractConvertForEachToLinqQueryProvider.cs index f169d4d60ca75..8719ee2a6bca3 100644 --- a/src/Features/Core/Portable/ConvertLinq/ConvertForEachToLinqQuery/AbstractConvertForEachToLinqQueryProvider.cs +++ b/src/Features/Core/Portable/ConvertLinq/ConvertForEachToLinqQuery/AbstractConvertForEachToLinqQueryProvider.cs @@ -150,7 +150,7 @@ private Task ApplyConversionAsync( bool convertToQuery, CancellationToken cancellationToken) { - var editor = new SyntaxEditor(converter.ForEachInfo.SemanticModel.SyntaxTree.GetRoot(cancellationToken), document.Project.Solution.Workspace.Services); + var editor = new SyntaxEditor(converter.ForEachInfo.SemanticModel.SyntaxTree.GetRoot(cancellationToken), document.Project.Solution.Services); converter.Convert(editor, convertToQuery, cancellationToken); var newRoot = editor.GetChangedRoot(); var rootWithLinqUsing = AddLinqUsing(converter, converter.ForEachInfo.SemanticModel, newRoot); diff --git a/src/Features/Core/Portable/ConvertNumericLiteral/AbstractConvertNumericLiteralCodeRefactoringProvider.cs b/src/Features/Core/Portable/ConvertNumericLiteral/AbstractConvertNumericLiteralCodeRefactoringProvider.cs index 7b0e927686e1c..43759242a9c4a 100644 --- a/src/Features/Core/Portable/ConvertNumericLiteral/AbstractConvertNumericLiteralCodeRefactoringProvider.cs +++ b/src/Features/Core/Portable/ConvertNumericLiteral/AbstractConvertNumericLiteralCodeRefactoringProvider.cs @@ -9,7 +9,7 @@ using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeRefactorings; using Microsoft.CodeAnalysis.Editing; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Shared.Utilities; diff --git a/src/Features/Core/Portable/ConvertToInterpolatedString/AbstractConvertConcatenationToInterpolatedStringRefactoringProvider.cs b/src/Features/Core/Portable/ConvertToInterpolatedString/AbstractConvertConcatenationToInterpolatedStringRefactoringProvider.cs index d4673d6909a22..e75ee2d2674e6 100644 --- a/src/Features/Core/Portable/ConvertToInterpolatedString/AbstractConvertConcatenationToInterpolatedStringRefactoringProvider.cs +++ b/src/Features/Core/Portable/ConvertToInterpolatedString/AbstractConvertConcatenationToInterpolatedStringRefactoringProvider.cs @@ -10,7 +10,7 @@ using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeRefactorings; using Microsoft.CodeAnalysis.Editing; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Simplification; diff --git a/src/Features/Core/Portable/ConvertToInterpolatedString/AbstractConvertPlaceholderToInterpolatedStringRefactoringProvider.cs b/src/Features/Core/Portable/ConvertToInterpolatedString/AbstractConvertPlaceholderToInterpolatedStringRefactoringProvider.cs index 50f5f0dd92a45..0a6157213d739 100644 --- a/src/Features/Core/Portable/ConvertToInterpolatedString/AbstractConvertPlaceholderToInterpolatedStringRefactoringProvider.cs +++ b/src/Features/Core/Portable/ConvertToInterpolatedString/AbstractConvertPlaceholderToInterpolatedStringRefactoringProvider.cs @@ -12,7 +12,7 @@ using Microsoft.CodeAnalysis.CodeRefactorings; using Microsoft.CodeAnalysis.Editing; using Microsoft.CodeAnalysis.Formatting; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Simplification; diff --git a/src/Features/Core/Portable/ConvertToInterpolatedString/ConvertRegularStringToInterpolatedStringRefactoringProvider.cs b/src/Features/Core/Portable/ConvertToInterpolatedString/ConvertRegularStringToInterpolatedStringRefactoringProvider.cs index 94c9847d25dae..662663933b8f6 100644 --- a/src/Features/Core/Portable/ConvertToInterpolatedString/ConvertRegularStringToInterpolatedStringRefactoringProvider.cs +++ b/src/Features/Core/Portable/ConvertToInterpolatedString/ConvertRegularStringToInterpolatedStringRefactoringProvider.cs @@ -11,7 +11,7 @@ using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeRefactorings; using Microsoft.CodeAnalysis.Editing; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Shared.Extensions; namespace Microsoft.CodeAnalysis.ConvertToInterpolatedString diff --git a/src/Features/Core/Portable/ConvertTupleToStruct/AbstractConvertTupleToStructCodeRefactoringProvider.cs b/src/Features/Core/Portable/ConvertTupleToStruct/AbstractConvertTupleToStructCodeRefactoringProvider.cs index 142ec9d1bf5bc..1dae439d47e89 100644 --- a/src/Features/Core/Portable/ConvertTupleToStruct/AbstractConvertTupleToStructCodeRefactoringProvider.cs +++ b/src/Features/Core/Portable/ConvertTupleToStruct/AbstractConvertTupleToStructCodeRefactoringProvider.cs @@ -22,7 +22,7 @@ using Microsoft.CodeAnalysis.GenerateEqualsAndGetHashCodeFromMembers; using Microsoft.CodeAnalysis.Host; using Microsoft.CodeAnalysis.Internal.Log; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Remote; using Microsoft.CodeAnalysis.Shared.Collections; @@ -212,13 +212,13 @@ public async Task ConvertToStructAsync( using (Logger.LogBlock(FunctionId.AbstractConvertTupleToStructCodeRefactoringProvider_ConvertToStructAsync, cancellationToken)) { var solution = document.Project.Solution; - var client = await RemoteHostClient.TryGetClientAsync(solution.Workspace, cancellationToken).ConfigureAwait(false); + var client = await RemoteHostClient.TryGetClientAsync(solution.Services, cancellationToken).ConfigureAwait(false); if (client != null) { var result = await client.TryInvokeAsync( solution, (service, solutionInfo, callbackId, cancellationToken) => service.ConvertToStructAsync(solutionInfo, callbackId, document.Id, span, scope, isRecord, cancellationToken), - callbackTarget: new RemoteOptionsProvider(solution.Workspace.Services, fallbackOptions), + callbackTarget: new RemoteOptionsProvider(solution.Services, fallbackOptions), cancellationToken).ConfigureAwait(false); if (!result.HasValue) @@ -332,7 +332,7 @@ private async Task ReplaceExpressionAndTypesInScopeAsync( var project = group.Key; var compilation = await project.GetCompilationAsync(cancellationToken).ConfigureAwait(false); - var generator = project.LanguageServices.GetRequiredService(); + var generator = project.Services.GetRequiredService(); // Get the fully qualified name for the new type we're creating. We'll use this // at replacement points so that we can find the right type even if we're in a diff --git a/src/Features/Core/Portable/Debugging/DebugInformationReaderProvider.cs b/src/Features/Core/Portable/Debugging/DebugInformationReaderProvider.cs index 6571f631d304e..54d0e69c4bf10 100644 --- a/src/Features/Core/Portable/Debugging/DebugInformationReaderProvider.cs +++ b/src/Features/Core/Portable/Debugging/DebugInformationReaderProvider.cs @@ -10,6 +10,7 @@ using System.Reflection.Metadata; using System.Runtime.InteropServices; using System.Threading; +using System.Threading.Tasks; using Microsoft.CodeAnalysis.EditAndContinue; using Microsoft.DiaSymReader; using Roslyn.Utilities; @@ -46,6 +47,18 @@ public Portable(MetadataReaderProvider pdbReaderProvider) public override EditAndContinueMethodDebugInfoReader CreateEditAndContinueMethodDebugInfoReader() => EditAndContinueMethodDebugInfoReader.Create(_pdbReaderProvider.GetMetadataReader()); + public override ValueTask CopyContentToAsync(Stream stream, CancellationToken cancellationToken) + { + var reader = _pdbReaderProvider.GetMetadataReader(); + unsafe + { + using var metadataStream = new UnmanagedMemoryStream(reader.MetadataPointer, reader.MetadataLength); + metadataStream.CopyTo(stream); + } + + return ValueTaskFactory.CompletedTask; + } + public override void Dispose() => _pdbReaderProvider.Dispose(); } @@ -66,6 +79,20 @@ public Native(Stream stream, ISymUnmanagedReader5 symReader, int version) public override EditAndContinueMethodDebugInfoReader CreateEditAndContinueMethodDebugInfoReader() => EditAndContinueMethodDebugInfoReader.Create(_symReader, _version); + public override async ValueTask CopyContentToAsync(Stream stream, CancellationToken cancellationToken) + { + var position = _stream.Position; + try + { + _stream.Position = 0; + await _stream.CopyToAsync(stream, bufferSize: 4 * 1024, cancellationToken).ConfigureAwait(false); + } + finally + { + _stream.Position = position; + } + } + public override void Dispose() { _stream.Dispose(); @@ -85,6 +112,8 @@ public override void Dispose() /// public abstract EditAndContinueMethodDebugInfoReader CreateEditAndContinueMethodDebugInfoReader(); + public abstract ValueTask CopyContentToAsync(Stream stream, CancellationToken cancellationToken); + /// /// Creates from a stream of Portable or Windows PDB. /// diff --git a/src/Features/Core/Portable/DesignerAttribute/AbstractDesignerAttributeIncrementalAnalyzer.cs b/src/Features/Core/Portable/DesignerAttribute/AbstractDesignerAttributeIncrementalAnalyzer.cs index d607e18a7bb80..49be4d188a8cb 100644 --- a/src/Features/Core/Portable/DesignerAttribute/AbstractDesignerAttributeIncrementalAnalyzer.cs +++ b/src/Features/Core/Portable/DesignerAttribute/AbstractDesignerAttributeIncrementalAnalyzer.cs @@ -4,72 +4,82 @@ using System; using System.Collections.Concurrent; +using System.Collections.Generic; using System.Collections.Immutable; +using System.Composition; using System.Linq; using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.ErrorReporting; +using Microsoft.CodeAnalysis.Host; +using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Shared.Extensions; -using Microsoft.CodeAnalysis.SolutionCrawler; using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.DesignerAttribute { - internal abstract class AbstractDesignerAttributeIncrementalAnalyzer : IncrementalAnalyzerBase + [ExportWorkspaceService(typeof(IDesignerAttributeDiscoveryService)), Shared] + internal sealed partial class DesignerAttributeDiscoveryService : IDesignerAttributeDiscoveryService { + /// + /// Protects mutable state in this type. + /// + private readonly SemaphoreSlim _gate = new SemaphoreSlim(initialCount: 1); + /// /// Keep track of the last information we reported. We will avoid notifying the host if we recompute and these /// don't change. /// - private readonly ConcurrentDictionary _documentToLastReportedInformation = - new ConcurrentDictionary(); + private readonly ConcurrentDictionary _documentToLastReportedInformation = new(); - protected AbstractDesignerAttributeIncrementalAnalyzer() + [ImportingConstructor] + [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] + public DesignerAttributeDiscoveryService() { } - protected abstract ValueTask ReportProjectRemovedAsync(ProjectId projectId, CancellationToken cancellationToken); - - protected abstract ValueTask ReportDesignerAttributeDataAsync(ImmutableArray data, CancellationToken cancellationToken); - - public override async Task RemoveProjectAsync(ProjectId projectId, CancellationToken cancellationToken) + public async ValueTask ProcessSolutionAsync( + Solution solution, + DocumentId? priorityDocumentId, + IDesignerAttributeDiscoveryService.ICallback callback, + CancellationToken cancellationToken) { - await ReportProjectRemovedAsync(projectId, cancellationToken).ConfigureAwait(false); - - foreach (var docId in _documentToLastReportedInformation.Keys) + using (await _gate.DisposableWaitAsync(cancellationToken).ConfigureAwait(false)) { - if (projectId == docId.ProjectId) - _documentToLastReportedInformation.TryRemove(docId, out _); - } - } + // Remove any documents that are now gone. + foreach (var docId in _documentToLastReportedInformation.Keys) + { + if (!solution.ContainsDocument(docId)) + _documentToLastReportedInformation.TryRemove(docId, out _); + } - public override Task RemoveDocumentAsync(DocumentId documentId, CancellationToken cancellationToken) - { - _documentToLastReportedInformation.TryRemove(documentId, out _); - return Task.CompletedTask; - } + // Handle the priority doc first. + var priorityDocument = solution.GetDocument(priorityDocumentId); + if (priorityDocument != null) + { + await ProcessProjectAsync(priorityDocument.Project, priorityDocument, callback, cancellationToken).ConfigureAwait(false); - public override Task AnalyzeProjectAsync(Project project, bool semanticsChanged, InvocationReasons reasons, CancellationToken cancellationToken) - => AnalyzeProjectAsync(project, specificDocument: null, cancellationToken); + // now scan all the other files from that project in case they were affected by the edited document. + await ProcessProjectAsync(priorityDocument.Project, specificDocument: null, callback, cancellationToken).ConfigureAwait(false); + } - public override Task AnalyzeDocumentAsync(Document document, SyntaxNode? body, InvocationReasons reasons, CancellationToken cancellationToken) - { - // don't need to reanalyze file if just a method body was edited. That can't - // affect designer attributes. - if (body != null) - return Task.CompletedTask; - - // When we register our analyzer we will get called into for every document to - // 'reanalyze' them all. Ignore those as we would prefer to analyze the project - // en-mass. - if (reasons.Contains(PredefinedInvocationReasons.Reanalyze)) - return Task.CompletedTask; - - return AnalyzeProjectAsync(document.Project, document, cancellationToken); + // Process the rest of the projects in dependency order so that their data is ready when we hit the + // projects that depend on them. + var dependencyGraph = solution.GetProjectDependencyGraph(); + foreach (var projectId in dependencyGraph.GetTopologicallySortedProjects(cancellationToken)) + { + if (projectId != priorityDocumentId?.ProjectId) + await ProcessProjectAsync(solution.GetRequiredProject(projectId), specificDocument: null, callback, cancellationToken).ConfigureAwait(false); + } + } } - private async Task AnalyzeProjectAsync(Project project, Document? specificDocument, CancellationToken cancellationToken) + private async Task ProcessProjectAsync( + Project project, + Document? specificDocument, + IDesignerAttributeDiscoveryService.ICallback callback, + CancellationToken cancellationToken) { if (!project.SupportsCompilation) return; @@ -83,33 +93,27 @@ private async Task AnalyzeProjectAsync(Project project, Document? specificDocume // Now get all the values that actually changed and notify VS about them. We don't need // to tell it about the ones that didn't change since that will have no effect on the // user experience. - var latestData = await ComputeLatestDataAsync( + var changedData = await ComputeChangedDataAsync( project, specificDocument, projectVersion, cancellationToken).ConfigureAwait(false); - var changedData = - latestData.Where(d => - { - _documentToLastReportedInformation.TryGetValue(d.document.Id, out var existingInfo); - return existingInfo.category != d.data.Category; - }).ToImmutableArray(); - + // Only bother reporting non-empty information to save an unnecessary RPC. if (!changedData.IsEmpty) - { - await ReportDesignerAttributeDataAsync(changedData.SelectAsArray(d => d.data), cancellationToken).ConfigureAwait(false); - } + await callback.ReportDesignerAttributeDataAsync(changedData, cancellationToken).ConfigureAwait(false); - // Now, keep track of what we've reported to the host so we won't report unchanged files in the future. - foreach (var (document, info) in latestData) - _documentToLastReportedInformation[document.Id] = (info.Category, projectVersion); + // Now, keep track of what we've reported to the host so we won't report unchanged files in the future. We + // do this after the report has gone through as we want to make sure that if it cancels for any reason we + // don't hold onto values that may not have made it all the way to the project system. + foreach (var data in changedData) + _documentToLastReportedInformation[data.DocumentId] = (data.Category, projectVersion); } - private async Task<(Document document, DesignerAttributeData data)[]> ComputeLatestDataAsync( + private async Task> ComputeChangedDataAsync( Project project, Document? specificDocument, VersionStamp projectVersion, CancellationToken cancellationToken) { var compilation = await project.GetRequiredCompilationAsync(cancellationToken).ConfigureAwait(false); var designerCategoryType = compilation.DesignerCategoryAttributeType(); - using var _ = ArrayBuilder>.GetInstance(out var tasks); + using var _1 = ArrayBuilder>.GetInstance(out var tasks); foreach (var document in project.Documents) { // If we're only analyzing a specific document, then skip the rest. @@ -132,10 +136,27 @@ private async Task AnalyzeProjectAsync(Project project, Document? specificDocume tasks.Add(ComputeDesignerAttributeDataAsync(designerCategoryType, document, cancellationToken)); } - return await Task.WhenAll(tasks).ConfigureAwait(false); + using var _2 = ArrayBuilder.GetInstance(tasks.Count, out var results); + + // Avoid unnecessary allocation of result array. + await Task.WhenAll((IEnumerable)tasks).ConfigureAwait(false); + + foreach (var task in tasks) + { + var dataOpt = await task.ConfigureAwait(false); + if (dataOpt == null) + continue; + + var data = dataOpt.Value; + _documentToLastReportedInformation.TryGetValue(data.DocumentId, out var existingInfo); + if (existingInfo.category != data.Category) + results.Add(data); + } + + return results.ToImmutableAndClear(); } - private static async Task<(Document document, DesignerAttributeData data)> ComputeDesignerAttributeDataAsync( + private static async Task ComputeDesignerAttributeDataAsync( INamedTypeSymbol? designerCategoryType, Document document, CancellationToken cancellationToken) { try @@ -148,18 +169,16 @@ private async Task AnalyzeProjectAsync(Project project, Document? specificDocume var category = await DesignerAttributeHelpers.ComputeDesignerAttributeCategoryAsync( designerCategoryType, document, cancellationToken).ConfigureAwait(false); - var data = new DesignerAttributeData + return new DesignerAttributeData { Category = category, DocumentId = document.Id, FilePath = document.FilePath, }; - - return (document, data); } catch (Exception e) when (FatalError.ReportAndCatchUnlessCanceled(e, cancellationToken)) { - return default; + return null; } } } diff --git a/src/Workspaces/Core/Portable/DesignerAttribute/DesignerAttributeData.cs b/src/Features/Core/Portable/DesignerAttribute/DesignerAttributeData.cs similarity index 100% rename from src/Workspaces/Core/Portable/DesignerAttribute/DesignerAttributeData.cs rename to src/Features/Core/Portable/DesignerAttribute/DesignerAttributeData.cs diff --git a/src/Workspaces/Core/Portable/DesignerAttribute/DesignerAttributeHelpers.cs b/src/Features/Core/Portable/DesignerAttribute/DesignerAttributeHelpers.cs similarity index 98% rename from src/Workspaces/Core/Portable/DesignerAttribute/DesignerAttributeHelpers.cs rename to src/Features/Core/Portable/DesignerAttribute/DesignerAttributeHelpers.cs index d7caaf212e12d..038f14f77fc8b 100644 --- a/src/Workspaces/Core/Portable/DesignerAttribute/DesignerAttributeHelpers.cs +++ b/src/Features/Core/Portable/DesignerAttribute/DesignerAttributeHelpers.cs @@ -6,7 +6,7 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.Host; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Shared.Extensions; namespace Microsoft.CodeAnalysis.DesignerAttribute diff --git a/src/Features/Core/Portable/DesignerAttribute/IDesignerAttributeDiscoveryService.cs b/src/Features/Core/Portable/DesignerAttribute/IDesignerAttributeDiscoveryService.cs new file mode 100644 index 0000000000000..c3bc3fbf0af0d --- /dev/null +++ b/src/Features/Core/Portable/DesignerAttribute/IDesignerAttributeDiscoveryService.cs @@ -0,0 +1,22 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Collections.Immutable; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.Host; + +namespace Microsoft.CodeAnalysis.DesignerAttribute +{ + internal partial interface IDesignerAttributeDiscoveryService : IWorkspaceService + { + public interface ICallback + { + ValueTask ReportDesignerAttributeDataAsync(ImmutableArray data, CancellationToken cancellationToken); + } + + ValueTask ProcessSolutionAsync(Solution solution, DocumentId? priorityDocumentId, ICallback callback, CancellationToken cancellationToken); + } +} diff --git a/src/Workspaces/Core/Portable/DesignerAttribute/IRemoteDesignerAttributeDiscoveryService.cs b/src/Features/Core/Portable/DesignerAttribute/IRemoteDesignerAttributeDiscoveryService.cs similarity index 67% rename from src/Workspaces/Core/Portable/DesignerAttribute/IRemoteDesignerAttributeDiscoveryService.cs rename to src/Features/Core/Portable/DesignerAttribute/IRemoteDesignerAttributeDiscoveryService.cs index f7e5dc13c27b4..4716273c30a92 100644 --- a/src/Workspaces/Core/Portable/DesignerAttribute/IRemoteDesignerAttributeDiscoveryService.cs +++ b/src/Features/Core/Portable/DesignerAttribute/IRemoteDesignerAttributeDiscoveryService.cs @@ -20,11 +20,10 @@ internal interface IRemoteDesignerAttributeDiscoveryService { internal interface ICallback { - ValueTask OnProjectRemovedAsync(RemoteServiceCallbackId callbackId, ProjectId projectId, CancellationToken cancellationToken); ValueTask ReportDesignerAttributeDataAsync(RemoteServiceCallbackId callbackId, ImmutableArray data, CancellationToken cancellationToken); } - ValueTask StartScanningForDesignerAttributesAsync(RemoteServiceCallbackId callbackId, CancellationToken cancellation); + ValueTask DiscoverDesignerAttributesAsync(RemoteServiceCallbackId callbackId, Checksum solutionChecksum, DocumentId? priorityDocument, CancellationToken cancellationToken); } [ExportRemoteServiceCallbackDispatcher(typeof(IRemoteDesignerAttributeDiscoveryService)), Shared] @@ -36,13 +35,10 @@ public RemoteDesignerAttributeDiscoveryCallbackDispatcher() { } - private IDesignerAttributeListener GetLogService(RemoteServiceCallbackId callbackId) - => (IDesignerAttributeListener)GetCallback(callbackId); - - public ValueTask OnProjectRemovedAsync(RemoteServiceCallbackId callbackId, ProjectId projectId, CancellationToken cancellationToken) - => GetLogService(callbackId).OnProjectRemovedAsync(projectId, cancellationToken); + private new IDesignerAttributeDiscoveryService.ICallback GetCallback(RemoteServiceCallbackId callbackId) + => (IDesignerAttributeDiscoveryService.ICallback)base.GetCallback(callbackId); public ValueTask ReportDesignerAttributeDataAsync(RemoteServiceCallbackId callbackId, ImmutableArray data, CancellationToken cancellationToken) - => GetLogService(callbackId).ReportDesignerAttributeDataAsync(data, cancellationToken); + => GetCallback(callbackId).ReportDesignerAttributeDataAsync(data, cancellationToken); } } diff --git a/src/Features/Core/Portable/Diagnostics/DiagnosticAnalyzerTelemetry.cs b/src/Features/Core/Portable/Diagnostics/DiagnosticAnalyzerTelemetry.cs index d18da21e37fa4..0d3e5b4dbe106 100644 --- a/src/Features/Core/Portable/Diagnostics/DiagnosticAnalyzerTelemetry.cs +++ b/src/Features/Core/Portable/Diagnostics/DiagnosticAnalyzerTelemetry.cs @@ -106,7 +106,7 @@ public void ReportAndClear(int correlationId) else { // annonymize analyzer and exception names: - m["Analyzer.NameHashCode"] = ComputeSha256Hash(analyzerName); + m["Analyzer.NameHashCode"] = AnalyzerNameForTelemetry.ComputeSha256Hash(analyzerName); } m["Analyzer.CodeBlock"] = analyzerInfo.CodeBlockActionsCount; @@ -130,11 +130,5 @@ public void ReportAndClear(int correlationId) })); } } - - private static string ComputeSha256Hash(string name) - { - using var sha256 = SHA256.Create(); - return Convert.ToBase64String(sha256.ComputeHash(Encoding.UTF8.GetBytes(name))); - } } } diff --git a/src/Features/Core/Portable/DocumentHighlighting/AbstractDocumentHighlightsService.cs b/src/Features/Core/Portable/DocumentHighlighting/AbstractDocumentHighlightsService.cs index d3e7679e64fd8..40452cfa3b2f9 100644 --- a/src/Features/Core/Portable/DocumentHighlighting/AbstractDocumentHighlightsService.cs +++ b/src/Features/Core/Portable/DocumentHighlighting/AbstractDocumentHighlightsService.cs @@ -12,7 +12,7 @@ using Microsoft.CodeAnalysis.EmbeddedLanguages; using Microsoft.CodeAnalysis.ErrorReporting; using Microsoft.CodeAnalysis.FindSymbols; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Remote; using Microsoft.CodeAnalysis.Shared.Extensions; @@ -71,7 +71,7 @@ private async Task> GetDocumentHighlightsInCu var solution = document.Project.Solution; var symbol = await SymbolFinder.FindSymbolAtPositionAsync( - semanticModel, position, solution.Workspace, cancellationToken).ConfigureAwait(false); + semanticModel, position, solution.Services, cancellationToken).ConfigureAwait(false); if (symbol == null) return ImmutableArray.Empty; @@ -236,7 +236,7 @@ private static async Task> CreateSpansAsync( // Document once https://github.com/dotnet/roslyn/issues/5260 is fixed. if (document == null) { - Debug.Assert(solution.Workspace.Kind is WorkspaceKind.Interactive or WorkspaceKind.MiscellaneousFiles); + Debug.Assert(solution.WorkspaceKind is WorkspaceKind.Interactive or WorkspaceKind.MiscellaneousFiles); continue; } @@ -261,19 +261,17 @@ private static async Task> CreateSpansAsync( await AddLocationSpanAsync(location, solution, spanSet, tagMap, HighlightSpanKind.Reference, cancellationToken).ConfigureAwait(false); } - using var listDisposer = ArrayBuilder.GetInstance(tagMap.Count, out var list); + using var _1 = ArrayBuilder.GetInstance(tagMap.Count, out var list); foreach (var kvp in tagMap) { - using var spansDisposer = ArrayBuilder.GetInstance(kvp.Value.Count, out var spans); + using var _2 = ArrayBuilder.GetInstance(kvp.Value.Count, out var spans); foreach (var span in kvp.Value) - { spans.Add(span); - } - list.Add(new DocumentHighlights(kvp.Key, spans.ToImmutable())); + list.Add(new DocumentHighlights(kvp.Key, spans.ToImmutableAndClear())); } - return list.ToImmutable(); + return list.ToImmutableAndClear(); } private static bool ShouldIncludeDefinition(ISymbol symbol) @@ -318,7 +316,7 @@ private static async Task AddLocationSpanAsync(Location location, Solution solut var root = await tree.GetRootAsync(cancellationToken).ConfigureAwait(false); var token = root.FindToken(location.SourceSpan.Start, findInsideTrivia: true); - return syntaxFacts.IsGenericName(token.Parent) || syntaxFacts.IsIndexerMemberCRef(token.Parent) + return syntaxFacts.IsGenericName(token.Parent) || syntaxFacts.IsIndexerMemberCref(token.Parent) ? new DocumentSpan(document, token.Span) : new DocumentSpan(document, location.SourceSpan); } diff --git a/src/Features/Core/Portable/DocumentHighlighting/IDocumentHighlightsService.cs b/src/Features/Core/Portable/DocumentHighlighting/IDocumentHighlightsService.cs index c9f7bdd501788..b5dc1c11e5ce6 100644 --- a/src/Features/Core/Portable/DocumentHighlighting/IDocumentHighlightsService.cs +++ b/src/Features/Core/Portable/DocumentHighlighting/IDocumentHighlightsService.cs @@ -6,9 +6,7 @@ using System.Runtime.Serialization; using System.Threading; using System.Threading.Tasks; -using Microsoft.CodeAnalysis.Features.EmbeddedLanguages.RegularExpressions.LanguageServices; using Microsoft.CodeAnalysis.Host; -using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Text; namespace Microsoft.CodeAnalysis.DocumentHighlighting diff --git a/src/Features/Core/Portable/DocumentationComments/CodeFixes/AbstractAddDocCommentNodesCodeFixProvider.cs b/src/Features/Core/Portable/DocumentationComments/CodeFixes/AbstractAddDocCommentNodesCodeFixProvider.cs index 14dbe2b659d2c..7b3008e0faef4 100644 --- a/src/Features/Core/Portable/DocumentationComments/CodeFixes/AbstractAddDocCommentNodesCodeFixProvider.cs +++ b/src/Features/Core/Portable/DocumentationComments/CodeFixes/AbstractAddDocCommentNodesCodeFixProvider.cs @@ -89,10 +89,7 @@ protected async Task AddParamTagAsync( } // This will be hit in the index is `0`, in which case the previous node is the summary node - if (nodeBeforeNewParamNode == null) - { - nodeBeforeNewParamNode = summaryNode; - } + nodeBeforeNewParamNode ??= summaryNode; newDocComment = newDocComment.InsertNodesAfter(nodeBeforeNewParamNode, new[] { GetNewNode(parameterName, isFirstNodeInComment: false) }); diff --git a/src/Features/Core/Portable/EditAndContinue/AbstractEditAndContinueAnalyzer.cs b/src/Features/Core/Portable/EditAndContinue/AbstractEditAndContinueAnalyzer.cs index 57d735c4ab410..7ee46bf54b46e 100644 --- a/src/Features/Core/Portable/EditAndContinue/AbstractEditAndContinueAnalyzer.cs +++ b/src/Features/Core/Portable/EditAndContinue/AbstractEditAndContinueAnalyzer.cs @@ -8,19 +8,18 @@ using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Linq; -using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Text; using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.Differencing; +using Microsoft.CodeAnalysis.EditAndContinue.Contracts; using Microsoft.CodeAnalysis.Emit; using Microsoft.CodeAnalysis.ErrorReporting; using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Shared.Utilities; using Microsoft.CodeAnalysis.Text; -using Microsoft.CodeAnalysis.EditAndContinue.Contracts; using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.EditAndContinue @@ -454,7 +453,7 @@ protected virtual string GetSuspensionPointDisplayName(SyntaxNode node, EditKind /// - a method, an indexer or a type (delegate) if the is a parameter, /// - a method or an type if the is a type parameter. /// - internal abstract bool TryGetAssociatedMemberDeclaration(SyntaxNode node, [NotNullWhen(true)] out SyntaxNode? declaration); + internal abstract bool TryGetAssociatedMemberDeclaration(SyntaxNode node, EditKind editKind, [NotNullWhen(true)] out SyntaxNode? declaration); internal abstract bool HasBackingField(SyntaxNode propertyDeclaration); @@ -495,11 +494,15 @@ public async Task AnalyzeDocumentAsync( AsyncLazy lazyCapabilities, CancellationToken cancellationToken) { - DocumentAnalysisResults.Log.Write("Analyzing document {0}", newDocument.Name); + var filePath = newDocument.FilePath; + Debug.Assert(newDocument.State.SupportsEditAndContinue()); Debug.Assert(!newActiveStatementSpans.IsDefault); Debug.Assert(newDocument.SupportsSyntaxTree); Debug.Assert(newDocument.SupportsSemanticModel); + Debug.Assert(filePath != null); + + DocumentAnalysisResults.Log.Write("Analyzing document '{0}'", filePath); // assume changes until we determine there are none so that EnC is blocked on unexpected exception: var hasChanges = true; @@ -515,9 +518,7 @@ public async Task AnalyzeDocumentAsync( var oldDocument = await oldProject.GetDocumentAsync(newDocument.Id, includeSourceGenerated: true, cancellationToken).ConfigureAwait(false); if (oldDocument != null) { - oldTree = await oldDocument.GetSyntaxTreeAsync(cancellationToken).ConfigureAwait(false); - Contract.ThrowIfNull(oldTree); - + oldTree = await oldDocument.GetRequiredSyntaxTreeAsync(cancellationToken).ConfigureAwait(false); oldRoot = await oldTree.GetRootAsync(cancellationToken).ConfigureAwait(false); oldText = await oldDocument.GetTextAsync(cancellationToken).ConfigureAwait(false); } @@ -549,8 +550,8 @@ public async Task AnalyzeDocumentAsync( { // Bail, since we can't do syntax diffing on broken trees (it would not produce useful results anyways). // If we needed to do so for some reason, we'd need to harden the syntax tree comparers. - DocumentAnalysisResults.Log.Write("{0}: syntax errors", newDocument.Name); - return DocumentAnalysisResults.SyntaxErrors(newDocument.Id, ImmutableArray.Empty, syntaxError, hasChanges); + DocumentAnalysisResults.Log.Write("{0}: syntax errors", filePath); + return DocumentAnalysisResults.SyntaxErrors(newDocument.Id, filePath, ImmutableArray.Empty, syntaxError, hasChanges); } if (!hasChanges) @@ -560,17 +561,17 @@ public async Task AnalyzeDocumentAsync( // a) comparing texts is cheaper than diffing trees // b) we need to ignore errors in unchanged documents - DocumentAnalysisResults.Log.Write("{0}: unchanged", newDocument.Name); - return DocumentAnalysisResults.Unchanged(newDocument.Id); + DocumentAnalysisResults.Log.Write("{0}: unchanged", filePath); + return DocumentAnalysisResults.Unchanged(newDocument.Id, filePath); } // Disallow modification of a file with experimental features enabled. // These features may not be handled well by the analysis below. if (ExperimentalFeaturesEnabled(newTree)) { - DocumentAnalysisResults.Log.Write("{0}: experimental features enabled", newDocument.Name); + DocumentAnalysisResults.Log.Write("{0}: experimental features enabled", filePath); - return DocumentAnalysisResults.SyntaxErrors(newDocument.Id, ImmutableArray.Create( + return DocumentAnalysisResults.SyntaxErrors(newDocument.Id, filePath, ImmutableArray.Create( new RudeEditDiagnostic(RudeEditKind.ExperimentalFeaturesEnabled, default)), syntaxError: null, hasChanges); } @@ -580,7 +581,7 @@ public async Task AnalyzeDocumentAsync( // If the document has changed at all, lets make sure Edit and Continue is supported if (!capabilities.Grant(EditAndContinueCapabilities.Baseline)) { - return DocumentAnalysisResults.SyntaxErrors(newDocument.Id, ImmutableArray.Create( + return DocumentAnalysisResults.SyntaxErrors(newDocument.Id, filePath, ImmutableArray.Create( new RudeEditDiagnostic(RudeEditKind.NotSupportedByRuntime, default)), syntaxError: null, hasChanges); } @@ -606,7 +607,7 @@ public async Task AnalyzeDocumentAsync( if (diagnostics.Count > 0 && !hasRudeEdits) { - DocumentAnalysisResults.Log.Write("{0} syntactic rude edits, first: '{1}'", diagnostics.Count, newDocument.FilePath); + DocumentAnalysisResults.Log.Write("{0} syntactic rude edits, first: '{1}'", diagnostics.Count, filePath); hasRudeEdits = true; } @@ -657,12 +658,13 @@ public async Task AnalyzeDocumentAsync( if (diagnostics.Count > 0 && !hasRudeEdits) { - DocumentAnalysisResults.Log.Write("{0}@{1}: rude edit ({2} total)", newDocument.FilePath, diagnostics.First().Span.Start, diagnostics.Count); + DocumentAnalysisResults.Log.Write("{0}@{1}: rude edit ({2} total)", filePath, diagnostics.First().Span.Start, diagnostics.Count); hasRudeEdits = true; } return new DocumentAnalysisResults( newDocument.Id, + filePath, newActiveStatements.MoveToImmutable(), diagnostics.ToImmutable(), syntaxError: null, @@ -684,7 +686,7 @@ public async Task AnalyzeDocumentAsync( new RudeEditDiagnostic(RudeEditKind.InternalError, span: default, arguments: new[] { newDocument.FilePath, e.ToString() }); // Report as "syntax error" - we can't analyze the document - return DocumentAnalysisResults.SyntaxErrors(newDocument.Id, ImmutableArray.Create(diagnostic), syntaxError: null, hasChanges); + return DocumentAnalysisResults.SyntaxErrors(newDocument.Id, filePath, ImmutableArray.Create(diagnostic), syntaxError: null, hasChanges); } } @@ -1157,17 +1159,23 @@ private void AnalyzeChangedMemberBody( } } - // exception handling around the statement: - CalculateExceptionRegionsAroundActiveStatement( - bodyMatch, - oldStatementSyntax, - newStatementSyntax, - newSpan, - activeStatementIndex, - isNonLeaf, - newExceptionRegions, - diagnostics, - cancellationToken); + // If there was a lambda, but we couldn't match its body to the new tree, then the lambda was + // removed, so we don't need to check it for active statements. If there wasn't a lambda then + // match here will be the same as bodyMatch. + if (match is not null) + { + // exception handling around the statement: + CalculateExceptionRegionsAroundActiveStatement( + match, + oldStatementSyntax, + newStatementSyntax, + newSpan, + activeStatementIndex, + isNonLeaf, + newExceptionRegions, + diagnostics, + cancellationToken); + } // We have already calculated the new location of this active statement when analyzing another member declaration. // This may only happen when two or more member declarations share the same body (VB AsNew clause). @@ -2649,18 +2657,36 @@ private async Task> AnalyzeSemanticsAsync( continue; } - // If the associated member declaration (accessor -> property/indexer/event, parameter -> method) has also been deleted skip - // the delete of the symbol as it will be deleted by the delete of the associated member. + var rudeEditKind = RudeEditKind.Delete; + + // If the associated member declaration (parameter/type parameter -> method) has also been deleted skip + // the delete of the symbol as it will be deleted by the delete of the associated member. We pass the edit kind + // in here to avoid property/event accessors from being caught up in this, because those deletes we want to process + // separately, below. // // Associated member declarations must be in the same document as the symbol, so we don't need to resolve their symbol. // In some cases the symbol even can't be resolved unambiguously. Consider e.g. resolving a method with its parameter deleted - // we wouldn't know which overload to resolve to. - if (TryGetAssociatedMemberDeclaration(oldDeclaration, out var oldAssociatedMemberDeclaration)) + if (TryGetAssociatedMemberDeclaration(oldDeclaration, EditKind.Delete, out var oldAssociatedMemberDeclaration)) { if (HasEdit(editMap, oldAssociatedMemberDeclaration, EditKind.Delete)) { continue; } + + // We allow deleting parameters, by issuing delete and insert edits for the old and new method + if (oldSymbol is IParameterSymbol) + { + if (TryAddParameterInsertOrDeleteEdits(semanticEdits, oldSymbol.ContainingSymbol, newModel, capabilities, syntaxMap, editScript, cancellationToken, out var notSupportedByRuntime)) + { + continue; + } + + if (notSupportedByRuntime) + { + rudeEditKind = RudeEditKind.DeleteNotSupportedByRuntime; + } + } } else if (oldSymbol.ContainingType != null) { @@ -2673,13 +2699,9 @@ private async Task> AnalyzeSemanticsAsync( continue; } - // Deleting an ordinary method is allowed, and we store the newContainingSymbol in NewSymbol for later use - // We don't currently allow deleting virtual or abstract methods, because if those are in the middle of - // an inheritance chain then throwing a missing method exception is not expected - if (oldSymbol is IMethodSymbol { MethodKind: MethodKind.Ordinary, IsExtern: false, ContainingType.TypeKind: TypeKind.Class or TypeKind.Struct } && - oldSymbol.GetSymbolModifiers() is { IsVirtual: false, IsAbstract: false, IsOverride: false }) + if (!hasActiveStatement && AllowsDeletion(oldSymbol)) { - semanticEdits.Add(new SemanticEditInfo(editKind, symbolKey, syntaxMap, syntaxMapTree: null, partialType: null, deletedSymbolContainer: containingSymbolKey)); + AddMemberOrAssociatedMemberSemanticEdits(semanticEdits, SemanticEditKind.Delete, oldSymbol, containingSymbolKey, syntaxMap, partialType: null, cancellationToken); continue; } } @@ -2687,7 +2709,7 @@ private async Task> AnalyzeSemanticsAsync( // deleting symbol is not allowed diagnostics.Add(new RudeEditDiagnostic( - RudeEditKind.Delete, + rudeEditKind, diagnosticSpan, oldDeclaration, new[] @@ -2828,14 +2850,14 @@ private async Task> AnalyzeSemanticsAsync( editKind = SemanticEditKind.Update; } } - else if (TryGetAssociatedMemberDeclaration(newDeclaration, out var newAssociatedMemberDeclaration) && + else if (TryGetAssociatedMemberDeclaration(newDeclaration, EditKind.Insert, out var newAssociatedMemberDeclaration) && HasEdit(editMap, newAssociatedMemberDeclaration, EditKind.Insert)) { // If the symbol is an accessor and the containing property/indexer/event declaration has also been inserted skip // the insert of the accessor as it will be inserted by the property/indexer/event. continue; } - else if (newSymbol is IParameterSymbol or ITypeParameterSymbol) + else if (newSymbol is ITypeParameterSymbol) { diagnostics.Add(new RudeEditDiagnostic( RudeEditKind.Insert, @@ -2845,6 +2867,19 @@ private async Task> AnalyzeSemanticsAsync( continue; } + else if (newSymbol is IParameterSymbol) + { + if (!TryAddParameterInsertOrDeleteEdits(semanticEdits, newSymbol.ContainingSymbol, oldModel, capabilities, syntaxMap, editScript, cancellationToken, out var notSupportedByRuntime)) + { + diagnostics.Add(new RudeEditDiagnostic( + notSupportedByRuntime ? RudeEditKind.InsertNotSupportedByRuntime : RudeEditKind.Insert, + GetDiagnosticSpan(newDeclaration, EditKind.Insert), + newDeclaration, + arguments: new[] { GetDisplayName(newDeclaration, EditKind.Insert) })); + } + + continue; + } else if (newContainingType != null && !IsGlobalMain(newSymbol)) { // The edit actually adds a new symbol into an existing or a new type. @@ -2852,7 +2887,7 @@ private async Task> AnalyzeSemanticsAsync( var containingSymbolKey = SymbolKey.Create(newContainingType, cancellationToken); oldContainingType = containingSymbolKey.Resolve(oldCompilation, ignoreAssemblyKey: true, cancellationToken).Symbol as INamedTypeSymbol; - if (oldContainingType != null && !CanAddNewMember(newSymbol, capabilities)) + if (oldContainingType != null && !CanAddNewMember(newSymbol, capabilities, cancellationToken)) { diagnostics.Add(new RudeEditDiagnostic( RudeEditKind.InsertNotSupportedByRuntime, @@ -3024,7 +3059,43 @@ private async Task> AnalyzeSemanticsAsync( Contract.ThrowIfNull(oldSymbol); AnalyzeSymbolUpdate(oldSymbol, newSymbol, edit.NewNode, newCompilation, editScript.Match, capabilities, diagnostics, semanticEdits, syntaxMap, cancellationToken); - if (newSymbol is INamedTypeSymbol or IFieldSymbol or IPropertySymbol or IEventSymbol or IParameterSymbol or ITypeParameterSymbol) + + if (newSymbol is INamedTypeSymbol or IFieldSymbol or IParameterSymbol or ITypeParameterSymbol) + { + continue; + } + + // For renames where the symbol allows deletion, we don't create an update edit, we create a delete + // and an add. During emit an empty body will be created for the old name. Sometimes + // when members are moved between documents in partial classes, they can appear as renames, so + // we also check that the old symbol can't be resolved in the new compilation + if (oldSymbol.Name != newSymbol.Name && + AllowsDeletion(oldSymbol) && + CanAddNewMember(oldSymbol, capabilities, cancellationToken) && + SymbolKey.Create(oldSymbol, cancellationToken).Resolve(newCompilation, ignoreAssemblyKey: true, cancellationToken).Symbol is null) + { + Contract.ThrowIfNull(oldDeclaration); + var activeStatementIndices = GetOverlappingActiveStatements(oldDeclaration, oldActiveStatements); + if (activeStatementIndices.Any()) + { + Contract.ThrowIfNull(newDeclaration); + AddRudeUpdateAroundActiveStatement(diagnostics, newDeclaration); + } + else + { + var containingSymbolKey = SymbolKey.Create(oldSymbol.ContainingType, cancellationToken); + + AddMemberOrAssociatedMemberSemanticEdits(semanticEdits, SemanticEditKind.Delete, oldSymbol, containingSymbolKey, syntaxMap, partialType: null, cancellationToken); + + AddMemberOrAssociatedMemberSemanticEdits(semanticEdits, SemanticEditKind.Insert, newSymbol, containingSymbolKey: null, syntaxMap, + partialType: IsPartialEdit(oldSymbol, newSymbol, editScript.Match.OldRoot.SyntaxTree, editScript.Match.NewRoot.SyntaxTree) ? symbolKey : null, + cancellationToken); + } + + continue; + } + + if (newSymbol is IPropertySymbol or IEventSymbol) { continue; } @@ -3182,6 +3253,169 @@ private async Task> AnalyzeSemanticsAsync( } } + /// + /// Adds a delete and insert edit for the old and new symbols that have had a parameter inserted or deleted + /// + /// The symbol that contains the parameter that has been added or deleted (either IMethodSymbol or IPropertySymbol) + /// The semantic model from the old compilation, for parameter inserts, or new compilation, for deletes + /// Whether the edit should be rejected because the runtime doesn't support inserting new methods. Otherwise a normal rude edit is appropriate. + /// Returns whether semantic edits were added, or if not then a rude edit should be created + private bool TryAddParameterInsertOrDeleteEdits(ArrayBuilder semanticEdits, ISymbol containingSymbol, SemanticModel? otherModel, EditAndContinueCapabilitiesGrantor capabilities, Func? syntaxMap, EditScript editScript, CancellationToken cancellationToken, out bool notSupportedByRuntime) + { + Debug.Assert(containingSymbol is IPropertySymbol or IMethodSymbol); + + notSupportedByRuntime = false; + + // Since we're inserting (or deleting) a parameter node, oldSymbol (or newSymbol) would have been null, + // and a symbolkey won't map to the other compilation because the parameters are different, so we have to go back to the edit map + // to find the declaration that contains the parameter, and its partner, and then its symbol, so we need to be sure we can get + // to syntax, and have a semantic model to get back to symbols. + if (otherModel is null || + containingSymbol.DeclaringSyntaxReferences.Length != 1) + { + return false; + } + + // We can ignore parameter inserts and deletes for partial method definitions, as we'll report them on the implementation. + // We return true here so no rude edit is raised. + if (containingSymbol is IMethodSymbol { IsPartialDefinition: true }) + { + return true; + } + + // We don't support delegate parameters + if (containingSymbol.ContainingType.IsDelegateType()) + { + return false; + } + + // We don't (for now) support parameter inserts/deletes on properties or indexers + if (containingSymbol is not IMethodSymbol) + { + return false; + } + + // Find the node that matches this declaration + SyntaxNode otherContainingNode; + var containingNode = containingSymbol.DeclaringSyntaxReferences[0].GetSyntax(cancellationToken); + if (editScript.Match.TryGetOldNode(containingNode, out var oldNode)) + { + otherContainingNode = oldNode; + } + else if (editScript.Match.TryGetNewNode(containingNode, out var newNode)) + { + otherContainingNode = newNode; + } + else + { + return false; + } + + var otherContainingSymbol = otherModel.GetDeclaredSymbol(otherContainingNode, cancellationToken); + if (otherContainingSymbol is null || !AllowsDeletion(otherContainingSymbol)) + { + return false; + } + + // Now we can work out which is the old and which is the new, depending on which map we found + // the match in + var oldSymbol = (otherContainingNode == oldNode) ? otherContainingSymbol : containingSymbol; + var newSymbol = (otherContainingNode == oldNode) ? containingSymbol : otherContainingSymbol; + + if (!CanAddNewMember(oldSymbol, capabilities, cancellationToken)) + { + notSupportedByRuntime = true; + return false; + } + + var containingSymbolKey = SymbolKey.Create(oldSymbol.ContainingType, cancellationToken); + + AddMemberOrAssociatedMemberSemanticEdits(semanticEdits, SemanticEditKind.Delete, oldSymbol, containingSymbolKey, syntaxMap, partialType: null, cancellationToken); + + var symbolKey = SymbolKey.Create(newSymbol, cancellationToken); + AddMemberOrAssociatedMemberSemanticEdits(semanticEdits, SemanticEditKind.Insert, newSymbol, containingSymbolKey: null, syntaxMap, + partialType: IsPartialEdit(oldSymbol, newSymbol, editScript.Match.OldRoot.SyntaxTree, editScript.Match.NewRoot.SyntaxTree) ? symbolKey : null, + cancellationToken); + + return true; + } + + /// + /// Returns whether or not the specified symbol can be deleted by the user. Normally deletes are a rude edit + /// but for some kinds of symbols we allow deletes, and synthesize an update to an empty method body during + /// emit. + /// + private static bool AllowsDeletion(ISymbol symbol) + { + // We don't currently allow deleting virtual or abstract methods, because if those are in the middle of + // an inheritance chain then throwing a missing method exception is not expected + if (symbol.GetSymbolModifiers() is not { IsVirtual: false, IsAbstract: false, IsOverride: false }) + return false; + + // Extern methods can't be deleted + if (symbol.IsExtern) + return false; + + // We don't allow deleting members from interfaces etc. only normal classes and structs + if (symbol.ContainingType is not { TypeKind: TypeKind.Class or TypeKind.Struct }) + return false; + + // We store the containing symbol in NewSymbol of the edit for later use. + if (symbol is IMethodSymbol + { + MethodKind: + MethodKind.Ordinary or + MethodKind.Constructor or + MethodKind.EventAdd or + MethodKind.EventRemove or + MethodKind.EventRaise or + MethodKind.Conversion or + MethodKind.UserDefinedOperator or + MethodKind.PropertyGet or + MethodKind.PropertySet + }) + { + return true; + } + + return symbol is IPropertySymbol or IEventSymbol; + } + + /// + /// Add semantic edits for the specified symbol, or the associated members of the specified symbol, + /// for example, edits for each accessor if a property symbol is passed in. + /// + private static void AddMemberOrAssociatedMemberSemanticEdits(ArrayBuilder semanticEdits, SemanticEditKind editKind, ISymbol symbol, SymbolKey? containingSymbolKey, Func? syntaxMap, SymbolKey? partialType, CancellationToken cancellationToken) + { + Debug.Assert(symbol is IMethodSymbol or IPropertySymbol or IEventSymbol); + + // We store the containing symbol in NewSymbol of the edit for later use. + if (symbol is IMethodSymbol) + { + AddEdit(symbol); + } + else if (symbol is IPropertySymbol propertySymbol) + { + AddEdit(propertySymbol.GetMethod); + AddEdit(propertySymbol.SetMethod); + } + else if (symbol is IEventSymbol eventSymbol) + { + AddEdit(eventSymbol.AddMethod); + AddEdit(eventSymbol.RemoveMethod); + AddEdit(eventSymbol.RaiseMethod); + } + + void AddEdit(ISymbol? symbol) + { + if (symbol is null) + return; + + var symbolKey = SymbolKey.Create(symbol, cancellationToken); + semanticEdits.Add(new SemanticEditInfo(editKind, symbolKey, syntaxMap, syntaxMapTree: null, partialType, deletedSymbolContainer: containingSymbolKey)); + } + } + private ImmutableArray<(ISymbol? oldSymbol, ISymbol? newSymbol, EditKind editKind)> GetNamespaceSymbolEdits( SemanticModel oldModel, SemanticModel newModel, @@ -3313,6 +3547,7 @@ private void ReportUpdatedSymbolDeclarationRudeEdits( out bool hasGeneratedAttributeChange, out bool hasGeneratedReturnTypeAttributeChange, out bool hasParameterRename, + out bool hasParameterTypeChange, CancellationToken cancellationToken) { var rudeEdit = RudeEditKind.None; @@ -3320,6 +3555,7 @@ private void ReportUpdatedSymbolDeclarationRudeEdits( hasGeneratedAttributeChange = false; hasGeneratedReturnTypeAttributeChange = false; hasParameterRename = false; + hasParameterTypeChange = false; if (oldSymbol.Kind != newSymbol.Kind) { @@ -3329,22 +3565,10 @@ private void ReportUpdatedSymbolDeclarationRudeEdits( { if (oldSymbol is IParameterSymbol && newSymbol is IParameterSymbol) { - if (capabilities.Grant(EditAndContinueCapabilities.UpdateParameters)) - { - hasParameterRename = true; - } - else - { - rudeEdit = RudeEditKind.RenamingNotSupportedByRuntime; - } - } - else - { - rudeEdit = RudeEditKind.Renamed; + // We defer checking parameter renames until later, because if their types have also changed + // then we'll be emitting a new method, so it won't be a rename any more } - - // specialize rude edit for accessors and conversion operators: - if (oldSymbol is IMethodSymbol oldMethod && newSymbol is IMethodSymbol newMethod) + else if (oldSymbol is IMethodSymbol oldMethod && newSymbol is IMethodSymbol newMethod) { if (oldMethod.AssociatedSymbol != null && newMethod.AssociatedSymbol != null) { @@ -3362,6 +3586,55 @@ private void ReportUpdatedSymbolDeclarationRudeEdits( { rudeEdit = RudeEditKind.ModifiersUpdate; } + else if (oldMethod.MethodKind == MethodKind.ExplicitInterfaceImplementation || newMethod.MethodKind == MethodKind.ExplicitInterfaceImplementation) + { + // Can't change from explicit to implicit interface implementation, or one interface to another + rudeEdit = RudeEditKind.Renamed; + } + else if (!AllowsDeletion(oldSymbol)) + { + rudeEdit = RudeEditKind.Renamed; + } + else if (!CanAddNewMember(oldSymbol, capabilities, cancellationToken)) + { + rudeEdit = RudeEditKind.RenamingNotSupportedByRuntime; + } + } + else if (oldSymbol is IPropertySymbol oldProperty && newSymbol is IPropertySymbol newProperty) + { + if (!oldProperty.ExplicitInterfaceImplementations.IsEmpty || !newProperty.ExplicitInterfaceImplementations.IsEmpty) + { + // Can't change from explicit to implicit interface implementation, or one interface to another + rudeEdit = RudeEditKind.Renamed; + } + else if (!AllowsDeletion(oldSymbol)) + { + rudeEdit = RudeEditKind.Renamed; + } + else if (!CanAddNewMember(oldSymbol, capabilities, cancellationToken)) + { + rudeEdit = RudeEditKind.RenamingNotSupportedByRuntime; + } + } + else if (oldSymbol is IEventSymbol oldEvent && newSymbol is IEventSymbol newEvent) + { + if (!oldEvent.ExplicitInterfaceImplementations.IsEmpty || !newEvent.ExplicitInterfaceImplementations.IsEmpty) + { + // Can't change from explicit to implicit interface implementation, or one interface to another + rudeEdit = RudeEditKind.Renamed; + } + else if (!AllowsDeletion(oldSymbol)) + { + rudeEdit = RudeEditKind.Renamed; + } + else if (!CanAddNewMember(oldSymbol, capabilities, cancellationToken)) + { + rudeEdit = RudeEditKind.RenamingNotSupportedByRuntime; + } + } + else + { + rudeEdit = RudeEditKind.Renamed; } } @@ -3526,7 +3799,19 @@ private void ReportUpdatedSymbolDeclarationRudeEdits( } else { - AnalyzeParameterType(oldParameter, newParameter, ref rudeEdit, ref hasGeneratedAttributeChange); + AnalyzeParameterType(oldParameter, newParameter, capabilities, ref rudeEdit, ref hasGeneratedAttributeChange, ref hasParameterTypeChange, cancellationToken); + + if (!hasParameterTypeChange && oldParameter.Name != newParameter.Name) + { + if (capabilities.Grant(EditAndContinueCapabilities.UpdateParameters)) + { + hasParameterRename = true; + } + else + { + rudeEdit = RudeEditKind.RenamingNotSupportedByRuntime; + } + } } } else if (oldSymbol is ITypeParameterSymbol oldTypeParameter && newSymbol is ITypeParameterSymbol newTypeParameter) @@ -3546,8 +3831,6 @@ private void ReportUpdatedSymbolDeclarationRudeEdits( if (rudeEdit != RudeEditKind.None) { - // so we'll just use the last global statement in the file - ReportUpdateRudeEdit(diagnostics, rudeEdit, oldSymbol, newSymbol, newNode, newCompilation, cancellationToken); } } @@ -3596,7 +3879,14 @@ private static void AnalyzeBaseTypes(INamedTypeSymbol oldType, INamedTypeSymbol } } - private static void AnalyzeParameterType(IParameterSymbol oldParameter, IParameterSymbol newParameter, ref RudeEditKind rudeEdit, ref bool hasGeneratedAttributeChange) + private void AnalyzeParameterType( + IParameterSymbol oldParameter, + IParameterSymbol newParameter, + EditAndContinueCapabilitiesGrantor capabilities, + ref RudeEditKind rudeEdit, + ref bool hasGeneratedAttributeChange, + ref bool hasParameterTypeChange, + CancellationToken cancellationToken) { if (!ParameterTypesEquivalent(oldParameter, newParameter, exact: true)) { @@ -3604,6 +3894,22 @@ private static void AnalyzeParameterType(IParameterSymbol oldParameter, IParamet { hasGeneratedAttributeChange = true; } + else if (newParameter.ContainingType.IsDelegateType() || newParameter.ContainingSymbol is not IMethodSymbol) + { + // We don't allow changing parameter types in delegates, or in properties or indexers + rudeEdit = RudeEditKind.TypeUpdate; + } + else if (AllowsDeletion(newParameter.ContainingSymbol)) + { + if (CanAddNewMember(newParameter.ContainingSymbol, capabilities, cancellationToken)) + { + hasParameterTypeChange = true; + } + else + { + rudeEdit = RudeEditKind.ChangingTypeNotSupportedByRuntime; + } + } else { rudeEdit = RudeEditKind.TypeUpdate; @@ -3695,14 +4001,14 @@ private void AnalyzeSymbolUpdate( ReportCustomAttributeRudeEdits(diagnostics, oldSymbol, newSymbol, newNode, newCompilation, capabilities, out var hasAttributeChange, out var hasReturnTypeAttributeChange, cancellationToken); - ReportUpdatedSymbolDeclarationRudeEdits(diagnostics, oldSymbol, newSymbol, newNode, newCompilation, capabilities, out var hasGeneratedAttributeChange, out var hasGeneratedReturnTypeAttributeChange, out var hasParameterRename, cancellationToken); + ReportUpdatedSymbolDeclarationRudeEdits(diagnostics, oldSymbol, newSymbol, newNode, newCompilation, capabilities, out var hasGeneratedAttributeChange, out var hasGeneratedReturnTypeAttributeChange, out var hasParameterRename, out var hasParameterTypeChange, cancellationToken); hasAttributeChange |= hasGeneratedAttributeChange; hasReturnTypeAttributeChange |= hasGeneratedReturnTypeAttributeChange; - if (hasParameterRename) + if (hasParameterRename || hasParameterTypeChange) { Debug.Assert(newSymbol is IParameterSymbol); - AddParameterUpdateSemanticEdit(semanticEdits, (IParameterSymbol)newSymbol, syntaxMap, cancellationToken); + AddParameterUpdateSemanticEdit(semanticEdits, (IParameterSymbol)oldSymbol, (IParameterSymbol)newSymbol, syntaxMap, reportDeleteAndInsertEdits: hasParameterTypeChange, cancellationToken); } else if (hasAttributeChange || hasReturnTypeAttributeChange) { @@ -3760,18 +4066,30 @@ private static void AddCustomAttributeSemanticEdits( } else if (newSymbol is IParameterSymbol newParameterSymbol) { - AddParameterUpdateSemanticEdit(semanticEdits, newParameterSymbol, syntaxMap, cancellationToken); + AddParameterUpdateSemanticEdit(semanticEdits, (IParameterSymbol)oldSymbol, newParameterSymbol, syntaxMap, reportDeleteAndInsertEdits: false, cancellationToken); } } - private static void AddParameterUpdateSemanticEdit(ArrayBuilder semanticEdits, IParameterSymbol newParameterSymbol, Func? syntaxMap, CancellationToken cancellationToken) + private static void AddParameterUpdateSemanticEdit(ArrayBuilder semanticEdits, IParameterSymbol oldParameterSymbol, IParameterSymbol newParameterSymbol, Func? syntaxMap, bool reportDeleteAndInsertEdits, CancellationToken cancellationToken) { var newContainingSymbol = newParameterSymbol.ContainingSymbol; - semanticEdits.Add(new SemanticEditInfo(SemanticEditKind.Update, SymbolKey.Create(newContainingSymbol, cancellationToken), syntaxMap, syntaxMapTree: null, partialType: null)); + + if (reportDeleteAndInsertEdits) + { + var oldContainingSymbol = oldParameterSymbol.ContainingSymbol; + var containingSymbolKey = SymbolKey.Create(oldContainingSymbol.ContainingSymbol, cancellationToken); + AddMemberOrAssociatedMemberSemanticEdits(semanticEdits, SemanticEditKind.Delete, oldContainingSymbol, containingSymbolKey, syntaxMap, partialType: null, cancellationToken); + AddMemberOrAssociatedMemberSemanticEdits(semanticEdits, SemanticEditKind.Insert, newContainingSymbol, containingSymbolKey: null, syntaxMap, partialType: null, cancellationToken); + } + else + { + semanticEdits.Add(new SemanticEditInfo(SemanticEditKind.Update, SymbolKey.Create(newContainingSymbol, cancellationToken), syntaxMap, syntaxMapTree: null, partialType: null)); + } // attributes applied on parameters of a delegate are applied to both Invoke and BeginInvoke methods if (newContainingSymbol.ContainingSymbol is INamedTypeSymbol { TypeKind: TypeKind.Delegate } newContainingDelegateType) { + Debug.Assert(reportDeleteAndInsertEdits == false); AddDelegateBeginInvokeEdit(semanticEdits, newContainingDelegateType, syntaxMap, cancellationToken); } } @@ -3976,23 +4294,21 @@ static bool IsSecurityAttribute(INamedTypeSymbol namedTypeSymbol) } } - private static bool CanAddNewMember(ISymbol newSymbol, EditAndContinueCapabilitiesGrantor capabilities) + private bool CanAddNewMember(ISymbol newSymbol, EditAndContinueCapabilitiesGrantor capabilities, CancellationToken cancellationToken) { - if (newSymbol is IMethodSymbol or IPropertySymbol) // Properties are just get_ and set_ methods + var requiredCapabilities = EditAndContinueCapabilities.None; + + if (newSymbol is IMethodSymbol or IEventSymbol or IPropertySymbol) { - return capabilities.Grant(EditAndContinueCapabilities.AddMethodToExistingType); + requiredCapabilities |= EditAndContinueCapabilities.AddMethodToExistingType; } - else if (newSymbol is IFieldSymbol field) - { - if (field.IsStatic) - { - return capabilities.Grant(EditAndContinueCapabilities.AddStaticFieldToExistingType); - } - return capabilities.Grant(EditAndContinueCapabilities.AddInstanceFieldToExistingType); + if (newSymbol is IFieldSymbol || newSymbol is IPropertySymbol { DeclaringSyntaxReferences: [var syntaxRef] } && HasBackingField(syntaxRef.GetSyntax(cancellationToken))) + { + requiredCapabilities |= newSymbol.IsStatic ? EditAndContinueCapabilities.AddStaticFieldToExistingType : EditAndContinueCapabilities.AddInstanceFieldToExistingType; } - return true; + return capabilities.Grant(requiredCapabilities); } private static void AddEditsForSynthesizedRecordMembers(Compilation compilation, INamedTypeSymbol recordType, ArrayBuilder semanticEdits, CancellationToken cancellationToken) @@ -4534,11 +4850,8 @@ private void AddConstructorEdits( private bool HasMemberInitializerContainingLambda(INamedTypeSymbol type, bool isStatic, ref bool? lazyHasMemberInitializerContainingLambda, CancellationToken cancellationToken) { - if (lazyHasMemberInitializerContainingLambda == null) - { - // checking the old type for existing lambdas (it's ok for the new initializers to contain lambdas) - lazyHasMemberInitializerContainingLambda = HasMemberInitializerContainingLambda(type, isStatic, cancellationToken); - } + // checking the old type for existing lambdas (it's ok for the new initializers to contain lambdas) + lazyHasMemberInitializerContainingLambda ??= HasMemberInitializerContainingLambda(type, isStatic, cancellationToken); return lazyHasMemberInitializerContainingLambda.Value; } diff --git a/src/Features/Core/Portable/EditAndContinue/ActiveStatementsMap.cs b/src/Features/Core/Portable/EditAndContinue/ActiveStatementsMap.cs index 81951a44c0655..b5f103b170012 100644 --- a/src/Features/Core/Portable/EditAndContinue/ActiveStatementsMap.cs +++ b/src/Features/Core/Portable/EditAndContinue/ActiveStatementsMap.cs @@ -188,6 +188,7 @@ void AddStatement(LinePositionSpan unmappedLineSpan, ActiveStatement activeState // Also guard against active statements unmapped to multiple locations in the unmapped file // (when multiple #line map to the same span that overlaps with the active statement). if (TryGetTextSpan(oldText.Lines, unmappedLineSpan, out var unmappedSpan) && + oldRoot.FullSpan.Contains(unmappedSpan.Start) && mappedStatements.Add(activeStatement)) { var exceptionRegions = analyzer.GetExceptionRegions(oldRoot, unmappedSpan, activeStatement.IsNonLeaf, cancellationToken); diff --git a/src/Features/Core/Portable/EditAndContinue/CommittedSolution.cs b/src/Features/Core/Portable/EditAndContinue/CommittedSolution.cs index 9cb9eb22dba6f..2e461af6354d0 100644 --- a/src/Features/Core/Portable/EditAndContinue/CommittedSolution.cs +++ b/src/Features/Core/Portable/EditAndContinue/CommittedSolution.cs @@ -335,7 +335,7 @@ internal static async Task>> var (project, documentStates) = projectDocumentStates; // Skip projects that do not support Roslyn EnC (e.g. F#, etc). - // Source files of these do not even need to be captured in the solution snapshot. + // Source files of these may not even be captured in the solution snapshot. if (!project.SupportsEditAndContinue()) { return Array.Empty(); diff --git a/src/Features/Core/Portable/EditAndContinue/Contracts/EditAndContinue/ManagedModuleUpdate.cs b/src/Features/Core/Portable/EditAndContinue/Contracts/EditAndContinue/ManagedModuleUpdate.cs deleted file mode 100644 index 3d67ff9c1003a..0000000000000 --- a/src/Features/Core/Portable/EditAndContinue/Contracts/EditAndContinue/ManagedModuleUpdate.cs +++ /dev/null @@ -1,155 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using System.Runtime.Serialization; -using System; -using System.Collections.Immutable; - -namespace Microsoft.CodeAnalysis.EditAndContinue.Contracts -{ - /// - /// Information about a collection of managed updates under a target module. - /// - [DataContract] - internal readonly struct ManagedModuleUpdates - { - /// - /// Creates a new ManagedModuleUpdates. - /// - /// Update status. - /// Collection of the module updates. - public ManagedModuleUpdates( - ManagedModuleUpdateStatus status, - ImmutableArray updates) - { - Status = status; - Updates = updates; - } - - /// - /// This is the kind of change made to the modules owned by the provider. - /// The change is aggregated across all modules owned by the provider: if one module has a rude edit - /// and another one has valid change, the resulting kind is . - /// If is empty, this has a value of . - /// - [DataMember(Name = "status")] - public ManagedModuleUpdateStatus Status { get; } - - /// - /// Expected to be empty if Status != Ready. - /// - [DataMember(Name = "updates")] - public ImmutableArray Updates { get; } - } - - /// - /// Information about a single update. This corresponds to an edit made by the user. - /// - [DataContract] - internal readonly struct ManagedModuleUpdate - { - /// - /// Creates a new ManagedModuleUpdate. - /// - /// Module ID which the update belongs to. - /// IL delta from the change. - /// Metadata delta from the change. - /// PDB delta from the change. - /// Sequence points affected by the symbolic data change. - /// Methods affected by the update. - /// Active statements affected by the update. - /// Exception regions affected by the update. - /// List of updated TypeDefs. - public ManagedModuleUpdate( - Guid module, - ImmutableArray ilDelta, - ImmutableArray metadataDelta, - ImmutableArray pdbDelta, - ImmutableArray sequencePoints, - ImmutableArray updatedMethods, - ImmutableArray updatedTypes, - ImmutableArray activeStatements, - ImmutableArray exceptionRegions, - EditAndContinueCapabilities requiredCapabilities) - { - Module = module; - - ILDelta = ilDelta; - MetadataDelta = metadataDelta; - - PdbDelta = pdbDelta; - SequencePoints = sequencePoints; - - UpdatedMethods = updatedMethods; - UpdatedTypes = updatedTypes; - - ActiveStatements = activeStatements; - ExceptionRegions = exceptionRegions; - RequiredCapabilities = requiredCapabilities; - } - - /// - /// Module version Identifier which the managed update was applied. This uniquely - /// identifies the symbol file.For Microsoft C++ or Microsoft .NET Framework binaries, - /// this is a unique value which is embedded in an exe/dll by linkers/compilers when the - /// dll/exe is built. A new value is generated each time that the dll/exe is compiled. - /// - [DataMember(Name = "module")] - public Guid Module { get; } - - /// - /// Collection of IL deltas affected by the update. Required by ICorDebugModule2::ApplyChanges. - /// - [DataMember(Name = "ilDelta")] - public ImmutableArray ILDelta { get; } - - /// - /// Collection of metadata deltas affected by the update. Required by ICorDebugModule2::ApplyChanges. - /// - [DataMember(Name = "metadataDelta")] - public ImmutableArray MetadataDelta { get; } - - /// - /// Collection of PDB deltas regarding the symbol information affected by the update. - /// - [DataMember(Name = "pdbDelta")] - public ImmutableArray PdbDelta { get; } - - /// - /// Collection of sequence points affected by the update. - /// This will alter the line number for one or more existing sequence point in the symbolic data. - /// - [DataMember(Name = "sequencePoints")] - public ImmutableArray SequencePoints { get; } - - /// - /// Method token for all the methods affected by the update. - /// - [DataMember(Name = "updatedMethods")] - public ImmutableArray UpdatedMethods { get; } - - /// - /// List of TypeDefs that have been modified during an edit. - /// This is passed on to the CLR as an event on each EnC update. - /// - [DataMember(Name = "updatedTypes")] - public ImmutableArray UpdatedTypes { get; } - - /// - /// Collection of active statements affected by the update. - /// This will not list duplicate active statements in multiple threads and will report an unique one instead. - /// - [DataMember(Name = "activeStatements")] - public ImmutableArray ActiveStatements { get; } - - /// - /// Collection of exception regions affected by the update. An exception region is enclosed by a try/catch/finally block. - /// - [DataMember(Name = "exceptionRegions")] - public ImmutableArray ExceptionRegions { get; } - - [DataMember(Name = "requiredCapabilities")] - public EditAndContinueCapabilities RequiredCapabilities { get; } - } -} diff --git a/src/Features/Core/Portable/EditAndContinue/Contracts/EditAndContinue/ManagedModuleUpdateStatus.cs b/src/Features/Core/Portable/EditAndContinue/Contracts/EditAndContinue/ManagedModuleUpdateStatus.cs deleted file mode 100644 index c7adef36950b5..0000000000000 --- a/src/Features/Core/Portable/EditAndContinue/Contracts/EditAndContinue/ManagedModuleUpdateStatus.cs +++ /dev/null @@ -1,33 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -namespace Microsoft.CodeAnalysis.EditAndContinue.Contracts -{ - /// - /// Indicates the state of a manage module update. - /// - internal enum ManagedModuleUpdateStatus - { - /// - /// No change made. - /// - None = 0, - - /// - /// All changes are valid, can be applied. - /// - Ready = 1, - - /// - /// Changes require restarting the application in order to be applied. - /// - RestartRequired = 2, - - /// - /// Some changes are errors that block rebuild of the module. - /// This means that the code is in a broken state that cannot be resolved by restarting the application. - /// - Blocked = 3 - } -} diff --git a/src/Features/Core/Portable/EditAndContinue/DebuggingSession.cs b/src/Features/Core/Portable/EditAndContinue/DebuggingSession.cs index 1f80311fa17b0..465683d2d47e4 100644 --- a/src/Features/Core/Portable/EditAndContinue/DebuggingSession.cs +++ b/src/Features/Core/Portable/EditAndContinue/DebuggingSession.cs @@ -34,6 +34,7 @@ internal sealed class DebuggingSession : IDisposable /// /// MVIDs read from the assembly built for given project id. + /// Only contains ids for projects that support EnC. /// private readonly Dictionary _projectModuleIds = new(); private readonly Dictionary _moduleIds = new(); @@ -50,7 +51,7 @@ internal sealed class DebuggingSession : IDisposable /// Therefore once an initial baseline is created it needs to be kept alive till the end of the debugging session, /// even when it's replaced in by a newer baseline. /// - private readonly Dictionary _projectEmitBaselines = new(); + private readonly Dictionary _projectEmitBaselines = new(); private readonly List _initialBaselineModuleReaders = new(); private readonly object _projectEmitBaselinesGuard = new(); @@ -93,7 +94,7 @@ internal sealed class DebuggingSession : IDisposable /// Last array of module updates generated during the debugging session. /// Useful for crash dump diagnostics. /// - private ImmutableArray _lastModuleUpdatesLog; + private ImmutableArray _lastModuleUpdatesLog; internal DebuggingSession( DebuggingSessionId id, @@ -241,10 +242,12 @@ private bool AddModulePreparedForUpdate(Guid mvid) /// /// /// An MVID and an error message to report, in case an IO exception occurred while reading the binary. - /// The MVID is default if either project not built, or an it can't be read from the module binary. + /// The MVID is if either the project is not built, or the MVID can't be read from the module binary. /// internal async Task<(Guid Mvid, Diagnostic? Error)> GetProjectModuleIdAsync(Project project, CancellationToken cancellationToken) { + Debug.Assert(project.SupportsEditAndContinue()); + lock (_projectModuleIdsGuard) { if (_projectModuleIds.TryGetValue(project.Id, out var id)) @@ -281,8 +284,14 @@ private bool AddModulePreparedForUpdate(Guid mvid) return id; } - _moduleIds[newId.Mvid] = project.Id; - return _projectModuleIds[project.Id] = newId; + // Do not cache failures. The error might be intermittent and might be corrected next time we attempt to read the MVID. + if (newId.Mvid != Guid.Empty) + { + _moduleIds[newId.Mvid] = project.Id; + _projectModuleIds[project.Id] = newId; + } + + return newId; } } @@ -298,43 +307,55 @@ private bool TryGetProjectId(Guid moduleId, [NotNullWhen(true)] out ProjectId? p /// Get for given project. /// /// True unless the project outputs can't be read. - internal bool TryGetOrCreateEmitBaseline(Project project, out ImmutableArray diagnostics, [NotNullWhen(true)] out EmitBaseline? baseline, [NotNullWhen(true)] out ReaderWriterLockSlim? baselineAccessLock) + internal bool TryGetOrCreateEmitBaseline( + Project project, + out ImmutableArray diagnostics, + [NotNullWhen(true)] out EmitBaseline? baseline, + out int baselineGeneration, + [NotNullWhen(true)] out ReaderWriterLockSlim? baselineAccessLock) { baselineAccessLock = _baselineAccessLock; lock (_projectEmitBaselinesGuard) { - if (_projectEmitBaselines.TryGetValue(project.Id, out baseline)) + if (_projectEmitBaselines.TryGetValue(project.Id, out var baselineAndGeneration)) { + (baseline, baselineGeneration) = baselineAndGeneration; diagnostics = ImmutableArray.Empty; return true; } } var outputs = GetCompilationOutputs(project); - if (!TryCreateInitialBaseline(outputs, project.Id, out diagnostics, out var newBaseline, out var debugInfoReaderProvider, out var metadataReaderProvider)) + if (!TryCreateInitialBaseline(outputs, project.Id, out diagnostics, out var initialBaseline, out var debugInfoReaderProvider, out var metadataReaderProvider)) { // Unable to read the DLL/PDB at this point (it might be open by another process). // Don't cache the failure so that the user can attempt to apply changes again. + baselineGeneration = -1; + baseline = null; return false; } + const int initialBaselineGeneration = 0; + lock (_projectEmitBaselinesGuard) { - if (_projectEmitBaselines.TryGetValue(project.Id, out baseline)) + if (_projectEmitBaselines.TryGetValue(project.Id, out var baselineAndGeneration)) { metadataReaderProvider.Dispose(); debugInfoReaderProvider.Dispose(); + (baseline, baselineGeneration) = baselineAndGeneration; return true; } - _projectEmitBaselines[project.Id] = newBaseline; + _projectEmitBaselines.Add(project.Id, (initialBaseline, initialBaselineGeneration)); _initialBaselineModuleReaders.Add(metadataReaderProvider); _initialBaselineModuleReaders.Add(debugInfoReaderProvider); } - baseline = newBaseline; + baseline = initialBaseline; + baselineGeneration = initialBaselineGeneration; return true; } @@ -505,7 +526,7 @@ public async ValueTask EmitSolutionUpdateAsync( LogSolutionUpdate(solutionUpdate); - if (solutionUpdate.ModuleUpdates.Status == ManagedModuleUpdateStatus.Ready) + if (solutionUpdate.ModuleUpdates.Status == ModuleUpdateStatus.Ready) { StorePendingUpdate(solution, solutionUpdate); } @@ -517,26 +538,24 @@ public async ValueTask EmitSolutionUpdateAsync( private void LogSolutionUpdate(SolutionUpdate update) { - EditAndContinueWorkspaceService.Log.Write("Solution update status: {0}", - ((int)update.ModuleUpdates.Status, typeof(ManagedModuleUpdateStatus))); + var log = EditAndContinueWorkspaceService.Log; - if (update.ModuleUpdates.Updates.Length > 0) + log.Write("Solution update status: {0}", + ((int)update.ModuleUpdates.Status, typeof(ModuleUpdateStatus))); + + foreach (var moduleUpdate in update.ModuleUpdates.Updates) { - var firstUpdate = update.ModuleUpdates.Updates[0]; - - EditAndContinueWorkspaceService.Log.Write("Solution update deltas: #{0} [types: #{1} (0x{2}:X8), methods: #{3} (0x{4}:X8)", - update.ModuleUpdates.Updates.Length, - firstUpdate.UpdatedTypes.Length, - firstUpdate.UpdatedTypes.FirstOrDefault(), - firstUpdate.UpdatedMethods.Length, - firstUpdate.UpdatedMethods.FirstOrDefault()); + log.Write("Module update: capabilities=[{0}], types=[{1}], methods=[{2}]", + ((int)moduleUpdate.RequiredCapabilities, typeof(EditAndContinueCapabilities)), + moduleUpdate.UpdatedTypes, + moduleUpdate.UpdatedMethods); } if (update.Diagnostics.Length > 0) { var firstProjectDiagnostic = update.Diagnostics[0]; - EditAndContinueWorkspaceService.Log.Write("Solution update diagnostics: #{0} [{1}: {2}, ...]", + log.Write("Solution update diagnostics: #{0} [{1}: {2}, ...]", update.Diagnostics.Length, firstProjectDiagnostic.ProjectId, firstProjectDiagnostic.Diagnostics[0]); @@ -546,7 +565,7 @@ private void LogSolutionUpdate(SolutionUpdate update) { var firstDocumentWithRudeEdits = update.DocumentsWithRudeEdits[0]; - EditAndContinueWorkspaceService.Log.Write("Solution update documents with rude edits: #{0} [{1}: {2}, ...]", + log.Write("Solution update documents with rude edits: #{0} [{1}: {2}, ...]", update.DocumentsWithRudeEdits.Length, firstDocumentWithRudeEdits.DocumentId, firstDocumentWithRudeEdits.Diagnostics[0].Kind); @@ -577,7 +596,7 @@ from region in moduleRegions.Regions { foreach (var (projectId, baseline) in pendingUpdate.EmitBaselines) { - _projectEmitBaselines[projectId] = baseline; + _projectEmitBaselines[projectId] = (baseline, _projectEmitBaselines[projectId].Generation + 1); } } @@ -615,9 +634,9 @@ public async ValueTask>> GetB var documentId = documentIds[i]; var document = await solution.GetTextDocumentAsync(documentId, cancellationToken).ConfigureAwait(false); - if (document?.FilePath == null) + if (document?.State.SupportsEditAndContinue() != true) { - // document has been deleted or has no path (can't have an active statement anymore): + // document has been deleted or doesn't support EnC (can't have an active statement anymore): continue; } @@ -627,6 +646,8 @@ public async ValueTask>> GetB continue; } + Contract.ThrowIfNull(document.FilePath); + // Multiple documents may have the same path (linked file). // The documents represent the files that #line directives map to. // Documents that have the same path must have different project id. @@ -648,7 +669,11 @@ public async ValueTask>> GetB } var newProject = solution.GetRequiredProject(projectId); - var analyzer = newProject.LanguageServices.GetRequiredService(); + + Debug.Assert(oldProject.SupportsEditAndContinue()); + Debug.Assert(newProject.SupportsEditAndContinue()); + + var analyzer = newProject.Services.GetRequiredService(); await foreach (var documentId in EditSession.GetChangedDocumentsAsync(oldProject, newProject, cancellationToken).ConfigureAwait(false)) { @@ -743,7 +768,7 @@ public async ValueTask> GetAdjustedActiveSta { try { - if (_isDisposed || !EditSession.InBreakState || !mappedDocument.State.SupportsEditAndContinue()) + if (_isDisposed || !EditSession.InBreakState || !mappedDocument.State.SupportsEditAndContinue() || !mappedDocument.Project.SupportsEditAndContinue()) { return ImmutableArray.Empty; } @@ -773,7 +798,7 @@ public async ValueTask> GetAdjustedActiveSta return ImmutableArray.Empty; } - var analyzer = newProject.LanguageServices.GetRequiredService(); + var analyzer = newProject.Services.GetRequiredService(); using var _ = ArrayBuilder.GetInstance(out var adjustedMappedSpans); @@ -925,7 +950,7 @@ public async ValueTask> GetAdjustedActiveSta return null; } - var analyzer = newDocument.Project.LanguageServices.GetRequiredService(); + var analyzer = newDocument.Project.Services.GetRequiredService(); var oldDocumentActiveStatements = await baseActiveStatements.GetOldActiveStatementsAsync(analyzer, oldDocument, cancellationToken).ConfigureAwait(false); return oldDocumentActiveStatements.GetStatement(baseActiveStatement.Ordinal).ExceptionRegions.IsActiveStatementCovered; } @@ -963,6 +988,10 @@ public async ValueTask> GetAdjustedActiveSta return null; } + // We only maintain module ids for projects that support EnC: + Debug.Assert(oldProject.SupportsEditAndContinue()); + Debug.Assert(newProject.SupportsEditAndContinue()); + documentId = await GetChangedDocumentContainingUnmappedActiveStatementAsync(activeStatementsMap, LastCommittedSolution, oldProject, newProject, baseActiveStatement, cancellationToken).ConfigureAwait(false); } else @@ -980,8 +1009,10 @@ async Task GetTaskAsync(ProjectId projectId) // TODO: https://github.com/dotnet/roslyn/issues/1204 // oldProject == null ==> project has been added - it may have active statements if the project was unloaded when debugging session started but the sources // correspond to the PDB. - var id = (oldProject != null) ? await GetChangedDocumentContainingUnmappedActiveStatementAsync( - activeStatementsMap, LastCommittedSolution, oldProject, newProject, baseActiveStatement, linkedTokenSource.Token).ConfigureAwait(false) : null; + var id = (oldProject?.SupportsEditAndContinue() == true) ? + await GetChangedDocumentContainingUnmappedActiveStatementAsync( + activeStatementsMap, LastCommittedSolution, oldProject, newProject, baseActiveStatement, linkedTokenSource.Token).ConfigureAwait(false) : + null; Interlocked.CompareExchange(ref documentId, id, null); if (id != null) @@ -1015,7 +1046,10 @@ async Task GetTaskAsync(ProjectId projectId) private static async ValueTask GetChangedDocumentContainingUnmappedActiveStatementAsync(ActiveStatementsMap baseActiveStatements, CommittedSolution oldSolution, Project oldProject, Project newProject, ActiveStatement activeStatement, CancellationToken cancellationToken) { Debug.Assert(oldProject.Id == newProject.Id); - var analyzer = newProject.LanguageServices.GetRequiredService(); + Debug.Assert(oldProject.SupportsEditAndContinue()); + Debug.Assert(newProject.SupportsEditAndContinue()); + + var analyzer = newProject.Services.GetRequiredService(); await foreach (var documentId in EditSession.GetChangedDocumentsAsync(oldProject, newProject, cancellationToken).ConfigureAwait(false)) { @@ -1042,7 +1076,7 @@ async Task GetTaskAsync(ProjectId projectId) private static void ReportTelemetry(DebuggingSessionTelemetry.Data data) { // report telemetry (fire and forget): - _ = Task.Run(() => DebuggingSessionTelemetry.Log(data, Logger.Log, LogAggregator.GetNextId)); + _ = Task.Run(() => DebuggingSessionTelemetry.Log(data, Logger.Log, CorrelationIdFactory.GetNextId)); } internal TestAccessor GetTestAccessor() @@ -1067,7 +1101,7 @@ public EmitBaseline GetProjectEmitBaseline(ProjectId id) { lock (_instance._projectEmitBaselinesGuard) { - return _instance._projectEmitBaselines[id]; + return _instance._projectEmitBaselines[id].Baseline; } } diff --git a/src/Features/Core/Portable/EditAndContinue/DebuggingSessionId.cs b/src/Features/Core/Portable/EditAndContinue/DebuggingSessionId.cs index a9d622a0147dc..41e0946b46176 100644 --- a/src/Features/Core/Portable/EditAndContinue/DebuggingSessionId.cs +++ b/src/Features/Core/Portable/EditAndContinue/DebuggingSessionId.cs @@ -6,33 +6,11 @@ using System.Runtime.Serialization; using System.Threading; -namespace Microsoft.CodeAnalysis.EditAndContinue -{ - [DataContract] - internal readonly struct DebuggingSessionId : IEquatable - { - [DataMember(Order = 0)] - private readonly int _id; - - public DebuggingSessionId(int id) - => _id = id; - - public override bool Equals(object? obj) - => obj is DebuggingSessionId id && Equals(id); - - public bool Equals(DebuggingSessionId other) - => _id == other._id; +namespace Microsoft.CodeAnalysis.EditAndContinue; - public override int GetHashCode() - => _id; - - public static bool operator ==(DebuggingSessionId left, DebuggingSessionId right) - => left.Equals(right); - - public static bool operator !=(DebuggingSessionId left, DebuggingSessionId right) - => !(left == right); - - public override string ToString() - => _id.ToString(); - } +[DataContract] +internal readonly record struct DebuggingSessionId([property: DataMember] int Ordinal) +{ + public override string ToString() + => Ordinal.ToString(); } diff --git a/src/Features/Core/Portable/EditAndContinue/DocumentAnalysisResults.cs b/src/Features/Core/Portable/EditAndContinue/DocumentAnalysisResults.cs index a0e8aefa458e5..fc5154393700c 100644 --- a/src/Features/Core/Portable/EditAndContinue/DocumentAnalysisResults.cs +++ b/src/Features/Core/Portable/EditAndContinue/DocumentAnalysisResults.cs @@ -13,13 +13,18 @@ namespace Microsoft.CodeAnalysis.EditAndContinue { internal sealed class DocumentAnalysisResults { - internal static readonly TraceLog Log = new(256, "EnC"); + internal static readonly TraceLog Log = new(256, "EnC", logDirectory: null); /// /// The state of the document the results are calculated for. /// public DocumentId DocumentId { get; } + /// + /// Document file path for logging. + /// + public string FilePath; + /// /// Spans of active statements in the document, or null if the document has syntax errors or has not changed. /// Calculated even in presence of rude edits so that the active statements can be rendered in the editor. @@ -93,6 +98,7 @@ internal sealed class DocumentAnalysisResults public DocumentAnalysisResults( DocumentId documentId, + string filePath, ImmutableArray activeStatementsOpt, ImmutableArray rudeEdits, Diagnostic? syntaxError, @@ -145,6 +151,7 @@ public DocumentAnalysisResults( } DocumentId = documentId; + FilePath = filePath; RudeEditErrors = rudeEdits; SyntaxError = syntaxError; SemanticEdits = semanticEditsOpt; @@ -168,9 +175,10 @@ public bool HasSignificantValidChanges /// /// Report errors blocking the document analysis. /// - public static DocumentAnalysisResults SyntaxErrors(DocumentId documentId, ImmutableArray rudeEdits, Diagnostic? syntaxError, bool hasChanges) + public static DocumentAnalysisResults SyntaxErrors(DocumentId documentId, string filePath, ImmutableArray rudeEdits, Diagnostic? syntaxError, bool hasChanges) => new( documentId, + filePath, activeStatementsOpt: default, rudeEdits, syntaxError, @@ -184,9 +192,10 @@ public static DocumentAnalysisResults SyntaxErrors(DocumentId documentId, Immuta /// /// Report unchanged document results. /// - public static DocumentAnalysisResults Unchanged(DocumentId documentId) + public static DocumentAnalysisResults Unchanged(DocumentId documentId, string filePath) => new( documentId, + filePath, activeStatementsOpt: default, rudeEdits: ImmutableArray.Empty, syntaxError: null, diff --git a/src/Features/Core/Portable/EditAndContinue/EditAndContinueCapabilities.cs b/src/Features/Core/Portable/EditAndContinue/EditAndContinueCapabilities.cs index bb6754826ddef..68ec1f0334f94 100644 --- a/src/Features/Core/Portable/EditAndContinue/EditAndContinueCapabilities.cs +++ b/src/Features/Core/Portable/EditAndContinue/EditAndContinueCapabilities.cs @@ -4,6 +4,7 @@ using System; using System.Collections.Immutable; +using Microsoft.CodeAnalysis.PooledObjects; namespace Microsoft.CodeAnalysis.EditAndContinue { @@ -61,13 +62,13 @@ public static EditAndContinueCapabilities Parse(ImmutableArray capabilit { caps |= capability switch { - "Baseline" => EditAndContinueCapabilities.Baseline, - "AddMethodToExistingType" => EditAndContinueCapabilities.AddMethodToExistingType, - "AddStaticFieldToExistingType" => EditAndContinueCapabilities.AddStaticFieldToExistingType, - "AddInstanceFieldToExistingType" => EditAndContinueCapabilities.AddInstanceFieldToExistingType, - "NewTypeDefinition" => EditAndContinueCapabilities.NewTypeDefinition, - "ChangeCustomAttributes" => EditAndContinueCapabilities.ChangeCustomAttributes, - "UpdateParameters" => EditAndContinueCapabilities.UpdateParameters, + nameof(EditAndContinueCapabilities.Baseline) => EditAndContinueCapabilities.Baseline, + nameof(EditAndContinueCapabilities.AddMethodToExistingType) => EditAndContinueCapabilities.AddMethodToExistingType, + nameof(EditAndContinueCapabilities.AddStaticFieldToExistingType) => EditAndContinueCapabilities.AddStaticFieldToExistingType, + nameof(EditAndContinueCapabilities.AddInstanceFieldToExistingType) => EditAndContinueCapabilities.AddInstanceFieldToExistingType, + nameof(EditAndContinueCapabilities.NewTypeDefinition) => EditAndContinueCapabilities.NewTypeDefinition, + nameof(EditAndContinueCapabilities.ChangeCustomAttributes) => EditAndContinueCapabilities.ChangeCustomAttributes, + nameof(EditAndContinueCapabilities.UpdateParameters) => EditAndContinueCapabilities.UpdateParameters, // To make it eaiser for runtimes to specify more broad capabilities "AddDefinitionToExistingType" => EditAndContinueCapabilities.AddMethodToExistingType | EditAndContinueCapabilities.AddStaticFieldToExistingType | EditAndContinueCapabilities.AddInstanceFieldToExistingType, @@ -78,5 +79,33 @@ public static EditAndContinueCapabilities Parse(ImmutableArray capabilit return caps; } + + public static ImmutableArray ToStringArray(this EditAndContinueCapabilities capabilities) + { + using var _ = ArrayBuilder.GetInstance(out var builder); + + if (capabilities.HasFlag(EditAndContinueCapabilities.Baseline)) + builder.Add(nameof(EditAndContinueCapabilities.Baseline)); + + if (capabilities.HasFlag(EditAndContinueCapabilities.AddMethodToExistingType)) + builder.Add(nameof(EditAndContinueCapabilities.AddMethodToExistingType)); + + if (capabilities.HasFlag(EditAndContinueCapabilities.AddStaticFieldToExistingType)) + builder.Add(nameof(EditAndContinueCapabilities.AddStaticFieldToExistingType)); + + if (capabilities.HasFlag(EditAndContinueCapabilities.AddInstanceFieldToExistingType)) + builder.Add(nameof(EditAndContinueCapabilities.AddInstanceFieldToExistingType)); + + if (capabilities.HasFlag(EditAndContinueCapabilities.NewTypeDefinition)) + builder.Add(nameof(EditAndContinueCapabilities.NewTypeDefinition)); + + if (capabilities.HasFlag(EditAndContinueCapabilities.ChangeCustomAttributes)) + builder.Add(nameof(EditAndContinueCapabilities.ChangeCustomAttributes)); + + if (capabilities.HasFlag(EditAndContinueCapabilities.UpdateParameters)) + builder.Add(nameof(EditAndContinueCapabilities.UpdateParameters)); + + return builder.ToImmutable(); + } } } diff --git a/src/Features/Core/Portable/EditAndContinue/EditAndContinueDiagnosticDescriptors.cs b/src/Features/Core/Portable/EditAndContinue/EditAndContinueDiagnosticDescriptors.cs index 20aff5aba372d..581f1a07d5bd0 100644 --- a/src/Features/Core/Portable/EditAndContinue/EditAndContinueDiagnosticDescriptors.cs +++ b/src/Features/Core/Portable/EditAndContinue/EditAndContinueDiagnosticDescriptors.cs @@ -154,6 +154,8 @@ void AddGeneralDiagnostic(EditAndContinueErrorCode code, string resourceName, Di AddRudeEdit(RudeEditKind.RenamingNotSupportedByRuntime, nameof(FeaturesResources.Renaming_0_requires_restarting_the_application_because_it_is_not_supported_by_the_runtime)); AddRudeEdit(RudeEditKind.ChangingNonCustomAttribute, nameof(FeaturesResources.Changing_pseudo_custom_attribute_0_of_1_requires_restarting_th_application)); AddRudeEdit(RudeEditKind.ChangingNamespace, nameof(FeaturesResources.Changing_the_containing_namespace_of_0_from_1_to_2_requires_restarting_th_application)); + AddRudeEdit(RudeEditKind.ChangingTypeNotSupportedByRuntime, nameof(FeaturesResources.Changing_the_type_of_0_requires_restarting_the_application)); + AddRudeEdit(RudeEditKind.DeleteNotSupportedByRuntime, nameof(FeaturesResources.Deleting_0_requires_restarting_the_application_because_is_not_supported_by_the_runtime)); // VB specific AddRudeEdit(RudeEditKind.HandlesClauseUpdate, nameof(FeaturesResources.Updating_the_Handles_clause_of_0_requires_restarting_the_application)); diff --git a/src/Features/Core/Portable/EditAndContinue/EditAndContinueDiagnosticUpdateSource.cs b/src/Features/Core/Portable/EditAndContinue/EditAndContinueDiagnosticUpdateSource.cs index ce6b9d38d57ec..f99e64a5b3760 100644 --- a/src/Features/Core/Portable/EditAndContinue/EditAndContinueDiagnosticUpdateSource.cs +++ b/src/Features/Core/Portable/EditAndContinue/EditAndContinueDiagnosticUpdateSource.cs @@ -57,11 +57,15 @@ public ValueTask> GetDiagnosticsAsync(Workspace w /// Clears all diagnostics reported thru this source. /// We do not track the particular reported diagnostics here since we can just clear all of them at once. /// - public void ClearDiagnostics() + public void ClearDiagnostics(bool isSessionEnding = false) { // If ClearDiagnostics is called and there weren't any diagnostics previously, then there is no point incrementing // our version number and potentially invalidating caches unnecessarily. - if (_previouslyHadDiagnostics) + // If the debug session is ending, however, we want to always increment otherwise we can get stuck. eg if the user + // makes a rude edit during a debug session, but doesn't apply the changes, the rude edit will be raised without + // this class knowing about it, and then if the debug session is stopped, we have no knowledge of any diagnostics here + // so don't bump our version number, but the document checksum also doesn't change, so we get stuck with the rude edit. + if (isSessionEnding || _previouslyHadDiagnostics) { _previouslyHadDiagnostics = false; _diagnosticsVersion++; diff --git a/src/Features/Core/Portable/EditAndContinue/EditAndContinueDocumentAnalysesCache.cs b/src/Features/Core/Portable/EditAndContinue/EditAndContinueDocumentAnalysesCache.cs index df6334f4ba757..48a498eac5783 100644 --- a/src/Features/Core/Portable/EditAndContinue/EditAndContinueDocumentAnalysesCache.cs +++ b/src/Features/Core/Portable/EditAndContinue/EditAndContinueDocumentAnalysesCache.cs @@ -135,7 +135,7 @@ private async Task> GetLatestUnmappedActiveStat using var _2 = ArrayBuilder.GetInstance(out var activeStatementSpansBuilder); var baseActiveStatements = await _baseActiveStatements.GetValueAsync(cancellationToken).ConfigureAwait(false); - var analyzer = newDocument.Project.LanguageServices.GetRequiredService(); + var analyzer = newDocument.Project.Services.GetRequiredService(); var oldActiveStatements = await baseActiveStatements.GetOldActiveStatementsAsync(analyzer, oldDocument, cancellationToken).ConfigureAwait(false); foreach (var oldActiveStatement in oldActiveStatements) @@ -193,7 +193,7 @@ private AsyncLazy GetDocumentAnalysisNoLock(Project bas { try { - var analyzer = document.Project.LanguageServices.GetRequiredService(); + var analyzer = document.Project.Services.GetRequiredService(); return await analyzer.AnalyzeDocumentAsync(baseProject, _baseActiveStatements, document, activeStatementSpans, _capabilities, cancellationToken).ConfigureAwait(false); } catch (Exception e) when (FatalError.ReportAndPropagateUnlessCanceled(e, cancellationToken)) diff --git a/src/Features/Core/Portable/EditAndContinue/EditAndContinueWorkspaceService.cs b/src/Features/Core/Portable/EditAndContinue/EditAndContinueWorkspaceService.cs index 385abcc994855..391992017bbad 100644 --- a/src/Features/Core/Portable/EditAndContinue/EditAndContinueWorkspaceService.cs +++ b/src/Features/Core/Portable/EditAndContinue/EditAndContinueWorkspaceService.cs @@ -6,6 +6,7 @@ using System.Collections.Generic; using System.Collections.Immutable; using System.Composition; +using System.IO; using System.Linq; using System.Threading; using System.Threading.Tasks; @@ -24,7 +25,7 @@ namespace Microsoft.CodeAnalysis.EditAndContinue [ExportWorkspaceService(typeof(IEditAndContinueWorkspaceService)), Shared] internal sealed class EditAndContinueWorkspaceService : IEditAndContinueWorkspaceService { - internal static readonly TraceLog Log = new(2048, "EnC"); + internal static readonly TraceLog Log = new(2048, "EnC", GetLogDirectory()); private Func _compilationOutputsProvider; @@ -41,6 +42,25 @@ public EditAndContinueWorkspaceService() _compilationOutputsProvider = GetCompilationOutputs; } + private static string? GetLogDirectory() + { + try + { + var path = Environment.GetEnvironmentVariable("Microsoft_CodeAnalysis_EditAndContinue_LogDir"); + if (string.IsNullOrWhiteSpace(path)) + { + return null; + } + + Directory.CreateDirectory(path); + return path; + } + catch + { + return null; + } + } + private static CompilationOutputs GetCompilationOutputs(Project project) { // The Project System doesn't always indicate whether we emit PDB, what kind of PDB we emit nor the path of the PDB. @@ -116,6 +136,7 @@ public async ValueTask StartDebuggingSessionAsync( _debuggingSessions.Add(session); } + Log.Write("Session #{0} started.", sessionId.Ordinal); return sessionId; } @@ -137,6 +158,8 @@ public void EndDebuggingSession(DebuggingSessionId sessionId, out ImmutableArray Contract.ThrowIfNull(debuggingSession, "Debugging session has not started."); debuggingSession.EndSession(out documentsToReanalyze, out var telemetryData); + + Log.Write("Session #{0} ended.", debuggingSession.Id.Ordinal); } public void BreakStateOrCapabilitiesChanged(DebuggingSessionId sessionId, bool? inBreakState, out ImmutableArray documentsToReanalyze) diff --git a/src/Features/Core/Portable/EditAndContinue/EditSession.cs b/src/Features/Core/Portable/EditAndContinue/EditSession.cs index 8da1f41df8a94..f987d837a6202 100644 --- a/src/Features/Core/Portable/EditAndContinue/EditSession.cs +++ b/src/Features/Core/Portable/EditAndContinue/EditSession.cs @@ -6,6 +6,7 @@ using System.Collections.Generic; using System.Collections.Immutable; using System.Diagnostics; +using System.IO; using System.Linq; using System.Reflection.Metadata; using System.Reflection.Metadata.Ecma335; @@ -76,7 +77,7 @@ internal sealed class EditSession internal readonly AsyncLazy BaseActiveStatements; /// - /// Cache of document EnC analyses. + /// Cache of document EnC analyses. /// internal readonly EditAndContinueDocumentAnalysesCache Analyses; @@ -87,8 +88,8 @@ internal sealed class EditSession internal readonly bool InBreakState; /// - /// A is added whenever EnC analyzer reports - /// rude edits or module diagnostics. At the end of the session we ask the diagnostic analyzer to reanalyze + /// A is added whenever EnC analyzer reports + /// rude edits or module diagnostics. At the end of the session we ask the diagnostic analyzer to reanalyze /// the documents to clean up the diagnostics. /// private readonly HashSet _documentsWithReportedDiagnostics = new(); @@ -557,7 +558,7 @@ internal void TrackDocumentWithReportedDiagnostics(DocumentId documentId) } } - private static ProjectAnalysisSummary GetProjectAnalysisSymmary(ImmutableArray documentAnalyses) + private static ProjectAnalysisSummary GetProjectAnalysisSummary(ImmutableArray documentAnalyses) { var hasChanges = false; var hasSignificantValidChanges = false; @@ -615,7 +616,7 @@ internal static async ValueTask GetProjectChangesAsync( using var _2 = ArrayBuilder.GetInstance(out var allLineEdits); using var _3 = ArrayBuilder.GetInstance(out var activeStatementsInChangedDocuments); - var analyzer = newProject.LanguageServices.GetRequiredService(); + var analyzer = newProject.Services.GetRequiredService(); var requiredCapabilities = EditAndContinueCapabilities.None; foreach (var analysis in changedDocumentAnalyses) @@ -795,7 +796,11 @@ public async ValueTask EmitSolutionUpdateAsync(Solution solution { try { - using var _1 = ArrayBuilder.GetInstance(out var deltas); + var log = EditAndContinueWorkspaceService.Log; + + log.Write("EmitSolutionUpdate: '{0}'", solution.FilePath); + + using var _1 = ArrayBuilder.GetInstance(out var deltas); using var _2 = ArrayBuilder<(Guid ModuleId, ImmutableArray<(ManagedModuleMethodId Method, NonRemappableRegion Region)>)>.GetInstance(out var nonRemappableRegions); using var _3 = ArrayBuilder<(ProjectId, EmitBaseline)>.GetInstance(out var emitBaselines); using var _4 = ArrayBuilder<(ProjectId, ImmutableArray)>.GetInstance(out var diagnostics); @@ -812,7 +817,7 @@ public async ValueTask EmitSolutionUpdateAsync(Solution solution var oldProject = oldSolution.GetProject(newProject.Id); if (oldProject == null) { - EditAndContinueWorkspaceService.Log.Write("EnC state of '{0}' [0x{1:X8}] queried: project not loaded", newProject.Id.DebugName, newProject.Id); + log.Write("EnC state of '{0}' queried: project not loaded", newProject.FilePath); // TODO (https://github.com/dotnet/roslyn/issues/1204): // @@ -834,6 +839,8 @@ public async ValueTask EmitSolutionUpdateAsync(Solution solution continue; } + log.Write("Found {0} potentially changed document(s) in project '{1}'", changedOrAddedDocuments.Count, newProject.FilePath); + var (mvid, mvidReadError) = await DebuggingSession.GetProjectModuleIdAsync(newProject, cancellationToken).ConfigureAwait(false); if (mvidReadError != null) { @@ -849,14 +856,14 @@ public async ValueTask EmitSolutionUpdateAsync(Solution solution if (mvid == Guid.Empty) { - EditAndContinueWorkspaceService.Log.Write("Emitting update of '{0}' [0x{1:X8}]: project not built", newProject.Id.DebugName, newProject.Id); + log.Write("Emitting update of '{0}': project not built", newProject.FilePath); continue; } // Ensure that all changed documents are in-sync. Once a document is in-sync it can't get out-of-sync. - // Therefore, results of further computations based on base snapshots of changed documents can't be invalidated by + // Therefore, results of further computations based on base snapshots of changed documents can't be invalidated by // incoming events updating the content of out-of-sync documents. - // + // // If in past we concluded that a document is out-of-sync, attempt to check one more time before we block apply. // The source file content might have been updated since the last time we checked. // @@ -865,7 +872,7 @@ public async ValueTask EmitSolutionUpdateAsync(Solution solution // another document is updated. If we encounter a significant case of this we should consider caching such a result per project, // rather then per document. Also, we might be observing an older semantics if the document that is causing the change is out-of-sync -- // e.g. the binary was built with an overload C.M(object), but a generator updated class C to also contain C.M(string), - // which change we have not observed yet. Then call-sites of C.M in a changed document observed by the analysis will be seen as C.M(object) + // which change we have not observed yet. Then call-sites of C.M in a changed document observed by the analysis will be seen as C.M(object) // instead of the true C.M(string). var (changedDocumentAnalyses, documentDiagnostics) = await AnalyzeDocumentsAsync(changedOrAddedDocuments, solutionActiveStatementSpanProvider, cancellationToken).ConfigureAwait(false); @@ -873,17 +880,26 @@ public async ValueTask EmitSolutionUpdateAsync(Solution solution { // The diagnostic hasn't been reported by GetDocumentDiagnosticsAsync since out-of-sync documents are likely to be synchronized // before the changes are attempted to be applied. If we still have any out-of-sync documents we report warnings and ignore changes in them. - // If in future the file is updated so that its content matches the PDB checksum, the document transitions to a matching state, + // 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((newProject.Id, documentDiagnostics)); } - var projectSummary = GetProjectAnalysisSymmary(changedDocumentAnalyses); + var projectSummary = GetProjectAnalysisSummary(changedDocumentAnalyses); + log.Write("Project summary for '{0}': {1}", projectSummary, newProject.FilePath); if (projectSummary == ProjectAnalysisSummary.NoChanges) { continue; } + foreach (var changedDocumentAnalysis in changedDocumentAnalyses) + { + if (changedDocumentAnalysis.HasChanges) + { + log.Write("Document changed, added, or deleted: '{0}'", changedDocumentAnalysis.FilePath); + } + } + // The capability of a module to apply edits may change during edit session if the user attaches debugger to // an additional process that doesn't support EnC (or detaches from such process). Before we apply edits // we need to check with the debugger. @@ -922,7 +938,7 @@ public async ValueTask EmitSolutionUpdateAsync(Solution solution continue; } - if (!DebuggingSession.TryGetOrCreateEmitBaseline(newProject, out var createBaselineDiagnostics, out var baseline, out var baselineAccessLock)) + if (!DebuggingSession.TryGetOrCreateEmitBaseline(newProject, out var createBaselineDiagnostics, out var baseline, out var baselineGeneration, out var baselineAccessLock)) { Debug.Assert(!createBaselineDiagnostics.IsEmpty); @@ -934,7 +950,20 @@ public async ValueTask EmitSolutionUpdateAsync(Solution solution continue; } - EditAndContinueWorkspaceService.Log.Write("Emitting update of '{0}' [0x{1:X8}]", newProject.Id.DebugName, newProject.Id); + log.Write("Emitting update of '{0}'", newProject.FilePath); + + if (log.FileLoggingEnabled) + { + foreach (var changedDocumentAnalysis in changedDocumentAnalyses) + { + if (changedDocumentAnalysis.HasChanges) + { + var oldDocument = await oldProject.GetDocumentAsync(changedDocumentAnalysis.DocumentId, includeSourceGenerated: true, cancellationToken).ConfigureAwait(false); + var newDocument = await newProject.GetDocumentAsync(changedDocumentAnalysis.DocumentId, includeSourceGenerated: true, cancellationToken).ConfigureAwait(false); + await log.WriteDocumentChangeAsync(oldDocument, newDocument, DebuggingSession.Id, baselineGeneration + 1, cancellationToken).ConfigureAwait(false); + } + } + } var oldCompilation = await oldProject.GetCompilationAsync(cancellationToken).ConfigureAwait(false); var newCompilation = await newProject.GetCompilationAsync(cancellationToken).ConfigureAwait(false); @@ -995,7 +1024,7 @@ public async ValueTask EmitSolutionUpdateAsync(Solution solution out var moduleNonRemappableRegions, out var exceptionRegionUpdates); - deltas.Add(new ManagedModuleUpdate( + var delta = new ModuleUpdate( mvid, ilStream.ToImmutableArray(), metadataStream.ToImmutableArray(), @@ -1005,10 +1034,17 @@ public async ValueTask EmitSolutionUpdateAsync(Solution solution changedTypeTokens, activeStatementsInUpdatedMethods, exceptionRegionUpdates, - projectChanges.RequiredCapabilities)); + projectChanges.RequiredCapabilities); + + deltas.Add(delta); nonRemappableRegions.Add((mvid, moduleNonRemappableRegions)); emitBaselines.Add((newProject.Id, emitResult.Baseline)); + + if (log.FileLoggingEnabled) + { + await LogDeltaFilesAsync(log, delta, baselineGeneration, oldProject, newProject, cancellationToken).ConfigureAwait(false); + } } } else @@ -1041,8 +1077,8 @@ public async ValueTask EmitSolutionUpdateAsync(Solution solution var update = isBlocked ? SolutionUpdate.Blocked(diagnostics.ToImmutable(), documentsWithRudeEdits.ToImmutable(), syntaxError, hasEmitErrors) : new SolutionUpdate( - new ManagedModuleUpdates( - (deltas.Count > 0) ? ManagedModuleUpdateStatus.Ready : ManagedModuleUpdateStatus.None, + new ModuleUpdates( + (deltas.Count > 0) ? ModuleUpdateStatus.Ready : ModuleUpdateStatus.None, deltas.ToImmutable()), nonRemappableRegions.ToImmutable(), emitBaselines.ToImmutable(), @@ -1058,6 +1094,35 @@ public async ValueTask EmitSolutionUpdateAsync(Solution solution } } + private async ValueTask LogDeltaFilesAsync(TraceLog log, ModuleUpdate delta, int baselineGeneration, Project oldProject, Project newProject, CancellationToken cancellationToken) + { + var sessionId = DebuggingSession.Id; + + if (baselineGeneration == 0) + { + var oldCompilationOutputs = DebuggingSession.GetCompilationOutputs(oldProject); + + await log.WriteToFileAsync( + async (stream, cancellationToken) => await oldCompilationOutputs.TryCopyAssemblyToAsync(stream, cancellationToken).ConfigureAwait(false), + sessionId, + newProject.Name, + PathUtilities.GetFileName(oldCompilationOutputs.AssemblyDisplayPath) ?? oldProject.Name + ".dll", + cancellationToken).ConfigureAwait(false); + + await log.WriteToFileAsync( + async (stream, cancellationToken) => await oldCompilationOutputs.TryCopyPdbToAsync(stream, cancellationToken).ConfigureAwait(false), + sessionId, + newProject.Name, + PathUtilities.GetFileName(oldCompilationOutputs.PdbDisplayPath) ?? oldProject.Name + ".pdb", + cancellationToken).ConfigureAwait(false); + } + + var generation = baselineGeneration + 1; + log.WriteToFile(sessionId, delta.ILDelta, newProject.Name, generation + ".il"); + log.WriteToFile(sessionId, delta.MetadataDelta, newProject.Name, generation + ".md"); + log.WriteToFile(sessionId, delta.PdbDelta, newProject.Name, generation + ".pdb"); + } + // internal for testing internal static void GetActiveStatementAndExceptionRegionSpans( Guid moduleId, @@ -1107,7 +1172,7 @@ void AddNonRemappableRegion(SourceFileSpan oldSpan, SourceFileSpan newSpan, bool if (oldActiveStatement.IsMethodUpToDate) { - // Start tracking non-remappable regions for active statements in methods that were up-to-date + // Start tracking non-remappable regions for active statements in methods that were up-to-date // when break state was entered and now being updated (regardless of whether the active span changed or not). if (isMethodUpdated) { @@ -1117,7 +1182,7 @@ void AddNonRemappableRegion(SourceFileSpan oldSpan, SourceFileSpan newSpan, bool { // If the method has been up-to-date and it is not updated now then either the active statement span has not changed, // or the entire method containing it moved. In neither case do we need to start tracking non-remapable region - // for the active statement since movement of whole method bodies (if any) is handled only on PDB level without + // for the active statement since movement of whole method bodies (if any) is handled only on PDB level without // triggering any remapping on the IL level. // // That said, we still add a non-remappable region for this active statement, so that we know in future sessions @@ -1205,7 +1270,7 @@ void AddNonRemappableRegion(SourceFileSpan oldSpan, SourceFileSpan newSpan, bool // Note: https://devdiv.visualstudio.com/DevDiv/_workitems/edit/1319289 // - // The update should include the file name, otherwise it is not possible for the debugger to find + // The update should include the file name, otherwise it is not possible for the debugger to find // the right IL span of the exception handler in case when multiple handlers in the same method // have the same mapped span but different mapped file name: // diff --git a/src/Features/Core/Portable/EditAndContinue/EmitSolutionUpdateResults.cs b/src/Features/Core/Portable/EditAndContinue/EmitSolutionUpdateResults.cs index 8c1d0d82e69c4..995c87bc0e275 100644 --- a/src/Features/Core/Portable/EditAndContinue/EmitSolutionUpdateResults.cs +++ b/src/Features/Core/Portable/EditAndContinue/EmitSolutionUpdateResults.cs @@ -22,7 +22,7 @@ internal readonly struct EmitSolutionUpdateResults internal readonly struct Data { [DataMember(Order = 0)] - public readonly ManagedModuleUpdates ModuleUpdates; + public readonly ModuleUpdates ModuleUpdates; [DataMember(Order = 1)] public readonly ImmutableArray Diagnostics; @@ -34,7 +34,7 @@ internal readonly struct Data public readonly DiagnosticData? SyntaxError; public Data( - ManagedModuleUpdates moduleUpdates, + ModuleUpdates moduleUpdates, ImmutableArray diagnostics, ImmutableArray<(DocumentId DocumentId, ImmutableArray Diagnostics)> rudeEdits, DiagnosticData? syntaxError) @@ -47,18 +47,18 @@ public Data( } public static readonly EmitSolutionUpdateResults Empty = - new(moduleUpdates: new ManagedModuleUpdates(ManagedModuleUpdateStatus.None, ImmutableArray.Empty), + new(moduleUpdates: new ModuleUpdates(ModuleUpdateStatus.None, ImmutableArray.Empty), diagnostics: ImmutableArray<(ProjectId, ImmutableArray)>.Empty, documentsWithRudeEdits: ImmutableArray<(DocumentId, ImmutableArray)>.Empty, syntaxError: null); - public readonly ManagedModuleUpdates ModuleUpdates; + public readonly ModuleUpdates ModuleUpdates; public readonly ImmutableArray<(ProjectId ProjectId, ImmutableArray Diagnostics)> Diagnostics; public readonly ImmutableArray<(DocumentId DocumentId, ImmutableArray Diagnostics)> RudeEdits; public readonly Diagnostic? SyntaxError; public EmitSolutionUpdateResults( - ManagedModuleUpdates moduleUpdates, + ModuleUpdates moduleUpdates, ImmutableArray<(ProjectId ProjectId, ImmutableArray Diagnostic)> diagnostics, ImmutableArray<(DocumentId DocumentId, ImmutableArray Diagnostics)> documentsWithRudeEdits, Diagnostic? syntaxError) @@ -133,6 +133,7 @@ internal static async ValueTask> GetH ImmutableArray diagnosticData, ImmutableArray<(DocumentId DocumentId, ImmutableArray Diagnostics)> rudeEdits, DiagnosticData? syntaxError, + ModuleUpdateStatus updateStatus, CancellationToken cancellationToken) { using var _ = ArrayBuilder.GetInstance(out var builder); @@ -153,7 +154,9 @@ internal static async ValueTask> GetH builder.Add(new ManagedHotReloadDiagnostic( data.Id, data.Message ?? FeaturesResources.Unknown_error_occurred, - ManagedHotReloadDiagnosticSeverity.Error, + (updateStatus == ModuleUpdateStatus.RestartRequired) ? + ManagedHotReloadDiagnosticSeverity.RestartRequired : + ManagedHotReloadDiagnosticSeverity.Error, fileSpan?.Path ?? "", fileSpan?.Span.ToSourceSpan() ?? default)); diff --git a/src/Features/Core/Portable/EditAndContinue/Extensions.cs b/src/Features/Core/Portable/EditAndContinue/Extensions.cs index 8bce6176d1ed0..0500361c47493 100644 --- a/src/Features/Core/Portable/EditAndContinue/Extensions.cs +++ b/src/Features/Core/Portable/EditAndContinue/Extensions.cs @@ -68,13 +68,17 @@ public static UnmappedActiveStatement GetStatement(this ImmutableArray + /// True if the project supports Edit and Continue. + /// Only depends on the language of the project and never changes. + /// public static bool SupportsEditAndContinue(this Project project) - => project.LanguageServices.GetService() != null; + => project.Services.GetService() != null; // Note: source generated files have relative paths: https://github.com/dotnet/roslyn/issues/51998 public static bool SupportsEditAndContinue(this TextDocumentState documentState) => !documentState.Attributes.DesignTimeOnly && documentState is not DocumentState or DocumentState { SupportsSyntaxTree: true } && - (PathUtilities.IsAbsolute(documentState.FilePath) || documentState is SourceGeneratedDocumentState); + (PathUtilities.IsAbsolute(documentState.FilePath) || documentState is SourceGeneratedDocumentState { FilePath: not null }); } } diff --git a/src/Features/Core/Portable/EditAndContinue/ModuleUpdate.cs b/src/Features/Core/Portable/EditAndContinue/ModuleUpdate.cs new file mode 100644 index 0000000000000..473376ff8be9b --- /dev/null +++ b/src/Features/Core/Portable/EditAndContinue/ModuleUpdate.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.Runtime.Serialization; +using System; +using System.Collections.Immutable; +using Microsoft.CodeAnalysis.EditAndContinue.Contracts; + +namespace Microsoft.CodeAnalysis.EditAndContinue; + +[DataContract] +internal readonly record struct ModuleUpdate( + [property: DataMember(Order = 0)] Guid Module, + [property: DataMember(Order = 1)] ImmutableArray ILDelta, + [property: DataMember(Order = 2)] ImmutableArray MetadataDelta, + [property: DataMember(Order = 3)] ImmutableArray PdbDelta, + [property: DataMember(Order = 4)] ImmutableArray SequencePoints, + [property: DataMember(Order = 5)] ImmutableArray UpdatedMethods, + [property: DataMember(Order = 6)] ImmutableArray UpdatedTypes, + [property: DataMember(Order = 7)] ImmutableArray ActiveStatements, + [property: DataMember(Order = 8)] ImmutableArray ExceptionRegions, + [property: DataMember(Order = 9)] EditAndContinueCapabilities RequiredCapabilities); + +[DataContract] +internal readonly record struct ModuleUpdates( + [property: DataMember(Order = 0)] ModuleUpdateStatus Status, + [property: DataMember(Order = 1)] ImmutableArray Updates); diff --git a/src/Features/Core/Portable/EditAndContinue/ModuleUpdateStatus.cs b/src/Features/Core/Portable/EditAndContinue/ModuleUpdateStatus.cs new file mode 100644 index 0000000000000..99e34c691aa77 --- /dev/null +++ b/src/Features/Core/Portable/EditAndContinue/ModuleUpdateStatus.cs @@ -0,0 +1,32 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +namespace Microsoft.CodeAnalysis.EditAndContinue; + +/// +/// Indicates the state of a manage module update. +/// +internal enum ModuleUpdateStatus +{ + /// + /// No change made. + /// + None = 0, + + /// + /// All changes are valid, can be applied. + /// + Ready = 1, + + /// + /// Changes require restarting the application in order to be applied. + /// + RestartRequired = 2, + + /// + /// Some changes are errors that block rebuild of the module. + /// This means that the code is in a broken state that cannot be resolved by restarting the application. + /// + Blocked = 3 +} diff --git a/src/Features/Core/Portable/EditAndContinue/PendingSolutionUpdate.cs b/src/Features/Core/Portable/EditAndContinue/PendingSolutionUpdate.cs index 687318753264b..2288e1e3169f6 100644 --- a/src/Features/Core/Portable/EditAndContinue/PendingSolutionUpdate.cs +++ b/src/Features/Core/Portable/EditAndContinue/PendingSolutionUpdate.cs @@ -13,13 +13,13 @@ internal sealed class PendingSolutionUpdate { public readonly Solution Solution; public readonly ImmutableArray<(ProjectId ProjectId, EmitBaseline Baseline)> EmitBaselines; - public readonly ImmutableArray Deltas; + public readonly ImmutableArray Deltas; public readonly ImmutableArray<(Guid ModuleId, ImmutableArray<(ManagedModuleMethodId Method, NonRemappableRegion Region)> Regions)> NonRemappableRegions; public PendingSolutionUpdate( Solution solution, ImmutableArray<(ProjectId ProjectId, EmitBaseline Baseline)> emitBaselines, - ImmutableArray deltas, + ImmutableArray deltas, ImmutableArray<(Guid ModuleId, ImmutableArray<(ManagedModuleMethodId Method, NonRemappableRegion Region)>)> nonRemappableRegions) { Solution = solution; diff --git a/src/Features/Core/Portable/EditAndContinue/Remote/RemoteDebuggingSessionProxy.cs b/src/Features/Core/Portable/EditAndContinue/Remote/RemoteDebuggingSessionProxy.cs index cb413a5162bf7..b6393772b9cbc 100644 --- a/src/Features/Core/Portable/EditAndContinue/Remote/RemoteDebuggingSessionProxy.cs +++ b/src/Features/Core/Portable/EditAndContinue/Remote/RemoteDebuggingSessionProxy.cs @@ -60,7 +60,7 @@ public async ValueTask BreakStateOrCapabilitiesChangedAsync(IDiagnosticAnalyzerS diagnosticService.Reanalyze(_workspace, documentIds: documentsToReanalyze); // clear emit/apply diagnostics reported previously: - diagnosticUpdateSource.ClearDiagnostics(); + diagnosticUpdateSource.ClearDiagnostics(isSessionEnding: false); } public async ValueTask EndDebuggingSessionAsync(Solution compileTimeSolution, EditAndContinueDiagnosticUpdateSource diagnosticUpdateSource, IDiagnosticAnalyzerService diagnosticService, CancellationToken cancellationToken) @@ -88,13 +88,13 @@ public async ValueTask EndDebuggingSessionAsync(Solution compileTimeSolution, Ed diagnosticService.Reanalyze(_workspace, documentIds: designTimeDocumentsToReanalyze); // clear emit/apply diagnostics reported previously: - diagnosticUpdateSource.ClearDiagnostics(); + diagnosticUpdateSource.ClearDiagnostics(isSessionEnding: true); Dispose(); } public async ValueTask<( - ManagedModuleUpdates updates, + ModuleUpdates updates, ImmutableArray diagnostics, ImmutableArray<(DocumentId DocumentId, ImmutableArray Diagnostics)> rudeEdits, DiagnosticData? syntaxError)> EmitSolutionUpdateAsync( @@ -104,7 +104,7 @@ public async ValueTask EndDebuggingSessionAsync(Solution compileTimeSolution, Ed EditAndContinueDiagnosticUpdateSource diagnosticUpdateSource, CancellationToken cancellationToken) { - ManagedModuleUpdates moduleUpdates; + ModuleUpdates moduleUpdates; ImmutableArray diagnosticData; ImmutableArray<(DocumentId DocumentId, ImmutableArray Diagnostics)> rudeEdits; DiagnosticData? syntaxError; @@ -137,7 +137,7 @@ public async ValueTask EndDebuggingSessionAsync(Solution compileTimeSolution, Ed } else { - moduleUpdates = new ManagedModuleUpdates(ManagedModuleUpdateStatus.RestartRequired, ImmutableArray.Empty); + moduleUpdates = new ModuleUpdates(ModuleUpdateStatus.RestartRequired, ImmutableArray.Empty); diagnosticData = ImmutableArray.Empty; rudeEdits = ImmutableArray<(DocumentId DocumentId, ImmutableArray Diagnostics)>.Empty; syntaxError = null; @@ -155,12 +155,12 @@ public async ValueTask EndDebuggingSessionAsync(Solution compileTimeSolution, Ed diagnosticData = ImmutableArray.Create(DiagnosticData.Create(diagnostic, project: null)); rudeEdits = ImmutableArray<(DocumentId DocumentId, ImmutableArray Diagnostics)>.Empty; - moduleUpdates = new ManagedModuleUpdates(ManagedModuleUpdateStatus.RestartRequired, ImmutableArray.Empty); + moduleUpdates = new ModuleUpdates(ModuleUpdateStatus.RestartRequired, ImmutableArray.Empty); syntaxError = null; } // clear emit/apply diagnostics reported previously: - diagnosticUpdateSource.ClearDiagnostics(); + diagnosticUpdateSource.ClearDiagnostics(isSessionEnding: false); // clear all reported rude edits: diagnosticService.Reanalyze(_workspace, documentIds: rudeEdits.Select(d => d.DocumentId)); @@ -209,7 +209,7 @@ await client.TryInvokeAsync( public async ValueTask GetCurrentActiveStatementPositionAsync(Solution solution, ActiveStatementSpanProvider activeStatementSpanProvider, ManagedInstructionId instructionId, CancellationToken cancellationToken) { - var client = await RemoteHostClient.TryGetClientAsync(_workspace.Services, cancellationToken).ConfigureAwait(false); + var client = await RemoteHostClient.TryGetClientAsync(_workspace.Services.SolutionServices, cancellationToken).ConfigureAwait(false); if (client == null) { return await GetLocalService().GetCurrentActiveStatementPositionAsync(_sessionId, solution, activeStatementSpanProvider, instructionId, cancellationToken).ConfigureAwait(false); @@ -226,7 +226,7 @@ await client.TryInvokeAsync( public async ValueTask IsActiveStatementInExceptionRegionAsync(Solution solution, ManagedInstructionId instructionId, CancellationToken cancellationToken) { - var client = await RemoteHostClient.TryGetClientAsync(_workspace.Services, cancellationToken).ConfigureAwait(false); + var client = await RemoteHostClient.TryGetClientAsync(_workspace.Services.SolutionServices, cancellationToken).ConfigureAwait(false); if (client == null) { return await GetLocalService().IsActiveStatementInExceptionRegionAsync(_sessionId, solution, instructionId, cancellationToken).ConfigureAwait(false); diff --git a/src/Features/Core/Portable/EditAndContinue/RudeEditKind.cs b/src/Features/Core/Portable/EditAndContinue/RudeEditKind.cs index 51651d78ee10a..1a80974d810b6 100644 --- a/src/Features/Core/Portable/EditAndContinue/RudeEditKind.cs +++ b/src/Features/Core/Portable/EditAndContinue/RudeEditKind.cs @@ -136,5 +136,7 @@ internal enum RudeEditKind : ushort RenamingNotSupportedByRuntime = 107, ChangingNonCustomAttribute = 108, ChangingNamespace = 109, + ChangingTypeNotSupportedByRuntime = 110, + DeleteNotSupportedByRuntime = 111, } } diff --git a/src/Features/Core/Portable/EditAndContinue/SolutionUpdate.cs b/src/Features/Core/Portable/EditAndContinue/SolutionUpdate.cs index 5a84e54d33718..0b98b8709d257 100644 --- a/src/Features/Core/Portable/EditAndContinue/SolutionUpdate.cs +++ b/src/Features/Core/Portable/EditAndContinue/SolutionUpdate.cs @@ -11,7 +11,7 @@ namespace Microsoft.CodeAnalysis.EditAndContinue { internal readonly struct SolutionUpdate { - public readonly ManagedModuleUpdates ModuleUpdates; + public readonly ModuleUpdates ModuleUpdates; public readonly ImmutableArray<(Guid ModuleId, ImmutableArray<(ManagedModuleMethodId Method, NonRemappableRegion Region)>)> NonRemappableRegions; public readonly ImmutableArray<(ProjectId ProjectId, EmitBaseline Baseline)> EmitBaselines; public readonly ImmutableArray<(ProjectId ProjectId, ImmutableArray Diagnostics)> Diagnostics; @@ -19,7 +19,7 @@ internal readonly struct SolutionUpdate public readonly Diagnostic? SyntaxError; public SolutionUpdate( - ManagedModuleUpdates moduleUpdates, + ModuleUpdates moduleUpdates, ImmutableArray<(Guid ModuleId, ImmutableArray<(ManagedModuleMethodId Method, NonRemappableRegion Region)>)> nonRemappableRegions, ImmutableArray<(ProjectId ProjectId, EmitBaseline Baseline)> emitBaselines, ImmutableArray<(ProjectId ProjectId, ImmutableArray Diagnostics)> diagnostics, @@ -40,7 +40,7 @@ public static SolutionUpdate Blocked( Diagnostic? syntaxError, bool hasEmitErrors) => new( - new(syntaxError != null || hasEmitErrors ? ManagedModuleUpdateStatus.Blocked : ManagedModuleUpdateStatus.RestartRequired, ImmutableArray.Empty), + new(syntaxError != null || hasEmitErrors ? ModuleUpdateStatus.Blocked : ModuleUpdateStatus.RestartRequired, ImmutableArray.Empty), ImmutableArray<(Guid, ImmutableArray<(ManagedModuleMethodId, NonRemappableRegion)>)>.Empty, ImmutableArray<(ProjectId, EmitBaseline)>.Empty, diagnostics, diff --git a/src/Features/Core/Portable/EditAndContinue/TraceLog.cs b/src/Features/Core/Portable/EditAndContinue/TraceLog.cs index 52a585ef5ade5..70ffea938c0cf 100644 --- a/src/Features/Core/Portable/EditAndContinue/TraceLog.cs +++ b/src/Features/Core/Portable/EditAndContinue/TraceLog.cs @@ -5,8 +5,13 @@ using System; using System.Collections.Immutable; using System.Diagnostics; +using System.IO; using System.Linq; +using System.Security.Cryptography; +using System.Text; using System.Threading; +using System.Threading.Tasks; +using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.EditAndContinue { @@ -24,23 +29,34 @@ internal readonly struct Arg { public readonly object? Object; public readonly int Int32; + public readonly ImmutableArray Tokens; public Arg(object? value) { Int32 = -1; Object = value ?? ""; + Tokens = default; + } + + public Arg(ImmutableArray tokens) + { + Int32 = -1; + Object = null; + Tokens = tokens; } public Arg(int value, Type? type = null) { Int32 = value; Object = type; + Tokens = default; } - public override string? ToString() - => (Object is null) ? Int32.ToString() : + public object? GetDebuggerDisplay() + => (!Tokens.IsDefault) ? string.Join(",", Tokens.Select(token => token.ToString("X8"))) : + (Object is null) ? Int32 : (Object is Type { IsEnum: true } type && Int32 >= 0) ? Enum.GetName(type, Int32) : - Object.ToString(); + Object; public static implicit operator Arg(string? value) => new(value); public static implicit operator Arg(int value) => new(value); @@ -51,6 +67,7 @@ public Arg(int value, Type? type = null) public static implicit operator Arg(ProjectAnalysisSummary value) => new((int)value, typeof(ProjectAnalysisSummary)); public static implicit operator Arg(RudeEditKind value) => new((int)value, typeof(RudeEditKind)); public static implicit operator Arg((int enumValue, Type enumType) value) => new(value.enumValue, value.enumType); + public static implicit operator Arg(ImmutableArray tokens) => new(tokens); } [DebuggerDisplay("{GetDebuggerDisplay(),nq}")] @@ -66,25 +83,59 @@ public Entry(string format, Arg[]? args) } internal string GetDebuggerDisplay() => - (MessageFormat == null) ? "" : string.Format(MessageFormat, Args?.Select(a => (object)a).ToArray() ?? Array.Empty()); + (MessageFormat == null) ? "" : string.Format(MessageFormat, Args?.Select(a => a.GetDebuggerDisplay()).ToArray() ?? Array.Empty()); } private readonly Entry[] _log; private readonly string _id; + private readonly string? _logDirectory; private int _currentLine; - public TraceLog(int logSize, string id) + public TraceLog(int logSize, string id, string? logDirectory) { _log = new Entry[logSize]; _id = id; + _logDirectory = logDirectory; } - private void Append(Entry entry) + public bool FileLoggingEnabled + => _logDirectory != null; + + private void AppendInMemory(Entry entry) { var index = Interlocked.Increment(ref _currentLine); _log[(index - 1) % _log.Length] = entry; } + private void AppendFileLoggingErrorInMemory(string? path, Exception e) + => AppendInMemory(new Entry("Error writing log file '{0}': {1}", new[] { new Arg(path), new Arg(e.Message) })); + + private void AppendToFile(Entry entry) + { + Debug.Assert(_logDirectory != null); + string? path = null; + + try + { + path = Path.Combine(_logDirectory, "Trace.log"); + File.AppendAllLines(path, new[] { entry.GetDebuggerDisplay() }); + } + catch (Exception e) + { + AppendFileLoggingErrorInMemory(path, e); + } + } + + private void Append(Entry entry) + { + AppendInMemory(entry); + + if (_logDirectory != null) + { + AppendToFile(entry); + } + } + public void Write(string str) => Write(str, args: null); @@ -103,6 +154,92 @@ public void DebugWrite(string format, params Arg[]? args) Debug.WriteLine(entry.ToString(), _id); } + private string CreateSessionDirectory(DebuggingSessionId sessionId, string relativePath) + { + Contract.ThrowIfNull(_logDirectory); + var directory = Path.Combine(_logDirectory, sessionId.Ordinal.ToString(), relativePath); + Directory.CreateDirectory(directory); + return directory; + } + + private string MakeSourceFileLogPath(Document document, string suffix, DebuggingSessionId sessionId, int generation) + { + Debug.Assert(document.FilePath != null); + Debug.Assert(document.Project.FilePath != null); + + var projectDir = PathUtilities.GetDirectoryName(document.Project.FilePath)!; + var documentDir = PathUtilities.GetDirectoryName(document.FilePath)!; + var extension = PathUtilities.GetExtension(document.FilePath); + var fileName = PathUtilities.GetFileName(document.FilePath, includeExtension: false); + + var relativeDir = PathUtilities.IsSameDirectoryOrChildOf(documentDir, projectDir) ? PathUtilities.GetRelativePath(projectDir, documentDir) : documentDir; + relativeDir = relativeDir.Replace('\\', '_').Replace('/', '_'); + + var directory = CreateSessionDirectory(sessionId, Path.Combine(document.Project.Name, relativeDir)); + return Path.Combine(directory, $"{fileName}.{generation}.{suffix}{extension}"); + } + + public void WriteToFile(DebuggingSessionId sessionId, ImmutableArray bytes, string directory, string fileName) + { + string? path = null; + try + { + path = Path.Combine(CreateSessionDirectory(sessionId, directory), fileName); + File.WriteAllBytes(path, bytes.ToArray()); + } + catch (Exception e) + { + AppendFileLoggingErrorInMemory(path, e); + } + } + + public async ValueTask WriteToFileAsync(Func writer, DebuggingSessionId sessionId, string directory, string fileName, CancellationToken cancellationToken) + { + string? path = null; + try + { + path = Path.Combine(CreateSessionDirectory(sessionId, directory), fileName); + using var file = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.Write | FileShare.Delete); + await writer(file, cancellationToken).ConfigureAwait(false); + } + catch (Exception e) + { + AppendFileLoggingErrorInMemory(path, e); + } + } + + private async ValueTask WriteDocumentAsync(Document document, string fileNameSuffix, DebuggingSessionId sessionId, int generation, CancellationToken cancellationToken) + { + Debug.Assert(document.FilePath != null); + + string? path = null; + try + { + path = MakeSourceFileLogPath(document, fileNameSuffix, sessionId, generation); + var text = await document.GetTextAsync(cancellationToken).ConfigureAwait(false); + using var file = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.Write | FileShare.Delete); + using var writer = new StreamWriter(file, text.Encoding ?? Encoding.UTF8); + text.Write(writer, cancellationToken); + } + catch (Exception e) + { + AppendFileLoggingErrorInMemory(path, e); + } + } + + public async ValueTask WriteDocumentChangeAsync(Document? oldDocument, Document? newDocument, DebuggingSessionId sessionId, int generation, CancellationToken cancellationToken) + { + if (oldDocument?.FilePath != null) + { + await WriteDocumentAsync(oldDocument, fileNameSuffix: "old", sessionId, generation, cancellationToken).ConfigureAwait(false); + } + + if (newDocument?.FilePath != null) + { + await WriteDocumentAsync(newDocument, fileNameSuffix: "new", sessionId, generation, cancellationToken).ConfigureAwait(false); + } + } + internal TestAccessor GetTestAccessor() => new(this); diff --git a/src/Features/Core/Portable/EmbeddedLanguages/AbstractEmbeddedLanguageFeatureService.cs b/src/Features/Core/Portable/EmbeddedLanguages/AbstractEmbeddedLanguageFeatureService.cs index c11383f7f8995..9a8f3577793a7 100644 --- a/src/Features/Core/Portable/EmbeddedLanguages/AbstractEmbeddedLanguageFeatureService.cs +++ b/src/Features/Core/Portable/EmbeddedLanguages/AbstractEmbeddedLanguageFeatureService.cs @@ -8,7 +8,7 @@ using System.Linq; using System.Threading; using Microsoft.CodeAnalysis.EmbeddedLanguages; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Shared.Utilities; diff --git a/src/Features/Core/Portable/EmbeddedLanguages/AbstractLanguageDetector.cs b/src/Features/Core/Portable/EmbeddedLanguages/AbstractLanguageDetector.cs index 4e57089a9f239..82711fd686d8c 100644 --- a/src/Features/Core/Portable/EmbeddedLanguages/AbstractLanguageDetector.cs +++ b/src/Features/Core/Portable/EmbeddedLanguages/AbstractLanguageDetector.cs @@ -7,7 +7,7 @@ using System.Threading; using Microsoft.CodeAnalysis.EmbeddedLanguages; using Microsoft.CodeAnalysis.EmbeddedLanguages.VirtualChars; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Shared.Extensions; namespace Microsoft.CodeAnalysis.Features.EmbeddedLanguages diff --git a/src/Features/Core/Portable/EmbeddedLanguages/Classification/AbstractEmbeddedLanguageClassificationService.cs b/src/Features/Core/Portable/EmbeddedLanguages/Classification/AbstractEmbeddedLanguageClassificationService.cs index 63d1937960821..5585601ac05d1 100644 --- a/src/Features/Core/Portable/EmbeddedLanguages/Classification/AbstractEmbeddedLanguageClassificationService.cs +++ b/src/Features/Core/Portable/EmbeddedLanguages/Classification/AbstractEmbeddedLanguageClassificationService.cs @@ -9,7 +9,7 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.EmbeddedLanguages; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Shared.Utilities; diff --git a/src/Features/Core/Portable/EmbeddedLanguages/DateAndTime/DateAndTimeEmbeddedCompletionProvider.cs b/src/Features/Core/Portable/EmbeddedLanguages/DateAndTime/DateAndTimeEmbeddedCompletionProvider.cs index f45e24f80bd6f..364944c6d154a 100644 --- a/src/Features/Core/Portable/EmbeddedLanguages/DateAndTime/DateAndTimeEmbeddedCompletionProvider.cs +++ b/src/Features/Core/Portable/EmbeddedLanguages/DateAndTime/DateAndTimeEmbeddedCompletionProvider.cs @@ -8,7 +8,7 @@ using Microsoft.CodeAnalysis.Completion; using Microsoft.CodeAnalysis.Completion.Providers; using Microsoft.CodeAnalysis.Features.EmbeddedLanguages.DateAndTime.LanguageServices; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Text; diff --git a/src/Features/Core/Portable/EmbeddedLanguages/DateAndTime/LanguageServices/DateAndTimeEmbeddedLanguage.cs b/src/Features/Core/Portable/EmbeddedLanguages/DateAndTime/LanguageServices/DateAndTimeEmbeddedLanguage.cs index 78ac73f97c508..7ca3818467e11 100644 --- a/src/Features/Core/Portable/EmbeddedLanguages/DateAndTime/LanguageServices/DateAndTimeEmbeddedLanguage.cs +++ b/src/Features/Core/Portable/EmbeddedLanguages/DateAndTime/LanguageServices/DateAndTimeEmbeddedLanguage.cs @@ -6,7 +6,7 @@ using System.Threading.Tasks; using Microsoft.CodeAnalysis.Completion.Providers; using Microsoft.CodeAnalysis.EmbeddedLanguages; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Shared.Extensions; namespace Microsoft.CodeAnalysis.Features.EmbeddedLanguages.DateAndTime.LanguageServices diff --git a/src/Features/Core/Portable/EmbeddedLanguages/DateAndTime/LanguageServices/DateAndTimeLanguageDetector.cs b/src/Features/Core/Portable/EmbeddedLanguages/DateAndTime/LanguageServices/DateAndTimeLanguageDetector.cs index b4d85fc549221..01dbca60da6ba 100644 --- a/src/Features/Core/Portable/EmbeddedLanguages/DateAndTime/LanguageServices/DateAndTimeLanguageDetector.cs +++ b/src/Features/Core/Portable/EmbeddedLanguages/DateAndTime/LanguageServices/DateAndTimeLanguageDetector.cs @@ -10,7 +10,7 @@ using System.Threading; using Microsoft.CodeAnalysis.EmbeddedLanguages; using Microsoft.CodeAnalysis.EmbeddedLanguages.VirtualChars; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Shared.Extensions; namespace Microsoft.CodeAnalysis.Features.EmbeddedLanguages.DateAndTime.LanguageServices diff --git a/src/Features/Core/Portable/EmbeddedLanguages/EmbeddedLanguageDetector.cs b/src/Features/Core/Portable/EmbeddedLanguages/EmbeddedLanguageDetector.cs index 9a1d2f263d5c0..a399709766c12 100644 --- a/src/Features/Core/Portable/EmbeddedLanguages/EmbeddedLanguageDetector.cs +++ b/src/Features/Core/Portable/EmbeddedLanguages/EmbeddedLanguageDetector.cs @@ -8,7 +8,7 @@ using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Threading; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Shared.Extensions; namespace Microsoft.CodeAnalysis.EmbeddedLanguages diff --git a/src/Features/Core/Portable/EmbeddedLanguages/EmbeddedLanguageInfo.cs b/src/Features/Core/Portable/EmbeddedLanguages/EmbeddedLanguageInfo.cs index fd1eef12d21e9..1aa5e8f6b04e1 100644 --- a/src/Features/Core/Portable/EmbeddedLanguages/EmbeddedLanguageInfo.cs +++ b/src/Features/Core/Portable/EmbeddedLanguages/EmbeddedLanguageInfo.cs @@ -5,7 +5,7 @@ using System.Collections.Immutable; using Microsoft.CodeAnalysis.EmbeddedLanguages.VirtualChars; using Microsoft.CodeAnalysis.Host; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Shared.Collections; namespace Microsoft.CodeAnalysis.EmbeddedLanguages diff --git a/src/EditorFeatures/Core/EmbeddedLanguages/Json/JsonBraceMatcher.cs b/src/Features/Core/Portable/EmbeddedLanguages/Json/LanguageServices/JsonBraceMatcher.cs similarity index 94% rename from src/EditorFeatures/Core/EmbeddedLanguages/Json/JsonBraceMatcher.cs rename to src/Features/Core/Portable/EmbeddedLanguages/Json/LanguageServices/JsonBraceMatcher.cs index 98ca3effb4f6b..5cae292905389 100644 --- a/src/EditorFeatures/Core/EmbeddedLanguages/Json/JsonBraceMatcher.cs +++ b/src/Features/Core/Portable/EmbeddedLanguages/Json/LanguageServices/JsonBraceMatcher.cs @@ -6,16 +6,13 @@ using System.Composition; using System.Threading; using Microsoft.CodeAnalysis.BraceMatching; -using Microsoft.CodeAnalysis.Editor; using Microsoft.CodeAnalysis.EmbeddedLanguages; using Microsoft.CodeAnalysis.EmbeddedLanguages.Common; using Microsoft.CodeAnalysis.EmbeddedLanguages.VirtualChars; -using Microsoft.CodeAnalysis.Features.EmbeddedLanguages.Json; -using Microsoft.CodeAnalysis.Features.EmbeddedLanguages.Json.LanguageServices; using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.Shared.Extensions; -namespace Microsoft.CodeAnalysis.EmbeddedLanguages.Json +namespace Microsoft.CodeAnalysis.Features.EmbeddedLanguages.Json.LanguageServices { using JsonToken = EmbeddedSyntaxToken; diff --git a/src/Features/Core/Portable/EmbeddedLanguages/Json/LanguageServices/JsonLanguageDetector.cs b/src/Features/Core/Portable/EmbeddedLanguages/Json/LanguageServices/JsonLanguageDetector.cs index 5a447931f040f..dd60351bf5a0c 100644 --- a/src/Features/Core/Portable/EmbeddedLanguages/Json/LanguageServices/JsonLanguageDetector.cs +++ b/src/Features/Core/Portable/EmbeddedLanguages/Json/LanguageServices/JsonLanguageDetector.cs @@ -11,7 +11,7 @@ using System.Threading; using Microsoft.CodeAnalysis.EmbeddedLanguages; using Microsoft.CodeAnalysis.EmbeddedLanguages.VirtualChars; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Shared.Extensions; using Roslyn.Utilities; diff --git a/src/EditorFeatures/Core/EmbeddedLanguages/RegularExpressions/RegexBraceMatcher.cs b/src/Features/Core/Portable/EmbeddedLanguages/RegularExpressions/LanguageServices/RegexBraceMatcher.cs similarity index 96% rename from src/EditorFeatures/Core/EmbeddedLanguages/RegularExpressions/RegexBraceMatcher.cs rename to src/Features/Core/Portable/EmbeddedLanguages/RegularExpressions/LanguageServices/RegexBraceMatcher.cs index ad557e7d64b1e..fdc89b1d4de59 100644 --- a/src/EditorFeatures/Core/EmbeddedLanguages/RegularExpressions/RegexBraceMatcher.cs +++ b/src/Features/Core/Portable/EmbeddedLanguages/RegularExpressions/LanguageServices/RegexBraceMatcher.cs @@ -7,14 +7,14 @@ using System.Composition; using System.Threading; using Microsoft.CodeAnalysis.BraceMatching; -using Microsoft.CodeAnalysis.Editor; +using Microsoft.CodeAnalysis.EmbeddedLanguages; using Microsoft.CodeAnalysis.EmbeddedLanguages.Common; +using Microsoft.CodeAnalysis.EmbeddedLanguages.RegularExpressions; using Microsoft.CodeAnalysis.EmbeddedLanguages.VirtualChars; -using Microsoft.CodeAnalysis.Features.EmbeddedLanguages.RegularExpressions.LanguageServices; using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.Shared.Extensions; -namespace Microsoft.CodeAnalysis.EmbeddedLanguages.RegularExpressions +namespace Microsoft.CodeAnalysis.Features.EmbeddedLanguages.RegularExpressions.LanguageServices { using RegexToken = EmbeddedSyntaxToken; using RegexTrivia = EmbeddedSyntaxTrivia; diff --git a/src/Features/Core/Portable/EmbeddedLanguages/RegularExpressions/LanguageServices/RegexLanguageDetector.cs b/src/Features/Core/Portable/EmbeddedLanguages/RegularExpressions/LanguageServices/RegexLanguageDetector.cs index 88e22b2dc30f9..900a6b5d829e0 100644 --- a/src/Features/Core/Portable/EmbeddedLanguages/RegularExpressions/LanguageServices/RegexLanguageDetector.cs +++ b/src/Features/Core/Portable/EmbeddedLanguages/RegularExpressions/LanguageServices/RegexLanguageDetector.cs @@ -12,7 +12,7 @@ using Microsoft.CodeAnalysis.EmbeddedLanguages; using Microsoft.CodeAnalysis.EmbeddedLanguages.RegularExpressions; using Microsoft.CodeAnalysis.EmbeddedLanguages.VirtualChars; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Shared.Extensions; using Roslyn.Utilities; diff --git a/src/Features/Core/Portable/Emit/CompilationOutputs.cs b/src/Features/Core/Portable/Emit/CompilationOutputs.cs index 824b7e2a68966..6b53a87de67e5 100644 --- a/src/Features/Core/Portable/Emit/CompilationOutputs.cs +++ b/src/Features/Core/Portable/Emit/CompilationOutputs.cs @@ -7,6 +7,8 @@ using System.Linq; using System.Reflection.Metadata; using System.Reflection.PortableExecutable; +using System.Threading; +using System.Threading.Tasks; using Microsoft.CodeAnalysis.Debugging; namespace Microsoft.CodeAnalysis.Emit @@ -148,5 +150,29 @@ internal virtual Guid ReadAssemblyModuleVersionId() /// /// New instance or null if the compiler generated no PDB (the symbols might be embedded in the assembly). protected abstract Stream? OpenPdbStream(); + + internal async ValueTask TryCopyAssemblyToAsync(Stream stream, CancellationToken cancellationToken) + { + var peImage = OpenAssemblyStreamChecked(); + if (peImage == null) + { + return false; + } + + await peImage.CopyToAsync(stream, bufferSize: 4 * 1024, cancellationToken).ConfigureAwait(false); + return true; + } + + internal async ValueTask TryCopyPdbToAsync(Stream stream, CancellationToken cancellationToken) + { + var pdb = OpenPdb(); + if (pdb == null) + { + return false; + } + + await pdb.CopyContentToAsync(stream, cancellationToken).ConfigureAwait(false); + return true; + } } } diff --git a/src/Features/Core/Portable/EncapsulateField/AbstractEncapsulateFieldService.cs b/src/Features/Core/Portable/EncapsulateField/AbstractEncapsulateFieldService.cs index eb9f6c39f1fc7..988746212db0d 100644 --- a/src/Features/Core/Portable/EncapsulateField/AbstractEncapsulateFieldService.cs +++ b/src/Features/Core/Portable/EncapsulateField/AbstractEncapsulateFieldService.cs @@ -21,6 +21,7 @@ using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Remote; using Microsoft.CodeAnalysis.Rename; +using Microsoft.CodeAnalysis.Rename.ConflictEngine; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Simplification; using Microsoft.CodeAnalysis.Text; @@ -109,7 +110,7 @@ public async Task EncapsulateFieldsAsync( using (Logger.LogBlock(FunctionId.Renamer_FindRenameLocationsAsync, cancellationToken)) { var solution = document.Project.Solution; - var client = await RemoteHostClient.TryGetClientAsync(solution.Workspace, cancellationToken).ConfigureAwait(false); + var client = await RemoteHostClient.TryGetClientAsync(solution.Services, cancellationToken).ConfigureAwait(false); if (client != null) { var fieldSymbolKeys = fields.SelectAsArray(f => SymbolKey.CreateString(f, cancellationToken)); @@ -117,7 +118,7 @@ public async Task EncapsulateFieldsAsync( var result = await client.TryInvokeAsync)>>( solution, (service, solutionInfo, callbackId, cancellationToken) => service.EncapsulateFieldsAsync(solutionInfo, callbackId, document.Id, fieldSymbolKeys, updateReferences, cancellationToken), - callbackTarget: new RemoteOptionsProvider(solution.Workspace.Services, fallbackOptions), + callbackTarget: new RemoteOptionsProvider(solution.Services, fallbackOptions), cancellationToken).ConfigureAwait(false); if (!result.HasValue) @@ -265,12 +266,12 @@ private async Task UpdateReferencesAsync( if (field.IsReadOnly) { // Inside the constructor we want to rename references the field to the final field name. - var constructorLocations = GetConstructorLocations(field.ContainingType); + var constructorLocations = GetConstructorLocations(solution, field.ContainingType); if (finalFieldName != field.Name && constructorLocations.Count > 0) { solution = await RenameAsync( solution, field, finalFieldName, - location => IntersectsWithAny(location, constructorLocations), + (docId, span) => IntersectsWithAny(docId, span, constructorLocations), fallbackOptions, cancellationToken).ConfigureAwait(false); @@ -278,13 +279,13 @@ private async Task UpdateReferencesAsync( var compilation = await document.Project.GetCompilationAsync(cancellationToken).ConfigureAwait(false); field = field.GetSymbolKey(cancellationToken).Resolve(compilation, cancellationToken: cancellationToken).Symbol as IFieldSymbol; - constructorLocations = GetConstructorLocations(field.ContainingType); + constructorLocations = GetConstructorLocations(solution, field.ContainingType); } // Outside the constructor we want to rename references to the field to final property name. return await RenameAsync( solution, field, generatedPropertyName, - location => !IntersectsWithAny(location, constructorLocations), + (documentId, span) => !IntersectsWithAny(documentId, span, constructorLocations), fallbackOptions, cancellationToken).ConfigureAwait(false); } @@ -300,7 +301,7 @@ private static async Task RenameAsync( Solution solution, IFieldSymbol field, string finalName, - Func filter, + Func filter, CodeCleanupOptionsProvider fallbackOptions, CancellationToken cancellationToken) { @@ -314,26 +315,29 @@ private static async Task RenameAsync( solution, field, options, fallbackOptions, cancellationToken).ConfigureAwait(false); var resolution = await initialLocations.Filter(filter).ResolveConflictsAsync( - finalName, nonConflictSymbols: null, cancellationToken).ConfigureAwait(false); + field, finalName, nonConflictSymbolKeys: default, cancellationToken).ConfigureAwait(false); - Contract.ThrowIfTrue(resolution.ErrorMessage != null); + Contract.ThrowIfFalse(resolution.IsSuccessful); return resolution.NewSolution; } - private static bool IntersectsWithAny(Location location, ISet constructorLocations) + private static bool IntersectsWithAny(DocumentId documentId, TextSpan span, ISet<(DocumentId documentId, TextSpan span)> constructorLocations) { foreach (var constructor in constructorLocations) { - if (location.IntersectsWith(constructor)) + if (constructor.documentId == documentId && + span.IntersectsWith(constructor.span)) + { return true; + } } return false; } - private ISet GetConstructorLocations(INamedTypeSymbol containingType) - => GetConstructorNodes(containingType).Select(n => n.GetLocation()).ToSet(); + private ISet<(DocumentId documentId, TextSpan span)> GetConstructorLocations(Solution solution, INamedTypeSymbol containingType) + => GetConstructorNodes(containingType).Select(n => (solution.GetRequiredDocument(n.SyntaxTree).Id, n.Span)).ToSet(); internal abstract IEnumerable GetConstructorNodes(INamedTypeSymbol containingType); diff --git a/src/Features/Core/Portable/ExternalAccess/Pythia/Api/PythiaCompletionProviderBase.cs b/src/Features/Core/Portable/ExternalAccess/Pythia/Api/PythiaCompletionProviderBase.cs index 14ae26946b567..34d8a68bcad77 100644 --- a/src/Features/Core/Portable/ExternalAccess/Pythia/Api/PythiaCompletionProviderBase.cs +++ b/src/Features/Core/Portable/ExternalAccess/Pythia/Api/PythiaCompletionProviderBase.cs @@ -9,7 +9,7 @@ using System.Threading.Tasks; using Microsoft.CodeAnalysis.Completion; using Microsoft.CodeAnalysis.Completion.Providers; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Shared.Utilities; using Microsoft.CodeAnalysis.Text; diff --git a/src/Features/Core/Portable/ExternalAccess/Pythia/Api/PythiaSymbolSorting.cs b/src/Features/Core/Portable/ExternalAccess/Pythia/Api/PythiaSymbolSorting.cs index 141d21e46464b..71021bc988992 100644 --- a/src/Features/Core/Portable/ExternalAccess/Pythia/Api/PythiaSymbolSorting.cs +++ b/src/Features/Core/Portable/ExternalAccess/Pythia/Api/PythiaSymbolSorting.cs @@ -3,7 +3,7 @@ // See the LICENSE file in the project root for more information. using System.Collections.Immutable; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; namespace Microsoft.CodeAnalysis.ExternalAccess.Pythia.Api { diff --git a/src/Features/Core/Portable/ExternalAccess/UnitTesting/API/UnitTestingHotReloadService.cs b/src/Features/Core/Portable/ExternalAccess/UnitTesting/API/UnitTestingHotReloadService.cs index abe08f1925be1..ba83a7954bcda 100644 --- a/src/Features/Core/Portable/ExternalAccess/UnitTesting/API/UnitTestingHotReloadService.cs +++ b/src/Features/Core/Portable/ExternalAccess/UnitTesting/API/UnitTestingHotReloadService.cs @@ -115,7 +115,7 @@ public async Task StartSessionAsync(Solution solution, ImmutableArray ca .EmitSolutionUpdateAsync(sessionId, solution, s_solutionActiveStatementSpanProvider, cancellationToken) .ConfigureAwait(false); - if (results.ModuleUpdates.Status == ManagedModuleUpdateStatus.Ready) + if (results.ModuleUpdates.Status == ModuleUpdateStatus.Ready) { if (commitUpdates) { diff --git a/src/Features/Core/Portable/ExternalAccess/VSTypeScript/Api/IVSTypeScriptCommentSlectionServiceImplementation.cs b/src/Features/Core/Portable/ExternalAccess/VSTypeScript/Api/IVSTypeScriptCommentSlectionServiceImplementation.cs index c87538e6e1721..8bfc75bf0de46 100644 --- a/src/Features/Core/Portable/ExternalAccess/VSTypeScript/Api/IVSTypeScriptCommentSlectionServiceImplementation.cs +++ b/src/Features/Core/Portable/ExternalAccess/VSTypeScript/Api/IVSTypeScriptCommentSlectionServiceImplementation.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +using System; using System.Collections.Immutable; using System.Threading; using System.Threading.Tasks; @@ -10,6 +11,7 @@ namespace Microsoft.CodeAnalysis.ExternalAccess.VSTypeScript.Api { + [Obsolete] internal interface IVSTypeScriptCommentSelectionServiceImplementation : ILanguageService { Task GetInfoAsync(Document document, TextSpan textSpan, CancellationToken cancellationToken); diff --git a/src/Features/Core/Portable/ExternalAccess/VSTypeScript/Api/VSTypeScriptCommentSelectionInfo.cs b/src/Features/Core/Portable/ExternalAccess/VSTypeScript/Api/VSTypeScriptCommentSelectionInfo.cs index f68ef72abc08b..8d08f300f6b71 100644 --- a/src/Features/Core/Portable/ExternalAccess/VSTypeScript/Api/VSTypeScriptCommentSelectionInfo.cs +++ b/src/Features/Core/Portable/ExternalAccess/VSTypeScript/Api/VSTypeScriptCommentSelectionInfo.cs @@ -2,10 +2,12 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +using System; using Microsoft.CodeAnalysis.CommentSelection; namespace Microsoft.CodeAnalysis.ExternalAccess.VSTypeScript.Api { + [Obsolete] internal readonly struct VSTypeScriptCommentSelectionInfo { internal readonly CommentSelectionInfo UnderlyingObject; diff --git a/src/Features/Core/Portable/ExternalAccess/VSTypeScript/Api/VSTypeScriptCompletionProvider.cs b/src/Features/Core/Portable/ExternalAccess/VSTypeScript/Api/VSTypeScriptCompletionProvider.cs index 5442c773800ce..31136a1d4cc32 100644 --- a/src/Features/Core/Portable/ExternalAccess/VSTypeScript/Api/VSTypeScriptCompletionProvider.cs +++ b/src/Features/Core/Portable/ExternalAccess/VSTypeScript/Api/VSTypeScriptCompletionProvider.cs @@ -18,7 +18,7 @@ public sealed override bool ShouldTriggerCompletion(SourceText text, int caretPo return ShouldTriggerCompletionImpl(text, caretPosition, trigger, CompletionOptions.Default.TriggerOnTypingLetters); } - internal sealed override bool ShouldTriggerCompletion(HostLanguageServices languageServices, SourceText text, int caretPosition, CompletionTrigger trigger, CompletionOptions options, OptionSet passThroughOptions) + internal sealed override bool ShouldTriggerCompletion(LanguageServices languageServices, SourceText text, int caretPosition, CompletionTrigger trigger, CompletionOptions options, OptionSet passThroughOptions) => ShouldTriggerCompletionImpl(text, caretPosition, trigger, options.TriggerOnTypingLetters); protected abstract bool ShouldTriggerCompletionImpl(SourceText text, int caretPosition, CompletionTrigger trigger, bool triggerOnTypingLetters); diff --git a/src/Features/Core/Portable/ExternalAccess/VSTypeScript/Api/VSTypeScriptCompletionServiceWithProviders.cs b/src/Features/Core/Portable/ExternalAccess/VSTypeScript/Api/VSTypeScriptCompletionServiceWithProviders.cs index 9100c2e190eec..b94ba57548138 100644 --- a/src/Features/Core/Portable/ExternalAccess/VSTypeScript/Api/VSTypeScriptCompletionServiceWithProviders.cs +++ b/src/Features/Core/Portable/ExternalAccess/VSTypeScript/Api/VSTypeScriptCompletionServiceWithProviders.cs @@ -5,6 +5,7 @@ using System; using System.Collections.Generic; using Microsoft.CodeAnalysis.Completion; +using Microsoft.CodeAnalysis.Host; using Microsoft.CodeAnalysis.PatternMatching; using Roslyn.Utilities; @@ -13,7 +14,7 @@ namespace Microsoft.CodeAnalysis.ExternalAccess.VSTypeScript.Api internal abstract class VSTypeScriptCompletionServiceWithProviders : CompletionService { internal VSTypeScriptCompletionServiceWithProviders(Workspace workspace) - : base(workspace) + : base(workspace.Services.SolutionServices) { } diff --git a/src/Features/Core/Portable/ExternalAccess/VSTypeScript/VSTypeScriptCommentSelectionService.cs b/src/Features/Core/Portable/ExternalAccess/VSTypeScript/VSTypeScriptCommentSelectionService.cs index 86c991686eb9e..59bf12fb8e7bd 100644 --- a/src/Features/Core/Portable/ExternalAccess/VSTypeScript/VSTypeScriptCommentSelectionService.cs +++ b/src/Features/Core/Portable/ExternalAccess/VSTypeScript/VSTypeScriptCommentSelectionService.cs @@ -19,32 +19,18 @@ namespace Microsoft.CodeAnalysis.ExternalAccess.VSTypeScript [ExportLanguageService(typeof(ICommentSelectionService), InternalLanguageNames.TypeScript), Shared] internal sealed class VSTypeScriptCommentSelectionService : ICommentSelectionService { - private readonly IVSTypeScriptCommentSelectionServiceImplementation? _impl; - [ImportingConstructor] [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] - public VSTypeScriptCommentSelectionService( - // Optional to work around test issue: https://github.com/dotnet/roslyn/issues/60690 - [Import(AllowDefault = true)] IVSTypeScriptCommentSelectionServiceImplementation? impl) - { - _impl = impl; - } - - public async Task GetInfoAsync(Document document, TextSpan textSpan, CancellationToken cancellationToken) + public VSTypeScriptCommentSelectionService() { - // Will never be null in product. - Contract.ThrowIfNull(_impl); - - var info = await _impl.GetInfoAsync(document, textSpan, cancellationToken).ConfigureAwait(false); - return info.UnderlyingObject; } - public Task FormatAsync(Document document, ImmutableArray changes, SyntaxFormattingOptions formattingOptions, CancellationToken cancellationToken) - { - // Will never be null in product. - Contract.ThrowIfNull(_impl); - - return _impl.FormatAsync(document, changes, cancellationToken); - } + public CommentSelectionInfo GetInfo() + => new( + supportsSingleLineComment: true, + supportsBlockComment: true, + singleLineCommentString: "//", + blockCommentStartString: "/*", + blockCommentEndString: "*/"); } } diff --git a/src/Features/Core/Portable/ExternalAccess/VSTypeScript/VSTypeScriptDocumentDiagnosticAnalyzer.cs b/src/Features/Core/Portable/ExternalAccess/VSTypeScript/VSTypeScriptDocumentDiagnosticAnalyzer.cs index 4dece56baec88..dcf9068cfa9b8 100644 --- a/src/Features/Core/Portable/ExternalAccess/VSTypeScript/VSTypeScriptDocumentDiagnosticAnalyzer.cs +++ b/src/Features/Core/Portable/ExternalAccess/VSTypeScript/VSTypeScriptDocumentDiagnosticAnalyzer.cs @@ -17,7 +17,7 @@ internal sealed class VSTypeScriptDocumentDiagnosticAnalyzer : DocumentDiagnosti public override Task> AnalyzeSyntaxAsync(Document document, CancellationToken cancellationToken) { - var analyzer = document.Project.LanguageServices.GetRequiredService().Implementation; + var analyzer = document.Project.Services.GetRequiredService().Implementation; if (analyzer == null) { return SpecializedTasks.EmptyImmutableArray(); @@ -28,7 +28,7 @@ public override Task> AnalyzeSyntaxAsync(Document doc public override Task> AnalyzeSemanticsAsync(Document document, CancellationToken cancellationToken) { - var analyzer = document.Project.LanguageServices.GetRequiredService().Implementation; + var analyzer = document.Project.Services.GetRequiredService().Implementation; if (analyzer == null) { return SpecializedTasks.EmptyImmutableArray(); diff --git a/src/Features/Core/Portable/ExternalAccess/VSTypeScript/VSTypeScriptProjectDiagnosticAnalyzer.cs b/src/Features/Core/Portable/ExternalAccess/VSTypeScript/VSTypeScriptProjectDiagnosticAnalyzer.cs index fcc82e9d7b65e..4e1ba8754c201 100644 --- a/src/Features/Core/Portable/ExternalAccess/VSTypeScript/VSTypeScriptProjectDiagnosticAnalyzer.cs +++ b/src/Features/Core/Portable/ExternalAccess/VSTypeScript/VSTypeScriptProjectDiagnosticAnalyzer.cs @@ -17,7 +17,7 @@ internal sealed class VSTypeScriptProjectDiagnosticAnalyzer : ProjectDiagnosticA public override Task> AnalyzeProjectAsync(Project project, CancellationToken cancellationToken) { - var analyzer = project.LanguageServices.GetRequiredService().Implementation; + var analyzer = project.Services.GetRequiredService().Implementation; if (analyzer == null) { return SpecializedTasks.EmptyImmutableArray(); diff --git a/src/Features/Core/Portable/ExternalAccess/Watch/Api/WatchHotReloadService.cs b/src/Features/Core/Portable/ExternalAccess/Watch/Api/WatchHotReloadService.cs index d9efe3de63314..f66c2c1517f25 100644 --- a/src/Features/Core/Portable/ExternalAccess/Watch/Api/WatchHotReloadService.cs +++ b/src/Features/Core/Portable/ExternalAccess/Watch/Api/WatchHotReloadService.cs @@ -98,7 +98,7 @@ public async Task StartSessionAsync(Solution solution, CancellationToken cancell var results = await _encService.EmitSolutionUpdateAsync(sessionId, solution, s_solutionActiveStatementSpanProvider, cancellationToken).ConfigureAwait(false); - if (results.ModuleUpdates.Status == ManagedModuleUpdateStatus.Ready) + if (results.ModuleUpdates.Status == ModuleUpdateStatus.Ready) { _encService.CommitSolutionUpdate(sessionId, out _); } diff --git a/src/Features/Core/Portable/ExtractClass/AbstractExtractClassRefactoringProvider.cs b/src/Features/Core/Portable/ExtractClass/AbstractExtractClassRefactoringProvider.cs index 6cded1b24ebad..d4c5a372230a4 100644 --- a/src/Features/Core/Portable/ExtractClass/AbstractExtractClassRefactoringProvider.cs +++ b/src/Features/Core/Portable/ExtractClass/AbstractExtractClassRefactoringProvider.cs @@ -3,12 +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.Tasks; using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeRefactorings; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.PullMemberUp; using Microsoft.CodeAnalysis.Shared.Extensions; +using Microsoft.CodeAnalysis.Text; using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.ExtractClass @@ -22,7 +25,7 @@ public AbstractExtractClassRefactoringProvider(IExtractClassOptionsService? serv _optionsService = service; } - protected abstract Task GetSelectedNodeAsync(CodeRefactoringContext context); + protected abstract Task> GetSelectedNodesAsync(CodeRefactoringContext context); protected abstract Task GetSelectedClassDeclarationAsync(CodeRefactoringContext context); public override async Task ComputeRefactoringsAsync(CodeRefactoringContext context) @@ -31,12 +34,13 @@ public override async Task ComputeRefactoringsAsync(CodeRefactoringContext conte // cases that won't work because the refactoring may try to add a document. There's non-trivial // work to support a user interaction that makes sense for those cases. // See: https://github.com/dotnet/roslyn/issues/50868 - if (!context.Document.Project.Solution.Workspace.CanApplyChange(ApplyChangesKind.AddDocument)) + var solution = context.Document.Project.Solution; + if (!solution.CanApplyChange(ApplyChangesKind.AddDocument)) { return; } - var optionsService = _optionsService ?? context.Document.Project.Solution.Workspace.Services.GetService(); + var optionsService = _optionsService ?? solution.Services.GetService(); if (optionsService is null) { return; @@ -55,28 +59,36 @@ public override async Task ComputeRefactoringsAsync(CodeRefactoringContext conte private async Task TryGetMemberActionAsync(CodeRefactoringContext context, IExtractClassOptionsService optionsService) { - var selectedMemberNode = await GetSelectedNodeAsync(context).ConfigureAwait(false); - if (selectedMemberNode is null) + var selectedMemberNodes = await GetSelectedNodesAsync(context).ConfigureAwait(false); + if (selectedMemberNodes.IsEmpty) { return null; } var (document, span, cancellationToken) = context; var semanticModel = await document.GetRequiredSemanticModelAsync(cancellationToken).ConfigureAwait(false); - var selectedMember = semanticModel.GetDeclaredSymbol(selectedMemberNode, cancellationToken); - if (selectedMember is null || selectedMember.ContainingType is null) - { - return null; - } + var memberNodeSymbolPairs = selectedMemberNodes + .SelectAsArray(m => (node: m, symbol: semanticModel.GetRequiredDeclaredSymbol(m, cancellationToken))) + // Use same logic as pull members up for determining if a selected member + // is valid to be moved into a base + .WhereAsArray(pair => MemberAndDestinationValidator.IsMemberValid(pair.symbol)); - // Use same logic as pull members up for determining if a selected member - // is valid to be moved into a base - if (!MemberAndDestinationValidator.IsMemberValid(selectedMember)) + if (memberNodeSymbolPairs.IsEmpty) { return null; } - var containingType = selectedMember.ContainingType; + var selectedMembers = memberNodeSymbolPairs.SelectAsArray(pair => pair.symbol); + + var containingType = selectedMembers.First().ContainingType; + Contract.ThrowIfNull(containingType); + + // Treat the entire nodes' span as the span of interest here. That way if the user's location is closer to + // a refactoring with a narrower span (for example, a span just on the name/parameters of a member, then it + // will take precedence over us). + var memberSpan = TextSpan.FromBounds( + memberNodeSymbolPairs.First().node.FullSpan.Start, + memberNodeSymbolPairs.Last().node.FullSpan.End); // Can't extract to a new type if there's already a base. Maybe // in the future we could inject a new type inbetween base and @@ -87,14 +99,15 @@ public override async Task ComputeRefactoringsAsync(CodeRefactoringContext conte } var syntaxFacts = document.GetRequiredLanguageService(); - var containingTypeDeclarationNode = selectedMemberNode.FirstAncestorOrSelf(syntaxFacts.IsTypeDeclaration); + var containingTypeDeclarationNode = selectedMemberNodes.First().FirstAncestorOrSelf(syntaxFacts.IsTypeDeclaration); Contract.ThrowIfNull(containingTypeDeclarationNode); + if (selectedMemberNodes.Any(m => m.FirstAncestorOrSelf(syntaxFacts.IsTypeDeclaration) != containingTypeDeclarationNode)) + { + return null; + } - // Treat the entire node's span as the span of interest here. That way if the user's location is closer to - // a refactoring with a narrower span (for example, a span just on the name/parameters of a member, then it - // will take precedence over us). return new ExtractClassWithDialogCodeAction( - document, selectedMemberNode.Span, optionsService, containingType, containingTypeDeclarationNode, context.Options, selectedMember); + document, memberSpan, optionsService, containingType, containingTypeDeclarationNode, context.Options, selectedMembers); } private async Task TryGetClassActionAsync(CodeRefactoringContext context, IExtractClassOptionsService optionsService) @@ -110,7 +123,7 @@ public override async Task ComputeRefactoringsAsync(CodeRefactoringContext conte return null; return new ExtractClassWithDialogCodeAction( - document, span, optionsService, originalType, selectedClassNode, context.Options, selectedMember: null); + document, span, optionsService, originalType, selectedClassNode, context.Options, selectedMembers: ImmutableArray.Empty); } } } diff --git a/src/Features/Core/Portable/ExtractClass/ExtractClassWithDialogCodeAction.cs b/src/Features/Core/Portable/ExtractClass/ExtractClassWithDialogCodeAction.cs index a273f6a2db893..7bcafac023831 100644 --- a/src/Features/Core/Portable/ExtractClass/ExtractClassWithDialogCodeAction.cs +++ b/src/Features/Core/Portable/ExtractClass/ExtractClassWithDialogCodeAction.cs @@ -13,7 +13,7 @@ using Microsoft.CodeAnalysis.CodeRefactorings.PullMemberUp; using Microsoft.CodeAnalysis.Editing; using Microsoft.CodeAnalysis.ExtractInterface; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Shared.Utilities; @@ -25,14 +25,16 @@ namespace Microsoft.CodeAnalysis.ExtractClass internal class ExtractClassWithDialogCodeAction : CodeActionWithOptions { private readonly Document _document; - private readonly ISymbol? _selectedMember; + private readonly ImmutableArray _selectedMembers; private readonly INamedTypeSymbol _selectedType; private readonly SyntaxNode _selectedTypeDeclarationNode; private readonly CleanCodeGenerationOptionsProvider _fallbackOptions; private readonly IExtractClassOptionsService _service; public TextSpan Span { get; } - public override string Title => FeaturesResources.Extract_base_class; + public override string Title => _selectedType.IsRecord + ? FeaturesResources.Extract_base_record + : FeaturesResources.Extract_base_class; internal override CodeActionPriority Priority { get; } @@ -43,106 +45,105 @@ public ExtractClassWithDialogCodeAction( INamedTypeSymbol selectedType, SyntaxNode selectedTypeDeclarationNode, CleanCodeGenerationOptionsProvider fallbackOptions, - ISymbol? selectedMember) + ImmutableArray selectedMembers) { _document = document; _service = service; _selectedType = selectedType; _selectedTypeDeclarationNode = selectedTypeDeclarationNode; _fallbackOptions = fallbackOptions; - _selectedMember = selectedMember; + _selectedMembers = selectedMembers; Span = span; // If the user brought up the lightbulb on a class itself, it's more likely that they want to extract a base // class. on a member however, we deprioritize this as there are likely more member-specific operations // they'd prefer to invoke instead. - Priority = selectedMember is null ? CodeActionPriority.Medium : CodeActionPriority.Low; + Priority = selectedMembers.IsEmpty ? CodeActionPriority.Medium : CodeActionPriority.Low; } public override object? GetOptions(CancellationToken cancellationToken) { - var extractClassService = _service ?? _document.Project.Solution.Workspace.Services.GetRequiredService(); - return extractClassService.GetExtractClassOptionsAsync(_document, _selectedType, _selectedMember, cancellationToken) + var extractClassService = _service ?? _document.Project.Solution.Services.GetRequiredService(); + return extractClassService.GetExtractClassOptionsAsync(_document, _selectedType, _selectedMembers, cancellationToken) .WaitAndGetResult_CanCallOnBackground(cancellationToken); } protected override async Task> ComputeOperationsAsync(object options, CancellationToken cancellationToken) { - if (options is ExtractClassOptions extractClassOptions) + if (options is not ExtractClassOptions extractClassOptions) { - // Map the symbols we're removing to annotations - // so we can find them easily - var codeGenerator = _document.GetRequiredLanguageService(); - var symbolMapping = await AnnotatedSymbolMapping.CreateAsync( - extractClassOptions.MemberAnalysisResults.Select(m => m.Member), - _document.Project.Solution, - _selectedTypeDeclarationNode, - cancellationToken).ConfigureAwait(false); + // If user click cancel button, options will be null and hit this branch + return SpecializedCollections.EmptyEnumerable(); + } - var namespaceService = _document.GetRequiredLanguageService(); - - // Create the symbol for the new type - var newType = CodeGenerationSymbolFactory.CreateNamedTypeSymbol( - _selectedType.GetAttributes(), - _selectedType.DeclaredAccessibility, - _selectedType.GetSymbolModifiers(), - TypeKind.Class, - extractClassOptions.TypeName, - typeParameters: ExtractTypeHelpers.GetRequiredTypeParametersForMembers(_selectedType, extractClassOptions.MemberAnalysisResults.Select(m => m.Member))); - - var containingNamespaceDisplay = namespaceService.GetContainingNamespaceDisplay( - _selectedType, - _document.Project.CompilationOptions); - - // Add the new type to the solution. It can go in a new file or - // be added to an existing. The returned document is always the document - // containing the new type - var (updatedDocument, typeAnnotation) = extractClassOptions.SameFile - ? await ExtractTypeHelpers.AddTypeToExistingFileAsync( - symbolMapping.AnnotatedSolution.GetRequiredDocument(_document.Id), - newType, - symbolMapping, - _fallbackOptions, - cancellationToken).ConfigureAwait(false) - : await ExtractTypeHelpers.AddTypeToNewFileAsync( - symbolMapping.AnnotatedSolution, - containingNamespaceDisplay, - extractClassOptions.FileName, - _document.Project.Id, - _document.Folders, - newType, - _document, - _fallbackOptions, - cancellationToken).ConfigureAwait(false); - - // Update the original type to have the new base - var solutionWithUpdatedOriginalType = await GetSolutionWithBaseAddedAsync( - updatedDocument.Project.Solution, - symbolMapping, + // Map the symbols we're removing to annotations + // so we can find them easily + var codeGenerator = _document.GetRequiredLanguageService(); + var symbolMapping = await AnnotatedSymbolMapping.CreateAsync( + extractClassOptions.MemberAnalysisResults.Select(m => m.Member), + _document.Project.Solution, + _selectedTypeDeclarationNode, + cancellationToken).ConfigureAwait(false); + + var namespaceService = _document.GetRequiredLanguageService(); + + // Create the symbol for the new type + var newType = CodeGenerationSymbolFactory.CreateNamedTypeSymbol( + _selectedType.GetAttributes(), + _selectedType.DeclaredAccessibility, + _selectedType.GetSymbolModifiers(), + _selectedType.IsRecord, + TypeKind.Class, + extractClassOptions.TypeName, + typeParameters: ExtractTypeHelpers.GetRequiredTypeParametersForMembers(_selectedType, extractClassOptions.MemberAnalysisResults.Select(m => m.Member))); + + var containingNamespaceDisplay = namespaceService.GetContainingNamespaceDisplay( + _selectedType, + _document.Project.CompilationOptions); + + // Add the new type to the solution. It can go in a new file or + // be added to an existing. The returned document is always the document + // containing the new type + var (updatedDocument, typeAnnotation) = extractClassOptions.SameFile + ? await ExtractTypeHelpers.AddTypeToExistingFileAsync( + symbolMapping.AnnotatedSolution.GetRequiredDocument(_document.Id), newType, - extractClassOptions.MemberAnalysisResults, - cancellationToken).ConfigureAwait(false); - - // After all the changes, make sure we're using the most up to date symbol - // as the destination for pulling members into - var documentWithTypeDeclaration = solutionWithUpdatedOriginalType.GetRequiredDocument(updatedDocument.Id); - var newTypeAfterEdits = await GetNewTypeSymbolAsync(documentWithTypeDeclaration, typeAnnotation, cancellationToken).ConfigureAwait(false); - - // Use Members Puller to move the members to the new symbol - var finalSolution = await PullMembersUpAsync( - solutionWithUpdatedOriginalType, - newTypeAfterEdits, symbolMapping, - extractClassOptions.MemberAnalysisResults, + _fallbackOptions, + cancellationToken).ConfigureAwait(false) + : await ExtractTypeHelpers.AddTypeToNewFileAsync( + symbolMapping.AnnotatedSolution, + containingNamespaceDisplay, + extractClassOptions.FileName, + _document.Project.Id, + _document.Folders, + newType, + _document, + _fallbackOptions, cancellationToken).ConfigureAwait(false); - return new[] { new ApplyChangesOperation(finalSolution) }; - } - else - { - // If user click cancel button, options will be null and hit this branch - return SpecializedCollections.EmptyEnumerable(); - } + // Update the original type to have the new base + var solutionWithUpdatedOriginalType = await GetSolutionWithBaseAddedAsync( + updatedDocument.Project.Solution, + symbolMapping, + newType, + extractClassOptions.MemberAnalysisResults, + cancellationToken).ConfigureAwait(false); + + // After all the changes, make sure we're using the most up to date symbol + // as the destination for pulling members into + var documentWithTypeDeclaration = solutionWithUpdatedOriginalType.GetRequiredDocument(updatedDocument.Id); + var newTypeAfterEdits = await GetNewTypeSymbolAsync(documentWithTypeDeclaration, typeAnnotation, cancellationToken).ConfigureAwait(false); + + // Use Members Puller to move the members to the new symbol + var finalSolution = await PullMembersUpAsync( + solutionWithUpdatedOriginalType, + newTypeAfterEdits, + symbolMapping, + extractClassOptions.MemberAnalysisResults, + cancellationToken).ConfigureAwait(false); + + return new[] { new ApplyChangesOperation(finalSolution) }; } private async Task PullMembersUpAsync( @@ -152,8 +153,8 @@ private async Task PullMembersUpAsync( ImmutableArray memberAnalysisResults, CancellationToken cancellationToken) { - using var _ = ArrayBuilder<(ISymbol member, bool makeAbstract)>.GetInstance(out var pullMembersBuilder); - using var _1 = ArrayBuilder.GetInstance(memberAnalysisResults.Length, out var remainingResults); + using var _1 = ArrayBuilder<(ISymbol member, bool makeAbstract)>.GetInstance(out var pullMembersBuilder); + using var _2 = ArrayBuilder.GetInstance(memberAnalysisResults.Length, out var remainingResults); remainingResults.AddRange(memberAnalysisResults); // For each document in the symbol mappings, we want to find the annotated nodes @@ -173,7 +174,7 @@ private async Task PullMembersUpAsync( var syntaxFacts = document.GetRequiredLanguageService(); var semanticModel = await document.GetRequiredSemanticModelAsync(cancellationToken).ConfigureAwait(false); var root = await document.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false); - using var _2 = ArrayBuilder.GetInstance(remainingResults.Count, out var resultsToRemove); + using var _3 = ArrayBuilder.GetInstance(remainingResults.Count, out var resultsToRemove); // Out of the remaining members that we need to move, does this // document contain the definition for that symbol? If so, add it to the builder diff --git a/src/Features/Core/Portable/ExtractClass/IExtractClassOptionsService.cs b/src/Features/Core/Portable/ExtractClass/IExtractClassOptionsService.cs index 3a8fb90d91357..c73db99b74e23 100644 --- a/src/Features/Core/Portable/ExtractClass/IExtractClassOptionsService.cs +++ b/src/Features/Core/Portable/ExtractClass/IExtractClassOptionsService.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +using System.Collections.Immutable; using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.Host; @@ -10,6 +11,6 @@ namespace Microsoft.CodeAnalysis.ExtractClass { internal interface IExtractClassOptionsService : IWorkspaceService { - Task GetExtractClassOptionsAsync(Document document, INamedTypeSymbol originalType, ISymbol? selectedMember, CancellationToken cancellationToken); + Task GetExtractClassOptionsAsync(Document document, INamedTypeSymbol originalType, ImmutableArray selectedMembers, CancellationToken cancellationToken); } } diff --git a/src/Features/Core/Portable/ExtractInterface/AbstractExtractInterfaceService.cs b/src/Features/Core/Portable/ExtractInterface/AbstractExtractInterfaceService.cs index 4b02de155e62f..8b15889567a05 100644 --- a/src/Features/Core/Portable/ExtractInterface/AbstractExtractInterfaceService.cs +++ b/src/Features/Core/Portable/ExtractInterface/AbstractExtractInterfaceService.cs @@ -16,7 +16,7 @@ using Microsoft.CodeAnalysis.Editing; using Microsoft.CodeAnalysis.Formatting; using Microsoft.CodeAnalysis.Host; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Notification; using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Shared.Extensions; @@ -272,11 +272,11 @@ internal static async Task GetExtractInterfaceOpt var candidateInterfaceName = type.TypeKind == TypeKind.Interface ? type.Name : "I" + type.Name; var defaultInterfaceName = NameGenerator.GenerateUniqueName(candidateInterfaceName, name => !conflictingTypeNames.Contains(name)); var syntaxFactsService = document.GetLanguageService(); - var notificationService = document.Project.Solution.Workspace.Services.GetService(); + var notificationService = document.Project.Solution.Services.GetService(); var formattingOptions = await document.GetSyntaxFormattingOptionsAsync(fallbackOptions, cancellationToken).ConfigureAwait(false); var generatedNameTypeParameterSuffix = ExtractTypeHelpers.GetTypeParameterSuffix(document, formattingOptions, type, extractableMembers, cancellationToken); - var service = document.Project.Solution.Workspace.Services.GetService(); + var service = document.Project.Solution.Services.GetService(); return await service.GetExtractInterfaceOptionsAsync( syntaxFactsService, notificationService, @@ -343,7 +343,7 @@ private async Task GetSolutionWithOriginalTypeUpdatedAsync( { var document = solution.GetDocument(documentId); var currentRoot = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); - var editor = new SyntaxEditor(currentRoot, solution.Workspace.Services); + var editor = new SyntaxEditor(currentRoot, solution.Services); var syntaxGenerator = SyntaxGenerator.GetGenerator(document); var typeReference = syntaxGenerator.TypeExpression(extractedInterfaceSymbol); diff --git a/src/Features/Core/Portable/ExtractInterface/IExtractInterfaceOptionsService.cs b/src/Features/Core/Portable/ExtractInterface/IExtractInterfaceOptionsService.cs index 01cb1c345bd04..dec07ec6b59fd 100644 --- a/src/Features/Core/Portable/ExtractInterface/IExtractInterfaceOptionsService.cs +++ b/src/Features/Core/Portable/ExtractInterface/IExtractInterfaceOptionsService.cs @@ -10,7 +10,7 @@ using Microsoft.CodeAnalysis.CodeCleanup; using Microsoft.CodeAnalysis.CodeGeneration; using Microsoft.CodeAnalysis.Host; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Notification; namespace Microsoft.CodeAnalysis.ExtractInterface diff --git a/src/Features/Core/Portable/ExtractMethod/AbstractSyntaxTriviaService.cs b/src/Features/Core/Portable/ExtractMethod/AbstractSyntaxTriviaService.cs index 7ae5049fd2133..42c50e3beac96 100644 --- a/src/Features/Core/Portable/ExtractMethod/AbstractSyntaxTriviaService.cs +++ b/src/Features/Core/Portable/ExtractMethod/AbstractSyntaxTriviaService.cs @@ -9,7 +9,7 @@ using System.Diagnostics; using System.Linq; using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Text; using Roslyn.Utilities; diff --git a/src/Features/Core/Portable/ExtractMethod/ExtractMethodResult.cs b/src/Features/Core/Portable/ExtractMethod/ExtractMethodResult.cs index 9e12986e6c5e7..29512b61a8670 100644 --- a/src/Features/Core/Portable/ExtractMethod/ExtractMethodResult.cs +++ b/src/Features/Core/Portable/ExtractMethod/ExtractMethodResult.cs @@ -95,7 +95,7 @@ internal ExtractMethodResult( var simplifiedDocument = await Simplifier.ReduceAsync(annotatedDocument, Simplifier.Annotation, cleanupOptions.SimplifierOptions, cancellationToken).ConfigureAwait(false); var simplifiedRoot = await simplifiedDocument.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false); - var services = DocumentWithoutFinalFormatting.Project.Solution.Workspace.Services; + var services = DocumentWithoutFinalFormatting.Project.Solution.Services; var formattedDocument = simplifiedDocument.WithSyntaxRoot( Formatter.Format(simplifiedRoot, Formatter.Annotation, services, cleanupOptions.FormattingOptions, FormattingRules, cancellationToken)); diff --git a/src/Features/Core/Portable/ExtractMethod/MethodExtractor.Analyzer.SymbolMapBuilder.cs b/src/Features/Core/Portable/ExtractMethod/MethodExtractor.Analyzer.SymbolMapBuilder.cs index ad7e030216acb..ce9102bf534d4 100644 --- a/src/Features/Core/Portable/ExtractMethod/MethodExtractor.Analyzer.SymbolMapBuilder.cs +++ b/src/Features/Core/Portable/ExtractMethod/MethodExtractor.Analyzer.SymbolMapBuilder.cs @@ -6,7 +6,7 @@ using System.Collections.Generic; using System.Threading; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Text; using Roslyn.Utilities; diff --git a/src/Features/Core/Portable/ExtractMethod/MethodExtractor.Analyzer.cs b/src/Features/Core/Portable/ExtractMethod/MethodExtractor.Analyzer.cs index 61b953af0485b..743fe3c251dcd 100644 --- a/src/Features/Core/Portable/ExtractMethod/MethodExtractor.Analyzer.cs +++ b/src/Features/Core/Portable/ExtractMethod/MethodExtractor.Analyzer.cs @@ -9,7 +9,7 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Shared.Extensions; using Roslyn.Utilities; @@ -348,7 +348,7 @@ private static Task CreateDocumentWithAnnotationsAsync(Semanti private Dictionary> GetSymbolMap(SemanticModel model) { - var syntaxFactsService = _semanticDocument.Document.Project.LanguageServices.GetService(); + var syntaxFactsService = _semanticDocument.Document.Project.Services.GetService(); var context = SelectionResult.GetContainingScope(); var symbolMap = SymbolMapBuilder.Build(syntaxFactsService, model, context, SelectionResult.FinalSpan, CancellationToken); return symbolMap; @@ -589,7 +589,7 @@ private bool IsWrittenInsideForFrameworkValueType( // we probably need to move the API to syntaxFact service not semanticFact. // // if one wants to get result that also considers semantic, he should use data control flow analysis API. - var semanticFacts = _semanticDocument.Document.Project.LanguageServices.GetRequiredService(); + var semanticFacts = _semanticDocument.Document.Project.Services.GetRequiredService(); return tokens.Any(t => semanticFacts.IsWrittenTo(model, t.Parent, CancellationToken.None)); } @@ -613,7 +613,7 @@ private bool SelectionContainsOnlyIdentifierWithSameType(ITypeSymbol type) private static bool UserDefinedValueType(Compilation compilation, ITypeSymbol type) { - if (!type.IsValueType || type.IsPointerType() || type.IsEnumType()) + if (!type.IsValueType || type is IPointerTypeSymbol || type.IsEnumType()) { return false; } @@ -912,7 +912,7 @@ private OperationStatus CheckReadOnlyFields(SemanticModel semanticModel, Diction } List? names = null; - var semanticFacts = _semanticDocument.Document.Project.LanguageServices.GetRequiredService(); + var semanticFacts = _semanticDocument.Document.Project.Services.GetRequiredService(); foreach (var pair in symbolMap.Where(p => p.Key.Kind == SymbolKind.Field)) { var field = (IFieldSymbol)pair.Key; diff --git a/src/Features/Core/Portable/ExtractMethod/SelectionResult.cs b/src/Features/Core/Portable/ExtractMethod/SelectionResult.cs index f5236e968d648..b77ea62268ce3 100644 --- a/src/Features/Core/Portable/ExtractMethod/SelectionResult.cs +++ b/src/Features/Core/Portable/ExtractMethod/SelectionResult.cs @@ -5,7 +5,7 @@ #nullable disable using System.Threading.Tasks; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Text; @@ -129,7 +129,7 @@ public bool ShouldPutAsyncModifier() // // for the case above, even if the selection contains "await", it doesn't belong to the enclosing block // which extract method is applied to - if (SemanticDocument.Project.LanguageServices.GetService().IsAwaitKeyword(currentToken) + if (SemanticDocument.Project.Services.GetService().IsAwaitKeyword(currentToken) && !UnderAnonymousOrLocalMethod(currentToken, firstToken, lastToken)) { return true; @@ -164,7 +164,7 @@ public bool ShouldCallConfigureAwaitFalse() private bool IsConfigureAwaitFalse(SyntaxNode node) { - var syntaxFacts = SemanticDocument.Project.LanguageServices.GetService(); + var syntaxFacts = SemanticDocument.Project.Services.GetService(); if (!syntaxFacts.IsInvocationExpression(node)) { return false; diff --git a/src/Features/Core/Portable/ExtractMethod/SelectionValidator.cs b/src/Features/Core/Portable/ExtractMethod/SelectionValidator.cs index aef1dfc561380..8644d736f6d6d 100644 --- a/src/Features/Core/Portable/ExtractMethod/SelectionValidator.cs +++ b/src/Features/Core/Portable/ExtractMethod/SelectionValidator.cs @@ -10,7 +10,7 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Text; diff --git a/src/Features/Core/Portable/FeaturesResources.resx b/src/Features/Core/Portable/FeaturesResources.resx index 8676a311179cf..acd04c3405ad7 100644 --- a/src/Features/Core/Portable/FeaturesResources.resx +++ b/src/Features/Core/Portable/FeaturesResources.resx @@ -625,12 +625,6 @@ Do you want to continue? Analyzer '{0}' threw the following exception: '{1}'. - - Simplify Names - - - Simplify Member Access - Remove qualification @@ -1151,12 +1145,6 @@ This version used in: {2} Add member name - - Use block body for lambda expressions - - - Use expression body for lambda expressions - Convert to LINQ (call form) @@ -2872,6 +2860,9 @@ Zero-width positive lookbehind assertions are typically used at the beginning of Silent + + Console.WriteLine + embedded Embedded is a technical term for "Embedded source", where souce files are embedded into the PDB @@ -3135,6 +3126,9 @@ Zero-width positive lookbehind assertions are typically used at the beginning of Sort Imports or usings + + if statement + Directives from '{0}' @@ -3150,4 +3144,21 @@ Zero-width positive lookbehind assertions are typically used at the beginning of Fixing '{0}' + + Pull selected members up to {0} + + + Pull selected members up + + + required + Used in the object initializer completion. + + + Deleting {0} requires restarting the application because is not supported by the runtime. + + + Extract base record... + {Locked="record"} "record" is a language construct for C# and should not be localized. + \ No newline at end of file diff --git a/src/Features/Core/Portable/FindSymbols/SymbolTree/SymbolTreeInfoIncrementalAnalyzer.cs b/src/Features/Core/Portable/FindSymbols/SymbolTree/SymbolTreeInfoIncrementalAnalyzer.cs new file mode 100644 index 0000000000000..389361e760886 --- /dev/null +++ b/src/Features/Core/Portable/FindSymbols/SymbolTree/SymbolTreeInfoIncrementalAnalyzer.cs @@ -0,0 +1,71 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Threading; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.Remote; +using Microsoft.CodeAnalysis.SolutionCrawler; + +namespace Microsoft.CodeAnalysis.FindSymbols.SymbolTree +{ + internal partial class SymbolTreeInfoIncrementalAnalyzerProvider + { + private class SymbolTreeInfoIncrementalAnalyzer : IncrementalAnalyzerBase + { + private readonly Workspace _workspace; + + public SymbolTreeInfoIncrementalAnalyzer(Workspace workspace) + => _workspace = workspace; + + public override async Task AnalyzeDocumentAsync(Document document, SyntaxNode bodyOpt, InvocationReasons reasons, CancellationToken cancellationToken) + { + var client = await RemoteHostClient.TryGetClientAsync(document.Project, cancellationToken).ConfigureAwait(false); + var isMethodBodyEdit = bodyOpt != null; + + if (client != null) + { + await client.TryInvokeAsync( + document.Project, (service, checksum, cancellationToken) => + service.AnalyzeDocumentAsync(checksum, document.Id, isMethodBodyEdit, cancellationToken), + cancellationToken).ConfigureAwait(false); + return; + } + + var service = _workspace.Services.GetRequiredService(); + await service.AnalyzeDocumentAsync(document, isMethodBodyEdit, cancellationToken).ConfigureAwait(false); + } + + public override async Task AnalyzeProjectAsync(Project project, bool semanticsChanged, InvocationReasons reasons, CancellationToken cancellationToken) + { + var client = await RemoteHostClient.TryGetClientAsync(project, cancellationToken).ConfigureAwait(false); + if (client != null) + { + await client.TryInvokeAsync( + project, (service, checksum, cancellationToken) => + service.AnalyzeProjectAsync(checksum, project.Id, cancellationToken), + cancellationToken).ConfigureAwait(false); + return; + } + + var service = _workspace.Services.GetRequiredService(); + await service.AnalyzeProjectAsync(project, cancellationToken).ConfigureAwait(false); + } + + public override async Task RemoveProjectAsync(ProjectId projectId, CancellationToken cancellationToken) + { + var client = await RemoteHostClient.TryGetClientAsync(_workspace, cancellationToken).ConfigureAwait(false); + if (client != null) + { + await client.TryInvokeAsync( + (service, cancellationToken) => service.RemoveProjectAsync(projectId, cancellationToken), + cancellationToken).ConfigureAwait(false); + return; + } + + var service = _workspace.Services.GetRequiredService(); + service.RemoveProject(projectId); + } + } + } +} diff --git a/src/Features/Core/Portable/IncrementalCaches/SymbolTreeInfoIncrementalAnalyzerProvider.cs b/src/Features/Core/Portable/FindSymbols/SymbolTree/SymbolTreeInfoIncrementalAnalyzerProvider.cs similarity index 53% rename from src/Features/Core/Portable/IncrementalCaches/SymbolTreeInfoIncrementalAnalyzerProvider.cs rename to src/Features/Core/Portable/FindSymbols/SymbolTree/SymbolTreeInfoIncrementalAnalyzerProvider.cs index 0d733508ad608..443c68b0eb854 100644 --- a/src/Features/Core/Portable/IncrementalCaches/SymbolTreeInfoIncrementalAnalyzerProvider.cs +++ b/src/Features/Core/Portable/FindSymbols/SymbolTree/SymbolTreeInfoIncrementalAnalyzerProvider.cs @@ -2,18 +2,12 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System; -using System.Collections.Concurrent; using System.Composition; -using Microsoft.CodeAnalysis.FindSymbols; -using Microsoft.CodeAnalysis.FindSymbols.SymbolTree; -using Microsoft.CodeAnalysis.Host; using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.SolutionCrawler; -namespace Microsoft.CodeAnalysis.IncrementalCaches +namespace Microsoft.CodeAnalysis.FindSymbols.SymbolTree { /// /// Features like add-using want to be able to quickly search symbol indices for projects and @@ -29,20 +23,11 @@ namespace Microsoft.CodeAnalysis.IncrementalCaches /// This means that as the project is being indexed, partial results may be returned. However /// once it is fully indexed, then total results will be returned. /// - [Shared] - [ExportIncrementalAnalyzerProvider(nameof(SymbolTreeInfoIncrementalAnalyzerProvider), new[] { WorkspaceKind.RemoteWorkspace })] - [ExportWorkspaceServiceFactory(typeof(ISymbolTreeInfoCacheService))] - internal partial class SymbolTreeInfoIncrementalAnalyzerProvider : IIncrementalAnalyzerProvider, IWorkspaceServiceFactory + [ExportIncrementalAnalyzerProvider( + highPriorityForActiveFile: false, name: nameof(SymbolTreeInfoIncrementalAnalyzerProvider), + workspaceKinds: new[] { WorkspaceKind.Host }), Shared] + internal partial class SymbolTreeInfoIncrementalAnalyzerProvider : IIncrementalAnalyzerProvider { - // Concurrent dictionaries so they can be read from the SymbolTreeInfoCacheService while they are being - // populated/updated by the IncrementalAnalyzer. - // - // We always keep around the latest computed information produced by the incremental analyzer. That way the - // values are hopefully ready when someone calls on them for the current solution. - - private readonly ConcurrentDictionary _projectIdToInfo = new(); - private readonly ConcurrentDictionary _metadataIdToInfo = new(); - [ImportingConstructor] [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] public SymbolTreeInfoIncrementalAnalyzerProvider() @@ -50,9 +35,6 @@ public SymbolTreeInfoIncrementalAnalyzerProvider() } public IIncrementalAnalyzer CreateIncrementalAnalyzer(Workspace workspace) - => new SymbolTreeInfoIncrementalAnalyzer(_projectIdToInfo, _metadataIdToInfo); - - public IWorkspaceService CreateService(HostWorkspaceServices workspaceServices) - => new SymbolTreeInfoCacheService(_projectIdToInfo, _metadataIdToInfo); + => new SymbolTreeInfoIncrementalAnalyzer(workspace); } } diff --git a/src/Features/Core/Portable/FindUsages/AbstractFindUsagesService_FindImplementations.cs b/src/Features/Core/Portable/FindUsages/AbstractFindUsagesService_FindImplementations.cs index 736573cc2a9ef..c11cdc7478e2a 100644 --- a/src/Features/Core/Portable/FindUsages/AbstractFindUsagesService_FindImplementations.cs +++ b/src/Features/Core/Portable/FindUsages/AbstractFindUsagesService_FindImplementations.cs @@ -41,7 +41,7 @@ public static async Task FindImplementationsAsync( IFindUsagesContext context, ISymbol symbol, Project project, CancellationToken cancellationToken) { var solution = project.Solution; - var client = await RemoteHostClient.TryGetClientAsync(solution.Workspace, cancellationToken).ConfigureAwait(false); + var client = await RemoteHostClient.TryGetClientAsync(solution.Services, cancellationToken).ConfigureAwait(false); if (client != null) { // Create a callback that we can pass to the server process to hear about the diff --git a/src/Features/Core/Portable/FindUsages/AbstractFindUsagesService_FindReferences.cs b/src/Features/Core/Portable/FindUsages/AbstractFindUsagesService_FindReferences.cs index 7d67940e9cbc3..aed53c984a196 100644 --- a/src/Features/Core/Portable/FindUsages/AbstractFindUsagesService_FindReferences.cs +++ b/src/Features/Core/Portable/FindUsages/AbstractFindUsagesService_FindReferences.cs @@ -10,7 +10,7 @@ using Microsoft.CodeAnalysis.Classification; using Microsoft.CodeAnalysis.FindSymbols; using Microsoft.CodeAnalysis.FindUsages; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Remote; @@ -73,7 +73,7 @@ private static async Task> GetThirdPartyDefinitio { using var _ = ArrayBuilder.GetInstance(out var result); - var factory = solution.Workspace.Services.GetRequiredService(); + var factory = solution.Services.GetRequiredService(); foreach (var definition in definitions) { @@ -130,7 +130,7 @@ public static async Task FindReferencesAsync( CancellationToken cancellationToken) { var solution = project.Solution; - var client = await RemoteHostClient.TryGetClientAsync(solution.Workspace, cancellationToken).ConfigureAwait(false); + var client = await RemoteHostClient.TryGetClientAsync(solution.Services, cancellationToken).ConfigureAwait(false); if (client != null) { // Create a callback that we can pass to the server process to hear about the diff --git a/src/Features/Core/Portable/FindUsages/FindUsagesHelpers.cs b/src/Features/Core/Portable/FindUsages/FindUsagesHelpers.cs index 818f39973d2c7..0d5296e5f9b30 100644 --- a/src/Features/Core/Portable/FindUsages/FindUsagesHelpers.cs +++ b/src/Features/Core/Portable/FindUsages/FindUsagesHelpers.cs @@ -40,7 +40,7 @@ public static string GetDisplayName(ISymbol symbol) // 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. - var mappingService = document.Project.Solution.Workspace.Services.GetService(); + var mappingService = document.Project.Solution.Services.GetService(); var mapping = await mappingService.MapSymbolAsync(document, symbol, cancellationToken).ConfigureAwait(false); if (mapping == null) diff --git a/src/Features/Core/Portable/Formatting/FormattingRuleUtilities.cs b/src/Features/Core/Portable/Formatting/FormattingRuleUtilities.cs index 3ae4200991149..4add878fa9a9f 100644 --- a/src/Features/Core/Portable/Formatting/FormattingRuleUtilities.cs +++ b/src/Features/Core/Portable/Formatting/FormattingRuleUtilities.cs @@ -4,16 +4,16 @@ using System.Collections.Generic; using System.Collections.Immutable; -using Microsoft.CodeAnalysis.Host; using Microsoft.CodeAnalysis.Text; namespace Microsoft.CodeAnalysis.Formatting.Rules; internal static class FormattingRuleUtilities { - public static ImmutableArray GetFormattingRules(ParsedDocument document, HostLanguageServices languageServices, TextSpan span, IEnumerable? additionalRules) + public static ImmutableArray GetFormattingRules( + ParsedDocument document, TextSpan span, IEnumerable? additionalRules) { - var formattingRuleFactory = languageServices.WorkspaceServices.GetRequiredService(); + var formattingRuleFactory = document.SolutionServices.GetRequiredService(); // Not sure why this is being done... there aren't any docs on CreateRule either. var position = (span.Start + span.End) / 2; @@ -23,6 +23,6 @@ public static ImmutableArray GetFormattingRules(ParsedDo rules = rules.AddRange(additionalRules); } - return rules.AddRange(Formatter.GetDefaultFormattingRules(languageServices)); + return rules.AddRange(Formatter.GetDefaultFormattingRules(document.LanguageServices)); } } diff --git a/src/Features/Core/Portable/FullyQualify/AbstractFullyQualifyCodeFixProvider.cs b/src/Features/Core/Portable/FullyQualify/AbstractFullyQualifyCodeFixProvider.cs index 9ea67da24c29a..709b926bd8245 100644 --- a/src/Features/Core/Portable/FullyQualify/AbstractFullyQualifyCodeFixProvider.cs +++ b/src/Features/Core/Portable/FullyQualify/AbstractFullyQualifyCodeFixProvider.cs @@ -12,7 +12,7 @@ using Microsoft.CodeAnalysis.Completion; using Microsoft.CodeAnalysis.FindSymbols; using Microsoft.CodeAnalysis.Internal.Log; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Shared.Utilities; using Roslyn.Utilities; @@ -63,7 +63,7 @@ public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context) return; } - var hideAdvancedMembers = context.Options.GetOptions(document.Project.LanguageServices).HideAdvancedMembers; + var hideAdvancedMembers = context.Options.GetOptions(document.Project.Services).HideAdvancedMembers; var semanticModel = await document.GetRequiredSemanticModelAsync(cancellationToken).ConfigureAwait(false); var matchingTypes = await GetMatchingTypesAsync(document, semanticModel, node, hideAdvancedMembers, cancellationToken).ConfigureAwait(false); @@ -155,7 +155,7 @@ private async Task> GetMatchingTypesAsync( cancellationToken.ThrowIfCancellationRequested(); var project = document.Project; - var syntaxFacts = project.LanguageServices.GetRequiredService(); + var syntaxFacts = project.Services.GetRequiredService(); syntaxFacts.GetNameAndArityOfSimpleName(node, out var name, out var arity); var looksGeneric = syntaxFacts.LooksGeneric(node); @@ -245,7 +245,7 @@ private async Task> GetMatchingNamespacesAsync( SyntaxNode simpleName, CancellationToken cancellationToken) { - var syntaxFacts = project.LanguageServices.GetRequiredService(); + var syntaxFacts = project.Services.GetRequiredService(); if (syntaxFacts.IsAttributeName(simpleName)) { return ImmutableArray.Empty; diff --git a/src/Features/Core/Portable/GenerateComparisonOperators/GenerateComparisonOperatorsCodeRefactoringProvider.cs b/src/Features/Core/Portable/GenerateComparisonOperators/GenerateComparisonOperatorsCodeRefactoringProvider.cs index db3a9b5eb553c..a21a246a0b0be 100644 --- a/src/Features/Core/Portable/GenerateComparisonOperators/GenerateComparisonOperatorsCodeRefactoringProvider.cs +++ b/src/Features/Core/Portable/GenerateComparisonOperators/GenerateComparisonOperatorsCodeRefactoringProvider.cs @@ -12,7 +12,7 @@ using Microsoft.CodeAnalysis.CodeGeneration; using Microsoft.CodeAnalysis.CodeRefactorings; using Microsoft.CodeAnalysis.Editing; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Shared.Extensions; using Roslyn.Utilities; diff --git a/src/Features/Core/Portable/GenerateConstructorFromMembers/AbstractGenerateConstructorFromMembersCodeRefactoringProvider.ConstructorDelegatingCodeAction.cs b/src/Features/Core/Portable/GenerateConstructorFromMembers/AbstractGenerateConstructorFromMembersCodeRefactoringProvider.ConstructorDelegatingCodeAction.cs index 74980c692d0d7..c5d4fb0ed81a1 100644 --- a/src/Features/Core/Portable/GenerateConstructorFromMembers/AbstractGenerateConstructorFromMembersCodeRefactoringProvider.ConstructorDelegatingCodeAction.cs +++ b/src/Features/Core/Portable/GenerateConstructorFromMembers/AbstractGenerateConstructorFromMembersCodeRefactoringProvider.ConstructorDelegatingCodeAction.cs @@ -49,7 +49,7 @@ protected override async Task GetChangedDocumentAsync(CancellationToke // Otherwise, just generate a normal constructor that assigns any provided // parameters into fields. var project = _document.Project; - var languageServices = project.Solution.Workspace.Services.GetLanguageServices(_state.ContainingType.Language); + var languageServices = project.Solution.Services.GetLanguageServices(_state.ContainingType.Language); var semanticModel = await _document.GetRequiredSemanticModelAsync(cancellationToken).ConfigureAwait(false); var factory = languageServices.GetRequiredService(); diff --git a/src/Features/Core/Portable/GenerateConstructorFromMembers/AbstractGenerateConstructorFromMembersCodeRefactoringProvider.GenerateConstructorWithDialogCodeAction.cs b/src/Features/Core/Portable/GenerateConstructorFromMembers/AbstractGenerateConstructorFromMembersCodeRefactoringProvider.GenerateConstructorWithDialogCodeAction.cs index ab6876731adfc..c3f7b853ed437 100644 --- a/src/Features/Core/Portable/GenerateConstructorFromMembers/AbstractGenerateConstructorFromMembersCodeRefactoringProvider.GenerateConstructorWithDialogCodeAction.cs +++ b/src/Features/Core/Portable/GenerateConstructorFromMembers/AbstractGenerateConstructorFromMembersCodeRefactoringProvider.GenerateConstructorWithDialogCodeAction.cs @@ -56,8 +56,7 @@ public GenerateConstructorWithDialogCodeAction( public override object GetOptions(CancellationToken cancellationToken) { - var workspace = _document.Project.Solution.Workspace; - var service = _service._pickMembersService_forTesting ?? workspace.Services.GetRequiredService(); + var service = _service._pickMembersService_forTesting ?? _document.Project.Solution.Services.GetRequiredService(); return service.PickMembers( FeaturesResources.Pick_members_to_be_used_as_constructor_parameters, @@ -79,7 +78,7 @@ protected override async Task> ComputeOperation // If we presented the 'Add null check' option, then persist whatever value // the user chose. That way we'll keep that as the default for the next time // the user opens the dialog. - var globalOptions = _document.Project.Solution.Workspace.Services.GetRequiredService(); + var globalOptions = _document.Project.Solution.Services.GetRequiredService(); globalOptions.SetGenerateEqualsAndGetHashCodeFromMembersGenerateOperators(_document.Project.Language, addNullChecksOption.Value); } diff --git a/src/Features/Core/Portable/GenerateConstructorFromMembers/AbstractGenerateConstructorFromMembersCodeRefactoringProvider.cs b/src/Features/Core/Portable/GenerateConstructorFromMembers/AbstractGenerateConstructorFromMembersCodeRefactoringProvider.cs index 3a9a32cac050b..0ad48aeeafdb5 100644 --- a/src/Features/Core/Portable/GenerateConstructorFromMembers/AbstractGenerateConstructorFromMembersCodeRefactoringProvider.cs +++ b/src/Features/Core/Portable/GenerateConstructorFromMembers/AbstractGenerateConstructorFromMembersCodeRefactoringProvider.cs @@ -13,7 +13,7 @@ using Microsoft.CodeAnalysis.Features.Intents; using Microsoft.CodeAnalysis.GenerateFromMembers; using Microsoft.CodeAnalysis.Internal.Log; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.PickMembers; using Microsoft.CodeAnalysis.PooledObjects; @@ -143,7 +143,7 @@ private async Task ComputeRefactoringsAsync( CleanCodeGenerationOptionsProvider fallbackOptions, CancellationToken cancellationToken) { - if (document.Project.Solution.Workspace.Kind == WorkspaceKind.MiscellaneousFiles) + if (document.Project.Solution.WorkspaceKind == WorkspaceKind.MiscellaneousFiles) { return; } @@ -222,7 +222,7 @@ private async Task ComputeRefactoringsAsync( if (canAddNullCheck) { - var globalOptions = document.Project.Solution.Workspace.Services.GetRequiredService(); + var globalOptions = document.Project.Solution.Services.GetRequiredService(); var optionValue = globalOptions.GetGenerateConstructorFromMembersOptionsAddNullChecks(document.Project.Language); pickMemberOptions.Add(new PickMembersOption( diff --git a/src/Features/Core/Portable/GenerateDefaultConstructors/AbstractGenerateDefaultConstructorCodeFixProvider.cs b/src/Features/Core/Portable/GenerateDefaultConstructors/AbstractGenerateDefaultConstructorCodeFixProvider.cs index 0bcd11a55e2ad..41c5a8b536f48 100644 --- a/src/Features/Core/Portable/GenerateDefaultConstructors/AbstractGenerateDefaultConstructorCodeFixProvider.cs +++ b/src/Features/Core/Portable/GenerateDefaultConstructors/AbstractGenerateDefaultConstructorCodeFixProvider.cs @@ -6,7 +6,7 @@ using System.Threading.Tasks; using Microsoft.CodeAnalysis.CodeFixes; using Microsoft.CodeAnalysis.CodeGeneration; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Text; diff --git a/src/Features/Core/Portable/GenerateDefaultConstructors/AbstractGenerateDefaultConstructorsService.State.cs b/src/Features/Core/Portable/GenerateDefaultConstructors/AbstractGenerateDefaultConstructorsService.State.cs index 13cd61f5743b8..6bc43b22fa612 100644 --- a/src/Features/Core/Portable/GenerateDefaultConstructors/AbstractGenerateDefaultConstructorsService.State.cs +++ b/src/Features/Core/Portable/GenerateDefaultConstructors/AbstractGenerateDefaultConstructorsService.State.cs @@ -5,7 +5,7 @@ using System.Collections.Immutable; using System.Linq; using System.Threading; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Shared.Utilities; using Microsoft.CodeAnalysis.Text; @@ -76,7 +76,7 @@ private bool TryInitialize( var semanticFacts = semanticDocument.Document.GetLanguageService(); var classConstructors = ClassType.InstanceConstructors; - var destinationProvider = semanticDocument.Project.Solution.Workspace.Services.GetLanguageServices(ClassType.Language); + var destinationProvider = semanticDocument.Project.Solution.Services.GetLanguageServices(ClassType.Language); var isCaseSensitive = syntaxFacts.IsCaseSensitive; UnimplementedConstructors = diff --git a/src/Features/Core/Portable/GenerateDefaultConstructors/GenerateDefaultConstructorsCodeRefactoringProvider.cs b/src/Features/Core/Portable/GenerateDefaultConstructors/GenerateDefaultConstructorsCodeRefactoringProvider.cs index df8236e8c94b6..4578319c368bd 100644 --- a/src/Features/Core/Portable/GenerateDefaultConstructors/GenerateDefaultConstructorsCodeRefactoringProvider.cs +++ b/src/Features/Core/Portable/GenerateDefaultConstructors/GenerateDefaultConstructorsCodeRefactoringProvider.cs @@ -42,7 +42,7 @@ public override async Task ComputeRefactoringsAsync(CodeRefactoringContext conte if (document.Project.IsSubmission) return; - if (document.Project.Solution.Workspace.Kind == WorkspaceKind.MiscellaneousFiles) + if (document.Project.Solution.WorkspaceKind == WorkspaceKind.MiscellaneousFiles) return; var service = document.GetRequiredLanguageService(); diff --git a/src/Features/Core/Portable/GenerateEqualsAndGetHashCodeFromMembers/AbstractGenerateEqualsAndGetHashCodeService.cs b/src/Features/Core/Portable/GenerateEqualsAndGetHashCodeFromMembers/AbstractGenerateEqualsAndGetHashCodeService.cs index ceec35e05c269..4e71bc620adba 100644 --- a/src/Features/Core/Portable/GenerateEqualsAndGetHashCodeFromMembers/AbstractGenerateEqualsAndGetHashCodeService.cs +++ b/src/Features/Core/Portable/GenerateEqualsAndGetHashCodeFromMembers/AbstractGenerateEqualsAndGetHashCodeService.cs @@ -12,7 +12,7 @@ using Microsoft.CodeAnalysis.Editing; using Microsoft.CodeAnalysis.Formatting; using Microsoft.CodeAnalysis.Formatting.Rules; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Shared.Extensions; diff --git a/src/Features/Core/Portable/GenerateEqualsAndGetHashCodeFromMembers/FormatLargeBinaryExpressionRule.cs b/src/Features/Core/Portable/GenerateEqualsAndGetHashCodeFromMembers/FormatLargeBinaryExpressionRule.cs index f6360c2bf4a3b..268f6e3a119b7 100644 --- a/src/Features/Core/Portable/GenerateEqualsAndGetHashCodeFromMembers/FormatLargeBinaryExpressionRule.cs +++ b/src/Features/Core/Portable/GenerateEqualsAndGetHashCodeFromMembers/FormatLargeBinaryExpressionRule.cs @@ -4,7 +4,7 @@ using System.Collections.Generic; using Microsoft.CodeAnalysis.Formatting.Rules; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; namespace Microsoft.CodeAnalysis.GenerateEqualsAndGetHashCodeFromMembers { diff --git a/src/Features/Core/Portable/GenerateEqualsAndGetHashCodeFromMembers/GenerateEqualsAndGetHashCodeFromMembersCodeRefactoringProvider.cs b/src/Features/Core/Portable/GenerateEqualsAndGetHashCodeFromMembers/GenerateEqualsAndGetHashCodeFromMembersCodeRefactoringProvider.cs index 2380d81fe6903..a52d823d26db6 100644 --- a/src/Features/Core/Portable/GenerateEqualsAndGetHashCodeFromMembers/GenerateEqualsAndGetHashCodeFromMembersCodeRefactoringProvider.cs +++ b/src/Features/Core/Portable/GenerateEqualsAndGetHashCodeFromMembers/GenerateEqualsAndGetHashCodeFromMembersCodeRefactoringProvider.cs @@ -17,7 +17,7 @@ using Microsoft.CodeAnalysis.GenerateFromMembers; using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.Internal.Log; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.PickMembers; using Microsoft.CodeAnalysis.PooledObjects; @@ -55,7 +55,7 @@ public GenerateEqualsAndGetHashCodeFromMembersCodeRefactoringProvider(IPickMembe public override async Task ComputeRefactoringsAsync(CodeRefactoringContext context) { var (document, textSpan, cancellationToken) = context; - if (document.Project.Solution.Workspace.Kind == WorkspaceKind.MiscellaneousFiles) + if (document.Project.Solution.WorkspaceKind == WorkspaceKind.MiscellaneousFiles) { return; } @@ -259,7 +259,7 @@ private async Task CreateCodeActionWithDialogAsync( if (CanImplementIEquatable(semanticModel, containingType, out var equatableTypeOpt)) { - var globalOptions = document.Project.Solution.Workspace.Services.GetRequiredService(); + var globalOptions = document.Project.Solution.Services.GetRequiredService(); var value = globalOptions.GetGenerateEqualsAndGetHashCodeFromMembersImplementIEquatable(document.Project.Language); var displayName = equatableTypeOpt.ToDisplayString(new SymbolDisplayFormat( @@ -274,7 +274,7 @@ private async Task CreateCodeActionWithDialogAsync( if (!HasOperators(containingType)) { - var globalOptions = document.Project.Solution.Workspace.Services.GetRequiredService(); + var globalOptions = document.Project.Solution.Services.GetRequiredService(); var value = globalOptions.GetGenerateEqualsAndGetHashCodeFromMembersGenerateOperators(document.Project.Language); pickMembersOptions.Add(new PickMembersOption( diff --git a/src/Features/Core/Portable/GenerateEqualsAndGetHashCodeFromMembers/GenerateEqualsAndHashWithDialogCodeAction.cs b/src/Features/Core/Portable/GenerateEqualsAndGetHashCodeFromMembers/GenerateEqualsAndHashWithDialogCodeAction.cs index 10f96c842ec61..240bdd89681b6 100644 --- a/src/Features/Core/Portable/GenerateEqualsAndGetHashCodeFromMembers/GenerateEqualsAndHashWithDialogCodeAction.cs +++ b/src/Features/Core/Portable/GenerateEqualsAndGetHashCodeFromMembers/GenerateEqualsAndHashWithDialogCodeAction.cs @@ -55,7 +55,7 @@ public GenerateEqualsAndGetHashCodeWithDialogCodeAction( public override object GetOptions(CancellationToken cancellationToken) { - var service = _service._pickMembersService_forTestingPurposes ?? _document.Project.Solution.Workspace.Services.GetRequiredService(); + var service = _service._pickMembersService_forTestingPurposes ?? _document.Project.Solution.Services.GetRequiredService(); return service.PickMembers(FeaturesResources.Pick_members_to_be_used_in_Equals_GetHashCode, _viableMembers, _pickMembersOptions); } @@ -75,7 +75,7 @@ protected override async Task> ComputeOperation var generateOperatorsOption = result.Options.FirstOrDefault(o => o.Id == GenerateOperatorsId); if (generateOperatorsOption != null || implementIEqutableOption != null) { - var globalOptions = _document.Project.Solution.Workspace.Services.GetRequiredService(); + var globalOptions = _document.Project.Solution.Services.GetRequiredService(); if (generateOperatorsOption != null) { diff --git a/src/Features/Core/Portable/GenerateFromMembers/AbstractGenerateFromMembersCodeRefactoringProvider.cs b/src/Features/Core/Portable/GenerateFromMembers/AbstractGenerateFromMembersCodeRefactoringProvider.cs index 3bc3a1a9663ca..05f1013cabe18 100644 --- a/src/Features/Core/Portable/GenerateFromMembers/AbstractGenerateFromMembersCodeRefactoringProvider.cs +++ b/src/Features/Core/Portable/GenerateFromMembers/AbstractGenerateFromMembersCodeRefactoringProvider.cs @@ -9,7 +9,7 @@ using Microsoft.CodeAnalysis.CodeGeneration; using Microsoft.CodeAnalysis.CodeRefactorings; using Microsoft.CodeAnalysis.Diagnostics.Analyzers.NamingStyles; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Shared.Naming; diff --git a/src/Features/Core/Portable/GenerateMember/AbstractGenerateMemberService.cs b/src/Features/Core/Portable/GenerateMember/AbstractGenerateMemberService.cs index 648baa30eac76..7420e24227e0f 100644 --- a/src/Features/Core/Portable/GenerateMember/AbstractGenerateMemberService.cs +++ b/src/Features/Core/Portable/GenerateMember/AbstractGenerateMemberService.cs @@ -7,7 +7,7 @@ using System.Collections.Generic; using System.Linq; using System.Threading; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Shared.Extensions; namespace Microsoft.CodeAnalysis.GenerateMember @@ -133,9 +133,9 @@ private static void TryDetermineTypeToGenerateInWorker( { var typeInfo = semanticModel.GetTypeInfo(beforeArrowExpression, cancellationToken); - if (typeInfo.Type.IsPointerType()) + if (typeInfo.Type is IPointerTypeSymbol pointerType) { - typeToGenerateIn = ((IPointerTypeSymbol)typeInfo.Type).PointedAtType as INamedTypeSymbol; + typeToGenerateIn = pointerType.PointedAtType as INamedTypeSymbol; isStatic = false; } } diff --git a/src/Features/Core/Portable/GenerateMember/GenerateConstructor/AbstractGenerateConstructorService.State.cs b/src/Features/Core/Portable/GenerateMember/GenerateConstructor/AbstractGenerateConstructorService.State.cs index 45ac8eea33b10..50d31151b6b92 100644 --- a/src/Features/Core/Portable/GenerateMember/GenerateConstructor/AbstractGenerateConstructorService.State.cs +++ b/src/Features/Core/Portable/GenerateMember/GenerateConstructor/AbstractGenerateConstructorService.State.cs @@ -14,7 +14,8 @@ using Microsoft.CodeAnalysis.Diagnostics.Analyzers.NamingStyles; using Microsoft.CodeAnalysis.Editing; using Microsoft.CodeAnalysis.FindSymbols; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.Host; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Shared.Utilities; @@ -238,8 +239,7 @@ private bool ClashesWithExistingConstructor() { Contract.ThrowIfNull(TypeToGenerateIn); - var destinationProvider = _document.Project.Solution.Workspace.Services.GetLanguageServices(TypeToGenerateIn.Language); - var syntaxFacts = destinationProvider.GetRequiredService(); + var syntaxFacts = _document.Project.Solution.Services.GetRequiredLanguageService(TypeToGenerateIn.Language); return TypeToGenerateIn.InstanceConstructors.Any(static (c, arg) => arg.self.Matches(c, arg.syntaxFacts), (self: this, syntaxFacts)); } @@ -579,7 +579,7 @@ public async Task GetChangedDocumentAsync( Contract.ThrowIfNull(TypeToGenerateIn); - var provider = document.Project.Solution.Workspace.Services.GetLanguageServices(TypeToGenerateIn.Language); + var provider = document.Project.Solution.Services.GetLanguageServices(TypeToGenerateIn.Language); var (members, assignments) = await GenerateMembersAndAssignmentsAsync(document, withFields, withProperties, cancellationToken).ConfigureAwait(false); var isThis = _delegatedConstructor.ContainingType.OriginalDefinition.Equals(TypeToGenerateIn.OriginalDefinition); var delegatingArguments = provider.GetService().CreateArguments(_delegatedConstructor.Parameters); @@ -614,7 +614,7 @@ public async Task GetChangedDocumentAsync( { Contract.ThrowIfNull(TypeToGenerateIn); - var provider = document.Project.Solution.Workspace.Services.GetLanguageServices(TypeToGenerateIn.Language); + var provider = document.Project.Solution.Services.GetLanguageServices(TypeToGenerateIn.Language); var members = withFields ? SyntaxGeneratorExtensions.CreateFieldsForParameters(_parameters, ParameterToNewFieldMap, IsContainedInUnsafeType) : withProperties ? SyntaxGeneratorExtensions.CreatePropertiesForParameters(_parameters, ParameterToNewPropertyMap, IsContainedInUnsafeType) : @@ -637,7 +637,7 @@ private async Task GenerateMemberDelegatingConstructorAsync( { Contract.ThrowIfNull(TypeToGenerateIn); - var provider = document.Project.Solution.Workspace.Services.GetLanguageServices(TypeToGenerateIn.Language); + var provider = document.Project.Solution.Services.GetLanguageServices(TypeToGenerateIn.Language); var semanticModel = await document.GetRequiredSemanticModelAsync(cancellationToken).ConfigureAwait(false); var newMemberMap = diff --git a/src/Features/Core/Portable/GenerateMember/GenerateConstructor/AbstractGenerateConstructorService.cs b/src/Features/Core/Portable/GenerateMember/GenerateConstructor/AbstractGenerateConstructorService.cs index be789d885a33e..710539166fa3a 100644 --- a/src/Features/Core/Portable/GenerateMember/GenerateConstructor/AbstractGenerateConstructorService.cs +++ b/src/Features/Core/Portable/GenerateMember/GenerateConstructor/AbstractGenerateConstructorService.cs @@ -12,7 +12,7 @@ using Microsoft.CodeAnalysis.CodeGeneration; using Microsoft.CodeAnalysis.Diagnostics.Analyzers.NamingStyles; using Microsoft.CodeAnalysis.Internal.Log; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Shared.Utilities; diff --git a/src/Features/Core/Portable/GenerateMember/GenerateConstructor/GenerateConstructorHelpers.cs b/src/Features/Core/Portable/GenerateMember/GenerateConstructor/GenerateConstructorHelpers.cs index 48b299a76edc6..916202a1bd4c9 100644 --- a/src/Features/Core/Portable/GenerateMember/GenerateConstructor/GenerateConstructorHelpers.cs +++ b/src/Features/Core/Portable/GenerateMember/GenerateConstructor/GenerateConstructorHelpers.cs @@ -7,7 +7,7 @@ using System.Collections.Immutable; using System.Diagnostics; using System.Linq; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Shared.Extensions; using Roslyn.Utilities; diff --git a/src/Features/Core/Portable/GenerateMember/GenerateEnumMember/AbstractGenerateEnumMemberService.CodeAction.cs b/src/Features/Core/Portable/GenerateMember/GenerateEnumMember/AbstractGenerateEnumMemberService.CodeAction.cs index a6fc19ef38e01..55eaf133cf7b8 100644 --- a/src/Features/Core/Portable/GenerateMember/GenerateEnumMember/AbstractGenerateEnumMemberService.CodeAction.cs +++ b/src/Features/Core/Portable/GenerateMember/GenerateEnumMember/AbstractGenerateEnumMemberService.CodeAction.cs @@ -8,7 +8,7 @@ using System.Threading.Tasks; using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeGeneration; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Shared.Utilities; namespace Microsoft.CodeAnalysis.GenerateMember.GenerateEnumMember @@ -33,7 +33,7 @@ public GenerateEnumMemberCodeAction( protected override async Task GetChangedDocumentAsync(CancellationToken cancellationToken) { - var languageServices = _document.Project.Solution.Workspace.Services.GetLanguageServices(_state.TypeToGenerateIn.Language); + var languageServices = _document.Project.Solution.Services.GetLanguageServices(_state.TypeToGenerateIn.Language); var codeGenerator = languageServices.GetService(); var semanticFacts = languageServices.GetService(); diff --git a/src/Features/Core/Portable/GenerateMember/GenerateEnumMember/AbstractGenerateEnumMemberService.State.cs b/src/Features/Core/Portable/GenerateMember/GenerateEnumMember/AbstractGenerateEnumMemberService.State.cs index 80bf5efc26087..6c03115e9265c 100644 --- a/src/Features/Core/Portable/GenerateMember/GenerateEnumMember/AbstractGenerateEnumMemberService.State.cs +++ b/src/Features/Core/Portable/GenerateMember/GenerateEnumMember/AbstractGenerateEnumMemberService.State.cs @@ -9,7 +9,7 @@ using System.Threading.Tasks; using Microsoft.CodeAnalysis.CodeGeneration; using Microsoft.CodeAnalysis.FindSymbols; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Shared.Extensions; namespace Microsoft.CodeAnalysis.GenerateMember.GenerateEnumMember diff --git a/src/Features/Core/Portable/GenerateMember/GenerateParameterizedMember/AbstractGenerateDeconstructMethodService.State.cs b/src/Features/Core/Portable/GenerateMember/GenerateParameterizedMember/AbstractGenerateDeconstructMethodService.State.cs index d737cd2ddcbf5..217fbf475bc9f 100644 --- a/src/Features/Core/Portable/GenerateMember/GenerateParameterizedMember/AbstractGenerateDeconstructMethodService.State.cs +++ b/src/Features/Core/Portable/GenerateMember/GenerateParameterizedMember/AbstractGenerateDeconstructMethodService.State.cs @@ -94,14 +94,14 @@ private static ImmutableArray TryMakeParameters(SemanticModel } var tupleElements = ((INamedTypeSymbol)targetType).TupleElements; - using var builderDisposer = ArrayBuilder.GetInstance(tupleElements.Length, out var builder); + using var _ = ArrayBuilder.GetInstance(tupleElements.Length, out var builder); foreach (var element in tupleElements) { builder.Add(CodeGenerationSymbolFactory.CreateParameterSymbol( attributes: default, RefKind.Out, isParams: false, element.Type, element.Name)); } - return builder.ToImmutable(); + return builder.ToImmutableAndClear(); } } } diff --git a/src/Features/Core/Portable/GenerateMember/GenerateParameterizedMember/AbstractGenerateMethodService.State.cs b/src/Features/Core/Portable/GenerateMember/GenerateParameterizedMember/AbstractGenerateMethodService.State.cs index 48d003ab15a21..7c3d7161c6aeb 100644 --- a/src/Features/Core/Portable/GenerateMember/GenerateParameterizedMember/AbstractGenerateMethodService.State.cs +++ b/src/Features/Core/Portable/GenerateMember/GenerateParameterizedMember/AbstractGenerateMethodService.State.cs @@ -9,7 +9,7 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.CodeGeneration; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Shared.Extensions; using Roslyn.Utilities; diff --git a/src/Features/Core/Portable/GenerateMember/GenerateParameterizedMember/AbstractGenerateMethodService.cs b/src/Features/Core/Portable/GenerateMember/GenerateParameterizedMember/AbstractGenerateMethodService.cs index 8cfbbfcdeb3d4..f96651cb6c86f 100644 --- a/src/Features/Core/Portable/GenerateMember/GenerateParameterizedMember/AbstractGenerateMethodService.cs +++ b/src/Features/Core/Portable/GenerateMember/GenerateParameterizedMember/AbstractGenerateMethodService.cs @@ -10,7 +10,7 @@ using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeGeneration; using Microsoft.CodeAnalysis.Internal.Log; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; namespace Microsoft.CodeAnalysis.GenerateMember.GenerateParameterizedMember { diff --git a/src/Features/Core/Portable/GenerateMember/GenerateParameterizedMember/AbstractGenerateParameterizedMemberService.CodeAction.cs b/src/Features/Core/Portable/GenerateMember/GenerateParameterizedMember/AbstractGenerateParameterizedMemberService.CodeAction.cs index 532abe2662021..562dc383c8e20 100644 --- a/src/Features/Core/Portable/GenerateMember/GenerateParameterizedMember/AbstractGenerateParameterizedMemberService.CodeAction.cs +++ b/src/Features/Core/Portable/GenerateMember/GenerateParameterizedMember/AbstractGenerateParameterizedMemberService.CodeAction.cs @@ -67,7 +67,7 @@ private string GetDisplayText( protected override async Task GetChangedDocumentAsync(CancellationToken cancellationToken) { - var syntaxFactory = _document.Project.Solution.Workspace.Services.GetLanguageServices(_state.TypeToGenerateIn.Language).GetService(); + var syntaxFactory = _document.Project.Solution.Services.GetLanguageServices(_state.TypeToGenerateIn.Language).GetService(); if (_generateProperty) { diff --git a/src/Features/Core/Portable/GenerateMember/GenerateParameterizedMember/AbstractGenerateParameterizedMemberService.SignatureInfo.cs b/src/Features/Core/Portable/GenerateMember/GenerateParameterizedMember/AbstractGenerateParameterizedMemberService.SignatureInfo.cs index ca4ee202ec3b1..5754f192b040c 100644 --- a/src/Features/Core/Portable/GenerateMember/GenerateParameterizedMember/AbstractGenerateParameterizedMemberService.SignatureInfo.cs +++ b/src/Features/Core/Portable/GenerateMember/GenerateParameterizedMember/AbstractGenerateParameterizedMemberService.SignatureInfo.cs @@ -13,7 +13,7 @@ using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CodeGeneration; using Microsoft.CodeAnalysis.Editing; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Shared.Utilities; @@ -122,7 +122,7 @@ public async ValueTask GenerateMethodAsync( methodKind: State.MethodKind); // Ensure no conflicts between type parameter names and parameter names. - var languageServiceProvider = Document.Project.Solution.Workspace.Services.GetLanguageServices(State.TypeToGenerateIn.Language); + var languageServiceProvider = Document.Project.Solution.Services.GetLanguageServices(State.TypeToGenerateIn.Language); var syntaxFacts = languageServiceProvider.GetService(); var equalityComparer = syntaxFacts.StringComparer; @@ -163,7 +163,7 @@ private async ValueTask FixTypeAsync( private IDictionary GetTypeArgumentToTypeParameterMap( CancellationToken cancellationToken) { - return _typeArgumentToTypeParameterMap ?? (_typeArgumentToTypeParameterMap = CreateTypeArgumentToTypeParameterMap(cancellationToken)); + return _typeArgumentToTypeParameterMap ??= CreateTypeArgumentToTypeParameterMap(cancellationToken); } private IDictionary CreateTypeArgumentToTypeParameterMap( diff --git a/src/Features/Core/Portable/GenerateMember/GenerateParameterizedMember/AbstractGenerateParameterizedMemberService.State.cs b/src/Features/Core/Portable/GenerateMember/GenerateParameterizedMember/AbstractGenerateParameterizedMemberService.State.cs index 1d9c925d6cd1a..ae282a0ff36af 100644 --- a/src/Features/Core/Portable/GenerateMember/GenerateParameterizedMember/AbstractGenerateParameterizedMemberService.State.cs +++ b/src/Features/Core/Portable/GenerateMember/GenerateParameterizedMember/AbstractGenerateParameterizedMemberService.State.cs @@ -10,7 +10,7 @@ using Microsoft.CodeAnalysis.CodeGeneration; using Microsoft.CodeAnalysis.Editing; using Microsoft.CodeAnalysis.FindSymbols; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Shared.Utilities; @@ -80,7 +80,7 @@ protected async Task TryFinishInitializingStateAsync(TService service, Sem var existingMethods = TypeToGenerateIn.GetMembers(IdentifierToken.ValueText) .OfType(); - var destinationProvider = document.Project.Solution.Workspace.Services.GetLanguageServices(TypeToGenerateIn.Language); + var destinationProvider = document.Project.Solution.Services.GetLanguageServices(TypeToGenerateIn.Language); var syntaxFacts = destinationProvider.GetService(); var syntaxFactory = destinationProvider.GetService(); IsContainedInUnsafeType = service.ContainingTypesOrSelfHasUnsafeKeyword(TypeToGenerateIn); diff --git a/src/Features/Core/Portable/GenerateMember/GenerateParameterizedMember/AbstractGenerateParameterizedMemberService.cs b/src/Features/Core/Portable/GenerateMember/GenerateParameterizedMember/AbstractGenerateParameterizedMemberService.cs index 1a6cf83fce85d..05ef56c7eb5a7 100644 --- a/src/Features/Core/Portable/GenerateMember/GenerateParameterizedMember/AbstractGenerateParameterizedMemberService.cs +++ b/src/Features/Core/Portable/GenerateMember/GenerateParameterizedMember/AbstractGenerateParameterizedMemberService.cs @@ -9,7 +9,7 @@ using System.Threading.Tasks; using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeGeneration; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.PooledObjects; namespace Microsoft.CodeAnalysis.GenerateMember.GenerateParameterizedMember @@ -54,7 +54,7 @@ protected async ValueTask> GetActionsAsync(Document d if (canGenerateAbstractly) result.Add(new GenerateParameterizedMemberCodeAction((TService)this, document, state, fallbackOptions, isAbstract: true, generateProperty: false)); - var semanticFacts = document.Project.Solution.Workspace.Services.GetLanguageServices(state.TypeToGenerateIn.Language).GetService(); + var semanticFacts = document.Project.Solution.Services.GetLanguageServices(state.TypeToGenerateIn.Language).GetService(); if (semanticFacts.SupportsParameterizedProperties && state.InvocationExpressionOpt != null) diff --git a/src/Features/Core/Portable/GenerateMember/GenerateVariable/AbstractGenerateVariableService.CodeAction.cs b/src/Features/Core/Portable/GenerateMember/GenerateVariable/AbstractGenerateVariableService.CodeAction.cs index 968550f4387f5..e190f45347cb1 100644 --- a/src/Features/Core/Portable/GenerateMember/GenerateVariable/AbstractGenerateVariableService.CodeAction.cs +++ b/src/Features/Core/Portable/GenerateMember/GenerateVariable/AbstractGenerateVariableService.CodeAction.cs @@ -11,7 +11,7 @@ using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeGeneration; using Microsoft.CodeAnalysis.Editing; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Shared.Extensions; using Roslyn.Utilities; @@ -111,7 +111,7 @@ private IMethodSymbol CreateAccessor(Accessibility accessibility) private ImmutableArray GenerateStatements() { - var syntaxFactory = _semanticDocument.Project.Solution.Workspace.Services.GetLanguageServices(_state.TypeToGenerateIn.Language).GetService(); + var syntaxFactory = _semanticDocument.Project.Solution.Services.GetLanguageServices(_state.TypeToGenerateIn.Language).GetService(); var throwStatement = CodeGenerationHelpers.GenerateThrowStatement( syntaxFactory, _semanticDocument, "System.NotImplementedException"); diff --git a/src/Features/Core/Portable/GenerateMember/GenerateVariable/AbstractGenerateVariableService.State.cs b/src/Features/Core/Portable/GenerateMember/GenerateVariable/AbstractGenerateVariableService.State.cs index 388b6f08e55a7..9bbd920cd6b52 100644 --- a/src/Features/Core/Portable/GenerateMember/GenerateVariable/AbstractGenerateVariableService.State.cs +++ b/src/Features/Core/Portable/GenerateMember/GenerateVariable/AbstractGenerateVariableService.State.cs @@ -12,7 +12,7 @@ using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CodeGeneration; using Microsoft.CodeAnalysis.FindSymbols; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Shared.Extensions; using Roslyn.Utilities; diff --git a/src/Features/Core/Portable/GenerateOverrides/GenerateOverridesCodeRefactoringProvider.cs b/src/Features/Core/Portable/GenerateOverrides/GenerateOverridesCodeRefactoringProvider.cs index 50dccb8e7320f..693b08e494c6c 100644 --- a/src/Features/Core/Portable/GenerateOverrides/GenerateOverridesCodeRefactoringProvider.cs +++ b/src/Features/Core/Portable/GenerateOverrides/GenerateOverridesCodeRefactoringProvider.cs @@ -9,7 +9,7 @@ using Microsoft.CodeAnalysis.CodeGeneration; using Microsoft.CodeAnalysis.CodeRefactorings; using Microsoft.CodeAnalysis.Host.Mef; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.PickMembers; using Microsoft.CodeAnalysis.Shared.Extensions; diff --git a/src/Features/Core/Portable/GenerateOverrides/GenerateOverridesWithDialogCodeAction.cs b/src/Features/Core/Portable/GenerateOverrides/GenerateOverridesWithDialogCodeAction.cs index f7dc65e2ca56f..298d6d77ba5d7 100644 --- a/src/Features/Core/Portable/GenerateOverrides/GenerateOverridesWithDialogCodeAction.cs +++ b/src/Features/Core/Portable/GenerateOverrides/GenerateOverridesWithDialogCodeAction.cs @@ -48,7 +48,7 @@ public GenerateOverridesWithDialogCodeAction( public override object GetOptions(CancellationToken cancellationToken) { - var services = _document.Project.Solution.Workspace.Services; + var services = _document.Project.Solution.Services; var pickMembersService = _service._pickMembersService_forTestingPurposes ?? services.GetRequiredService(); var globalOptionService = services.GetService(); diff --git a/src/Features/Core/Portable/GenerateType/AbstractGenerateTypeService.CodeAction.cs b/src/Features/Core/Portable/GenerateType/AbstractGenerateTypeService.CodeAction.cs index 1634966b324f1..7653605db70c0 100644 --- a/src/Features/Core/Portable/GenerateType/AbstractGenerateTypeService.CodeAction.cs +++ b/src/Features/Core/Portable/GenerateType/AbstractGenerateTypeService.CodeAction.cs @@ -7,7 +7,7 @@ using System.Threading.Tasks; using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeGeneration; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Notification; using Microsoft.CodeAnalysis.ProjectManagement; using Microsoft.CodeAnalysis.Shared.Extensions; @@ -101,9 +101,9 @@ internal GenerateTypeCodeActionWithOption(TService service, Document document, S public override object GetOptions(CancellationToken cancellationToken) { - var generateTypeOptionsService = _document.Project.Solution.Workspace.Services.GetRequiredService(); - var notificationService = _document.Project.Solution.Workspace.Services.GetService(); - var projectManagementService = _document.Project.Solution.Workspace.Services.GetService(); + 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 typeKindValue = GetTypeKindOption(_state); var isPublicOnlyAccessibility = IsPublicOnlyAccessibility(_state, _document.Project); diff --git a/src/Features/Core/Portable/GenerateType/AbstractGenerateTypeService.Editor.cs b/src/Features/Core/Portable/GenerateType/AbstractGenerateTypeService.Editor.cs index 285c551d9fd3b..1648359380c0c 100644 --- a/src/Features/Core/Portable/GenerateType/AbstractGenerateTypeService.Editor.cs +++ b/src/Features/Core/Portable/GenerateType/AbstractGenerateTypeService.Editor.cs @@ -16,7 +16,7 @@ using Microsoft.CodeAnalysis.CodeCleanup; using Microsoft.CodeAnalysis.CodeGeneration; using Microsoft.CodeAnalysis.Formatting; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Text; using Microsoft.CodeAnalysis.Utilities; @@ -139,7 +139,7 @@ internal async Task> GetOperationsAsync() : TargetProjectChangeInLanguage.CSharpToVisualBasic; // Get the cross language service - _targetLanguageService = _generateTypeOptionsResult.Project.LanguageServices.GetService(); + _targetLanguageService = _generateTypeOptionsResult.Project.Services.GetService(); } if (_generateTypeOptionsResult.IsNewFile) diff --git a/src/Features/Core/Portable/GenerateType/AbstractGenerateTypeService.GenerateNamedType.cs b/src/Features/Core/Portable/GenerateType/AbstractGenerateTypeService.GenerateNamedType.cs index 6dcc4435cb33d..d1aa5b76062a8 100644 --- a/src/Features/Core/Portable/GenerateType/AbstractGenerateTypeService.GenerateNamedType.cs +++ b/src/Features/Core/Portable/GenerateType/AbstractGenerateTypeService.GenerateNamedType.cs @@ -13,7 +13,7 @@ using Microsoft.CodeAnalysis.CodeGeneration; using Microsoft.CodeAnalysis.Editing; using Microsoft.CodeAnalysis.GenerateMember.GenerateConstructor; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Shared.Extensions; using Roslyn.Utilities; @@ -216,7 +216,7 @@ private async Task AddFieldDelegatingConstructorAsync( } // Empty Constructor for Struct is not allowed - if (!(parameters.Count == 0 && options != null && (options.TypeKind == TypeKind.Struct || options.TypeKind == TypeKind.Structure))) + if (!(parameters.Count == 0 && options is { TypeKind: TypeKind.Struct })) { members.AddRange(factory.CreateMemberDelegatingConstructor( _semanticDocument.SemanticModel, diff --git a/src/Features/Core/Portable/GenerateType/AbstractGenerateTypeService.State.cs b/src/Features/Core/Portable/GenerateType/AbstractGenerateTypeService.State.cs index 891afd5d275d0..7986a5dc70c76 100644 --- a/src/Features/Core/Portable/GenerateType/AbstractGenerateTypeService.State.cs +++ b/src/Features/Core/Portable/GenerateType/AbstractGenerateTypeService.State.cs @@ -11,7 +11,7 @@ using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CodeGeneration; using Microsoft.CodeAnalysis.FindSymbols; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Shared.Extensions; using Roslyn.Utilities; @@ -301,8 +301,7 @@ private async Task DetermineNamespaceOrTypeToGenerateInAsync( // If the 2 documents are in different project then we must have Public Accessibility. // If we are generating in a website project, we also want to type to be public so the // designer files can access the type. - if (documentToBeGeneratedIn.Project != document.Project || - GeneratedTypesMustBePublic(documentToBeGeneratedIn.Project)) + if (documentToBeGeneratedIn.Project != document.Project) { IsPublicAccessibilityForTypeGeneration = true; } diff --git a/src/Features/Core/Portable/GenerateType/AbstractGenerateTypeService.cs b/src/Features/Core/Portable/GenerateType/AbstractGenerateTypeService.cs index 597bc6ed94bac..9baaefdd9d7d1 100644 --- a/src/Features/Core/Portable/GenerateType/AbstractGenerateTypeService.cs +++ b/src/Features/Core/Portable/GenerateType/AbstractGenerateTypeService.cs @@ -16,8 +16,7 @@ using Microsoft.CodeAnalysis.CodeGeneration; using Microsoft.CodeAnalysis.Formatting; using Microsoft.CodeAnalysis.Internal.Log; -using Microsoft.CodeAnalysis.LanguageServices; -using Microsoft.CodeAnalysis.LanguageServices.ProjectInfoService; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Shared.Utilities; @@ -115,8 +114,7 @@ private ImmutableArray GetActions( var generateNewTypeInDialog = false; if (state.NamespaceToGenerateInOpt != null) { - var workspace = document.Project.Solution.Workspace; - if (workspace == null || workspace.CanApplyChange(ApplyChangesKind.AddDocument)) + if (document.Project.Solution.CanApplyChange(ApplyChangesKind.AddDocument)) { generateNewTypeInDialog = true; result.Add(new GenerateTypeCodeAction((TService)this, document.Document, state, fallbackOptions, intoNamespace: true, inNewFile: true)); @@ -199,8 +197,8 @@ protected static ImmutableArray GetTypeParameters( // For anything that was a type parameter, just use the name (if we haven't already // used it). Otherwise, synthesize new names for the parameters. - using var namesDisposer = ArrayBuilder.GetInstance(arity, out var names); - using var isFixedDisposer = ArrayBuilder.GetInstance(arity, out var isFixed); + using var _1 = ArrayBuilder.GetInstance(arity, out var names); + using var _2 = ArrayBuilder.GetInstance(arity, out var isFixed); for (var i = 0; i < arity; i++) { var argument = i < arguments.Count ? arguments[i] : null; @@ -293,16 +291,5 @@ protected static async Task IsWithinTheImportingNamespaceAsync(Document do return false; } - - protected static bool GeneratedTypesMustBePublic(Project project) - { - var projectInfoService = project.Solution.Workspace.Services.GetService(); - if (projectInfoService != null) - { - return projectInfoService.GeneratedTypesMustBePublic(project); - } - - return false; - } } } diff --git a/src/Features/Core/Portable/GenerateType/IGenerateTypeOptionService.cs b/src/Features/Core/Portable/GenerateType/IGenerateTypeOptionService.cs index a5a449810eb2c..3422d60751005 100644 --- a/src/Features/Core/Portable/GenerateType/IGenerateTypeOptionService.cs +++ b/src/Features/Core/Portable/GenerateType/IGenerateTypeOptionService.cs @@ -5,7 +5,7 @@ #nullable disable using Microsoft.CodeAnalysis.Host; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Notification; using Microsoft.CodeAnalysis.ProjectManagement; diff --git a/src/Features/Core/Portable/GoToDefinition/AbstractFindDefinitionService.cs b/src/Features/Core/Portable/GoToDefinition/AbstractFindDefinitionService.cs index 88c55975f02f1..7102992b46fb2 100644 --- a/src/Features/Core/Portable/GoToDefinition/AbstractFindDefinitionService.cs +++ b/src/Features/Core/Portable/GoToDefinition/AbstractFindDefinitionService.cs @@ -18,13 +18,13 @@ public async Task> FindDefinitionsAsync( Document document, int position, CancellationToken cancellationToken) { var symbolService = document.GetRequiredLanguageService(); - var (symbol, _) = await symbolService.GetSymbolAndBoundSpanAsync(document, position, includeType: true, cancellationToken).ConfigureAwait(false); + var (symbol, project, _) = await symbolService.GetSymbolProjectAndBoundSpanAsync(document, position, includeType: true, cancellationToken).ConfigureAwait(false); - symbol = await SymbolFinder.FindSourceDefinitionAsync(symbol, document.Project.Solution, cancellationToken).ConfigureAwait(false) ?? symbol; + symbol = await SymbolFinder.FindSourceDefinitionAsync(symbol, project.Solution, cancellationToken).ConfigureAwait(false) ?? symbol; // Try to compute source definitions from symbol. return symbol != null - ? NavigableItemFactory.GetItemsFromPreferredSourceLocations(document.Project.Solution, symbol, displayTaggedParts: FindUsagesHelpers.GetDisplayParts(symbol), cancellationToken: cancellationToken) + ? NavigableItemFactory.GetItemsFromPreferredSourceLocations(project.Solution, symbol, displayTaggedParts: FindUsagesHelpers.GetDisplayParts(symbol), cancellationToken: cancellationToken) : ImmutableArray.Empty; } } diff --git a/src/Features/Core/Portable/GoToDefinition/AbstractGoToDefinitionSymbolService.cs b/src/Features/Core/Portable/GoToDefinition/AbstractGoToDefinitionSymbolService.cs index f451481a8b698..520c984cb0c63 100644 --- a/src/Features/Core/Portable/GoToDefinition/AbstractGoToDefinitionSymbolService.cs +++ b/src/Features/Core/Portable/GoToDefinition/AbstractGoToDefinitionSymbolService.cs @@ -7,8 +7,9 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.FindSymbols; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Shared.Extensions; +using Microsoft.CodeAnalysis.SymbolMapping; using Microsoft.CodeAnalysis.Text; namespace Microsoft.CodeAnalysis.GoToDefinition @@ -19,9 +20,10 @@ internal abstract class AbstractGoToDefinitionSymbolService : IGoToDefinitionSym protected abstract int? GetTargetPositionIfControlFlow(SemanticModel semanticModel, SyntaxToken token); - public async Task<(ISymbol?, TextSpan)> GetSymbolAndBoundSpanAsync(Document document, int position, bool includeType, CancellationToken cancellationToken) + public async Task<(ISymbol?, Project, TextSpan)> GetSymbolProjectAndBoundSpanAsync(Document document, int position, bool includeType, CancellationToken cancellationToken) { - var services = document.Project.Solution.Workspace.Services; + var project = document.Project; + var services = document.Project.Solution.Services; var semanticModel = await document.GetRequiredSemanticModelAsync(cancellationToken).ConfigureAwait(false); var semanticInfo = await SymbolFinder.GetSemanticInfoAtPositionAsync(semanticModel, position, services, cancellationToken).ConfigureAwait(false); @@ -29,10 +31,28 @@ internal abstract class AbstractGoToDefinitionSymbolService : IGoToDefinitionSym if (symbol is null) { - return (null, semanticInfo.Span); + return (null, project, semanticInfo.Span); } - return (FindRelatedExplicitlyDeclaredSymbol(symbol, semanticModel.Compilation), semanticInfo.Span); + // 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. + // For example when looking at a file from Source Link, it could be a partial type that + // only has a subset of the type actually part of the project (because the rest hasn't been + // downloaded) so we want to ensure we're navigating based on the original metadata symbol. + var mappingService = services.GetRequiredService(); + var mapping = await mappingService.MapSymbolAsync(document, symbol, cancellationToken).ConfigureAwait(false); + + // If the mapping fails, we proceed as normal with the symbol we originally found. + if (mapping is not null) + { + symbol = mapping.Symbol; + project = mapping.Project; + } + + // The compilation will have already been realised, either by the semantic model or the symbol mapping + var compilation = await project.GetRequiredCompilationAsync(cancellationToken).ConfigureAwait(false); + return (FindRelatedExplicitlyDeclaredSymbol(symbol, compilation), project, semanticInfo.Span); } public async Task GetTargetIfControlFlowAsync(Document document, int position, CancellationToken cancellationToken) diff --git a/src/Features/Core/Portable/GoToDefinition/IGoToDefinitionSymbolService.cs b/src/Features/Core/Portable/GoToDefinition/IGoToDefinitionSymbolService.cs index 7d9261be1096b..3d8b43a94b0a4 100644 --- a/src/Features/Core/Portable/GoToDefinition/IGoToDefinitionSymbolService.cs +++ b/src/Features/Core/Portable/GoToDefinition/IGoToDefinitionSymbolService.cs @@ -11,7 +11,7 @@ namespace Microsoft.CodeAnalysis.GoToDefinition { internal interface IGoToDefinitionSymbolService : ILanguageService { - Task<(ISymbol?, TextSpan)> GetSymbolAndBoundSpanAsync(Document document, int position, bool includeType, CancellationToken cancellationToken); + Task<(ISymbol?, Project, TextSpan)> GetSymbolProjectAndBoundSpanAsync(Document document, int position, bool includeType, CancellationToken cancellationToken); /// /// If the position is on a control flow keyword (continue, break, yield, return , etc), returns the relevant position in the corresponding control flow statement. diff --git a/src/Features/Core/Portable/ImplementAbstractClass/AbstractImplementAbstractClassCodeFixProvider.cs b/src/Features/Core/Portable/ImplementAbstractClass/AbstractImplementAbstractClassCodeFixProvider.cs index 5bd2c638e25d9..02142593a8170 100644 --- a/src/Features/Core/Portable/ImplementAbstractClass/AbstractImplementAbstractClassCodeFixProvider.cs +++ b/src/Features/Core/Portable/ImplementAbstractClass/AbstractImplementAbstractClassCodeFixProvider.cs @@ -42,7 +42,7 @@ public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context) return; var data = await ImplementAbstractClassData.TryGetDataAsync( - document, classNode, GetClassIdentifier(classNode), context.Options.GetImplementTypeGenerationOptions(document.Project.LanguageServices), cancellationToken).ConfigureAwait(false); + document, classNode, GetClassIdentifier(classNode), context.Options.GetImplementTypeGenerationOptions(document.Project.Services), cancellationToken).ConfigureAwait(false); if (data == null) return; diff --git a/src/Features/Core/Portable/ImplementAbstractClass/ImplementAbstractClassData.cs b/src/Features/Core/Portable/ImplementAbstractClass/ImplementAbstractClassData.cs index 47eb4f3de379c..efdc95e1e3d0b 100644 --- a/src/Features/Core/Portable/ImplementAbstractClass/ImplementAbstractClassData.cs +++ b/src/Features/Core/Portable/ImplementAbstractClass/ImplementAbstractClassData.cs @@ -14,7 +14,7 @@ using Microsoft.CodeAnalysis.CodeGeneration; using Microsoft.CodeAnalysis.Editing; using Microsoft.CodeAnalysis.ImplementType; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Shared.Utilities; using Roslyn.Utilities; diff --git a/src/Features/Core/Portable/ImplementInterface/AbstractImplementInterfaceService.CodeAction.cs b/src/Features/Core/Portable/ImplementInterface/AbstractImplementInterfaceService.CodeAction.cs index 619ceafc23503..3d2da50b868b5 100644 --- a/src/Features/Core/Portable/ImplementInterface/AbstractImplementInterfaceService.CodeAction.cs +++ b/src/Features/Core/Portable/ImplementInterface/AbstractImplementInterfaceService.CodeAction.cs @@ -15,7 +15,7 @@ using Microsoft.CodeAnalysis.CodeGeneration; using Microsoft.CodeAnalysis.Editing; using Microsoft.CodeAnalysis.ImplementType; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Shared.Utilities; diff --git a/src/Features/Core/Portable/ImplementInterface/AbstractImplementInterfaceService.CodeAction_Method.cs b/src/Features/Core/Portable/ImplementInterface/AbstractImplementInterfaceService.CodeAction_Method.cs index 5915a9cde4d2c..86f9621d2a1a9 100644 --- a/src/Features/Core/Portable/ImplementInterface/AbstractImplementInterfaceService.CodeAction_Method.cs +++ b/src/Features/Core/Portable/ImplementInterface/AbstractImplementInterfaceService.CodeAction_Method.cs @@ -5,7 +5,7 @@ using System.Collections.Immutable; using Microsoft.CodeAnalysis.CodeGeneration; using Microsoft.CodeAnalysis.Editing; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Shared.Extensions; namespace Microsoft.CodeAnalysis.ImplementInterface diff --git a/src/Features/Core/Portable/ImplementInterface/AbstractImplementInterfaceService.CodeAction_Property.cs b/src/Features/Core/Portable/ImplementInterface/AbstractImplementInterfaceService.CodeAction_Property.cs index 47b30b67aa0b5..64c04db8fe1c1 100644 --- a/src/Features/Core/Portable/ImplementInterface/AbstractImplementInterfaceService.CodeAction_Property.cs +++ b/src/Features/Core/Portable/ImplementInterface/AbstractImplementInterfaceService.CodeAction_Property.cs @@ -7,7 +7,7 @@ using Microsoft.CodeAnalysis.CodeGeneration; using Microsoft.CodeAnalysis.Editing; using Microsoft.CodeAnalysis.ImplementType; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Shared.Utilities; using Roslyn.Utilities; @@ -39,7 +39,7 @@ private ISymbol GenerateProperty( compilation, property, accessibility, generateAbstractly, useExplicitInterfaceSymbol, propertyGenerationBehavior, attributesToRemove); - var syntaxFacts = Document.Project.LanguageServices.GetRequiredService(); + var syntaxFacts = Document.Project.Services.GetRequiredService(); var parameterNames = NameGenerator.EnsureUniqueness( property.Parameters.SelectAsArray(p => p.Name), @@ -154,7 +154,7 @@ private ImmutableArray GetGetAccessorStatements( if (generateAbstractly) return default; - var generator = Document.Project.LanguageServices.GetRequiredService(); + var generator = Document.Project.Services.GetRequiredService(); return generator.GetGetAccessorStatements(compilation, property, ThroughMember, propertyGenerationBehavior == ImplementTypePropertyGenerationBehavior.PreferAutoProperties); } diff --git a/src/Features/Core/Portable/ImplementInterface/AbstractImplementInterfaceService.DisposePatternCodeAction.cs b/src/Features/Core/Portable/ImplementInterface/AbstractImplementInterfaceService.DisposePatternCodeAction.cs index 759fccc14a59c..4e53e6363d9d1 100644 --- a/src/Features/Core/Portable/ImplementInterface/AbstractImplementInterfaceService.DisposePatternCodeAction.cs +++ b/src/Features/Core/Portable/ImplementInterface/AbstractImplementInterfaceService.DisposePatternCodeAction.cs @@ -15,7 +15,7 @@ using Microsoft.CodeAnalysis.Editing; using Microsoft.CodeAnalysis.Formatting; using Microsoft.CodeAnalysis.ImplementType; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Shared.Utilities; @@ -340,7 +340,7 @@ public async ValueTask GetAccessibilityModifiers return value.Value; } - var fallbackFormattingOptions = await ((OptionsProvider)Options.FallbackOptions).GetOptionsAsync(document.Project.LanguageServices, cancellationToken).ConfigureAwait(false); + var fallbackFormattingOptions = await ((OptionsProvider)Options.FallbackOptions).GetOptionsAsync(document.Project.Services, cancellationToken).ConfigureAwait(false); return fallbackFormattingOptions.AccessibilityModifiersRequired; } diff --git a/src/Features/Core/Portable/IncrementalCaches/SymbolTreeInfoCacheService.cs b/src/Features/Core/Portable/IncrementalCaches/SymbolTreeInfoCacheService.cs deleted file mode 100644 index 5b5a10165c9a2..0000000000000 --- a/src/Features/Core/Portable/IncrementalCaches/SymbolTreeInfoCacheService.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. - -#nullable disable - -using System.Collections.Concurrent; -using System.Threading; -using System.Threading.Tasks; -using Microsoft.CodeAnalysis.FindSymbols; -using Microsoft.CodeAnalysis.FindSymbols.SymbolTree; - -namespace Microsoft.CodeAnalysis.IncrementalCaches -{ - internal partial class SymbolTreeInfoIncrementalAnalyzerProvider - { - private class SymbolTreeInfoCacheService : ISymbolTreeInfoCacheService - { - // Shared with SymbolTreeInfoIncrementalAnalyzer. They populate these values, we read from them. - - private readonly ConcurrentDictionary _projectIdToInfo; - private readonly ConcurrentDictionary _metadataIdToInfo; - - public SymbolTreeInfoCacheService( - ConcurrentDictionary projectIdToInfo, - ConcurrentDictionary metadataIdToInfo) - { - _projectIdToInfo = projectIdToInfo; - _metadataIdToInfo = metadataIdToInfo; - } - - public async ValueTask TryGetMetadataSymbolTreeInfoAsync( - Solution solution, - PortableExecutableReference reference, - CancellationToken cancellationToken) - { - var metadataId = SymbolTreeInfo.GetMetadataIdNoThrow(reference); - if (metadataId == null) - return null; - - var checksum = SymbolTreeInfo.GetMetadataChecksum(solution, reference, cancellationToken); - - // See if the last value produced matches what the caller is asking for. If so, return that. - if (_metadataIdToInfo.TryGetValue(metadataId, out var metadataInfo) && - metadataInfo.SymbolTreeInfo.Checksum == checksum) - { - return metadataInfo.SymbolTreeInfo; - } - - // If we didn't have it in our cache, see if we can load it from disk. - // Note: pass 'loadOnly' so we only attempt to load from disk, not to actually - // try to create the metadata. - var info = await SymbolTreeInfo.GetInfoForMetadataReferenceAsync( - solution, reference, checksum, loadOnly: true, cancellationToken).ConfigureAwait(false); - return info; - } - - public async Task TryGetSourceSymbolTreeInfoAsync( - Project project, CancellationToken cancellationToken) - { - // See if the last value produced matches what the caller is asking for. If so, return that. - var checksum = await SymbolTreeInfo.GetSourceSymbolsChecksumAsync(project, cancellationToken).ConfigureAwait(false); - if (_projectIdToInfo.TryGetValue(project.Id, out var projectInfo) && - projectInfo.Checksum == checksum) - { - return projectInfo; - } - - // If we didn't have it in our cache, see if we can load it from disk. - // Note: pass 'loadOnly' so we only attempt to load from disk, not to actually - // try to create the index. - var info = await SymbolTreeInfo.GetInfoForSourceAssemblyAsync( - project, checksum, loadOnly: true, cancellationToken).ConfigureAwait(false); - return info; - } - } - } -} diff --git a/src/Features/Core/Portable/IncrementalCaches/SymbolTreeInfoIncrementalAnalyzer.cs b/src/Features/Core/Portable/IncrementalCaches/SymbolTreeInfoIncrementalAnalyzer.cs deleted file mode 100644 index faadfbd0c2e32..0000000000000 --- a/src/Features/Core/Portable/IncrementalCaches/SymbolTreeInfoIncrementalAnalyzer.cs +++ /dev/null @@ -1,197 +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.Collections.Concurrent; -using System.Collections.Generic; -using System.Diagnostics; -using System.Threading; -using System.Threading.Tasks; -using Microsoft.CodeAnalysis.FindSymbols; -using Microsoft.CodeAnalysis.PooledObjects; -using Microsoft.CodeAnalysis.Shared.Collections; -using Microsoft.CodeAnalysis.SolutionCrawler; -using Roslyn.Utilities; - -namespace Microsoft.CodeAnalysis.IncrementalCaches -{ - internal partial class SymbolTreeInfoIncrementalAnalyzerProvider - { - private class SymbolTreeInfoIncrementalAnalyzer : IncrementalAnalyzerBase - { - // Shared with SymbolTreeInfoCacheService. We populate the values, they read from them. - - private readonly ConcurrentDictionary _projectIdToInfo; - private readonly ConcurrentDictionary _metadataIdToInfo; - - public SymbolTreeInfoIncrementalAnalyzer( - ConcurrentDictionary projectToInfo, - ConcurrentDictionary metadataIdToInfo) - { - _projectIdToInfo = projectToInfo; - _metadataIdToInfo = metadataIdToInfo; - } - - private static bool SupportAnalysis(Project project) - => project.SupportsCompilation; - - public override async Task AnalyzeDocumentAsync(Document document, SyntaxNode bodyOpt, InvocationReasons reasons, CancellationToken cancellationToken) - { - if (!SupportAnalysis(document.Project)) - return; - - if (bodyOpt != null) - { - // This was a method body edit. We can reuse the existing SymbolTreeInfo if - // we have one. We can't just bail out here as the change in the document means - // we'll have a new checksum. We need to get that new checksum so that our - // cached information is valid. - if (_projectIdToInfo.TryGetValue(document.Project.Id, out var cachedInfo)) - { - var checksum = await SymbolTreeInfo.GetSourceSymbolsChecksumAsync( - document.Project, cancellationToken).ConfigureAwait(false); - - var newInfo = cachedInfo.WithChecksum(checksum); - _projectIdToInfo[document.Project.Id] = newInfo; - return; - } - } - - await UpdateSymbolTreeInfoAsync(document.Project, cancellationToken).ConfigureAwait(false); - } - - public override Task AnalyzeProjectAsync(Project project, bool semanticsChanged, InvocationReasons reasons, CancellationToken cancellationToken) - { - if (!SupportAnalysis(project)) - return Task.CompletedTask; - - return UpdateSymbolTreeInfoAsync(project, cancellationToken); - } - - private async Task UpdateSymbolTreeInfoAsync(Project project, CancellationToken cancellationToken) - { - Debug.Assert(SupportAnalysis(project)); - - // Produce the indices for the source and metadata symbols in parallel. - using var _ = ArrayBuilder.GetInstance(out var tasks); - - tasks.Add(Task.Run(() => this.UpdateSourceSymbolTreeInfoAsync(project, cancellationToken), cancellationToken)); - tasks.Add(Task.Run(() => this.UpdateReferencesAsync(project, cancellationToken), cancellationToken)); - - await Task.WhenAll(tasks).ConfigureAwait(false); - } - - private async Task UpdateSourceSymbolTreeInfoAsync(Project project, CancellationToken cancellationToken) - { - var checksum = await SymbolTreeInfo.GetSourceSymbolsChecksumAsync(project, cancellationToken).ConfigureAwait(false); - if (!_projectIdToInfo.TryGetValue(project.Id, out var projectInfo) || - projectInfo.Checksum != checksum) - { - projectInfo = await SymbolTreeInfo.GetInfoForSourceAssemblyAsync( - project, checksum, loadOnly: false, cancellationToken).ConfigureAwait(false); - - Contract.ThrowIfNull(projectInfo); - Contract.ThrowIfTrue(projectInfo.Checksum != checksum, "If we computed a SymbolTreeInfo, then its checksum much match our checksum."); - - // Mark that we're up to date with this project. Future calls with the same - // semantic version can bail out immediately. - _projectIdToInfo[project.Id] = projectInfo; - } - } - - private async Task UpdateReferencesAsync(Project project, CancellationToken cancellationToken) - { - // Process all metadata references. If it remote workspace, do this in parallel. - using var pendingTasks = new TemporaryArray(); - - foreach (var reference in project.MetadataReferences) - { - if (reference is not PortableExecutableReference portableExecutableReference) - continue; - - if (cancellationToken.IsCancellationRequested) - { - // Break out of this loop to make sure other pending operations process cancellation before - // returning. - break; - } - - var updateTask = UpdateReferenceAsync(_metadataIdToInfo, project, portableExecutableReference, cancellationToken); - if (updateTask.Status != TaskStatus.RanToCompletion) - pendingTasks.Add(updateTask); - } - - if (pendingTasks.Count > 0) - { - // If any update operations did not complete synchronously (including any cancelled operations), - // wait for them to complete now. - await Task.WhenAll(pendingTasks.ToImmutableAndClear()).ConfigureAwait(false); - } - - // ⚠ This local function must be 'async' to ensure exceptions are captured in the resulting task and - // not thrown directly to the caller. - static async Task UpdateReferenceAsync( - ConcurrentDictionary metadataIdToInfo, - Project project, - PortableExecutableReference reference, - CancellationToken cancellationToken) - { - var metadataId = SymbolTreeInfo.GetMetadataIdNoThrow(reference); - if (metadataId == null) - return; - - // 🐉 PERF: GetMetadataChecksum indirectly uses a ConditionalWeakTable. This call is intentionally - // placed before the first 'await' of this asynchronous method to ensure it executes in the - // synchronous portion of the caller. https://dev.azure.com/devdiv/DevDiv/_workitems/edit/1270250 - var checksum = SymbolTreeInfo.GetMetadataChecksum(project.Solution, reference, cancellationToken); - if (!metadataIdToInfo.TryGetValue(metadataId, out var metadataInfo) || - metadataInfo.SymbolTreeInfo.Checksum != checksum) - { - var info = await SymbolTreeInfo.GetInfoForMetadataReferenceAsync( - project.Solution, reference, checksum, loadOnly: false, cancellationToken: cancellationToken).ConfigureAwait(false); - - Contract.ThrowIfNull(info); - Contract.ThrowIfTrue(info.Checksum != checksum, "If we computed a SymbolTreeInfo, then its checksum much match our checksum."); - - // Note, getting the info may fail (for example, bogus metadata). That's ok. - // We still want to cache that result so that don't try to continuously produce - // this info over and over again. - metadataInfo = new MetadataInfo(info, metadataInfo.ReferencingProjects ?? new HashSet()); - metadataIdToInfo[metadataId] = metadataInfo; - } - - // Keep track that this dll is referenced by this project. - lock (metadataInfo.ReferencingProjects) - { - metadataInfo.ReferencingProjects.Add(project.Id); - } - } - } - - public override Task RemoveProjectAsync(ProjectId projectId, CancellationToken cancellationToken) - { - _projectIdToInfo.TryRemove(projectId, out _); - RemoveMetadataReferences(projectId); - - return Task.CompletedTask; - } - - private void RemoveMetadataReferences(ProjectId projectId) - { - foreach (var (id, info) in _metadataIdToInfo.ToArray()) - { - lock (info.ReferencingProjects) - { - info.ReferencingProjects.Remove(projectId); - - // If this metadata dll isn't referenced by any project. We can just dump it. - if (info.ReferencingProjects.Count == 0) - _metadataIdToInfo.TryRemove(id, out _); - } - } - } - } - } -} diff --git a/src/Features/Core/Portable/IncrementalCaches/SyntaxTreeInfoIncrementalAnalyzerProvider.cs b/src/Features/Core/Portable/IncrementalCaches/SyntaxTreeInfoIncrementalAnalyzerProvider.cs deleted file mode 100644 index 285fc09e1f2a7..0000000000000 --- a/src/Features/Core/Portable/IncrementalCaches/SyntaxTreeInfoIncrementalAnalyzerProvider.cs +++ /dev/null @@ -1,42 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using System; -using System.Composition; -using System.Threading; -using System.Threading.Tasks; -using Microsoft.CodeAnalysis.FindSymbols; -using Microsoft.CodeAnalysis.Host.Mef; -using Microsoft.CodeAnalysis.SolutionCrawler; - -namespace Microsoft.CodeAnalysis.IncrementalCaches -{ - [ExportIncrementalAnalyzerProvider(nameof(SyntaxTreeInfoIncrementalAnalyzerProvider), new[] { WorkspaceKind.RemoteWorkspace }), Shared] - internal class SyntaxTreeInfoIncrementalAnalyzerProvider : IIncrementalAnalyzerProvider - { - [ImportingConstructor] - [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] - public SyntaxTreeInfoIncrementalAnalyzerProvider() - { - } - - public IIncrementalAnalyzer CreateIncrementalAnalyzer(Workspace workspace) - => new IncrementalAnalyzer(); - - private class IncrementalAnalyzer : IncrementalAnalyzerBase - { - public override async Task AnalyzeSyntaxAsync(Document document, InvocationReasons reasons, CancellationToken cancellationToken) - { - if (!document.SupportsSyntaxTree) - { - // Not a language we can produce indices for (i.e. TypeScript). Bail immediately. - return; - } - - await SyntaxTreeIndex.PrecalculateAsync(document, cancellationToken).ConfigureAwait(false); - await TopLevelSyntaxTreeIndex.PrecalculateAsync(document, cancellationToken).ConfigureAwait(false); - } - } - } -} diff --git a/src/Features/Core/Portable/InheritanceMargin/AbstractInheritanceMarginService.cs b/src/Features/Core/Portable/InheritanceMargin/AbstractInheritanceMarginService.cs index 2e1b571421bcb..c5319dcb54eef 100644 --- a/src/Features/Core/Portable/InheritanceMargin/AbstractInheritanceMarginService.cs +++ b/src/Features/Core/Portable/InheritanceMargin/AbstractInheritanceMarginService.cs @@ -10,7 +10,7 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.FindUsages; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Remote; using Microsoft.CodeAnalysis.Shared.Extensions; @@ -47,7 +47,7 @@ public async ValueTask> GetInheritanceMemb CancellationToken cancellationToken) { var solution = document.Project.Solution; - var remoteClient = await RemoteHostClient.TryGetClientAsync(solution.Workspace.Services, cancellationToken).ConfigureAwait(false); + var remoteClient = await RemoteHostClient.TryGetClientAsync(solution.Services, cancellationToken).ConfigureAwait(false); if (remoteClient != null) { // Also, make it clear to the remote side that they should be using frozen semantics, just like we are. diff --git a/src/Features/Core/Portable/InheritanceMargin/AbstractInheritanceMarginService_Helpers.cs b/src/Features/Core/Portable/InheritanceMargin/AbstractInheritanceMarginService_Helpers.cs index 18098d6079267..fa5d715000fa3 100644 --- a/src/Features/Core/Portable/InheritanceMargin/AbstractInheritanceMarginService_Helpers.cs +++ b/src/Features/Core/Portable/InheritanceMargin/AbstractInheritanceMarginService_Helpers.cs @@ -13,7 +13,7 @@ using Microsoft.CodeAnalysis.FindSymbols; using Microsoft.CodeAnalysis.FindSymbols.FindReferences; using Microsoft.CodeAnalysis.FindUsages; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Remote; using Microsoft.CodeAnalysis.Shared.Extensions; @@ -87,7 +87,7 @@ private static async ValueTask> GetSymbolI var sourceText = await document.GetTextAsync(cancellationToken).ConfigureAwait(false); var semanticModel = await document.GetRequiredSemanticModelAsync(cancellationToken).ConfigureAwait(false); - var mappingService = document.Project.Solution.Workspace.Services.GetRequiredService(); + var mappingService = document.Project.Solution.Services.GetRequiredService(); using var _ = ArrayBuilder<(ISymbol symbol, int lineNumber)>.GetInstance(out var builder); Project? project = null; diff --git a/src/Features/Core/Portable/InitializeParameter/AbstractAddParameterCheckCodeRefactoringProvider.cs b/src/Features/Core/Portable/InitializeParameter/AbstractAddParameterCheckCodeRefactoringProvider.cs index 19a66efb6fa5f..34b3d469c4d01 100644 --- a/src/Features/Core/Portable/InitializeParameter/AbstractAddParameterCheckCodeRefactoringProvider.cs +++ b/src/Features/Core/Portable/InitializeParameter/AbstractAddParameterCheckCodeRefactoringProvider.cs @@ -12,7 +12,7 @@ using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeGeneration; using Microsoft.CodeAnalysis.Editing; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Operations; using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.PooledObjects; @@ -381,7 +381,7 @@ private async Task AddNullCheckStatementAsync( var semanticModel = await document.GetRequiredSemanticModelAsync(cancellationToken).ConfigureAwait(false); var root = await document.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false); - var editor = new SyntaxEditor(root, document.Project.Solution.Workspace.Services); + var editor = new SyntaxEditor(root, document.Project.Solution.Services); var nullCheckStatement = generateNullCheck(semanticModel, editor.Generator); // We may be inserting a statement into a single-line container. In that case, diff --git a/src/Features/Core/Portable/InitializeParameter/AbstractInitializeMemberFromParameterCodeRefactoringProviderMemberCreation.cs b/src/Features/Core/Portable/InitializeParameter/AbstractInitializeMemberFromParameterCodeRefactoringProviderMemberCreation.cs index fcd16b9173052..3995f8abe8900 100644 --- a/src/Features/Core/Portable/InitializeParameter/AbstractInitializeMemberFromParameterCodeRefactoringProviderMemberCreation.cs +++ b/src/Features/Core/Portable/InitializeParameter/AbstractInitializeMemberFromParameterCodeRefactoringProviderMemberCreation.cs @@ -437,7 +437,7 @@ private async Task AddSingleSymbolInitializationAsync( CodeGenerationOptionsProvider fallbackOptions, CancellationToken cancellationToken) { - var services = document.Project.Solution.Workspace.Services; + var services = document.Project.Solution.Services; var root = await document.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false); var editor = new SyntaxEditor(root, services); var generator = editor.Generator; diff --git a/src/Features/Core/Portable/InitializeParameter/AbstractInitializeParameterCodeRefactoringProvider.cs b/src/Features/Core/Portable/InitializeParameter/AbstractInitializeParameterCodeRefactoringProvider.cs index 4d527d0befb76..a0182783d3181 100644 --- a/src/Features/Core/Portable/InitializeParameter/AbstractInitializeParameterCodeRefactoringProvider.cs +++ b/src/Features/Core/Portable/InitializeParameter/AbstractInitializeParameterCodeRefactoringProvider.cs @@ -12,7 +12,7 @@ using Microsoft.CodeAnalysis.CodeGeneration; using Microsoft.CodeAnalysis.CodeRefactorings; using Microsoft.CodeAnalysis.Editing; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Operations; using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Shared.Extensions; diff --git a/src/Features/Core/Portable/InlineHints/AbstractInlineHintsService.cs b/src/Features/Core/Portable/InlineHints/AbstractInlineHintsService.cs index 010899b408704..57f94a2a62dc0 100644 --- a/src/Features/Core/Portable/InlineHints/AbstractInlineHintsService.cs +++ b/src/Features/Core/Portable/InlineHints/AbstractInlineHintsService.cs @@ -6,7 +6,7 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.Host; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Text; diff --git a/src/Features/Core/Portable/InlineHints/AbstractInlineParameterNameHintsService.cs b/src/Features/Core/Portable/InlineHints/AbstractInlineParameterNameHintsService.cs index 763e2b8b65b1d..8c894d4d1b946 100644 --- a/src/Features/Core/Portable/InlineHints/AbstractInlineParameterNameHintsService.cs +++ b/src/Features/Core/Portable/InlineHints/AbstractInlineParameterNameHintsService.cs @@ -7,7 +7,7 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Shared.Extensions; @@ -38,7 +38,7 @@ protected abstract void AddAllParameterNameHintLocations( public async Task> GetInlineHintsAsync(Document document, TextSpan textSpan, InlineParameterHintsOptions options, SymbolDescriptionOptions displayOptions, CancellationToken cancellationToken) { // TODO: https://github.com/dotnet/roslyn/issues/57283 - var globalOptions = document.Project.Solution.Workspace.Services.GetRequiredService(); + var globalOptions = document.Project.Solution.Services.GetRequiredService(); var displayAllOverride = globalOptions.InlineHintsOptionsDisplayAllOverride; var enabledForParameters = displayAllOverride || options.EnabledForParameters; diff --git a/src/Features/Core/Portable/InlineHints/AbstractInlineTypeHintsService.cs b/src/Features/Core/Portable/InlineHints/AbstractInlineTypeHintsService.cs index fcc4e9e6bfb8e..0ca5ccc787ec4 100644 --- a/src/Features/Core/Portable/InlineHints/AbstractInlineTypeHintsService.cs +++ b/src/Features/Core/Portable/InlineHints/AbstractInlineTypeHintsService.cs @@ -8,7 +8,7 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Shared.Extensions; @@ -34,7 +34,7 @@ public async Task> GetInlineHintsAsync( Document document, TextSpan textSpan, InlineTypeHintsOptions options, SymbolDescriptionOptions displayOptions, CancellationToken cancellationToken) { // TODO: https://github.com/dotnet/roslyn/issues/57283 - var globalOptions = document.Project.Solution.Workspace.Services.GetRequiredService(); + var globalOptions = document.Project.Solution.Services.GetRequiredService(); var displayAllOverride = globalOptions.InlineHintsOptionsDisplayAllOverride; var enabledForTypes = options.EnabledForTypes; diff --git a/src/Features/Core/Portable/InlineHints/IInlineHintsService.cs b/src/Features/Core/Portable/InlineHints/IInlineHintsService.cs index a2e2e3412f803..4ad032d32722a 100644 --- a/src/Features/Core/Portable/InlineHints/IInlineHintsService.cs +++ b/src/Features/Core/Portable/InlineHints/IInlineHintsService.cs @@ -6,7 +6,7 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.Host; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Text; diff --git a/src/Features/Core/Portable/InlineHints/IInlineParameterNameHintsService.cs b/src/Features/Core/Portable/InlineHints/IInlineParameterNameHintsService.cs index d79821085aeb8..6892cf950b36e 100644 --- a/src/Features/Core/Portable/InlineHints/IInlineParameterNameHintsService.cs +++ b/src/Features/Core/Portable/InlineHints/IInlineParameterNameHintsService.cs @@ -6,7 +6,7 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.Host; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Text; namespace Microsoft.CodeAnalysis.InlineHints diff --git a/src/Features/Core/Portable/InlineHints/IInlineTypeHintsService.cs b/src/Features/Core/Portable/InlineHints/IInlineTypeHintsService.cs index 2227402a1a8d0..e09f58bc2e7fc 100644 --- a/src/Features/Core/Portable/InlineHints/IInlineTypeHintsService.cs +++ b/src/Features/Core/Portable/InlineHints/IInlineTypeHintsService.cs @@ -6,7 +6,7 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.Host; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Text; namespace Microsoft.CodeAnalysis.InlineHints diff --git a/src/Features/Core/Portable/InlineHints/InlineHintHelpers.cs b/src/Features/Core/Portable/InlineHints/InlineHintHelpers.cs index 19fbdec7499c9..979f0d985b29c 100644 --- a/src/Features/Core/Portable/InlineHints/InlineHintHelpers.cs +++ b/src/Features/Core/Portable/InlineHints/InlineHintHelpers.cs @@ -9,7 +9,7 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.DocumentationComments; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Shared.Extensions; namespace Microsoft.CodeAnalysis.InlineHints diff --git a/src/Features/Core/Portable/InlineHints/InlineHintsOptions.cs b/src/Features/Core/Portable/InlineHints/InlineHintsOptions.cs index 987b454eee768..b61e5555ba31d 100644 --- a/src/Features/Core/Portable/InlineHints/InlineHintsOptions.cs +++ b/src/Features/Core/Portable/InlineHints/InlineHintsOptions.cs @@ -3,7 +3,7 @@ // See the LICENSE file in the project root for more information. using System.Runtime.Serialization; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; namespace Microsoft.CodeAnalysis.InlineHints; diff --git a/src/Features/Core/Portable/InlineMethod/AbstractInlineMethodRefactoringProvider.InlineContext.cs b/src/Features/Core/Portable/InlineMethod/AbstractInlineMethodRefactoringProvider.InlineContext.cs index 436286776be60..ca0df0fe66236 100644 --- a/src/Features/Core/Portable/InlineMethod/AbstractInlineMethodRefactoringProvider.InlineContext.cs +++ b/src/Features/Core/Portable/InlineMethod/AbstractInlineMethodRefactoringProvider.InlineContext.cs @@ -9,7 +9,7 @@ using System.Threading.Tasks; using Microsoft.CodeAnalysis.Editing; using Microsoft.CodeAnalysis.FindSymbols; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Operations; using Microsoft.CodeAnalysis.Shared.Extensions; using Roslyn.Utilities; diff --git a/src/Features/Core/Portable/InlineMethod/AbstractInlineMethodRefactoringProvider.MethodParametersInfo.cs b/src/Features/Core/Portable/InlineMethod/AbstractInlineMethodRefactoringProvider.MethodParametersInfo.cs index 10566b9b4ec3a..1057567437fcc 100644 --- a/src/Features/Core/Portable/InlineMethod/AbstractInlineMethodRefactoringProvider.MethodParametersInfo.cs +++ b/src/Features/Core/Portable/InlineMethod/AbstractInlineMethodRefactoringProvider.MethodParametersInfo.cs @@ -9,7 +9,7 @@ using System.Threading.Tasks; using Microsoft.CodeAnalysis.Editing; using Microsoft.CodeAnalysis.FindSymbols; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Operations; using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Shared.Extensions; diff --git a/src/Features/Core/Portable/InlineMethod/AbstractInlineMethodRefactoringProvider.cs b/src/Features/Core/Portable/InlineMethod/AbstractInlineMethodRefactoringProvider.cs index 05013fd119e96..b1dd905339867 100644 --- a/src/Features/Core/Portable/InlineMethod/AbstractInlineMethodRefactoringProvider.cs +++ b/src/Features/Core/Portable/InlineMethod/AbstractInlineMethodRefactoringProvider.cs @@ -10,7 +10,7 @@ using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeRefactorings; using Microsoft.CodeAnalysis.Editing; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Operations; using Microsoft.CodeAnalysis.Shared.Extensions; diff --git a/src/Features/Core/Portable/IntroduceUsingStatement/AbstractIntroduceUsingStatementCodeRefactoringProvider.cs b/src/Features/Core/Portable/IntroduceUsingStatement/AbstractIntroduceUsingStatementCodeRefactoringProvider.cs index 6bd43c8fdc30c..7343a095556e2 100644 --- a/src/Features/Core/Portable/IntroduceUsingStatement/AbstractIntroduceUsingStatementCodeRefactoringProvider.cs +++ b/src/Features/Core/Portable/IntroduceUsingStatement/AbstractIntroduceUsingStatementCodeRefactoringProvider.cs @@ -11,7 +11,7 @@ using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeRefactorings; using Microsoft.CodeAnalysis.Formatting; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Operations; using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Shared.Extensions; diff --git a/src/Features/Core/Portable/IntroduceVariable/AbstractIntroduceParameterDocumentRewriter.cs b/src/Features/Core/Portable/IntroduceVariable/AbstractIntroduceParameterDocumentRewriter.cs index 49b032e9aa5a8..1795e453b2608 100644 --- a/src/Features/Core/Portable/IntroduceVariable/AbstractIntroduceParameterDocumentRewriter.cs +++ b/src/Features/Core/Portable/IntroduceVariable/AbstractIntroduceParameterDocumentRewriter.cs @@ -12,7 +12,7 @@ using Microsoft.CodeAnalysis.CodeGeneration; using Microsoft.CodeAnalysis.Editing; using Microsoft.CodeAnalysis.Formatting; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Shared.Extensions; using Roslyn.Utilities; diff --git a/src/Features/Core/Portable/IntroduceVariable/AbstractIntroduceParameterService.cs b/src/Features/Core/Portable/IntroduceVariable/AbstractIntroduceParameterService.cs index 6b023951cd426..e98953c2ce910 100644 --- a/src/Features/Core/Portable/IntroduceVariable/AbstractIntroduceParameterService.cs +++ b/src/Features/Core/Portable/IntroduceVariable/AbstractIntroduceParameterService.cs @@ -13,7 +13,7 @@ using Microsoft.CodeAnalysis.CodeRefactorings; using Microsoft.CodeAnalysis.Editing; using Microsoft.CodeAnalysis.FindSymbols; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Operations; using Microsoft.CodeAnalysis.Shared.Collections; using Microsoft.CodeAnalysis.Shared.Extensions; @@ -40,7 +40,7 @@ internal abstract partial class AbstractIntroduceParameterService< public sealed override async Task ComputeRefactoringsAsync(CodeRefactoringContext context) { var (document, textSpan, cancellationToken) = context; - if (document.Project.Solution.Workspace.Kind == WorkspaceKind.MiscellaneousFiles) + if (document.Project.Solution.WorkspaceKind == WorkspaceKind.MiscellaneousFiles) { return; } diff --git a/src/Features/Core/Portable/IntroduceVariable/AbstractIntroduceVariableService.AbstractIntroduceVariableCodeAction.cs b/src/Features/Core/Portable/IntroduceVariable/AbstractIntroduceVariableService.AbstractIntroduceVariableCodeAction.cs index 993d92c6821fd..5759c6ab37958 100644 --- a/src/Features/Core/Portable/IntroduceVariable/AbstractIntroduceVariableService.AbstractIntroduceVariableCodeAction.cs +++ b/src/Features/Core/Portable/IntroduceVariable/AbstractIntroduceVariableService.AbstractIntroduceVariableCodeAction.cs @@ -8,7 +8,7 @@ using System.Threading.Tasks; using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeCleanup; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Simplification; diff --git a/src/Features/Core/Portable/IntroduceVariable/AbstractIntroduceVariableService.State.cs b/src/Features/Core/Portable/IntroduceVariable/AbstractIntroduceVariableService.State.cs index 037a04da51273..ac39f3057353e 100644 --- a/src/Features/Core/Portable/IntroduceVariable/AbstractIntroduceVariableService.State.cs +++ b/src/Features/Core/Portable/IntroduceVariable/AbstractIntroduceVariableService.State.cs @@ -11,7 +11,7 @@ using Microsoft.CodeAnalysis.CodeCleanup; using Microsoft.CodeAnalysis.CodeRefactorings; using Microsoft.CodeAnalysis.Editing; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Shared.Utilities; using Microsoft.CodeAnalysis.Text; @@ -266,7 +266,7 @@ private bool CanIntroduceVariable( // // In essence, this says "i can be replaced with an expression as long as I'm not being // written to". - var semanticFacts = Document.Project.LanguageServices.GetService(); + var semanticFacts = Document.Project.Services.GetService(); return semanticFacts.CanReplaceWithRValue(Document.SemanticModel, Expression, cancellationToken); } diff --git a/src/Features/Core/Portable/IntroduceVariable/AbstractIntroduceVariableService.cs b/src/Features/Core/Portable/IntroduceVariable/AbstractIntroduceVariableService.cs index d979c0dce0cec..080f2d36e6471 100644 --- a/src/Features/Core/Portable/IntroduceVariable/AbstractIntroduceVariableService.cs +++ b/src/Features/Core/Portable/IntroduceVariable/AbstractIntroduceVariableService.cs @@ -15,7 +15,7 @@ using Microsoft.CodeAnalysis.Editing; using Microsoft.CodeAnalysis.Formatting; using Microsoft.CodeAnalysis.Internal.Log; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Operations; using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Shared.Extensions; @@ -299,7 +299,7 @@ protected ISet FindMatches( bool allOccurrences, CancellationToken cancellationToken) { - var syntaxFacts = currentDocument.Project.LanguageServices.GetService(); + var syntaxFacts = currentDocument.Project.Services.GetService(); var originalSemanticModel = originalDocument.SemanticModel; var currentSemanticModel = currentDocument.SemanticModel; diff --git a/src/Features/Core/Portable/IntroduceVariable/IntroduceLocalForExpressionCodeRefactoringProvider.cs b/src/Features/Core/Portable/IntroduceVariable/IntroduceLocalForExpressionCodeRefactoringProvider.cs index d2c221535baf8..3ce3b09db1cf8 100644 --- a/src/Features/Core/Portable/IntroduceVariable/IntroduceLocalForExpressionCodeRefactoringProvider.cs +++ b/src/Features/Core/Portable/IntroduceVariable/IntroduceLocalForExpressionCodeRefactoringProvider.cs @@ -10,7 +10,7 @@ using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeRefactorings; using Microsoft.CodeAnalysis.Editing; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Text; diff --git a/src/Features/Core/Portable/IntroduceVariable/IntroduceVariableCodeRefactoringProvider.cs b/src/Features/Core/Portable/IntroduceVariable/IntroduceVariableCodeRefactoringProvider.cs index 0a567e53a1313..a43064ab8acf4 100644 --- a/src/Features/Core/Portable/IntroduceVariable/IntroduceVariableCodeRefactoringProvider.cs +++ b/src/Features/Core/Portable/IntroduceVariable/IntroduceVariableCodeRefactoringProvider.cs @@ -31,7 +31,7 @@ public IntroduceVariableCodeRefactoringProvider() public override async Task ComputeRefactoringsAsync(CodeRefactoringContext context) { var (document, textSpan, cancellationToken) = context; - if (document.Project.Solution.Workspace.Kind == WorkspaceKind.MiscellaneousFiles) + if (document.Project.Solution.WorkspaceKind == WorkspaceKind.MiscellaneousFiles) { return; } diff --git a/src/Features/Core/Portable/InvertConditional/AbstractInvertConditionalCodeRefactoringProvider.cs b/src/Features/Core/Portable/InvertConditional/AbstractInvertConditionalCodeRefactoringProvider.cs index 2a613a5b741f2..46d44b03bcbe8 100644 --- a/src/Features/Core/Portable/InvertConditional/AbstractInvertConditionalCodeRefactoringProvider.cs +++ b/src/Features/Core/Portable/InvertConditional/AbstractInvertConditionalCodeRefactoringProvider.cs @@ -46,7 +46,7 @@ private static async Task InvertConditionalAsync( var semanticModel = await document.GetRequiredSemanticModelAsync(cancellationToken).ConfigureAwait(false); var root = await document.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false); - var editor = new SyntaxEditor(root, document.Project.Solution.Workspace.Services); + var editor = new SyntaxEditor(root, document.Project.Solution.Services); editor.Generator.SyntaxFacts.GetPartsOfConditionalExpression(conditional, out var condition, out var whenTrue, out var whenFalse); diff --git a/src/Features/Core/Portable/InvertLogical/AbstractInvertLogicalCodeRefactoringProvider.cs b/src/Features/Core/Portable/InvertLogical/AbstractInvertLogicalCodeRefactoringProvider.cs index 32127658f5ccd..a5ffc3d7ad63d 100644 --- a/src/Features/Core/Portable/InvertLogical/AbstractInvertLogicalCodeRefactoringProvider.cs +++ b/src/Features/Core/Portable/InvertLogical/AbstractInvertLogicalCodeRefactoringProvider.cs @@ -9,7 +9,7 @@ using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeRefactorings; using Microsoft.CodeAnalysis.Editing; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Shared.Extensions; namespace Microsoft.CodeAnalysis.InvertLogical diff --git a/src/Features/Core/Portable/LanguageServices/AnonymousTypeDisplayService/AbstractStructuralTypeDisplayService.StructuralTypeCollectorVisitor.cs b/src/Features/Core/Portable/LanguageServices/AnonymousTypeDisplayService/AbstractStructuralTypeDisplayService.StructuralTypeCollectorVisitor.cs index 8d1660ba3edfd..c310c9a133725 100644 --- a/src/Features/Core/Portable/LanguageServices/AnonymousTypeDisplayService/AbstractStructuralTypeDisplayService.StructuralTypeCollectorVisitor.cs +++ b/src/Features/Core/Portable/LanguageServices/AnonymousTypeDisplayService/AbstractStructuralTypeDisplayService.StructuralTypeCollectorVisitor.cs @@ -6,7 +6,7 @@ using System.Collections.Generic; using Microsoft.CodeAnalysis.Shared.Extensions; -namespace Microsoft.CodeAnalysis.LanguageServices +namespace Microsoft.CodeAnalysis.LanguageService { internal partial class AbstractStructuralTypeDisplayService { diff --git a/src/Features/Core/Portable/LanguageServices/AnonymousTypeDisplayService/AbstractStructuralTypeDisplayService.cs b/src/Features/Core/Portable/LanguageServices/AnonymousTypeDisplayService/AbstractStructuralTypeDisplayService.cs index a42ef1e1fa6fb..18ae78ea6f8ae 100644 --- a/src/Features/Core/Portable/LanguageServices/AnonymousTypeDisplayService/AbstractStructuralTypeDisplayService.cs +++ b/src/Features/Core/Portable/LanguageServices/AnonymousTypeDisplayService/AbstractStructuralTypeDisplayService.cs @@ -9,7 +9,7 @@ using Microsoft.CodeAnalysis.Shared.Extensions; using Roslyn.Utilities; -namespace Microsoft.CodeAnalysis.LanguageServices +namespace Microsoft.CodeAnalysis.LanguageService { internal abstract partial class AbstractStructuralTypeDisplayService : IStructuralTypeDisplayService { diff --git a/src/Features/Core/Portable/LanguageServices/AnonymousTypeDisplayService/IStructuralTypeDisplayService.cs b/src/Features/Core/Portable/LanguageServices/AnonymousTypeDisplayService/IStructuralTypeDisplayService.cs index 35539381050cd..b646196bfb0d7 100644 --- a/src/Features/Core/Portable/LanguageServices/AnonymousTypeDisplayService/IStructuralTypeDisplayService.cs +++ b/src/Features/Core/Portable/LanguageServices/AnonymousTypeDisplayService/IStructuralTypeDisplayService.cs @@ -5,7 +5,7 @@ using System.Collections.Immutable; using Microsoft.CodeAnalysis.Host; -namespace Microsoft.CodeAnalysis.LanguageServices +namespace Microsoft.CodeAnalysis.LanguageService { internal interface IStructuralTypeDisplayService : ILanguageService { diff --git a/src/Features/Core/Portable/LanguageServices/AnonymousTypeDisplayService/StructuralTypeDisplayInfo.cs b/src/Features/Core/Portable/LanguageServices/AnonymousTypeDisplayService/StructuralTypeDisplayInfo.cs index b6a0348927c1b..4214a3856969f 100644 --- a/src/Features/Core/Portable/LanguageServices/AnonymousTypeDisplayService/StructuralTypeDisplayInfo.cs +++ b/src/Features/Core/Portable/LanguageServices/AnonymousTypeDisplayService/StructuralTypeDisplayInfo.cs @@ -4,7 +4,7 @@ using System.Collections.Generic; -namespace Microsoft.CodeAnalysis.LanguageServices +namespace Microsoft.CodeAnalysis.LanguageService { internal readonly struct StructuralTypeDisplayInfo { diff --git a/src/Features/Core/Portable/LanguageServices/ProjectInfoService/IProjectInfoService.cs b/src/Features/Core/Portable/LanguageServices/ProjectInfoService/IProjectInfoService.cs deleted file mode 100644 index 010eea5593e0a..0000000000000 --- a/src/Features/Core/Portable/LanguageServices/ProjectInfoService/IProjectInfoService.cs +++ /dev/null @@ -1,15 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -#nullable disable - -using Microsoft.CodeAnalysis.Host; - -namespace Microsoft.CodeAnalysis.LanguageServices.ProjectInfoService -{ - internal interface IProjectInfoService : IWorkspaceService - { - bool GeneratedTypesMustBePublic(Project project); - } -} diff --git a/src/Features/Core/Portable/LanguageServices/SymbolDisplayService/AbstractSymbolDisplayService.AbstractSymbolDescriptionBuilder.cs b/src/Features/Core/Portable/LanguageServices/SymbolDisplayService/AbstractSymbolDisplayService.AbstractSymbolDescriptionBuilder.cs index be0defbb43304..5f7341f91bdca 100644 --- a/src/Features/Core/Portable/LanguageServices/SymbolDisplayService/AbstractSymbolDisplayService.AbstractSymbolDescriptionBuilder.cs +++ b/src/Features/Core/Portable/LanguageServices/SymbolDisplayService/AbstractSymbolDisplayService.AbstractSymbolDescriptionBuilder.cs @@ -20,7 +20,7 @@ using Microsoft.CodeAnalysis.Shared.Extensions; using Roslyn.Utilities; -namespace Microsoft.CodeAnalysis.LanguageServices +namespace Microsoft.CodeAnalysis.LanguageService { internal partial class AbstractSymbolDisplayService { @@ -88,14 +88,14 @@ protected abstract partial class AbstractSymbolDescriptionBuilder private readonly Dictionary> _documentationMap = new(); private readonly Func _getNavigationHint; - protected readonly HostWorkspaceServices Services; + protected readonly SolutionServices Services; protected readonly SymbolDescriptionOptions Options; protected readonly CancellationToken CancellationToken; protected AbstractSymbolDescriptionBuilder( SemanticModel semanticModel, int position, - HostWorkspaceServices services, + SolutionServices services, IStructuralTypeDisplayService structuralTypeDisplayService, SymbolDescriptionOptions options, CancellationToken cancellationToken) @@ -169,7 +169,7 @@ private async Task AddPartsAsync(ImmutableArray symbols) private void AddDocumentationContent(ISymbol symbol) { - var formatter = Services.GetLanguageServices(_semanticModel.Language).GetRequiredService(); + var formatter = Services.GetRequiredLanguageService(_semanticModel.Language); if (symbol is IParameterSymbol or ITypeParameterSymbol) { diff --git a/src/Features/Core/Portable/LanguageServices/SymbolDisplayService/AbstractSymbolDisplayService.AnonymousTypes.cs b/src/Features/Core/Portable/LanguageServices/SymbolDisplayService/AbstractSymbolDisplayService.AnonymousTypes.cs index 538f6fad51520..bbac6a2f33e75 100644 --- a/src/Features/Core/Portable/LanguageServices/SymbolDisplayService/AbstractSymbolDisplayService.AnonymousTypes.cs +++ b/src/Features/Core/Portable/LanguageServices/SymbolDisplayService/AbstractSymbolDisplayService.AnonymousTypes.cs @@ -6,7 +6,7 @@ using Microsoft.CodeAnalysis.Shared.Extensions; using Roslyn.Utilities; -namespace Microsoft.CodeAnalysis.LanguageServices +namespace Microsoft.CodeAnalysis.LanguageService { internal partial class AbstractSymbolDisplayService { diff --git a/src/Features/Core/Portable/LanguageServices/SymbolDisplayService/AbstractSymbolDisplayService.cs b/src/Features/Core/Portable/LanguageServices/SymbolDisplayService/AbstractSymbolDisplayService.cs index 765118247d6c6..72cb3c6bc34d5 100644 --- a/src/Features/Core/Portable/LanguageServices/SymbolDisplayService/AbstractSymbolDisplayService.cs +++ b/src/Features/Core/Portable/LanguageServices/SymbolDisplayService/AbstractSymbolDisplayService.cs @@ -13,14 +13,14 @@ using Microsoft.CodeAnalysis.Host; using Roslyn.Utilities; -namespace Microsoft.CodeAnalysis.LanguageServices +namespace Microsoft.CodeAnalysis.LanguageService { internal abstract partial class AbstractSymbolDisplayService : ISymbolDisplayService { - protected readonly HostLanguageServices Services; + protected readonly LanguageServices Services; protected readonly IStructuralTypeDisplayService AnonymousTypeDisplayService; - protected AbstractSymbolDisplayService(HostLanguageServices services) + protected AbstractSymbolDisplayService(LanguageServices services) { Services = services; AnonymousTypeDisplayService = services.GetService(); diff --git a/src/Features/Core/Portable/LanguageServices/SymbolDisplayService/ISymbolDisplayService.cs b/src/Features/Core/Portable/LanguageServices/SymbolDisplayService/ISymbolDisplayService.cs index 47f5ad86a2f05..08ed0a35ac86e 100644 --- a/src/Features/Core/Portable/LanguageServices/SymbolDisplayService/ISymbolDisplayService.cs +++ b/src/Features/Core/Portable/LanguageServices/SymbolDisplayService/ISymbolDisplayService.cs @@ -11,7 +11,7 @@ using Microsoft.CodeAnalysis.Classification; using Microsoft.CodeAnalysis.Host; -namespace Microsoft.CodeAnalysis.LanguageServices +namespace Microsoft.CodeAnalysis.LanguageService { internal interface ISymbolDisplayService : ILanguageService { diff --git a/src/Features/Core/Portable/LanguageServices/SymbolDisplayService/SymbolDescriptionGroups.cs b/src/Features/Core/Portable/LanguageServices/SymbolDisplayService/SymbolDescriptionGroups.cs index 0783fb9a11271..da105817ed781 100644 --- a/src/Features/Core/Portable/LanguageServices/SymbolDisplayService/SymbolDescriptionGroups.cs +++ b/src/Features/Core/Portable/LanguageServices/SymbolDisplayService/SymbolDescriptionGroups.cs @@ -6,7 +6,7 @@ using System; -namespace Microsoft.CodeAnalysis.LanguageServices +namespace Microsoft.CodeAnalysis.LanguageService { [Flags] internal enum SymbolDescriptionGroups diff --git a/src/Features/Core/Portable/LanguageServices/SymbolDisplayService/SymbolDescriptionOptions.cs b/src/Features/Core/Portable/LanguageServices/SymbolDisplayService/SymbolDescriptionOptions.cs index 9fe79b2b2bb58..21766f34d8062 100644 --- a/src/Features/Core/Portable/LanguageServices/SymbolDisplayService/SymbolDescriptionOptions.cs +++ b/src/Features/Core/Portable/LanguageServices/SymbolDisplayService/SymbolDescriptionOptions.cs @@ -6,7 +6,7 @@ using Microsoft.CodeAnalysis.Classification; using Microsoft.CodeAnalysis.QuickInfo; -namespace Microsoft.CodeAnalysis.LanguageServices; +namespace Microsoft.CodeAnalysis.LanguageService; [DataContract] internal readonly record struct SymbolDescriptionOptions diff --git a/src/Features/Core/Portable/MakeMethodAsynchronous/AbstractMakeMethodAsynchronousCodeFixProvider.cs b/src/Features/Core/Portable/MakeMethodAsynchronous/AbstractMakeMethodAsynchronousCodeFixProvider.cs index 1784c37a94cd3..d98d90e6582d2 100644 --- a/src/Features/Core/Portable/MakeMethodAsynchronous/AbstractMakeMethodAsynchronousCodeFixProvider.cs +++ b/src/Features/Core/Portable/MakeMethodAsynchronous/AbstractMakeMethodAsynchronousCodeFixProvider.cs @@ -10,7 +10,7 @@ using System.Threading.Tasks; using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeFixes; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Rename; using Microsoft.CodeAnalysis.Shared.Extensions; using Roslyn.Utilities; diff --git a/src/Features/Core/Portable/MakeMethodSynchronous/AbstractMakeMethodSynchronousCodeFixProvider.cs b/src/Features/Core/Portable/MakeMethodSynchronous/AbstractMakeMethodSynchronousCodeFixProvider.cs index fa992de4336e9..a1aaf48eeb015 100644 --- a/src/Features/Core/Portable/MakeMethodSynchronous/AbstractMakeMethodSynchronousCodeFixProvider.cs +++ b/src/Features/Core/Portable/MakeMethodSynchronous/AbstractMakeMethodSynchronousCodeFixProvider.cs @@ -15,7 +15,7 @@ using Microsoft.CodeAnalysis.Editing; using Microsoft.CodeAnalysis.FindSymbols; using Microsoft.CodeAnalysis.Formatting; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Rename; using Microsoft.CodeAnalysis.Shared.Extensions; using Roslyn.Utilities; @@ -165,7 +165,7 @@ private static async Task RemoveAwaitFromCallersAsync( var syntaxFactsService = document.GetLanguageService(); var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); - var editor = new SyntaxEditor(root, currentSolution.Workspace.Services); + var editor = new SyntaxEditor(root, currentSolution.Services); foreach (var location in group) { diff --git a/src/Features/Core/Portable/MetadataAsSource/AbstractMetadataAsSourceService.WrappedNamedTypeSymbol.cs b/src/Features/Core/Portable/MetadataAsSource/AbstractMetadataAsSourceService.WrappedNamedTypeSymbol.cs index 8439fc7c3bd27..02a938f0e1094 100644 --- a/src/Features/Core/Portable/MetadataAsSource/AbstractMetadataAsSourceService.WrappedNamedTypeSymbol.cs +++ b/src/Features/Core/Portable/MetadataAsSource/AbstractMetadataAsSourceService.WrappedNamedTypeSymbol.cs @@ -144,6 +144,8 @@ public ImmutableArray ToMinimalDisplayParts(SemanticModel sem public bool IsNativeIntegerType => _symbol.IsNativeIntegerType; + public bool IsFileLocal => _symbol.IsFileLocal; + public INamedTypeSymbol NativeIntegerUnderlyingType => _symbol.NativeIntegerUnderlyingType; NullableAnnotation ITypeSymbol.NullableAnnotation => throw new NotImplementedException(); diff --git a/src/Features/Core/Portable/MetadataAsSource/AbstractMetadataAsSourceService.cs b/src/Features/Core/Portable/MetadataAsSource/AbstractMetadataAsSourceService.cs index 59d7a4a7fee9b..62edf7c350005 100644 --- a/src/Features/Core/Portable/MetadataAsSource/AbstractMetadataAsSourceService.cs +++ b/src/Features/Core/Portable/MetadataAsSource/AbstractMetadataAsSourceService.cs @@ -13,7 +13,7 @@ using Microsoft.CodeAnalysis.DocumentationComments; using Microsoft.CodeAnalysis.Formatting; using Microsoft.CodeAnalysis.Formatting.Rules; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Simplification; diff --git a/src/Features/Core/Portable/MetadataAsSource/DecompilationMetadataAsSourceFileProvider.cs b/src/Features/Core/Portable/MetadataAsSource/DecompilationMetadataAsSourceFileProvider.cs index cd9cc69fd9f60..4f73c403fafa3 100644 --- a/src/Features/Core/Portable/MetadataAsSource/DecompilationMetadataAsSourceFileProvider.cs +++ b/src/Features/Core/Portable/MetadataAsSource/DecompilationMetadataAsSourceFileProvider.cs @@ -115,7 +115,7 @@ public DecompilationMetadataAsSourceFileProvider(IImplementationAssemblyLookupSe if (!useDecompiler) { - var sourceFromMetadataService = temporaryDocument.Project.LanguageServices.GetRequiredService(); + var sourceFromMetadataService = temporaryDocument.Project.Services.GetRequiredService(); temporaryDocument = await sourceFromMetadataService.AddSourceToAsync(temporaryDocument, compilation, symbol, options.GenerationOptions, cancellationToken).ConfigureAwait(false); } @@ -184,6 +184,10 @@ public DecompilationMetadataAsSourceFileProvider(IImplementationAssemblyLookupSe GlobalAssemblyCache.Instance.ResolvePartialName(fullAssemblyName, out assemblyLocation, preferredCulture: CultureInfo.CurrentCulture); isReferenceAssembly = assemblyLocation is null; } + catch (IOException) + { + // If we get an IO exception we can safely ignore it, and the system will show the metadata view of the reference assembly. + } catch (Exception e) when (FatalError.ReportAndCatch(e, ErrorSeverity.Diagnostic)) { } diff --git a/src/Features/Core/Portable/MetadataAsSource/MetadataAsSourceFileService.cs b/src/Features/Core/Portable/MetadataAsSource/MetadataAsSourceFileService.cs index b07e6a41d964d..46a1f0bbd464a 100644 --- a/src/Features/Core/Portable/MetadataAsSource/MetadataAsSourceFileService.cs +++ b/src/Features/Core/Portable/MetadataAsSource/MetadataAsSourceFileService.cs @@ -167,10 +167,7 @@ public bool ShouldCollapseOnOpen(string? filePath, BlockStructureOptions blockSt private void InitializeWorkspace(Project project) { - if (_workspace == null) - { - _workspace = new MetadataAsSourceWorkspace(this, project.Solution.Workspace.Services.HostServices); - } + _workspace ??= new MetadataAsSourceWorkspace(this, project.Solution.Workspace.Services.HostServices); } internal async Task MapSymbolAsync(Document document, SymbolKey symbolId, CancellationToken cancellationToken) diff --git a/src/Features/Core/Portable/MetadataAsSource/MetadataAsSourceOptions.cs b/src/Features/Core/Portable/MetadataAsSource/MetadataAsSourceOptions.cs index 9a1d16c598423..f32f5bb377709 100644 --- a/src/Features/Core/Portable/MetadataAsSource/MetadataAsSourceOptions.cs +++ b/src/Features/Core/Portable/MetadataAsSource/MetadataAsSourceOptions.cs @@ -31,6 +31,13 @@ internal readonly record struct MetadataAsSourceOptions( [DataMember] public bool AlwaysUseDefaultSymbolServers { get; init; } = true; - public static MetadataAsSourceOptions GetDefault(HostLanguageServices languageServices) + /// + /// to disallow downloading PDBs and trying to find source from + /// Source Link or embedded source. + /// + [DataMember] + public bool NavigateToSourceLinkAndEmbeddedSources { get; init; } = true; + + public static MetadataAsSourceOptions GetDefault(LanguageServices languageServices) => new(GenerationOptions: CleanCodeGenerationOptions.GetDefault(languageServices)); } diff --git a/src/Features/Core/Portable/MetadataAsSource/SymbolMappingServiceFactory.cs b/src/Features/Core/Portable/MetadataAsSource/SymbolMappingServiceFactory.cs index e4c5d32488f63..ca591cd197ec5 100644 --- a/src/Features/Core/Portable/MetadataAsSource/SymbolMappingServiceFactory.cs +++ b/src/Features/Core/Portable/MetadataAsSource/SymbolMappingServiceFactory.cs @@ -23,24 +23,27 @@ public SymbolMappingServiceFactory() } public IWorkspaceService CreateService(HostWorkspaceServices workspaceServices) - => new SymbolMappingService(); + => new SymbolMappingService(((MetadataAsSourceWorkspace)workspaceServices.Workspace).FileService); private sealed class SymbolMappingService : ISymbolMappingService { + private readonly MetadataAsSourceFileService _fileService; + + public SymbolMappingService(MetadataAsSourceFileService fileService) + { + _fileService = fileService; + } + public Task MapSymbolAsync(Document document, SymbolKey symbolId, CancellationToken cancellationToken) { - if (document.Project.Solution.Workspace is not MetadataAsSourceWorkspace workspace) - { + if (document.Project.Solution.WorkspaceKind is not WorkspaceKind.MetadataAsSource) throw new ArgumentException(FeaturesResources.Document_must_be_contained_in_the_workspace_that_created_this_service, nameof(document)); - } - return workspace.FileService.MapSymbolAsync(document, symbolId, cancellationToken); + return _fileService.MapSymbolAsync(document, symbolId, cancellationToken); } - public async Task MapSymbolAsync(Document document, ISymbol symbol, CancellationToken cancellationToken) - { - return await MapSymbolAsync(document, SymbolKey.Create(symbol, cancellationToken), cancellationToken).ConfigureAwait(false); - } + public Task MapSymbolAsync(Document document, ISymbol symbol, CancellationToken cancellationToken) + => MapSymbolAsync(document, SymbolKey.Create(symbol, cancellationToken), cancellationToken); } } } diff --git a/src/Features/Core/Portable/Microsoft.CodeAnalysis.Features.csproj b/src/Features/Core/Portable/Microsoft.CodeAnalysis.Features.csproj index 80ff821edb8ef..661fa8469e3e2 100644 --- a/src/Features/Core/Portable/Microsoft.CodeAnalysis.Features.csproj +++ b/src/Features/Core/Portable/Microsoft.CodeAnalysis.Features.csproj @@ -133,14 +133,14 @@ + - - - - + diff --git a/src/Features/Core/Portable/MoveDeclarationNearReference/AbstractMoveDeclarationNearReferenceCodeRefactoringProvider.cs b/src/Features/Core/Portable/MoveDeclarationNearReference/AbstractMoveDeclarationNearReferenceCodeRefactoringProvider.cs index d11500464c0f8..b09f15eb2a6cf 100644 --- a/src/Features/Core/Portable/MoveDeclarationNearReference/AbstractMoveDeclarationNearReferenceCodeRefactoringProvider.cs +++ b/src/Features/Core/Portable/MoveDeclarationNearReference/AbstractMoveDeclarationNearReferenceCodeRefactoringProvider.cs @@ -8,7 +8,7 @@ using System.Threading.Tasks; using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeRefactorings; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Shared.Extensions; namespace Microsoft.CodeAnalysis.MoveDeclarationNearReference diff --git a/src/Features/Core/Portable/MoveStaticMembers/AbstractMoveStaticMembersRefactoringProvider.cs b/src/Features/Core/Portable/MoveStaticMembers/AbstractMoveStaticMembersRefactoringProvider.cs index 82123c7a12c82..fdcccd58e0383 100644 --- a/src/Features/Core/Portable/MoveStaticMembers/AbstractMoveStaticMembersRefactoringProvider.cs +++ b/src/Features/Core/Portable/MoveStaticMembers/AbstractMoveStaticMembersRefactoringProvider.cs @@ -2,32 +2,35 @@ // The .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.Tasks; using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeRefactorings; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.PullMemberUp; using Microsoft.CodeAnalysis.Shared.Extensions; +using Microsoft.CodeAnalysis.Text; +using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.MoveStaticMembers { internal abstract class AbstractMoveStaticMembersRefactoringProvider : CodeRefactoringProvider { - protected abstract Task GetSelectedNodeAsync(CodeRefactoringContext context); + protected abstract Task> GetSelectedNodesAsync(CodeRefactoringContext context); public override async Task ComputeRefactoringsAsync(CodeRefactoringContext context) { var (document, span, cancellationToken) = context; - var service = document.Project.Solution.Workspace.Services.GetService(); + var service = document.Project.Solution.Services.GetService(); if (service == null) { return; } - var memberDeclaration = await GetSelectedNodeAsync(context).ConfigureAwait(false); - if (memberDeclaration == null) + var selectedMemberNodes = await GetSelectedNodesAsync(context).ConfigureAwait(false); + if (selectedMemberNodes.IsEmpty) { return; } @@ -38,26 +41,34 @@ public override async Task ComputeRefactoringsAsync(CodeRefactoringContext conte return; } - var selectedType = semanticModel.GetEnclosingNamedType(span.Start, cancellationToken); - if (selectedType == null) + var memberNodeSymbolPairs = selectedMemberNodes + .SelectAsArray(m => (node: m, symbol: semanticModel.GetRequiredDeclaredSymbol(m, cancellationToken))) + // Use same logic as pull members up for determining if a selected member + // is valid to be moved into a base + .WhereAsArray(pair => MemberAndDestinationValidator.IsMemberValid(pair.symbol) && pair.symbol.IsStatic); + + if (memberNodeSymbolPairs.IsEmpty) { return; } - var selectedMembers = selectedType.GetMembers() - .WhereAsArray(m => m.IsStatic && - MemberAndDestinationValidator.IsMemberValid(m) && - m.DeclaringSyntaxReferences.Any(static (sr, memberDeclaration) => memberDeclaration.FullSpan.Contains(sr.Span), memberDeclaration)); - if (selectedMembers.IsEmpty) + var selectedMembers = memberNodeSymbolPairs.SelectAsArray(pair => pair.symbol); + + var containingType = selectedMembers.First().ContainingType; + Contract.ThrowIfNull(containingType); + if (selectedMembers.Any(m => !m.ContainingType.Equals(containingType))) { return; } - var syntaxFacts = document.GetRequiredLanguageService(); + // we want to use a span which covers all the selected viable member nodes, so that more specific nodes have priority + var memberSpan = TextSpan.FromBounds( + memberNodeSymbolPairs.First().node.FullSpan.Start, + memberNodeSymbolPairs.Last().node.FullSpan.End); - var action = new MoveStaticMembersWithDialogCodeAction(document, span, service, selectedType, context.Options, selectedMember: selectedMembers[0]); + var action = new MoveStaticMembersWithDialogCodeAction(document, service, containingType, context.Options, selectedMembers); - context.RegisterRefactoring(action, selectedMembers[0].DeclaringSyntaxReferences[0].Span); + context.RegisterRefactoring(action, memberSpan); } } } diff --git a/src/Features/Core/Portable/MoveStaticMembers/IMoveStaticMembersOptionsService.cs b/src/Features/Core/Portable/MoveStaticMembers/IMoveStaticMembersOptionsService.cs index fa6cee14dfc15..46b4840be3c36 100644 --- a/src/Features/Core/Portable/MoveStaticMembers/IMoveStaticMembersOptionsService.cs +++ b/src/Features/Core/Portable/MoveStaticMembers/IMoveStaticMembersOptionsService.cs @@ -2,12 +2,13 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +using System.Collections.Immutable; using Microsoft.CodeAnalysis.Host; namespace Microsoft.CodeAnalysis.MoveStaticMembers { internal interface IMoveStaticMembersOptionsService : IWorkspaceService { - MoveStaticMembersOptions GetMoveMembersToTypeOptions(Document document, INamedTypeSymbol selectedType, ISymbol? selectedNodeSymbol); + MoveStaticMembersOptions GetMoveMembersToTypeOptions(Document document, INamedTypeSymbol selectedType, ImmutableArray selectedNodeSymbols); } } diff --git a/src/Features/Core/Portable/MoveStaticMembers/MoveStaticMembersOptions.cs b/src/Features/Core/Portable/MoveStaticMembers/MoveStaticMembersOptions.cs index a9d08e971892f..6975629882700 100644 --- a/src/Features/Core/Portable/MoveStaticMembers/MoveStaticMembersOptions.cs +++ b/src/Features/Core/Portable/MoveStaticMembers/MoveStaticMembersOptions.cs @@ -4,6 +4,7 @@ using System.Collections.Immutable; using System.Linq; +using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.MoveStaticMembers { @@ -13,9 +14,16 @@ internal readonly struct MoveStaticMembersOptions public string FileName { get; } - public string TypeName { get; } + public bool IsNewType { get; } - public string NamespaceDisplay { get; } + // only has value when IsNewType is false + public INamedTypeSymbol? Destination { get; } + + // only has value when IsNewType is true + public string? TypeName { get; } + + // only has value when IsNewType is true + public string? NamespaceDisplay { get; } public ImmutableArray SelectedMembers { get; } @@ -25,6 +33,23 @@ internal readonly struct MoveStaticMembersOptions ImmutableArray.Empty, isCancelled: true); + public MoveStaticMembersOptions( + INamedTypeSymbol destination, + ImmutableArray selectedMembers, + bool isCancelled = false) + { + var sourceLocation = destination.DeclaringSyntaxReferences.First(); + RoslynDebug.AssertNotNull(sourceLocation.SyntaxTree); + + IsCancelled = isCancelled; + FileName = sourceLocation.SyntaxTree.FilePath; + IsNewType = false; + Destination = destination; + TypeName = null; + NamespaceDisplay = null; + SelectedMembers = selectedMembers; + } + public MoveStaticMembersOptions( string fileName, string fullTypeName, @@ -33,6 +58,8 @@ public MoveStaticMembersOptions( { IsCancelled = isCancelled; FileName = fileName; + IsNewType = true; + Destination = null; var namespacesAndType = fullTypeName.Split(separator: '.'); TypeName = namespacesAndType.Last(); NamespaceDisplay = string.Join(separator: ".", namespacesAndType.Take(namespacesAndType.Length - 1)); diff --git a/src/Features/Core/Portable/MoveStaticMembers/MoveStaticMembersWithDialogCodeAction.cs b/src/Features/Core/Portable/MoveStaticMembers/MoveStaticMembersWithDialogCodeAction.cs index f3dc5a851c09e..645411e7d0c19 100644 --- a/src/Features/Core/Portable/MoveStaticMembers/MoveStaticMembersWithDialogCodeAction.cs +++ b/src/Features/Core/Portable/MoveStaticMembers/MoveStaticMembersWithDialogCodeAction.cs @@ -13,7 +13,7 @@ using Microsoft.CodeAnalysis.CodeRefactorings.PullMemberUp; using Microsoft.CodeAnalysis.Editing; using Microsoft.CodeAnalysis.FindSymbols; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Shared.Utilities; using Microsoft.CodeAnalysis.Simplification; @@ -25,33 +25,30 @@ namespace Microsoft.CodeAnalysis.MoveStaticMembers internal class MoveStaticMembersWithDialogCodeAction : CodeActionWithOptions { private readonly Document _document; - private readonly ISymbol? _selectedMember; + private readonly ImmutableArray _selectedMembers; private readonly INamedTypeSymbol _selectedType; private readonly IMoveStaticMembersOptionsService _service; private readonly CleanCodeGenerationOptionsProvider _fallbackOptions; - public TextSpan Span { get; } public override string Title => FeaturesResources.Move_static_members_to_another_type; public MoveStaticMembersWithDialogCodeAction( Document document, - TextSpan span, IMoveStaticMembersOptionsService service, INamedTypeSymbol selectedType, CleanCodeGenerationOptionsProvider fallbackOptions, - ISymbol? selectedMember = null) + ImmutableArray selectedMembers) { _document = document; _service = service; _selectedType = selectedType; _fallbackOptions = fallbackOptions; - _selectedMember = selectedMember; - Span = span; + _selectedMembers = selectedMembers; } public override object? GetOptions(CancellationToken cancellationToken) { - return _service.GetMoveMembersToTypeOptions(_document, _selectedType, _selectedMember); + return _service.GetMoveMembersToTypeOptions(_document, _selectedType, _selectedMembers); } protected override async Task> ComputeOperationsAsync(object options, CancellationToken cancellationToken) @@ -75,6 +72,26 @@ protected override async Task> ComputeOperation root = root.TrackNodes(memberNodes); var sourceDoc = _document.WithSyntaxRoot(root); + if (!moveOptions.IsNewType) + { + // we already have our destination type, but we need to find the document it is in + // When it is an existing type, "FileName" points to a full path rather than just the name + // There should be no two docs that have the same file path + var destinationDocId = _document.Project.Solution.GetDocumentIdsWithFilePath(moveOptions.FileName).Single(); + var fixedSolution = await RefactorAndMoveAsync( + moveOptions.SelectedMembers, + memberNodes, + sourceDoc.Project.Solution, + moveOptions.Destination!, + // TODO: Find a way to merge/change generic type args for classes, or change PullMembersUp to handle instead + typeArgIndices: ImmutableArray.Empty, + sourceDoc.Id, + destinationDocId, + cancellationToken).ConfigureAwait(false); + return new CodeActionOperation[] { new ApplyChangesOperation(fixedSolution) }; + } + + // otherwise, we need to create a destination ourselves var typeParameters = ExtractTypeHelpers.GetRequiredTypeParametersForMembers(_selectedType, moveOptions.SelectedMembers); // which indices of the old type params should we keep for a new class reference, used for refactoring usages var typeArgIndices = Enumerable.Range(0, _selectedType.TypeParameters.Length) @@ -87,7 +104,7 @@ protected override async Task> ComputeOperation Accessibility.NotApplicable, DeclarationModifiers.Static, GetNewTypeKind(_selectedType), - moveOptions.TypeName, + moveOptions.TypeName!, typeParameters: typeParameters); var (newDoc, annotation) = await ExtractTypeHelpers.AddTypeToNewFileAsync( @@ -137,6 +154,60 @@ private static TypeKind GetNewTypeKind(INamedTypeSymbol oldType) return oldType.TypeKind; } + /// + /// Finds references, refactors them, then moves the selected members to the destination. + /// Used when the destination type/file already exists. + /// + /// selected member symbols + /// nodes corresponding to those symbols in the old solution, should have been annotated + /// solution without any members moved/refactored + /// the type to move to, should be inserted into a document already + /// generic type arg indices to keep when refactoring generic class access to the new type. Empty if not relevant + /// Id of the document where the mebers are being moved from + /// The solution with references refactored and members moved to the newType + private async Task RefactorAndMoveAsync( + ImmutableArray selectedMembers, + ImmutableArray oldMemberNodes, + Solution oldSolution, + INamedTypeSymbol newType, + ImmutableArray typeArgIndices, + DocumentId sourceDocId, + DocumentId newTypeDocId, + CancellationToken cancellationToken) + { + // annotate our new type, in case our refactoring changes it + var newTypeDoc = await oldSolution.GetRequiredDocumentAsync(newTypeDocId, cancellationToken: cancellationToken).ConfigureAwait(false); + var newTypeRoot = await newTypeDoc.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false); + var newTypeNode = newType.DeclaringSyntaxReferences + .SelectAsArray(sRef => sRef.GetSyntax(cancellationToken)) + .First(node => newTypeRoot.Contains(node)); + newTypeRoot = newTypeRoot.TrackNodes(newTypeNode); + oldSolution = newTypeDoc.WithSyntaxRoot(newTypeRoot).Project.Solution; + + // refactor references across the entire solution + var memberReferenceLocations = await FindMemberReferencesAsync(selectedMembers, oldSolution, cancellationToken).ConfigureAwait(false); + var projectToLocations = memberReferenceLocations.ToLookup(loc => loc.location.Document.Project.Id); + var solutionWithFixedReferences = await RefactorReferencesAsync(projectToLocations, oldSolution, newType, typeArgIndices, cancellationToken).ConfigureAwait(false); + + var sourceDoc = solutionWithFixedReferences.GetRequiredDocument(sourceDocId); + + // get back tracked nodes from our changes + var root = await sourceDoc.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false); + var semanticModel = await sourceDoc.GetRequiredSemanticModelAsync(cancellationToken).ConfigureAwait(false); + var members = oldMemberNodes + .Select(node => root.GetCurrentNode(node)) + .WhereNotNull() + .SelectAsArray(node => (semanticModel.GetDeclaredSymbol(node, cancellationToken), false)); + + newTypeDoc = solutionWithFixedReferences.GetRequiredDocument(newTypeDoc.Id); + newTypeRoot = await newTypeDoc.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false); + var newTypeSemanticModel = await newTypeDoc.GetRequiredSemanticModelAsync(cancellationToken).ConfigureAwait(false); + newType = (INamedTypeSymbol)newTypeSemanticModel.GetRequiredDeclaredSymbol(newTypeRoot.GetCurrentNode(newTypeNode)!, cancellationToken); + + var pullMembersUpOptions = PullMembersUpOptionsBuilder.BuildPullMembersUpOptions(newType, members); + return await MembersPuller.PullMembersUpAsync(sourceDoc, pullMembersUpOptions, _fallbackOptions, cancellationToken).ConfigureAwait(false); + } + private static async Task RefactorReferencesAsync( ILookup projectToLocations, Solution solution, diff --git a/src/Features/Core/Portable/MoveToNamespace/AbstractMoveToNamespaceCodeAction.cs b/src/Features/Core/Portable/MoveToNamespace/AbstractMoveToNamespaceCodeAction.cs index b19e8aecaab99..6d3cccd76b5fd 100644 --- a/src/Features/Core/Portable/MoveToNamespace/AbstractMoveToNamespaceCodeAction.cs +++ b/src/Features/Core/Portable/MoveToNamespace/AbstractMoveToNamespaceCodeAction.cs @@ -65,7 +65,7 @@ private static ImmutableArray CreateRenameOperations(MoveTo using var _ = PooledObjects.ArrayBuilder.GetInstance(out var operations); operations.Add(new ApplyChangesOperation(moveToNamespaceResult.UpdatedSolution)); - var symbolRenameCodeActionOperationFactory = moveToNamespaceResult.UpdatedSolution.Workspace.Services.GetService(); + var symbolRenameCodeActionOperationFactory = moveToNamespaceResult.UpdatedSolution.Services.GetService(); // It's possible we're not in a host context providing this service, in which case // just provide a code action that won't notify of the symbol rename. diff --git a/src/Features/Core/Portable/MoveToNamespace/AbstractMoveToNamespaceService.cs b/src/Features/Core/Portable/MoveToNamespace/AbstractMoveToNamespaceService.cs index 94a2974f22c40..d201d81fea02d 100644 --- a/src/Features/Core/Portable/MoveToNamespace/AbstractMoveToNamespaceService.cs +++ b/src/Features/Core/Portable/MoveToNamespace/AbstractMoveToNamespaceService.cs @@ -17,7 +17,7 @@ using Microsoft.CodeAnalysis.CodeRefactorings.MoveType; using Microsoft.CodeAnalysis.Formatting; using Microsoft.CodeAnalysis.Host; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Text; using Roslyn.Utilities; @@ -270,11 +270,8 @@ private static async Task MoveTypeToNamespaceAsync( var syntaxRoot = await mergedDocument.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); var syntaxNode = syntaxRoot.GetAnnotatedNodes(AbstractMoveTypeService.NamespaceScopeMovedAnnotation).SingleOrDefault(); - if (syntaxNode == null) - { - // The type might be declared in global namespace - syntaxNode = container.FirstAncestorOrSelf() ?? syntaxRoot; - } + // The type might be declared in global namespace + syntaxNode ??= container.FirstAncestorOrSelf() ?? syntaxRoot; return await MoveItemsInNamespaceAsync( mergedDocument, diff --git a/src/Features/Core/Portable/MoveToNamespace/IMoveToNamespaceOptionsService.cs b/src/Features/Core/Portable/MoveToNamespace/IMoveToNamespaceOptionsService.cs index 8093285b75d61..cbe2a5f91dd27 100644 --- a/src/Features/Core/Portable/MoveToNamespace/IMoveToNamespaceOptionsService.cs +++ b/src/Features/Core/Portable/MoveToNamespace/IMoveToNamespaceOptionsService.cs @@ -6,7 +6,7 @@ using System.Collections.Immutable; using Microsoft.CodeAnalysis.Host; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; namespace Microsoft.CodeAnalysis.MoveToNamespace { diff --git a/src/Features/Core/Portable/NameTupleElement/AbstractNameTupleElementCodeRefactoringProvider.cs b/src/Features/Core/Portable/NameTupleElement/AbstractNameTupleElementCodeRefactoringProvider.cs index 24502132948b0..b47c13ada623c 100644 --- a/src/Features/Core/Portable/NameTupleElement/AbstractNameTupleElementCodeRefactoringProvider.cs +++ b/src/Features/Core/Portable/NameTupleElement/AbstractNameTupleElementCodeRefactoringProvider.cs @@ -8,7 +8,7 @@ using System.Threading.Tasks; using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeRefactorings; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Text; @@ -41,7 +41,7 @@ public override async Task ComputeRefactoringsAsync(CodeRefactoringContext conte private static async Task<(SyntaxNode root, TArgumentSyntax argument, string argumentName)> TryGetArgumentInfoAsync( Document document, TextSpan span, CancellationToken cancellationToken) { - if (document.Project.Solution.Workspace.Kind == WorkspaceKind.MiscellaneousFiles) + if (document.Project.Solution.WorkspaceKind == WorkspaceKind.MiscellaneousFiles) { return default; } diff --git a/src/Features/Core/Portable/NavigateTo/AbstractNavigateToSearchService.CachedDocumentSearch.cs b/src/Features/Core/Portable/NavigateTo/AbstractNavigateToSearchService.CachedDocumentSearch.cs index cf40acadcdcbe..fb9ebfb9e4604 100644 --- a/src/Features/Core/Portable/NavigateTo/AbstractNavigateToSearchService.CachedDocumentSearch.cs +++ b/src/Features/Core/Portable/NavigateTo/AbstractNavigateToSearchService.CachedDocumentSearch.cs @@ -77,7 +77,7 @@ await client.TryInvokeAsync( return; } - var storageService = solution.Workspace.Services.GetPersistentStorageService(); + var storageService = solution.Services.GetPersistentStorageService(); await SearchCachedDocumentsInCurrentProcessAsync( storageService, documentKeys, priorityDocumentKeys, searchPattern, kinds, onItemFound, cancellationToken).ConfigureAwait(false); } diff --git a/src/Features/Core/Portable/NavigateTo/INavigateToSearcherHost.cs b/src/Features/Core/Portable/NavigateTo/INavigateToSearcherHost.cs index cedc87754286a..534a316b3bf80 100644 --- a/src/Features/Core/Portable/NavigateTo/INavigateToSearcherHost.cs +++ b/src/Features/Core/Portable/NavigateTo/INavigateToSearcherHost.cs @@ -56,7 +56,7 @@ public DefaultNavigateToSearchHost( public async ValueTask IsFullyLoadedAsync(CancellationToken cancellationToken) { - var service = _solution.Workspace.Services.GetRequiredService(); + var service = _solution.Services.GetRequiredService(); // We consider ourselves fully loaded when both the project system has completed loaded // us, and we've totally hydrated the oop side. Until that happens, we'll attempt to @@ -102,7 +102,7 @@ private Task GetRemoteHostHydrateTask() s_remoteHostHydrateTask = Task.Run(async () => { - var client = await RemoteHostClient.TryGetClientAsync(_solution.Workspace, _disposalToken).ConfigureAwait(false); + var client = await RemoteHostClient.TryGetClientAsync(_solution.Services, _disposalToken).ConfigureAwait(false); if (client != null) { await client.TryInvokeAsync( diff --git a/src/Features/Core/Portable/NavigateTo/NavigateToSearcher.cs b/src/Features/Core/Portable/NavigateTo/NavigateToSearcher.cs index a38aec59832de..a2216f1517eef 100644 --- a/src/Features/Core/Portable/NavigateTo/NavigateToSearcher.cs +++ b/src/Features/Core/Portable/NavigateTo/NavigateToSearcher.cs @@ -60,7 +60,7 @@ private NavigateToSearcher( return new ValueTask(); }); - var docTrackingService = _solution.Workspace.Services.GetRequiredService(); + var docTrackingService = _solution.Services.GetRequiredService(); // If the workspace is tracking documents, use that to prioritize our search // order. That way we provide results for the documents the user is working diff --git a/src/Features/Core/Portable/Navigation/DefaultDocumentNavigationServiceFactory.cs b/src/Features/Core/Portable/Navigation/DefaultDocumentNavigationServiceFactory.cs index 19da337832380..79b20a9c41ea6 100644 --- a/src/Features/Core/Portable/Navigation/DefaultDocumentNavigationServiceFactory.cs +++ b/src/Features/Core/Portable/Navigation/DefaultDocumentNavigationServiceFactory.cs @@ -24,10 +24,7 @@ public DefaultDocumentNavigationServiceFactory() public IWorkspaceService CreateService(HostWorkspaceServices workspaceServices) { - if (_singleton == null) - { - _singleton = new DefaultDocumentNavigationService(); - } + _singleton ??= new DefaultDocumentNavigationService(); return _singleton; } diff --git a/src/Features/Core/Portable/Navigation/DefaultSymbolNavigationServiceFactory.cs b/src/Features/Core/Portable/Navigation/DefaultSymbolNavigationServiceFactory.cs index 0cd9b6da0403f..9c329e6a5471d 100644 --- a/src/Features/Core/Portable/Navigation/DefaultSymbolNavigationServiceFactory.cs +++ b/src/Features/Core/Portable/Navigation/DefaultSymbolNavigationServiceFactory.cs @@ -24,10 +24,7 @@ public DefaultSymbolNavigationServiceFactory() public IWorkspaceService CreateService(HostWorkspaceServices workspaceServices) { - if (_singleton == null) - { - _singleton = new DefaultSymbolNavigationService(); - } + _singleton ??= new DefaultSymbolNavigationService(); return _singleton; } diff --git a/src/Features/Core/Portable/NavigationBar/AbstractNavigationBarItemService.cs b/src/Features/Core/Portable/NavigationBar/AbstractNavigationBarItemService.cs index 479edda568a01..80bc42666c650 100644 --- a/src/Features/Core/Portable/NavigationBar/AbstractNavigationBarItemService.cs +++ b/src/Features/Core/Portable/NavigationBar/AbstractNavigationBarItemService.cs @@ -7,7 +7,7 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Remote; using Microsoft.CodeAnalysis.Text; using static Microsoft.CodeAnalysis.NavigationBar.RoslynNavigationBarItem; diff --git a/src/Features/Core/Portable/PdbSourceDocument/ImplementationAssemblyLookupService.cs b/src/Features/Core/Portable/PdbSourceDocument/ImplementationAssemblyLookupService.cs index e06c69826cd20..f6fa8cbf50d7d 100644 --- a/src/Features/Core/Portable/PdbSourceDocument/ImplementationAssemblyLookupService.cs +++ b/src/Features/Core/Portable/PdbSourceDocument/ImplementationAssemblyLookupService.cs @@ -20,6 +20,12 @@ namespace Microsoft.CodeAnalysis.PdbSourceDocument [Export(typeof(IImplementationAssemblyLookupService)), Shared] internal class ImplementationAssemblyLookupService : IImplementationAssemblyLookupService { + // We need to generate the namespace name in the same format that is used in metadata, which + // is SymbolDisplayFormat.QualifiedNameOnlyFormat, which this is a copy of. + private static readonly SymbolDisplayFormat s_metadataSymbolDisplayFormat = new SymbolDisplayFormat( + globalNamespaceStyle: SymbolDisplayGlobalNamespaceStyle.Omitted, + typeQualificationStyle: SymbolDisplayTypeQualificationStyle.NameAndContainingTypesAndNamespaces); + private static readonly string PathSeparatorString = Path.DirectorySeparatorChar.ToString(); // Cache for any type forwards. Key is the dll being inspected. Value is a dictionary @@ -56,6 +62,7 @@ public bool TryFindImplementationAssemblyPath(string referencedDllPath, [NotNull // Only the top most containing type in the ExportedType table actually points to an assembly // so no point looking for nested types. var typeSymbol = MetadataAsSourceHelpers.GetTopLevelContainingNamedType(symbol); + var namespaceName = typeSymbol.ContainingNamespace.ToDisplayString(s_metadataSymbolDisplayFormat); try { @@ -66,7 +73,7 @@ public bool TryFindImplementationAssemblyPath(string referencedDllPath, [NotNull { // If there are no type forwards in this DLL, or not one for this type, then it means // we've found the right DLL - if (typeForwards?.TryGetValue((typeSymbol.ContainingNamespace.MetadataName, typeSymbol.MetadataName), out var assemblyName) != true) + if (typeForwards?.TryGetValue((namespaceName, typeSymbol.MetadataName), out var assemblyName) != true) { return dllPath; } diff --git a/src/Features/Core/Portable/PdbSourceDocument/PdbSourceDocumentMetadataAsSourceFileProvider.cs b/src/Features/Core/Portable/PdbSourceDocument/PdbSourceDocumentMetadataAsSourceFileProvider.cs index f9d75c28ed977..889c39da2f215 100644 --- a/src/Features/Core/Portable/PdbSourceDocument/PdbSourceDocumentMetadataAsSourceFileProvider.cs +++ b/src/Features/Core/Portable/PdbSourceDocument/PdbSourceDocumentMetadataAsSourceFileProvider.cs @@ -57,6 +57,10 @@ public PdbSourceDocumentMetadataAsSourceFileProvider( public async Task GetGeneratedFileAsync(Workspace workspace, Project project, ISymbol symbol, bool signaturesOnly, MetadataAsSourceOptions options, string tempPath, CancellationToken cancellationToken) { + // Check if the user wants to look for PDB source documents at all + if (!options.NavigateToSourceLinkAndEmbeddedSources) + return null; + // we don't support signatures only mode if (signaturesOnly) return null; @@ -107,7 +111,7 @@ public PdbSourceDocumentMetadataAsSourceFileProvider( // Now that we have the right DLL, we need to look up the symbol in this DLL, because the one // we have is from the reference assembly. To do this we create an empty compilation, // add our DLL as a reference, and use SymbolKey to map the type across. - var compilationFactory = project.LanguageServices.GetRequiredService(); + var compilationFactory = project.Services.GetRequiredService(); var dllReference = IOUtilities.PerformIO(() => MetadataReference.CreateFromFile(dllPath)); if (dllReference is null) { @@ -117,11 +121,11 @@ public PdbSourceDocumentMetadataAsSourceFileProvider( var tmpCompilation = compilationFactory .CreateCompilation("tmp", compilationFactory.GetDefaultCompilationOptions()) - .AddReferences(project.MetadataReferences) .AddReferences(dllReference); var key = SymbolKey.Create(symbolToFind, cancellationToken); - var newSymbol = key.Resolve(tmpCompilation, ignoreAssemblyKey: true, cancellationToken).Symbol; + var resolution = key.Resolve(tmpCompilation, ignoreAssemblyKey: true, cancellationToken); + var newSymbol = resolution.Symbol; if (newSymbol is null) { _logger?.Log(FeaturesResources.Could_not_find_implementation_of_symbol_0, symbolToFind.MetadataName); diff --git a/src/Features/Core/Portable/PreferFrameworkType/PreferFrameworkTypeDiagnosticAnalyzerBase.cs b/src/Features/Core/Portable/PreferFrameworkType/PreferFrameworkTypeDiagnosticAnalyzerBase.cs index 8b716e5e9f08d..39616c22376d2 100644 --- a/src/Features/Core/Portable/PreferFrameworkType/PreferFrameworkTypeDiagnosticAnalyzerBase.cs +++ b/src/Features/Core/Portable/PreferFrameworkType/PreferFrameworkTypeDiagnosticAnalyzerBase.cs @@ -20,7 +20,7 @@ internal abstract class PreferFrameworkTypeDiagnosticAnalyzerBase(CodeStyleOptions2.PreferIntrinsicPredefinedTypeKeywordInDeclaration, CodeStyleOptions2.PreferIntrinsicPredefinedTypeKeywordInMemberAccess), + options: ImmutableHashSet.Create(CodeStyleOptions2.PreferIntrinsicPredefinedTypeKeywordInDeclaration, CodeStyleOptions2.PreferIntrinsicPredefinedTypeKeywordInMemberAccess), new LocalizableResourceString(nameof(FeaturesResources.Use_framework_type), FeaturesResources.ResourceManager, typeof(FeaturesResources)), new LocalizableResourceString(nameof(FeaturesResources.Use_framework_type), FeaturesResources.ResourceManager, typeof(FeaturesResources))) { @@ -39,7 +39,6 @@ public override bool OpenFileOnly(SimplifierOptions? options) public override DiagnosticAnalyzerCategory GetAnalyzerCategory() => DiagnosticAnalyzerCategory.SemanticSpanAnalysis; - protected abstract string GetLanguageName(); protected abstract ImmutableArray SyntaxKindsOfInterest { get; } protected abstract bool IsPredefinedTypeReplaceableWithFrameworkType(TPredefinedTypeSyntax node); protected abstract bool IsInMemberAccessOrCrefReferenceContext(TExpressionSyntax node); diff --git a/src/Features/Core/Portable/PublicAPI.Unshipped.txt b/src/Features/Core/Portable/PublicAPI.Unshipped.txt index 8b137891791fe..a4611d86ace1e 100644 --- a/src/Features/Core/Portable/PublicAPI.Unshipped.txt +++ b/src/Features/Core/Portable/PublicAPI.Unshipped.txt @@ -1 +1 @@ - +Microsoft.CodeAnalysis.Completion.CompletionList.ItemsList.get -> System.Collections.Generic.IReadOnlyList diff --git a/src/Features/Core/Portable/PullMemberUp/AbstractPullMemberUpRefactoringProvider.cs b/src/Features/Core/Portable/PullMemberUp/AbstractPullMemberUpRefactoringProvider.cs index 39580abc1b7b5..a702cbe068d58 100644 --- a/src/Features/Core/Portable/PullMemberUp/AbstractPullMemberUpRefactoringProvider.cs +++ b/src/Features/Core/Portable/PullMemberUp/AbstractPullMemberUpRefactoringProvider.cs @@ -10,6 +10,7 @@ using Microsoft.CodeAnalysis.CodeRefactorings.PullMemberUp.Dialog; using Microsoft.CodeAnalysis.PullMemberUp; using Microsoft.CodeAnalysis.Shared.Extensions; +using Microsoft.CodeAnalysis.Text; using Roslyn.Utilities; using static Microsoft.CodeAnalysis.CodeActions.CodeAction; @@ -19,7 +20,7 @@ internal abstract partial class AbstractPullMemberUpRefactoringProvider : CodeRe { private IPullMemberUpOptionsService? _service; - protected abstract Task GetSelectedNodeAsync(CodeRefactoringContext context); + protected abstract Task> GetSelectedNodesAsync(CodeRefactoringContext context); /// /// Test purpose only @@ -33,32 +34,45 @@ public override async Task ComputeRefactoringsAsync(CodeRefactoringContext conte // constructor, operator and finalizer are excluded. var (document, _, cancellationToken) = context; - _service ??= document.Project.Solution.Workspace.Services.GetService(); + _service ??= document.Project.Solution.Services.GetService(); if (_service == null) { return; } - var selectedMemberNode = await GetSelectedNodeAsync(context).ConfigureAwait(false); - if (selectedMemberNode == null) + var selectedMemberNodes = await GetSelectedNodesAsync(context).ConfigureAwait(false); + if (selectedMemberNodes.IsEmpty) { return; } var semanticModel = await document.GetRequiredSemanticModelAsync(cancellationToken).ConfigureAwait(false); - var selectedMember = semanticModel.GetDeclaredSymbol(selectedMemberNode); - if (selectedMember == null || selectedMember.ContainingType == null) + var memberNodeSymbolPairs = selectedMemberNodes + .SelectAsArray(m => (node: m, symbol: semanticModel.GetRequiredDeclaredSymbol(m, cancellationToken))) + .WhereAsArray(pair => MemberAndDestinationValidator.IsMemberValid(pair.symbol)); + + if (memberNodeSymbolPairs.IsEmpty) { return; } - if (!MemberAndDestinationValidator.IsMemberValid(selectedMember)) + var selectedMembers = memberNodeSymbolPairs.SelectAsArray(pair => pair.symbol); + + var containingType = selectedMembers.First().ContainingType; + Contract.ThrowIfNull(containingType); + if (selectedMembers.Any(m => !m.ContainingType.Equals(containingType))) { return; } + // we want to use a span which covers all the selected viable member nodes, so that more specific nodes have priority + var memberSpan = TextSpan.FromBounds( + memberNodeSymbolPairs.First().node.FullSpan.Start, + memberNodeSymbolPairs.Last().node.FullSpan.End); + var allDestinations = FindAllValidDestinations( - selectedMember, + selectedMembers, + containingType, document.Project.Solution, cancellationToken); if (allDestinations.Length == 0) @@ -66,23 +80,29 @@ public override async Task ComputeRefactoringsAsync(CodeRefactoringContext conte return; } - var allActions = allDestinations.Select(destination => MembersPuller.TryComputeCodeAction(document, selectedMember, destination, context.Options)) - .WhereNotNull().Concat(new PullMemberUpWithDialogCodeAction(document, selectedMember, _service, context.Options)) + var allActions = allDestinations.Select(destination => MembersPuller.TryComputeCodeAction(document, selectedMembers, destination, context.Options)) + .WhereNotNull() + .Concat(new PullMemberUpWithDialogCodeAction(document, selectedMembers, _service, context.Options)) .ToImmutableArray(); + var title = selectedMembers.IsSingle() + ? string.Format(FeaturesResources.Pull_0_up, selectedMembers.Single().ToNameDisplayString()) + : FeaturesResources.Pull_selected_members_up; + var nestedCodeAction = CodeActionWithNestedActions.Create( - string.Format(FeaturesResources.Pull_0_up, selectedMember.ToNameDisplayString()), + title, allActions, isInlinable: true); - context.RegisterRefactoring(nestedCodeAction, selectedMemberNode.Span); + + context.RegisterRefactoring(nestedCodeAction, memberSpan); } private static ImmutableArray FindAllValidDestinations( - ISymbol selectedMember, + ImmutableArray selectedMembers, + INamedTypeSymbol containingType, Solution solution, CancellationToken cancellationToken) { - var containingType = selectedMember.ContainingType; - var allDestinations = selectedMember.IsKind(SymbolKind.Field) + var allDestinations = selectedMembers.All(m => m.IsKind(SymbolKind.Field)) ? containingType.GetBaseTypes().ToImmutableArray() : containingType.AllInterfaces.Concat(containingType.GetBaseTypes()).ToImmutableArray(); diff --git a/src/Features/Core/Portable/PullMemberUp/Dialog/IPullMemberUpOptionsService.cs b/src/Features/Core/Portable/PullMemberUp/Dialog/IPullMemberUpOptionsService.cs index 8004f331aeec2..5959054f7296a 100644 --- a/src/Features/Core/Portable/PullMemberUp/Dialog/IPullMemberUpOptionsService.cs +++ b/src/Features/Core/Portable/PullMemberUp/Dialog/IPullMemberUpOptionsService.cs @@ -4,6 +4,7 @@ #nullable disable +using System.Collections.Immutable; using Microsoft.CodeAnalysis.Host; using Microsoft.CodeAnalysis.PullMemberUp; @@ -11,6 +12,6 @@ namespace Microsoft.CodeAnalysis.CodeRefactorings.PullMemberUp.Dialog { internal interface IPullMemberUpOptionsService : IWorkspaceService { - PullMembersUpOptions GetPullMemberUpOptions(Document document, ISymbol selectedNodeSymbol); + PullMembersUpOptions GetPullMemberUpOptions(Document document, ImmutableArray selectedNodeSymbols); } } diff --git a/src/Features/Core/Portable/PullMemberUp/Dialog/PullMemberUpWithDialogCodeAction.cs b/src/Features/Core/Portable/PullMemberUp/Dialog/PullMemberUpWithDialogCodeAction.cs index 11e8506369501..81c7843ee27ea 100644 --- a/src/Features/Core/Portable/PullMemberUp/Dialog/PullMemberUpWithDialogCodeAction.cs +++ b/src/Features/Core/Portable/PullMemberUp/Dialog/PullMemberUpWithDialogCodeAction.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.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.CodeActions; @@ -20,7 +21,7 @@ private sealed class PullMemberUpWithDialogCodeAction : CodeActionWithOptions /// /// Member which user initially selects. It will be selected initially when the dialog pops up. /// - private readonly ISymbol _selectedMember; + private readonly ImmutableArray _selectedMembers; private readonly Document _document; private readonly IPullMemberUpOptionsService _service; private readonly CleanCodeGenerationOptionsProvider _fallbackOptions; @@ -29,19 +30,19 @@ private sealed class PullMemberUpWithDialogCodeAction : CodeActionWithOptions public PullMemberUpWithDialogCodeAction( Document document, - ISymbol selectedMember, + ImmutableArray selectedMembers, IPullMemberUpOptionsService service, CleanCodeGenerationOptionsProvider fallbackOptions) { _document = document; - _selectedMember = selectedMember; + _selectedMembers = selectedMembers; _service = service; _fallbackOptions = fallbackOptions; } public override object GetOptions(CancellationToken cancellationToken) { - return _service.GetPullMemberUpOptions(_document, _selectedMember); + return _service.GetPullMemberUpOptions(_document, _selectedMembers); } protected override async Task> ComputeOperationsAsync(object options, CancellationToken cancellationToken) diff --git a/src/Features/Core/Portable/PullMemberUp/MemberAndDestinationValidator.cs b/src/Features/Core/Portable/PullMemberUp/MemberAndDestinationValidator.cs index 13dc19da2887a..3aa851987b463 100644 --- a/src/Features/Core/Portable/PullMemberUp/MemberAndDestinationValidator.cs +++ b/src/Features/Core/Portable/PullMemberUp/MemberAndDestinationValidator.cs @@ -29,6 +29,11 @@ public static bool IsDestinationValid(Solution solution, INamedTypeSymbol destin public static bool IsMemberValid(ISymbol member) { + if (member.IsImplicitlyDeclared) + { + return false; + } + // Static, abstract and accessiblity are not checked here but in PullMembersUpOptionsBuilder.cs since there are // two refactoring options provided for pull members up, // 1. Quick Action (Only allow members that don't cause error) @@ -36,8 +41,7 @@ public static bool IsMemberValid(ISymbol member) return member switch { IMethodSymbol methodSymbol => methodSymbol.MethodKind == MethodKind.Ordinary, - IFieldSymbol fieldSymbol => !fieldSymbol.IsImplicitlyDeclared, - _ => member.IsKind(SymbolKind.Property) || member.IsKind(SymbolKind.Event), + _ => member.IsKind(SymbolKind.Property) || member.IsKind(SymbolKind.Event) || member.IsKind(SymbolKind.Field), }; } } diff --git a/src/Features/Core/Portable/PullMemberUp/MembersPuller.cs b/src/Features/Core/Portable/PullMemberUp/MembersPuller.cs index 6fd304cd19ae3..d7f9d2dca159c 100644 --- a/src/Features/Core/Portable/PullMemberUp/MembersPuller.cs +++ b/src/Features/Core/Portable/PullMemberUp/MembersPuller.cs @@ -14,7 +14,7 @@ using Microsoft.CodeAnalysis.CodeGeneration; using Microsoft.CodeAnalysis.Editing; using Microsoft.CodeAnalysis.Formatting; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.PullMemberUp; @@ -36,18 +36,23 @@ internal static class MembersPuller public static CodeAction TryComputeCodeAction( Document document, - ISymbol selectedMember, + ImmutableArray selectedMembers, INamedTypeSymbol destination, CleanCodeGenerationOptionsProvider fallbackOptions) { - var result = PullMembersUpOptionsBuilder.BuildPullMembersUpOptions(destination, ImmutableArray.Create((member: selectedMember, makeAbstract: false))); + var result = PullMembersUpOptionsBuilder.BuildPullMembersUpOptions(destination, + selectedMembers.SelectAsArray(m => (member: m, makeAbstract: false))); + if (result.PullUpOperationNeedsToDoExtraChanges || - IsSelectedMemberDeclarationAlreadyInDestination(selectedMember, destination)) + selectedMembers.Any(IsSelectedMemberDeclarationAlreadyInDestination, destination)) { return null; } - var title = string.Format(FeaturesResources.Pull_0_up_to_1, selectedMember.Name, result.Destination.Name); + var title = selectedMembers.IsSingle() + ? string.Format(FeaturesResources.Pull_0_up_to_1, selectedMembers.Single().Name, result.Destination.Name) + : string.Format(FeaturesResources.Pull_selected_members_up_to_0, result.Destination.Name); + return SolutionChangeAction.Create( title, cancellationToken => PullMembersUpAsync(document, result, fallbackOptions, cancellationToken), @@ -95,7 +100,7 @@ private static async Task PullMembersIntoInterfaceAsync( { var solution = document.Project.Solution; var solutionEditor = new SolutionEditor(solution); - var codeGenerationService = document.Project.LanguageServices.GetRequiredService(); + var codeGenerationService = document.Project.Services.GetRequiredService(); var destinationSyntaxNode = await codeGenerationService.FindMostRelevantNameSpaceOrTypeDeclarationAsync( solution, pullMemberUpOptions.Destination, location: null, cancellationToken).ConfigureAwait(false); var symbolToDeclarationsMap = await InitializeSymbolToDeclarationsMapAsync(pullMemberUpOptions, cancellationToken).ConfigureAwait(false); @@ -275,7 +280,7 @@ private static async Task PullMembersIntoClassAsync( { var solution = document.Project.Solution; var solutionEditor = new SolutionEditor(solution); - var codeGenerationService = document.Project.LanguageServices.GetRequiredService(); + var codeGenerationService = document.Project.Services.GetRequiredService(); var destinationSyntaxNode = await codeGenerationService.FindMostRelevantNameSpaceOrTypeDeclarationAsync( solution, result.Destination, location: null, cancellationToken).ConfigureAwait(false); diff --git a/src/Features/Core/Portable/QuickInfo/CommonQuickInfoContext.cs b/src/Features/Core/Portable/QuickInfo/CommonQuickInfoContext.cs index c0a531af1baf4..aa85abbb79e10 100644 --- a/src/Features/Core/Portable/QuickInfo/CommonQuickInfoContext.cs +++ b/src/Features/Core/Portable/QuickInfo/CommonQuickInfoContext.cs @@ -4,20 +4,20 @@ using System.Threading; using Microsoft.CodeAnalysis.Host; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; namespace Microsoft.CodeAnalysis.QuickInfo { internal readonly struct CommonQuickInfoContext { - public readonly HostWorkspaceServices Services; + public readonly SolutionServices Services; public readonly SemanticModel SemanticModel; public readonly int Position; public readonly SymbolDescriptionOptions Options; public readonly CancellationToken CancellationToken; public CommonQuickInfoContext( - HostWorkspaceServices services, + SolutionServices services, SemanticModel semanticModel, int position, SymbolDescriptionOptions options, diff --git a/src/Features/Core/Portable/QuickInfo/CommonSemanticQuickInfoProvider.cs b/src/Features/Core/Portable/QuickInfo/CommonSemanticQuickInfoProvider.cs index b253a90e583b3..1969a5646d061 100644 --- a/src/Features/Core/Portable/QuickInfo/CommonSemanticQuickInfoProvider.cs +++ b/src/Features/Core/Portable/QuickInfo/CommonSemanticQuickInfoProvider.cs @@ -9,7 +9,7 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.Host; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Shared.Collections; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Shared.Utilities; @@ -28,7 +28,7 @@ internal abstract partial class CommonSemanticQuickInfoProvider : CommonQuickInf var cancellationToken = context.CancellationToken; var semanticModel = await context.Document.GetRequiredSemanticModelAsync(cancellationToken).ConfigureAwait(false); - var services = context.Document.Project.Solution.Workspace.Services; + var services = context.Document.Project.Solution.Services; return await CreateContentAsync( services, semanticModel, token, tokenInformation, supportedPlatforms, context.Options, cancellationToken).ConfigureAwait(false); } @@ -56,7 +56,7 @@ internal abstract partial class CommonSemanticQuickInfoProvider : CommonQuickInf return await ComputeFromLinkedDocumentsAsync(context, token, linkedDocumentIds).ConfigureAwait(false); var semanticModel = await document.GetRequiredSemanticModelAsync(cancellationToken).ConfigureAwait(false); - var services = document.Project.Solution.Workspace.Services; + var services = document.Project.Solution.Services; var tokenInformation = BindToken(services, semanticModel, token, cancellationToken); return (tokenInformation, supportedPlatforms: null); } @@ -79,7 +79,7 @@ internal abstract partial class CommonSemanticQuickInfoProvider : CommonQuickInf var cancellationToken = context.CancellationToken; var document = context.Document; var solution = document.Project.Solution; - var services = solution.Workspace.Services; + var services = solution.Services; var semanticModel = await document.GetRequiredSemanticModelAsync(cancellationToken).ConfigureAwait(false); var mainTokenInformation = BindToken(services, semanticModel, token, cancellationToken); @@ -149,7 +149,7 @@ private static SyntaxToken FindTokenInLinkedDocument( } protected static Task CreateContentAsync( - HostWorkspaceServices services, + SolutionServices services, SemanticModel semanticModel, SyntaxToken token, TokenInformation tokenInformation, @@ -157,7 +157,7 @@ protected static Task CreateContentAsync( SymbolDescriptionOptions options, CancellationToken cancellationToken) { - var syntaxFactsService = services.GetLanguageServices(semanticModel.Language).GetRequiredService(); + var syntaxFactsService = services.GetRequiredLanguageService(semanticModel.Language); var symbols = tokenInformation.Symbols; @@ -182,7 +182,7 @@ protected static Task CreateContentAsync( protected virtual NullableFlowState GetNullabilityAnalysis(SemanticModel semanticModel, ISymbol symbol, SyntaxNode node, CancellationToken cancellationToken) => NullableFlowState.None; private TokenInformation BindToken( - HostWorkspaceServices services, SemanticModel semanticModel, SyntaxToken token, CancellationToken cancellationToken) + SolutionServices services, SemanticModel semanticModel, SyntaxToken token, CancellationToken cancellationToken) { var languageServices = services.GetLanguageServices(semanticModel.Language); var syntaxFacts = languageServices.GetRequiredService(); @@ -228,7 +228,7 @@ private TokenInformation BindToken( return new TokenInformation(ImmutableArray.Empty); } - private ImmutableArray GetSymbolsFromToken(SyntaxToken token, HostWorkspaceServices services, SemanticModel semanticModel, CancellationToken cancellationToken) + private ImmutableArray GetSymbolsFromToken(SyntaxToken token, SolutionServices services, SemanticModel semanticModel, CancellationToken cancellationToken) { if (GetBindableNodeForTokenIndicatingLambda(token, out var lambdaSyntax)) { diff --git a/src/Features/Core/Portable/QuickInfo/QuickInfoContext.cs b/src/Features/Core/Portable/QuickInfo/QuickInfoContext.cs index 964aa0182b422..2eefc084ec7a4 100644 --- a/src/Features/Core/Portable/QuickInfo/QuickInfoContext.cs +++ b/src/Features/Core/Portable/QuickInfo/QuickInfoContext.cs @@ -4,7 +4,7 @@ using System; using System.Threading; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; namespace Microsoft.CodeAnalysis.QuickInfo { diff --git a/src/Features/Core/Portable/QuickInfo/QuickInfoService.cs b/src/Features/Core/Portable/QuickInfo/QuickInfoService.cs index acd2a8b721ffa..53fce4aee8923 100644 --- a/src/Features/Core/Portable/QuickInfo/QuickInfoService.cs +++ b/src/Features/Core/Portable/QuickInfo/QuickInfoService.cs @@ -6,7 +6,7 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.Host; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Shared.Extensions; using Roslyn.Utilities; diff --git a/src/Features/Core/Portable/QuickInfo/QuickInfoServiceWithProviders.cs b/src/Features/Core/Portable/QuickInfo/QuickInfoServiceWithProviders.cs index 8e28097574134..0fc2fced72db1 100644 --- a/src/Features/Core/Portable/QuickInfo/QuickInfoServiceWithProviders.cs +++ b/src/Features/Core/Portable/QuickInfo/QuickInfoServiceWithProviders.cs @@ -10,7 +10,7 @@ using Microsoft.CodeAnalysis.Extensions; using Microsoft.CodeAnalysis.Host; using Microsoft.CodeAnalysis.Host.Mef; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Shared.Utilities; namespace Microsoft.CodeAnalysis.QuickInfo @@ -20,10 +20,10 @@ namespace Microsoft.CodeAnalysis.QuickInfo /// internal abstract class QuickInfoServiceWithProviders : QuickInfoService { - private readonly HostLanguageServices _services; + private readonly LanguageServices _services; private ImmutableArray _providers; - protected QuickInfoServiceWithProviders(HostLanguageServices services) + protected QuickInfoServiceWithProviders(LanguageServices services) { _services = services; } @@ -32,7 +32,7 @@ private ImmutableArray GetProviders() { if (_providers.IsDefault) { - var mefExporter = (IMefHostExportProvider)_services.WorkspaceServices.HostServices; + var mefExporter = _services.SolutionServices.ExportProvider; var providers = ExtensionOrderer .Order(mefExporter.GetExports() @@ -48,7 +48,7 @@ private ImmutableArray GetProviders() internal override async Task GetQuickInfoAsync(Document document, int position, SymbolDescriptionOptions options, CancellationToken cancellationToken) { - var extensionManager = _services.WorkspaceServices.GetRequiredService(); + var extensionManager = _services.SolutionServices.GetRequiredService(); // returns the first non-empty quick info found (based on provider order) foreach (var provider in GetProviders()) @@ -81,7 +81,7 @@ private ImmutableArray GetProviders() internal async Task GetQuickInfoAsync(SemanticModel semanticModel, int position, SymbolDescriptionOptions options, CancellationToken cancellationToken) { - var extensionManager = _services.WorkspaceServices.GetRequiredService(); + var extensionManager = _services.SolutionServices.GetRequiredService(); // returns the first non-empty quick info found (based on provider order) foreach (var provider in GetProviders().OfType()) @@ -90,7 +90,7 @@ private ImmutableArray GetProviders() { if (!extensionManager.IsDisabled(provider)) { - var context = new CommonQuickInfoContext(_services.WorkspaceServices, semanticModel, position, options, cancellationToken); + var context = new CommonQuickInfoContext(_services.SolutionServices, semanticModel, position, options, cancellationToken); var info = await provider.GetQuickInfoAsync(context).ConfigureAwait(false); if (info != null) diff --git a/src/Features/Core/Portable/QuickInfo/QuickInfoUtilities.cs b/src/Features/Core/Portable/QuickInfo/QuickInfoUtilities.cs index b94291ce89641..1471856b6ade7 100644 --- a/src/Features/Core/Portable/QuickInfo/QuickInfoUtilities.cs +++ b/src/Features/Core/Portable/QuickInfo/QuickInfoUtilities.cs @@ -10,7 +10,7 @@ using System.Threading.Tasks; using Microsoft.CodeAnalysis.DocumentationComments; using Microsoft.CodeAnalysis.Host; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Shared.Utilities; @@ -21,11 +21,11 @@ namespace Microsoft.CodeAnalysis.QuickInfo { internal static class QuickInfoUtilities { - public static Task CreateQuickInfoItemAsync(HostWorkspaceServices services, SemanticModel semanticModel, TextSpan span, ImmutableArray symbols, SymbolDescriptionOptions options, CancellationToken cancellationToken) + 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, cancellationToken); public static async Task CreateQuickInfoItemAsync( - HostWorkspaceServices services, + SolutionServices services, SemanticModel semanticModel, TextSpan span, ImmutableArray symbols, @@ -35,7 +35,7 @@ public static async Task CreateQuickInfoItemAsync( SymbolDescriptionOptions options, CancellationToken cancellationToken) { - var descriptionService = services.GetLanguageServices(semanticModel.Language).GetRequiredService(); + var descriptionService = services.GetRequiredLanguageService(semanticModel.Language); var groups = await descriptionService.ToDescriptionGroupsAsync(semanticModel, span.Start, symbols, options, cancellationToken).ConfigureAwait(false); using var _1 = ArrayBuilder.GetInstance(out var sections); diff --git a/src/Features/Core/Portable/RemoveUnusedVariable/AbstractRemoveUnusedVariableCodeFixProvider.cs b/src/Features/Core/Portable/RemoveUnusedVariable/AbstractRemoveUnusedVariableCodeFixProvider.cs index a2435223bf191..9a9a0694255d0 100644 --- a/src/Features/Core/Portable/RemoveUnusedVariable/AbstractRemoveUnusedVariableCodeFixProvider.cs +++ b/src/Features/Core/Portable/RemoveUnusedVariable/AbstractRemoveUnusedVariableCodeFixProvider.cs @@ -15,7 +15,7 @@ using Microsoft.CodeAnalysis.Editing; using Microsoft.CodeAnalysis.FindSymbols; using Microsoft.CodeAnalysis.Formatting; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Shared.Extensions; using Roslyn.Utilities; diff --git a/src/Features/Core/Portable/ReplaceConditionalWithStatements/AbstractReplaceConditionalWithStatementsCodeRefactoringProvider.cs b/src/Features/Core/Portable/ReplaceConditionalWithStatements/AbstractReplaceConditionalWithStatementsCodeRefactoringProvider.cs index 65c4a7b3a1212..72b4b6ddaea1b 100644 --- a/src/Features/Core/Portable/ReplaceConditionalWithStatements/AbstractReplaceConditionalWithStatementsCodeRefactoringProvider.cs +++ b/src/Features/Core/Portable/ReplaceConditionalWithStatements/AbstractReplaceConditionalWithStatementsCodeRefactoringProvider.cs @@ -12,7 +12,7 @@ using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeRefactorings; using Microsoft.CodeAnalysis.Editing; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Shared.Extensions; using Roslyn.Utilities; diff --git a/src/Features/Core/Portable/ReplaceDocCommentTextWithTag/AbstractReplaceDocCommentTextWithTagCodeRefactoringProvider.cs b/src/Features/Core/Portable/ReplaceDocCommentTextWithTag/AbstractReplaceDocCommentTextWithTagCodeRefactoringProvider.cs index 22d25acc9a9c1..9da6e86589e40 100644 --- a/src/Features/Core/Portable/ReplaceDocCommentTextWithTag/AbstractReplaceDocCommentTextWithTagCodeRefactoringProvider.cs +++ b/src/Features/Core/Portable/ReplaceDocCommentTextWithTag/AbstractReplaceDocCommentTextWithTagCodeRefactoringProvider.cs @@ -11,7 +11,7 @@ using System.Threading.Tasks; using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeRefactorings; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Text; diff --git a/src/Features/Core/Portable/ReplaceMethodWithProperty/AbstractReplaceMethodWithPropertyService.cs b/src/Features/Core/Portable/ReplaceMethodWithProperty/AbstractReplaceMethodWithPropertyService.cs index f321673a32e5a..7858917f545ba 100644 --- a/src/Features/Core/Portable/ReplaceMethodWithProperty/AbstractReplaceMethodWithPropertyService.cs +++ b/src/Features/Core/Portable/ReplaceMethodWithProperty/AbstractReplaceMethodWithPropertyService.cs @@ -6,7 +6,7 @@ using System.Threading.Tasks; using System.Collections.Generic; using Microsoft.CodeAnalysis.CodeRefactorings; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; namespace Microsoft.CodeAnalysis.ReplaceMethodWithProperty { diff --git a/src/Features/Core/Portable/ReplaceMethodWithProperty/ReplaceMethodWithPropertyCodeRefactoringProvider.cs b/src/Features/Core/Portable/ReplaceMethodWithProperty/ReplaceMethodWithPropertyCodeRefactoringProvider.cs index f70b36b4c957e..be0568baf8ff0 100644 --- a/src/Features/Core/Portable/ReplaceMethodWithProperty/ReplaceMethodWithPropertyCodeRefactoringProvider.cs +++ b/src/Features/Core/Portable/ReplaceMethodWithProperty/ReplaceMethodWithPropertyCodeRefactoringProvider.cs @@ -222,7 +222,7 @@ private async Task UpdateReferencesInDocumentAsync( { var root = await originalDocument.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false); - var editor = new SyntaxEditor(root, originalDocument.Project.Solution.Workspace.Services); + var editor = new SyntaxEditor(root, originalDocument.Project.Solution.Services); var service = originalDocument.GetRequiredLanguageService(); ReplaceGetReferences(propertyName, nameChanged, getReferences, root, editor, service, cancellationToken); @@ -367,7 +367,7 @@ private static async Task ReplaceGetMethodsAndRemoveSetMethodsAsync( var syntaxTree = await updatedDocument.GetRequiredSyntaxTreeAsync(cancellationToken).ConfigureAwait(false); var root = await updatedDocument.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false); - var editor = new SyntaxEditor(root, updatedSolution.Workspace.Services); + var editor = new SyntaxEditor(root, updatedSolution.Services); var codeGenerationOptions = await updatedDocument.GetCodeGenerationOptionsAsync(fallbackOptions, cancellationToken).ConfigureAwait(false); var parseOptions = syntaxTree.Options; diff --git a/src/Features/Core/Portable/ReplacePropertyWithMethods/AbstractReplacePropertyWithMethodsService.cs b/src/Features/Core/Portable/ReplacePropertyWithMethods/AbstractReplacePropertyWithMethodsService.cs index a05462248be0a..13382edc1561a 100644 --- a/src/Features/Core/Portable/ReplacePropertyWithMethods/AbstractReplacePropertyWithMethodsService.cs +++ b/src/Features/Core/Portable/ReplacePropertyWithMethods/AbstractReplacePropertyWithMethodsService.cs @@ -10,7 +10,7 @@ using Microsoft.CodeAnalysis.CodeGeneration; using Microsoft.CodeAnalysis.CodeRefactorings; using Microsoft.CodeAnalysis.Editing; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Simplification; using Roslyn.Utilities; diff --git a/src/Features/Core/Portable/ReplacePropertyWithMethods/ReplacePropertyWithMethodsCodeRefactoringProvider.cs b/src/Features/Core/Portable/ReplacePropertyWithMethods/ReplacePropertyWithMethodsCodeRefactoringProvider.cs index faf980fd7d5a9..9c8edcdf5771f 100644 --- a/src/Features/Core/Portable/ReplacePropertyWithMethods/ReplacePropertyWithMethodsCodeRefactoringProvider.cs +++ b/src/Features/Core/Portable/ReplacePropertyWithMethods/ReplacePropertyWithMethodsCodeRefactoringProvider.cs @@ -16,7 +16,7 @@ using Microsoft.CodeAnalysis.CodeRefactorings; using Microsoft.CodeAnalysis.Editing; using Microsoft.CodeAnalysis.FindSymbols; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Shared.Utilities; @@ -225,7 +225,7 @@ private async Task UpdateReferencesInDocumentAsync( { var root = await originalDocument.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false); - var editor = new SyntaxEditor(root, originalDocument.Project.Solution.Workspace.Services); + var editor = new SyntaxEditor(root, originalDocument.Project.Solution.Services); var service = originalDocument.GetRequiredLanguageService(); await ReplaceReferencesAsync( @@ -361,7 +361,7 @@ private static async Task ReplaceDefinitionsWithMethodsAsync( var root = await updatedDocument.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false); - var editor = new SyntaxEditor(root, updatedSolution.Workspace.Services); + var editor = new SyntaxEditor(root, updatedSolution.Services); // First replace all the properties with the appropriate getters/setters. foreach (var (property, declaration) in currentDefinitions) diff --git a/src/Features/Core/Portable/Shared/Extensions/ISymbolExtensions_Sorting.cs b/src/Features/Core/Portable/Shared/Extensions/ISymbolExtensions_Sorting.cs index 954c3bc76b57b..00d9d935b63ca 100644 --- a/src/Features/Core/Portable/Shared/Extensions/ISymbolExtensions_Sorting.cs +++ b/src/Features/Core/Portable/Shared/Extensions/ISymbolExtensions_Sorting.cs @@ -9,7 +9,7 @@ using System.Collections.Immutable; using System.Globalization; using System.Linq; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Shared.Extensions diff --git a/src/Features/Core/Portable/Shared/Naming/IdentifierNameParts.cs b/src/Features/Core/Portable/Shared/Naming/IdentifierNameParts.cs index c55bbdda570c3..4cee32558ff66 100644 --- a/src/Features/Core/Portable/Shared/Naming/IdentifierNameParts.cs +++ b/src/Features/Core/Portable/Shared/Naming/IdentifierNameParts.cs @@ -53,7 +53,7 @@ private static string RemovePrefixesAndSuffixes(ISymbol symbol, ImmutableArray p.Name); var syntaxGenerator = SyntaxGenerator.GetGenerator(document); - return Formatter.Format(syntaxGenerator.SyntaxGeneratorInternal.TypeParameterList(typeParameterNames), document.Project.Solution.Workspace.Services, formattingOptions, cancellationToken).ToString(); + return Formatter.Format(syntaxGenerator.SyntaxGeneratorInternal.TypeParameterList(typeParameterNames), document.Project.Solution.Services, formattingOptions, cancellationToken).ToString(); } public static ImmutableArray GetRequiredTypeParametersForMembers(INamedTypeSymbol type, IEnumerable includedMembers) diff --git a/src/Features/Core/Portable/SignatureHelp/AbstractSignatureHelpProvider.cs b/src/Features/Core/Portable/SignatureHelp/AbstractSignatureHelpProvider.cs index 0c2d3a8138d30..e54618dfa9cb8 100644 --- a/src/Features/Core/Portable/SignatureHelp/AbstractSignatureHelpProvider.cs +++ b/src/Features/Core/Portable/SignatureHelp/AbstractSignatureHelpProvider.cs @@ -8,7 +8,7 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Shared.Utilities; diff --git a/src/Features/Core/Portable/SignatureHelp/CommonSignatureHelpUtilities.cs b/src/Features/Core/Portable/SignatureHelp/CommonSignatureHelpUtilities.cs index 1e8953b378fd2..caf31131bb9b8 100644 --- a/src/Features/Core/Portable/SignatureHelp/CommonSignatureHelpUtilities.cs +++ b/src/Features/Core/Portable/SignatureHelp/CommonSignatureHelpUtilities.cs @@ -11,7 +11,7 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Operations; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Text; diff --git a/src/Features/Core/Portable/SimplifyThisOrMe/AbstractSimplifyThisOrMeCodeFixProvider.cs b/src/Features/Core/Portable/SimplifyThisOrMe/AbstractSimplifyThisOrMeCodeFixProvider.cs index cacc384398b07..c70a943b4f3b5 100644 --- a/src/Features/Core/Portable/SimplifyThisOrMe/AbstractSimplifyThisOrMeCodeFixProvider.cs +++ b/src/Features/Core/Portable/SimplifyThisOrMe/AbstractSimplifyThisOrMeCodeFixProvider.cs @@ -12,7 +12,7 @@ using Microsoft.CodeAnalysis.CodeFixes; using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.Editing; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Shared.Extensions; using Roslyn.Utilities; diff --git a/src/Features/Core/Portable/SimplifyThisOrMe/AbstractSimplifyThisOrMeDiagnosticAnalyzer.cs b/src/Features/Core/Portable/SimplifyThisOrMe/AbstractSimplifyThisOrMeDiagnosticAnalyzer.cs index 27b8cde332b52..479dd3e5dde3b 100644 --- a/src/Features/Core/Portable/SimplifyThisOrMe/AbstractSimplifyThisOrMeDiagnosticAnalyzer.cs +++ b/src/Features/Core/Portable/SimplifyThisOrMe/AbstractSimplifyThisOrMeDiagnosticAnalyzer.cs @@ -6,7 +6,7 @@ using System.Threading; using Microsoft.CodeAnalysis.CodeStyle; using Microsoft.CodeAnalysis.Diagnostics; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.QualifyMemberAccess; using Microsoft.CodeAnalysis.Shared.Extensions; @@ -21,7 +21,7 @@ internal abstract class AbstractSimplifyThisOrMeDiagnosticAnalyzer< TExpressionSyntax, TThisExpressionSyntax, TMemberAccessExpressionSyntax> : - AbstractBuiltInCodeStyleDiagnosticAnalyzer + AbstractBuiltInUnnecessaryCodeStyleDiagnosticAnalyzer where TLanguageKindEnum : struct where TExpressionSyntax : SyntaxNode where TThisExpressionSyntax : TExpressionSyntax @@ -30,10 +30,10 @@ internal abstract class AbstractSimplifyThisOrMeDiagnosticAnalyzer< protected AbstractSimplifyThisOrMeDiagnosticAnalyzer() : base(IDEDiagnosticIds.RemoveThisOrMeQualificationDiagnosticId, EnforceOnBuildValues.RemoveQualification, - ImmutableHashSet.Create(CodeStyleOptions2.QualifyFieldAccess, CodeStyleOptions2.QualifyPropertyAccess, CodeStyleOptions2.QualifyMethodAccess, CodeStyleOptions2.QualifyEventAccess), + ImmutableHashSet.Create(CodeStyleOptions2.QualifyFieldAccess, CodeStyleOptions2.QualifyPropertyAccess, CodeStyleOptions2.QualifyMethodAccess, CodeStyleOptions2.QualifyEventAccess), + fadingOption: null, new LocalizableResourceString(nameof(FeaturesResources.Remove_qualification), FeaturesResources.ResourceManager, typeof(FeaturesResources)), - new LocalizableResourceString(nameof(WorkspacesResources.Name_can_be_simplified), WorkspacesResources.ResourceManager, typeof(WorkspacesResources)), - isUnnecessary: true) + new LocalizableResourceString(nameof(AnalyzersResources.Name_can_be_simplified), AnalyzersResources.ResourceManager, typeof(AnalyzersResources))) { } diff --git a/src/Features/Core/Portable/SimplifyTypeNames/AbstractSimplifyTypeNamesCodeFixProvider.cs b/src/Features/Core/Portable/SimplifyTypeNames/AbstractSimplifyTypeNamesCodeFixProvider.cs index 4b11dab8d3a37..167905f1e873a 100644 --- a/src/Features/Core/Portable/SimplifyTypeNames/AbstractSimplifyTypeNamesCodeFixProvider.cs +++ b/src/Features/Core/Portable/SimplifyTypeNames/AbstractSimplifyTypeNamesCodeFixProvider.cs @@ -12,7 +12,7 @@ using Microsoft.CodeAnalysis.CodeFixes; using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.Editing; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Simplification; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Text; diff --git a/src/Features/Core/Portable/Snippets/AbstractSnippetService.cs b/src/Features/Core/Portable/Snippets/AbstractSnippetService.cs new file mode 100644 index 0000000000000..3cf776e009557 --- /dev/null +++ b/src/Features/Core/Portable/Snippets/AbstractSnippetService.cs @@ -0,0 +1,81 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Composition; +using System.Diagnostics; +using System.Linq; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.Host.Mef; +using Microsoft.CodeAnalysis.PooledObjects; +using Microsoft.CodeAnalysis.Snippets.SnippetProviders; +using Roslyn.Utilities; + +namespace Microsoft.CodeAnalysis.Snippets +{ + internal abstract class AbstractSnippetService : ISnippetService + { + private readonly ImmutableArray> _lazySnippetProviders; + private readonly Dictionary _identifierToProviderMap = new(); + private readonly object _snippetProvidersLock = new(); + private ImmutableArray _snippetProviders; + + public AbstractSnippetService(IEnumerable> lazySnippetProviders) + { + _lazySnippetProviders = lazySnippetProviders.ToImmutableArray(); + } + + /// + /// This should never be called prior to GetSnippetsAsync because it gets populated + /// at that point in time. + /// + public ISnippetProvider GetSnippetProvider(string snippetIdentifier) + { + Contract.ThrowIfFalse(_identifierToProviderMap.ContainsKey(snippetIdentifier)); + return _identifierToProviderMap[snippetIdentifier]; + } + + /// + /// Iterates through all providers and determines if the snippet + /// can be added to the Completion list at the corresponding position. + /// + public async Task> GetSnippetsAsync(Document document, int position, CancellationToken cancellationToken) + { + using var _ = ArrayBuilder.GetInstance(out var arrayBuilder); + foreach (var provider in GetSnippetProviders(document)) + { + var snippetData = await provider.GetSnippetDataAsync(document, position, cancellationToken).ConfigureAwait(false); + arrayBuilder.AddIfNotNull(snippetData); + } + + return arrayBuilder.ToImmutable(); + } + + private ImmutableArray GetSnippetProviders(Document document) + { + lock (_snippetProvidersLock) + { + if (_snippetProviders.IsDefault) + { + using var _ = ArrayBuilder.GetInstance(out var arrayBuilder); + foreach (var provider in _lazySnippetProviders.Where(p => p.Metadata.Language == document.Project.Language)) + { + var providerData = provider.Value; + Debug.Assert(!_identifierToProviderMap.TryGetValue(providerData.SnippetIdentifier, out var _)); + _identifierToProviderMap.Add(providerData.SnippetIdentifier, providerData); + arrayBuilder.Add(providerData); + } + + _snippetProviders = arrayBuilder.ToImmutable(); + } + } + + return _snippetProviders; + } + } +} diff --git a/src/Features/Core/Portable/SolutionCrawler/Extensibility/ExportPerLanguageIncrementalAnalyzerProviderAttribute.cs b/src/Features/Core/Portable/Snippets/ExportSnippetProviderAttribute.cs similarity index 65% rename from src/Features/Core/Portable/SolutionCrawler/Extensibility/ExportPerLanguageIncrementalAnalyzerProviderAttribute.cs rename to src/Features/Core/Portable/Snippets/ExportSnippetProviderAttribute.cs index 84143af841e4e..d20fbfefef59b 100644 --- a/src/Features/Core/Portable/SolutionCrawler/Extensibility/ExportPerLanguageIncrementalAnalyzerProviderAttribute.cs +++ b/src/Features/Core/Portable/Snippets/ExportSnippetProviderAttribute.cs @@ -4,18 +4,19 @@ using System; using System.Composition; +using Microsoft.CodeAnalysis.Snippets.SnippetProviders; -namespace Microsoft.CodeAnalysis.SolutionCrawler +namespace Microsoft.CodeAnalysis.Snippets { [MetadataAttribute] [AttributeUsage(AttributeTargets.Class)] - internal class ExportPerLanguageIncrementalAnalyzerProviderAttribute : ExportAttribute + internal sealed class ExportSnippetProviderAttribute : ExportAttribute { public string Name { get; } public string Language { get; } - public ExportPerLanguageIncrementalAnalyzerProviderAttribute(string name, string language) - : base(typeof(IPerLanguageIncrementalAnalyzerProvider)) + public ExportSnippetProviderAttribute(string name, string language) + : base(typeof(ISnippetProvider)) { Name = name ?? throw new ArgumentNullException(nameof(name)); Language = language ?? throw new ArgumentNullException(nameof(language)); diff --git a/src/Features/Core/Portable/Snippets/IRoslynLSPSnippetExpander.cs b/src/Features/Core/Portable/Snippets/IRoslynLSPSnippetExpander.cs new file mode 100644 index 0000000000000..7b0763207e898 --- /dev/null +++ b/src/Features/Core/Portable/Snippets/IRoslynLSPSnippetExpander.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; +using System.Collections.Generic; +using System.Text; +using Microsoft.CodeAnalysis.Text; + +namespace Microsoft.CodeAnalysis.Snippets +{ + internal interface IRoslynLSPSnippetExpander + { + bool CanExpandSnippet(); + } +} diff --git a/src/Features/Core/Portable/Snippets/ISnippetService.cs b/src/Features/Core/Portable/Snippets/ISnippetService.cs new file mode 100644 index 0000000000000..f005325da09da --- /dev/null +++ b/src/Features/Core/Portable/Snippets/ISnippetService.cs @@ -0,0 +1,30 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.Host; +using Microsoft.CodeAnalysis.Snippets.SnippetProviders; +using Microsoft.CodeAnalysis.Text; + +namespace Microsoft.CodeAnalysis.Snippets +{ + internal interface ISnippetService : ILanguageService + { + /// + /// Retrieves all possible types of snippets for a particular position + /// + Task> GetSnippetsAsync(Document document, int position, CancellationToken cancellationToken); + + /// + /// Gets the corresponding provider from a snippet identifier. + /// Called upon by the AbstractSnippetCompletionProvider + /// + ISnippetProvider GetSnippetProvider(string snippetIdentifier); + } +} diff --git a/src/Features/Core/Portable/Snippets/RoslynLSPSnippetConverter.cs b/src/Features/Core/Portable/Snippets/RoslynLSPSnippetConverter.cs new file mode 100644 index 0000000000000..a57a48e25bc39 --- /dev/null +++ b/src/Features/Core/Portable/Snippets/RoslynLSPSnippetConverter.cs @@ -0,0 +1,148 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation 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.Text; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.CodeFixes; +using Microsoft.CodeAnalysis.PooledObjects; +using Microsoft.CodeAnalysis.Text; +using Roslyn.Utilities; + +namespace Microsoft.CodeAnalysis.Snippets +{ + internal static class RoslynLSPSnippetConverter + { + /// + /// Extends the TextChange to encompass all placeholder positions as well as caret position. + /// Generates a LSP formatted snippet from a TextChange, list of placeholders, and caret position. + /// + public static async Task GenerateLSPSnippetAsync(Document document, int caretPosition, ImmutableArray placeholders, TextChange textChange, int triggerLocation, CancellationToken cancellationToken) + { + var extendedTextChange = await ExtendSnippetTextChangeAsync(document, textChange, placeholders, caretPosition, triggerLocation, cancellationToken).ConfigureAwait(false); + return ConvertToLSPSnippetString(extendedTextChange, placeholders, caretPosition); + } + + /// + /// Iterates through every index in the snippet string and determines where the + /// LSP formatted chunks should be inserted for each placeholder. + /// + private static string ConvertToLSPSnippetString(TextChange textChange, ImmutableArray placeholders, int caretPosition) + { + var textChangeStart = textChange.Span.Start; + var textChangeText = textChange.NewText; + Contract.ThrowIfNull(textChangeText); + + using var _1 = PooledStringBuilder.GetInstance(out var lspSnippetString); + using var _2 = PooledDictionary.GetInstance(out var dictionary); + PopulateMapOfSpanStartsToLSPStringItem(dictionary, placeholders, textChangeStart); + + // Need to go through the length + 1 since caret postions occur before and after the + // character position. + // If there is a caret at the end of the line, then it's position + // will be equivalent to the length of the TextChange. + for (var i = 0; i < textChange.Span.Length + 1;) + { + if (i == caretPosition - textChangeStart) + { + lspSnippetString.Append("$0"); + } + + //Tries to see if a value exists at that position in the map, and if so it + // generates a string that is LSP formatted. + if (dictionary.TryGetValue(i, out var placeholderInfo)) + { + var str = $"${{{placeholderInfo.priority}:{placeholderInfo.identifier}}}"; + lspSnippetString.Append(str); + + // Skip past the entire identifier in the TextChange text + i += placeholderInfo.identifier.Length; + } + else + { + if (i < textChangeText.Length) + { + lspSnippetString.Append(textChangeText[i]); + i++; + } + else + { + break; + } + } + } + + return lspSnippetString.ToString(); + } + + /// + /// Preprocesses the list of placeholders into a dictionary that maps the insertion position + /// in the string to the placeholder's identifier and the priority associated with it. + /// + private static void PopulateMapOfSpanStartsToLSPStringItem(Dictionary dictionary, ImmutableArray placeholders, int textChangeStart) + { + for (var i = 0; i < placeholders.Length; i++) + { + var placeholder = placeholders[i]; + foreach (var position in placeholder.PlaceHolderPositions) + { + // i + 1 since the placeholder priority is set according to the index in the + // placeholders array, starting at 1. + // We should never be adding two placeholders in the same position since identifiers + // must have a length greater than 0. + dictionary.Add(position - textChangeStart, (placeholder.Identifier, i + 1)); + } + } + } + + /// + /// We need to extend the snippet's TextChange if any of the placeholders or + /// if the caret position comes before or after the span of the TextChange. + /// If so, then find the new string that encompasses all of the placeholders + /// and caret position. + /// This is important for the cases in which the document does not determine the TextChanges from + /// the original document accurately. + /// + private static async Task ExtendSnippetTextChangeAsync(Document document, TextChange textChange, ImmutableArray placeholders, int caretPosition, int triggerLocation, CancellationToken cancellationToken) + { + var extendedSpan = GetUpdatedTextSpan(textChange, placeholders, caretPosition, triggerLocation); + var documentText = await document.GetTextAsync(cancellationToken).ConfigureAwait(false); + var newString = documentText.ToString(extendedSpan); + var newTextChange = new TextChange(extendedSpan, newString); + + return newTextChange; + } + + /// + /// Iterates through the placeholders and determines if any of the positions + /// come before or after what is indicated by the snippet's TextChange. + /// If so, adjust the starting and ending position accordingly. + /// + private static TextSpan GetUpdatedTextSpan(TextChange textChange, ImmutableArray placeholders, int caretPosition, int triggerLocation) + { + var textChangeText = textChange.NewText; + Contract.ThrowIfNull(textChangeText); + + var startPosition = textChange.Span.Start; + var endPosition = textChange.Span.Start + textChangeText.Length; + + if (placeholders.Length > 0) + { + startPosition = Math.Min(startPosition, placeholders.Min(placeholder => placeholder.PlaceHolderPositions.Min())); + endPosition = Math.Max(endPosition, placeholders.Max(placeholder => placeholder.PlaceHolderPositions.Max())); + } + + startPosition = Math.Min(startPosition, caretPosition); + endPosition = Math.Max(endPosition, caretPosition); + + startPosition = Math.Min(startPosition, triggerLocation); + + return TextSpan.FromBounds(startPosition, endPosition); + } + } +} diff --git a/src/Features/Core/Portable/Snippets/SnippetChange.cs b/src/Features/Core/Portable/Snippets/SnippetChange.cs new file mode 100644 index 0000000000000..584d9a7aea2d8 --- /dev/null +++ b/src/Features/Core/Portable/Snippets/SnippetChange.cs @@ -0,0 +1,48 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Collections.Generic; +using System.Collections.Immutable; +using Microsoft.CodeAnalysis.Text; + +namespace Microsoft.CodeAnalysis.Snippets +{ + /// + /// Encapsulates the information that makes up a Snippet. + /// + internal readonly struct SnippetChange + { + /// + /// The TextChange's associated with introducing a snippet into a document + /// + public readonly ImmutableArray TextChanges; + + /// + /// The position that the cursor should end up on + /// + public readonly int CursorPosition; + + /// + /// The items that we will want to rename as well as the ordering + /// in which to visit those items. + /// + public readonly ImmutableArray Placeholders; + + public SnippetChange( + ImmutableArray textChanges, + int cursorPosition, + ImmutableArray placeholders) + { + if (textChanges.IsEmpty) + { + throw new ArgumentException($"{nameof(textChanges)} must not be empty."); + } + + TextChanges = textChanges; + CursorPosition = cursorPosition; + Placeholders = placeholders; + } + } +} diff --git a/src/Features/Core/Portable/Snippets/SnippetData.cs b/src/Features/Core/Portable/Snippets/SnippetData.cs new file mode 100644 index 0000000000000..fd2a59d833e65 --- /dev/null +++ b/src/Features/Core/Portable/Snippets/SnippetData.cs @@ -0,0 +1,30 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Text; + +namespace Microsoft.CodeAnalysis.Snippets +{ + /// + /// Stores only the data needed for the creation of a CompletionItem. + /// Avoids using the Snippet and creating a TextChange/finding cursor + /// position before we know it was the selected CompletionItem. + /// + internal struct SnippetData + { + public readonly string Description; + public readonly string SnippetIdentifier; + public readonly ImmutableArray AdditionalFilterTexts; + + public SnippetData(string description, string snippetIdentifier, ImmutableArray additionalFilterTexts) + { + Description = description; + SnippetIdentifier = snippetIdentifier; + AdditionalFilterTexts = additionalFilterTexts; + } + } +} diff --git a/src/Features/Core/Portable/Snippets/SnippetPlaceholder.cs b/src/Features/Core/Portable/Snippets/SnippetPlaceholder.cs new file mode 100644 index 0000000000000..5932bdfeff17d --- /dev/null +++ b/src/Features/Core/Portable/Snippets/SnippetPlaceholder.cs @@ -0,0 +1,47 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Text; +using Microsoft.CodeAnalysis.Text; + +namespace Microsoft.CodeAnalysis.Snippets +{ + internal readonly struct SnippetPlaceholder + { + /// + /// The identifier in the snippet that needs to be renamed. + /// + public readonly string Identifier; + + /// + /// The positions associated with the identifier that will need to + /// be converted into LSP formatted strings. + /// + public readonly ImmutableArray PlaceHolderPositions; + + /// + /// + /// For loop would have two placeholders: + /// + /// for (var {1:i} = 0; {1:i} < {2:length}; {1:i}++) + /// + /// Identifier: i, 3 associated positions
+ /// Identifier: length, 1 associated position
+ ///
+ ///
+ public SnippetPlaceholder(string identifier, ImmutableArray placeholderPositions) + { + if (identifier.Length == 0) + { + throw new ArgumentException($"{nameof(identifier)} must not be an empty string."); + } + + Identifier = identifier; + PlaceHolderPositions = placeholderPositions; + } + } +} diff --git a/src/Features/Core/Portable/Snippets/SnippetProviders/AbstractConsoleSnippetProvider.cs b/src/Features/Core/Portable/Snippets/SnippetProviders/AbstractConsoleSnippetProvider.cs new file mode 100644 index 0000000000000..0ce83c454f3ae --- /dev/null +++ b/src/Features/Core/Portable/Snippets/SnippetProviders/AbstractConsoleSnippetProvider.cs @@ -0,0 +1,169 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation 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.Editing; +using Microsoft.CodeAnalysis.Formatting; +using Microsoft.CodeAnalysis.Host.Mef; +using Microsoft.CodeAnalysis.LanguageService; +using Microsoft.CodeAnalysis.PooledObjects; +using Microsoft.CodeAnalysis.Shared.Extensions; +using Microsoft.CodeAnalysis.Shared.Extensions.ContextQuery; +using Microsoft.CodeAnalysis.Simplification; +using Microsoft.CodeAnalysis.Snippets; +using Microsoft.CodeAnalysis.Text; +using Roslyn.Utilities; + +namespace Microsoft.CodeAnalysis.Snippets +{ + internal abstract class AbstractConsoleSnippetProvider : AbstractSnippetProvider + { + protected abstract SyntaxNode? GetAsyncSupportingDeclaration(SyntaxToken token); + + public override string SnippetIdentifier => "cw"; + + public override string SnippetDescription => FeaturesResources.console_writeline; + + public override ImmutableArray AdditionalFilterTexts { get; } = ImmutableArray.Create("Console", "WriteLine"); + + protected override async Task IsValidSnippetLocationAsync(Document document, int position, CancellationToken cancellationToken) + { + var semanticModel = await document.ReuseExistingSpeculativeModelAsync(position, cancellationToken).ConfigureAwait(false); + var consoleSymbol = await GetSymbolFromMetaDataNameAsync(document, cancellationToken).ConfigureAwait(false); + if (consoleSymbol is null) + { + return false; + } + + var syntaxContext = document.GetRequiredLanguageService().CreateContext(document, semanticModel, position, cancellationToken); + return syntaxContext.IsStatementContext || syntaxContext.IsGlobalStatementContext; + } + + protected override async Task> GenerateSnippetTextChangesAsync(Document document, int position, CancellationToken cancellationToken) + { + var snippetTextChange = await GenerateSnippetTextChangeAsync(document, position, cancellationToken).ConfigureAwait(false); + return ImmutableArray.Create(snippetTextChange); + } + + private async Task GenerateSnippetTextChangeAsync(Document document, int position, CancellationToken cancellationToken) + { + var consoleSymbol = await GetSymbolFromMetaDataNameAsync(document, cancellationToken).ConfigureAwait(false); + Contract.ThrowIfNull(consoleSymbol); + var generator = SyntaxGenerator.GetGenerator(document); + var tree = await document.GetRequiredSyntaxTreeAsync(cancellationToken).ConfigureAwait(false); + var token = tree.FindTokenOnLeftOfPosition(position, cancellationToken); + + // We know symbol is not null at this point since it was checked when determining + // if we are in a valid location to insert the snippet. + var typeExpression = generator.TypeExpression(consoleSymbol); + var declaration = GetAsyncSupportingDeclaration(token); + var isAsync = declaration is not null && generator.GetModifiers(declaration).IsAsync; + + var invocation = isAsync + ? generator.AwaitExpression(generator.InvocationExpression( + generator.MemberAccessExpression(generator.MemberAccessExpression(typeExpression, generator.IdentifierName(nameof(Console.Out))), generator.IdentifierName(nameof(Console.Out.WriteLineAsync))))) + : generator.InvocationExpression(generator.MemberAccessExpression(typeExpression, generator.IdentifierName(nameof(Console.WriteLine)))); + var expressionStatement = generator.ExpressionStatement(invocation); + + // Need to normalize the whitespace for the asynchronous case because it doesn't insert a space following the await + return new TextChange(TextSpan.FromBounds(position, position), expressionStatement.NormalizeWhitespace().ToFullString()); + } + + /// + /// Tries to get the location after the open parentheses in the argument list. + /// If it can't, then we default to the end of the snippet's span. + /// + protected override int GetTargetCaretPosition(ISyntaxFactsService syntaxFacts, SyntaxNode caretTarget, SourceText sourceText) + { + var invocationExpression = caretTarget.DescendantNodes().Where(syntaxFacts.IsInvocationExpression).FirstOrDefault(); + if (invocationExpression is null) + { + return caretTarget.Span.End; + } + + var argumentListNode = syntaxFacts.GetArgumentListOfInvocationExpression(invocationExpression); + if (argumentListNode is null) + { + return caretTarget.Span.End; + } + + syntaxFacts.GetPartsOfArgumentList(argumentListNode, out var openParenToken, out _, out _); + return openParenToken.Span.End; + } + + protected override async Task AnnotateNodesToReformatAsync(Document document, + SyntaxAnnotation findSnippetAnnotation, SyntaxAnnotation cursorAnnotation, int position, CancellationToken cancellationToken) + { + var root = await document.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false); + var syntaxFacts = document.GetRequiredLanguageService(); + var snippetExpressionNode = FindAddedSnippetSyntaxNode(root, position, syntaxFacts); + if (snippetExpressionNode is null) + { + return root; + } + + var consoleSymbol = await GetSymbolFromMetaDataNameAsync(document, cancellationToken).ConfigureAwait(false); + + var reformatSnippetNode = snippetExpressionNode.WithAdditionalAnnotations(findSnippetAnnotation, cursorAnnotation, Simplifier.Annotation, SymbolAnnotation.Create(consoleSymbol!), Formatter.Annotation); + return root.ReplaceNode(snippetExpressionNode, reformatSnippetNode); + } + + protected override ImmutableArray GetPlaceHolderLocationsList(SyntaxNode node, ISyntaxFacts syntaxFacts, CancellationToken cancellationToken) + { + return ImmutableArray.Empty; + } + + private static SyntaxToken? GetOpenParenToken(SyntaxNode node, ISyntaxFacts syntaxFacts) + { + var invocationExpression = node.DescendantNodes().Where(syntaxFacts.IsInvocationExpression).FirstOrDefault(); + if (invocationExpression is null) + { + return null; + } + + var argumentListNode = syntaxFacts.GetArgumentListOfInvocationExpression(invocationExpression); + if (argumentListNode is null) + { + return null; + } + + syntaxFacts.GetPartsOfArgumentList(argumentListNode, out var openParenToken, out _, out _); + + return openParenToken; + } + + protected override SyntaxNode? FindAddedSnippetSyntaxNode(SyntaxNode root, int position, ISyntaxFacts syntaxFacts) + { + var closestNode = root.FindNode(TextSpan.FromBounds(position, position)); + var nearestExpressionStatement = closestNode.FirstAncestorOrSelf(syntaxFacts.IsExpressionStatement); + if (nearestExpressionStatement is null) + { + return null; + } + + // Checking to see if that expression statement that we found is + // starting at the same position as the position we inserted + // the Console WriteLine expression statement. + if (nearestExpressionStatement.SpanStart != position) + { + return null; + } + + return nearestExpressionStatement; + } + + private static async Task GetSymbolFromMetaDataNameAsync(Document document, CancellationToken cancellationToken) + { + var compilation = await document.Project.GetRequiredCompilationAsync(cancellationToken).ConfigureAwait(false); + var symbol = compilation.GetBestTypeByMetadataName(typeof(Console).FullName!); + return symbol; + } + } +} diff --git a/src/Features/Core/Portable/Snippets/SnippetProviders/AbstractIfSnippetProvider.cs b/src/Features/Core/Portable/Snippets/SnippetProviders/AbstractIfSnippetProvider.cs new file mode 100644 index 0000000000000..e3a93da718025 --- /dev/null +++ b/src/Features/Core/Portable/Snippets/SnippetProviders/AbstractIfSnippetProvider.cs @@ -0,0 +1,111 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Linq; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.Editing; +using Microsoft.CodeAnalysis.Formatting; +using Microsoft.CodeAnalysis.LanguageService; +using Microsoft.CodeAnalysis.PooledObjects; +using Microsoft.CodeAnalysis.Shared.Extensions; +using Microsoft.CodeAnalysis.Shared.Extensions.ContextQuery; +using Microsoft.CodeAnalysis.Simplification; +using Microsoft.CodeAnalysis.Text; + +namespace Microsoft.CodeAnalysis.Snippets +{ + internal abstract class AbstractIfSnippetProvider : AbstractSnippetProvider + { + public override string SnippetIdentifier => "if"; + + public override string SnippetDescription => FeaturesResources.if_statement; + + public override ImmutableArray AdditionalFilterTexts { get; } = ImmutableArray.Create("statement"); + + protected abstract void GetIfStatementCondition(SyntaxNode node, out SyntaxNode condition); + protected abstract void GetIfStatementCursorPosition(SourceText text, SyntaxNode node, out int position); + + protected override async Task IsValidSnippetLocationAsync(Document document, int position, CancellationToken cancellationToken) + { + var semanticModel = await document.ReuseExistingSpeculativeModelAsync(position, cancellationToken).ConfigureAwait(false); + + var syntaxContext = document.GetRequiredLanguageService().CreateContext(document, semanticModel, position, cancellationToken); + return syntaxContext.IsStatementContext || syntaxContext.IsGlobalStatementContext; + } + + protected override Task> GenerateSnippetTextChangesAsync(Document document, int position, CancellationToken cancellationToken) + { + var snippetTextChange = GenerateSnippetTextChange(document, position); + return Task.FromResult(ImmutableArray.Create(snippetTextChange)); + } + + private static TextChange GenerateSnippetTextChange(Document document, int position) + { + var generator = SyntaxGenerator.GetGenerator(document); + var ifStatement = generator.IfStatement(generator.TrueLiteralExpression(), Array.Empty()); + + return new TextChange(TextSpan.FromBounds(position, position), ifStatement.ToFullString()); + } + + protected override int GetTargetCaretPosition(ISyntaxFactsService syntaxFacts, SyntaxNode caretTarget, SourceText sourceText) + { + GetIfStatementCursorPosition(sourceText, caretTarget, out var cursorPosition); + + // Place at the end of the node specified for cursor position. + // Is the statement node in C# and the "Then" keyword + return cursorPosition; + } + + protected override async Task AnnotateNodesToReformatAsync(Document document, + SyntaxAnnotation findSnippetAnnotation, SyntaxAnnotation cursorAnnotation, int position, CancellationToken cancellationToken) + { + var root = await document.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false); + var syntaxFacts = document.GetRequiredLanguageService(); + var snippetExpressionNode = FindAddedSnippetSyntaxNode(root, position, syntaxFacts); + if (snippetExpressionNode is null) + { + return root; + } + + var reformatSnippetNode = snippetExpressionNode.WithAdditionalAnnotations(findSnippetAnnotation, cursorAnnotation, Simplifier.Annotation, Formatter.Annotation); + return root.ReplaceNode(snippetExpressionNode, reformatSnippetNode); + } + + protected override ImmutableArray GetPlaceHolderLocationsList(SyntaxNode node, ISyntaxFacts syntaxFacts, CancellationToken cancellationToken) + { + using var _ = ArrayBuilder.GetInstance(out var arrayBuilder); + GetIfStatementCondition(node, out var condition); + arrayBuilder.Add(new SnippetPlaceholder(identifier: condition.ToString(), placeholderPositions: ImmutableArray.Create(condition.SpanStart))); + + return arrayBuilder.ToImmutableArray(); + } + + protected override SyntaxNode? FindAddedSnippetSyntaxNode(SyntaxNode root, int position, ISyntaxFacts syntaxFacts) + { + var closestNode = root.FindNode(TextSpan.FromBounds(position, position), getInnermostNodeForTie: true); + + var nearestStatement = closestNode.DescendantNodesAndSelf(syntaxFacts.IsIfStatement).FirstOrDefault(); + + if (nearestStatement is null) + { + return null; + } + + // Checking to see if that expression statement that we found is + // starting at the same position as the position we inserted + // the if statement. + if (nearestStatement.SpanStart != position) + { + return null; + } + + return nearestStatement; + } + } +} diff --git a/src/Features/Core/Portable/Snippets/SnippetProviders/AbstractSnippetProvider.cs b/src/Features/Core/Portable/Snippets/SnippetProviders/AbstractSnippetProvider.cs new file mode 100644 index 0000000000000..c226868dce6e7 --- /dev/null +++ b/src/Features/Core/Portable/Snippets/SnippetProviders/AbstractSnippetProvider.cs @@ -0,0 +1,227 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .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; +using Microsoft.CodeAnalysis.AddImport; +using Microsoft.CodeAnalysis.Editing; +using Microsoft.CodeAnalysis.Formatting; +using Microsoft.CodeAnalysis.Host; +using Microsoft.CodeAnalysis.LanguageService; +using Microsoft.CodeAnalysis.Shared.Extensions; +using Microsoft.CodeAnalysis.Simplification; +using Microsoft.CodeAnalysis.Snippets.SnippetProviders; +using Microsoft.CodeAnalysis.Text; +using Roslyn.Utilities; + +namespace Microsoft.CodeAnalysis.Snippets +{ + internal abstract class AbstractSnippetProvider : ISnippetProvider + { + public abstract string SnippetIdentifier { get; } + public abstract string SnippetDescription { get; } + + public virtual ImmutableArray AdditionalFilterTexts => ImmutableArray.Empty; + + protected readonly SyntaxAnnotation _cursorAnnotation = new(); + protected readonly SyntaxAnnotation _findSnippetAnnotation = new(); + + /// + /// Implemented by each SnippetProvider to determine if that particular position is a valid + /// location for the snippet to be inserted. + /// + protected abstract Task IsValidSnippetLocationAsync(Document document, int position, CancellationToken cancellationToken); + + /// + /// Generates the new snippet's TextChanges that are being inserted into the document + /// + protected abstract Task> GenerateSnippetTextChangesAsync(Document document, int position, CancellationToken cancellationToken); + + /// + /// Method for each snippet to locate the inserted SyntaxNode to reformat + /// + protected abstract Task AnnotateNodesToReformatAsync(Document document, SyntaxAnnotation reformatAnnotation, SyntaxAnnotation cursorAnnotation, int position, CancellationToken cancellationToken); + protected abstract int GetTargetCaretPosition(ISyntaxFactsService syntaxFacts, SyntaxNode caretTarget, SourceText sourceText); + + /// + /// Every SnippetProvider will need a method to retrieve the "main" snippet syntax once it has been inserted as a TextChange. + /// + protected abstract SyntaxNode? FindAddedSnippetSyntaxNode(SyntaxNode root, int position, ISyntaxFacts syntaxFacts); + + /// + /// Method to find the locations that must be renamed and where tab stops must be inserted into the snippet. + /// + protected abstract ImmutableArray GetPlaceHolderLocationsList(SyntaxNode node, ISyntaxFacts syntaxFacts, CancellationToken cancellationToken); + + /// + /// Determines if the location is valid for a snippet, + /// if so, then it creates a SnippetData. + /// + public async Task GetSnippetDataAsync(Document document, int position, CancellationToken cancellationToken) + { + var syntaxFacts = document.GetRequiredLanguageService(); + var syntaxTree = await document.GetSyntaxTreeAsync(cancellationToken).ConfigureAwait(false); + if (syntaxFacts.IsInNonUserCode(syntaxTree, position, cancellationToken)) + { + return null; + } + + if (!await IsValidSnippetLocationAsync(document, position, cancellationToken).ConfigureAwait(false)) + { + return null; + } + + return new SnippetData(SnippetDescription, SnippetIdentifier, AdditionalFilterTexts); + } + + /// + /// Handles all the work to generate the Snippet. + /// Reformats the document with the snippet TextChange and annotates + /// appropriately for the cursor to get the target cursor position. + /// + public async Task GetSnippetAsync(Document document, int position, CancellationToken cancellationToken) + { + var syntaxFacts = document.GetRequiredLanguageService(); + + // Generates the snippet as a list of textchanges + var textChanges = await GenerateSnippetTextChangesAsync(document, position, cancellationToken).ConfigureAwait(false); + + // Applies the snippet textchanges to the document + var snippetDocument = await GetDocumentWithSnippetAsync(document, textChanges, cancellationToken).ConfigureAwait(false); + + // Finds the inserted snippet and replaces the node in the document with a node that has added trivia + // since all trivia is removed when converted to a TextChange. + var snippetWithTriviaDocument = await GetDocumentWithSnippetAndTriviaAsync(snippetDocument, position, syntaxFacts, cancellationToken).ConfigureAwait(false); + + // Adds annotations to inserted snippet to be formatted, simplified, add imports if needed, etc. + var formatAnnotatedSnippetDocument = await AddFormatAnnotationAsync(snippetWithTriviaDocument, position, cancellationToken).ConfigureAwait(false); + + // Goes through and calls upon the formatting engines that the previous step annotated. + var reformattedDocument = await CleanupDocumentAsync(formatAnnotatedSnippetDocument, cancellationToken).ConfigureAwait(false); + + // Finds the added snippet and adds identation where necessary (braces). + var documentWithIndentation = await AddIndentationToDocumentAsync(reformattedDocument, position, syntaxFacts, cancellationToken).ConfigureAwait(false); + + var reformattedRoot = await documentWithIndentation.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false); + var caretTarget = reformattedRoot.GetAnnotatedNodes(_cursorAnnotation).FirstOrDefault(); + var mainChangeNode = reformattedRoot.GetAnnotatedNodes(_findSnippetAnnotation).FirstOrDefault(); + + var annotatedReformattedDocument = documentWithIndentation.WithSyntaxRoot(reformattedRoot); + + // All the TextChanges from the original document. Will include any imports (if necessary) and all snippet associated + // changes after having been formatted. + var changes = await annotatedReformattedDocument.GetTextChangesAsync(document, cancellationToken).ConfigureAwait(false); + + // Gets a listing of the identifiers that need to be found in the snippet TextChange + // and their associated TextSpan so they can later be converted into an LSP snippet format. + var placeholders = GetPlaceHolderLocationsList(mainChangeNode, syntaxFacts, cancellationToken); + + // All the changes from the original document to the most updated. Will later be + // collpased into one collapsed TextChange. + var changesArray = changes.ToImmutableArray(); + var sourceText = await annotatedReformattedDocument.GetTextAsync(cancellationToken).ConfigureAwait(false); + + return new SnippetChange( + textChanges: changesArray, + cursorPosition: GetTargetCaretPosition(syntaxFacts, caretTarget, sourceText), + placeholders: placeholders); + } + + /// + /// Descends into the inserted snippet to add back trivia on every token. + /// + private static SyntaxNode? GenerateElasticTriviaForSyntax(ISyntaxFacts syntaxFacts, SyntaxNode? node) + { + if (node is null) + { + return null; + } + + var nodeWithTrivia = node.ReplaceTokens(node.DescendantTokens(descendIntoTrivia: true), + (oldtoken, _) => oldtoken.WithAdditionalAnnotations(SyntaxAnnotation.ElasticAnnotation) + .WithAppendedTrailingTrivia(syntaxFacts.ElasticMarker) + .WithPrependedLeadingTrivia(syntaxFacts.ElasticMarker)); + + return nodeWithTrivia; + } + + private async Task CleanupDocumentAsync( + Document document, CancellationToken cancellationToken) + { + if (document.SupportsSyntaxTree) + { + var addImportPlacementOptions = await document.GetAddImportPlacementOptionsAsync(fallbackOptions: null, cancellationToken).ConfigureAwait(false); + var simplifierOptions = await document.GetSimplifierOptionsAsync(fallbackOptions: null, cancellationToken).ConfigureAwait(false); + var syntaxFormattingOptions = await document.GetSyntaxFormattingOptionsAsync(fallbackOptions: null, cancellationToken).ConfigureAwait(false); + + document = await ImportAdder.AddImportsFromSymbolAnnotationAsync( + document, _findSnippetAnnotation, addImportPlacementOptions, cancellationToken: cancellationToken).ConfigureAwait(false); + + document = await Simplifier.ReduceAsync(document, _findSnippetAnnotation, simplifierOptions, cancellationToken: cancellationToken).ConfigureAwait(false); + + // format any node with explicit formatter annotation + document = await Formatter.FormatAsync(document, _findSnippetAnnotation, syntaxFormattingOptions, cancellationToken: cancellationToken).ConfigureAwait(false); + + // format any elastic whitespace + document = await Formatter.FormatAsync(document, SyntaxAnnotation.ElasticAnnotation, syntaxFormattingOptions, cancellationToken: cancellationToken).ConfigureAwait(false); + } + + return document; + } + + /// + /// Locates the snippet that was inserted. Generates trivia for every token in that syntaxnode. + /// Replaces the SyntaxNodes and gets back the new document. + /// + private async Task GetDocumentWithSnippetAndTriviaAsync(Document snippetDocument, int position, ISyntaxFacts syntaxFacts, CancellationToken cancellationToken) + { + var root = await snippetDocument.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false); + var nearestStatement = FindAddedSnippetSyntaxNode(root, position, syntaxFacts); + + if (nearestStatement is null) + { + return snippetDocument; + } + + var nearestStatementWithTrivia = GenerateElasticTriviaForSyntax(syntaxFacts, nearestStatement); + + if (nearestStatementWithTrivia is null) + { + return snippetDocument; + } + + root = root.ReplaceNode(nearestStatement, nearestStatementWithTrivia); + return snippetDocument.WithSyntaxRoot(root); + } + + private static async Task GetDocumentWithSnippetAsync(Document document, ImmutableArray snippets, CancellationToken cancellationToken) + { + var originalText = await document.GetTextAsync(cancellationToken).ConfigureAwait(false); + + originalText = originalText.WithChanges(snippets); + var snippetDocument = document.WithText(originalText); + + return snippetDocument; + } + + private async Task AddFormatAnnotationAsync(Document document, int position, CancellationToken cancellationToken) + { + var annotatedSnippetRoot = await AnnotateNodesToReformatAsync(document, _findSnippetAnnotation, _cursorAnnotation, position, cancellationToken).ConfigureAwait(false); + document = document.WithSyntaxRoot(annotatedSnippetRoot); + return document; + } + + /// + /// Certain snippets require more indentation - snippets with blocks. + /// The SyntaxGenerator does not insert this space for us nor does the LSP Snippet Expander. + /// We need to manually add that spacing to snippets containing blocks. + /// + protected virtual async Task AddIndentationToDocumentAsync(Document document, int position, ISyntaxFacts syntaxFacts, CancellationToken cancellationToken) + { + return await Task.FromResult(document).ConfigureAwait(false); + } + } +} diff --git a/src/Features/Core/Portable/Snippets/SnippetProviders/ISnippetProvider.cs b/src/Features/Core/Portable/Snippets/SnippetProviders/ISnippetProvider.cs new file mode 100644 index 0000000000000..a4205fba2106c --- /dev/null +++ b/src/Features/Core/Portable/Snippets/SnippetProviders/ISnippetProvider.cs @@ -0,0 +1,37 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Collections.Generic; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.Host; +using Microsoft.CodeAnalysis.Text; + +namespace Microsoft.CodeAnalysis.Snippets.SnippetProviders +{ + internal interface ISnippetProvider + { + /// + /// What we use to identify each SnippetProvider on the completion list + /// + string SnippetIdentifier { get; } + + /// + /// What is being displayed for the description of the snippet + /// + string SnippetDescription { get; } + + /// + /// Determines if a snippet can exist at a particular location. + /// + Task GetSnippetDataAsync(Document document, int position, CancellationToken cancellationToken); + + /// + /// Gets the Snippet from the corresponding snippet provider. + /// + Task GetSnippetAsync(Document document, int position, CancellationToken cancellationToken); + } +} diff --git a/src/Features/Core/Portable/Snippets/SnippetUtilities.cs b/src/Features/Core/Portable/Snippets/SnippetUtilities.cs index d868e29267f93..21704b61251e7 100644 --- a/src/Features/Core/Portable/Snippets/SnippetUtilities.cs +++ b/src/Features/Core/Portable/Snippets/SnippetUtilities.cs @@ -3,7 +3,7 @@ // See the LICENSE file in the project root for more information. using Microsoft.CodeAnalysis.Text; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using System.Diagnostics.CodeAnalysis; namespace Microsoft.CodeAnalysis; diff --git a/src/Features/Core/Portable/SolutionCrawler/AbstractDocumentDifferenceService.cs b/src/Features/Core/Portable/SolutionCrawler/AbstractDocumentDifferenceService.cs index 46507e86acd7f..c8fed27f51909 100644 --- a/src/Features/Core/Portable/SolutionCrawler/AbstractDocumentDifferenceService.cs +++ b/src/Features/Core/Portable/SolutionCrawler/AbstractDocumentDifferenceService.cs @@ -6,7 +6,7 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.ErrorReporting; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Text; using Roslyn.Utilities; @@ -19,7 +19,7 @@ internal abstract class AbstractDocumentDifferenceService : IDocumentDifferenceS { try { - var syntaxFactsService = newDocument.Project.LanguageServices.GetService(); + var syntaxFactsService = newDocument.Project.Services.GetService(); if (syntaxFactsService == null) { // somehow, we can't get the service. without it, there is nothing we can do. diff --git a/src/Features/Core/Portable/SolutionCrawler/AggregateIncrementalAnalyzer.cs b/src/Features/Core/Portable/SolutionCrawler/AggregateIncrementalAnalyzer.cs deleted file mode 100644 index 3b508c8240096..0000000000000 --- a/src/Features/Core/Portable/SolutionCrawler/AggregateIncrementalAnalyzer.cs +++ /dev/null @@ -1,179 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using System; -using System.Collections.Generic; -using System.Collections.Immutable; -using System.Diagnostics.CodeAnalysis; -using System.Threading; -using System.Threading.Tasks; -using Microsoft.CodeAnalysis.Options; - -#if NETSTANDARD2_0 -using Roslyn.Utilities; -#endif - -namespace Microsoft.CodeAnalysis.SolutionCrawler -{ - internal class AggregateIncrementalAnalyzer : IIncrementalAnalyzer - { - public readonly ImmutableDictionary> Analyzers; - - public AggregateIncrementalAnalyzer(Workspace workspace, IncrementalAnalyzerProviderBase owner, List> providers) - { - Analyzers = providers.ToImmutableDictionary( - p => p.Metadata.Language, p => new Lazy(() => p.Value.CreatePerLanguageIncrementalAnalyzer(workspace, owner), isThreadSafe: true)); - } - - public async Task NewSolutionSnapshotAsync(Solution solution, CancellationToken cancellationToken) - { - foreach (var (_, analyzer) in Analyzers) - { - if (analyzer.IsValueCreated) - { - await analyzer.Value.NewSolutionSnapshotAsync(solution, cancellationToken).ConfigureAwait(false); - } - } - } - - public async Task DocumentOpenAsync(Document document, CancellationToken cancellationToken) - { - if (TryGetAnalyzer(document.Project, out var analyzer)) - { - await analyzer.DocumentOpenAsync(document, cancellationToken).ConfigureAwait(false); - } - } - - public async Task DocumentResetAsync(Document document, CancellationToken cancellationToken) - { - if (TryGetAnalyzer(document.Project, out var analyzer)) - { - await analyzer.DocumentResetAsync(document, cancellationToken).ConfigureAwait(false); - } - } - - public async Task DocumentCloseAsync(Document document, CancellationToken cancellationToken) - { - if (TryGetAnalyzer(document.Project, out var analyzer)) - { - await analyzer.DocumentCloseAsync(document, cancellationToken).ConfigureAwait(false); - } - } - - public async Task ActiveDocumentSwitchedAsync(TextDocument document, CancellationToken cancellationToken) - { - if (TryGetAnalyzer(document.Project, out var analyzer)) - { - await analyzer.ActiveDocumentSwitchedAsync(document, cancellationToken).ConfigureAwait(false); - } - } - - public async Task AnalyzeSyntaxAsync(Document document, InvocationReasons reasons, CancellationToken cancellationToken) - { - if (TryGetAnalyzer(document.Project, out var analyzer)) - { - await analyzer.AnalyzeSyntaxAsync(document, reasons, cancellationToken).ConfigureAwait(false); - } - } - - public async Task AnalyzeDocumentAsync(Document document, SyntaxNode bodyOpt, InvocationReasons reasons, CancellationToken cancellationToken) - { - if (TryGetAnalyzer(document.Project, out var analyzer)) - { - await analyzer.AnalyzeDocumentAsync(document, bodyOpt, reasons, cancellationToken).ConfigureAwait(false); - } - } - - public async Task AnalyzeProjectAsync(Project project, bool semanticsChanged, InvocationReasons reasons, CancellationToken cancellationToken) - { - if (TryGetAnalyzer(project, out var analyzer)) - { - await analyzer.AnalyzeProjectAsync(project, semanticsChanged, reasons, cancellationToken).ConfigureAwait(false); - } - } - - private bool TryGetAnalyzer(Project project, [NotNullWhen(true)] out IIncrementalAnalyzer? analyzer) - { - if (!Analyzers.TryGetValue(project.Language, out var lazyAnalyzer)) - { - analyzer = null; - return false; - } - - analyzer = lazyAnalyzer.Value; - return true; - } - - public async Task RemoveDocumentAsync(DocumentId documentId, CancellationToken cancellationToken) - { - foreach (var (_, analyzer) in Analyzers) - { - if (analyzer.IsValueCreated) - { - await analyzer.Value.RemoveDocumentAsync(documentId, cancellationToken).ConfigureAwait(false); - } - } - } - - public async Task RemoveProjectAsync(ProjectId projectId, CancellationToken cancellationToken) - { - foreach (var (_, analyzer) in Analyzers) - { - if (analyzer.IsValueCreated) - { - await analyzer.Value.RemoveProjectAsync(projectId, cancellationToken).ConfigureAwait(false); - } - } - } - - public async Task NonSourceDocumentOpenAsync(TextDocument textDocument, CancellationToken cancellationToken) - { - if (TryGetAnalyzer(textDocument.Project, out var analyzer)) - { - await analyzer.NonSourceDocumentOpenAsync(textDocument, cancellationToken).ConfigureAwait(false); - } - } - - public async Task NonSourceDocumentCloseAsync(TextDocument textDocument, CancellationToken cancellationToken) - { - if (TryGetAnalyzer(textDocument.Project, out var analyzer)) - { - await analyzer.NonSourceDocumentCloseAsync(textDocument, cancellationToken).ConfigureAwait(false); - } - } - - public async Task NonSourceDocumentResetAsync(TextDocument textDocument, CancellationToken cancellationToken) - { - if (TryGetAnalyzer(textDocument.Project, out var analyzer)) - { - await analyzer.NonSourceDocumentResetAsync(textDocument, cancellationToken).ConfigureAwait(false); - } - } - - public async Task AnalyzeNonSourceDocumentAsync(TextDocument textDocument, InvocationReasons reasons, CancellationToken cancellationToken) - { - if (TryGetAnalyzer(textDocument.Project, out var analyzer)) - { - await analyzer.AnalyzeNonSourceDocumentAsync(textDocument, reasons, cancellationToken).ConfigureAwait(false); - } - } - - public void LogAnalyzerCountSummary() - { - } - - public int Priority => 1; - - public void Shutdown() - { - foreach (var (_, analyzer) in Analyzers) - { - if (analyzer.IsValueCreated) - { - analyzer.Value.Shutdown(); - } - } - } - } -} diff --git a/src/Features/Core/Portable/SolutionCrawler/Extensibility/IPerLanguageIncrementalAnalyzerProvider.cs b/src/Features/Core/Portable/SolutionCrawler/Extensibility/IPerLanguageIncrementalAnalyzerProvider.cs deleted file mode 100644 index f2564bd37ec99..0000000000000 --- a/src/Features/Core/Portable/SolutionCrawler/Extensibility/IPerLanguageIncrementalAnalyzerProvider.cs +++ /dev/null @@ -1,11 +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.SolutionCrawler -{ - internal interface IPerLanguageIncrementalAnalyzerProvider - { - IIncrementalAnalyzer CreatePerLanguageIncrementalAnalyzer(Workspace workspace, IIncrementalAnalyzerProvider provider); - } -} diff --git a/src/Features/Core/Portable/SolutionCrawler/Extensibility/PerLanguageIncrementalAnalyzerProviderMetadata.cs b/src/Features/Core/Portable/SolutionCrawler/Extensibility/PerLanguageIncrementalAnalyzerProviderMetadata.cs deleted file mode 100644 index 8fa2a31b97319..0000000000000 --- a/src/Features/Core/Portable/SolutionCrawler/Extensibility/PerLanguageIncrementalAnalyzerProviderMetadata.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.Collections.Generic; -using Microsoft.CodeAnalysis.Host.Mef; -using Roslyn.Utilities; - -namespace Microsoft.CodeAnalysis.SolutionCrawler -{ - internal class PerLanguageIncrementalAnalyzerProviderMetadata : LanguageMetadata - { - public string? Name { get; } - - public PerLanguageIncrementalAnalyzerProviderMetadata(IDictionary data) - : base(data) - { - Name = (string?)data.GetValueOrDefault("Name"); - } - } -} diff --git a/src/Features/Core/Portable/SolutionCrawler/IncrementalAnalyzerProviderBase.cs b/src/Features/Core/Portable/SolutionCrawler/IncrementalAnalyzerProviderBase.cs deleted file mode 100644 index dfa762e728df9..0000000000000 --- a/src/Features/Core/Portable/SolutionCrawler/IncrementalAnalyzerProviderBase.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; -using System.Collections.Generic; -using System.Linq; - -namespace Microsoft.CodeAnalysis.SolutionCrawler -{ - internal class IncrementalAnalyzerProviderBase : IIncrementalAnalyzerProvider - { - private readonly List> _providers; - - protected IncrementalAnalyzerProviderBase( - string name, IEnumerable> providers) - { - _providers = providers.Where(p => p.Metadata.Name == name).ToList(); - } - - public virtual IIncrementalAnalyzer CreateIncrementalAnalyzer(Workspace workspace) - => new AggregateIncrementalAnalyzer(workspace, this, _providers); - } -} diff --git a/src/Features/Core/Portable/SolutionCrawler/SolutionCrawlerLogger.cs b/src/Features/Core/Portable/SolutionCrawler/SolutionCrawlerLogger.cs index 181cef3b13f01..54b3d0c2b3463 100644 --- a/src/Features/Core/Portable/SolutionCrawler/SolutionCrawlerLogger.cs +++ b/src/Features/Core/Portable/SolutionCrawler/SolutionCrawlerLogger.cs @@ -43,14 +43,6 @@ internal static class SolutionCrawlerLogger private const string ActiveFileProcessDocument = nameof(ActiveFileProcessDocument); private const string ActiveFileProcessDocumentCancellation = nameof(ActiveFileProcessDocumentCancellation); - private const string Max = "Maximum"; - private const string Min = "Minimum"; - private const string Median = nameof(Median); - private const string Mean = nameof(Mean); - private const string Mode = nameof(Mode); - private const string Range = nameof(Range); - private const string Count = nameof(Count); - public static void LogRegistration(int correlationId, Workspace workspace) { Logger.Log(FunctionId.WorkCoordinatorRegistrationService_Register, KeyValueLogMessage.Create(m => @@ -134,10 +126,10 @@ public static void LogWorkCoordinatorShutdownTimeout(int correlationId) })); } - public static void LogWorkspaceEvent(LogAggregator logAggregator, int kind) + public static void LogWorkspaceEvent(CountLogAggregator logAggregator, WorkspaceChangeKind kind) => logAggregator.IncreaseCount(kind); - public static void LogWorkCoordinatorShutdown(int correlationId, LogAggregator logAggregator) + public static void LogWorkCoordinatorShutdown(int correlationId, CountLogAggregator logAggregator) { Logger.Log(FunctionId.WorkCoordinator_Shutdown, KeyValueLogMessage.Create(m => { @@ -145,23 +137,23 @@ public static void LogWorkCoordinatorShutdown(int correlationId, LogAggregator l foreach (var kv in logAggregator) { - var change = ((WorkspaceChangeKind)kv.Key).ToString(); + var change = kv.Key.ToString(); m[change] = kv.Value.GetCount(); } })); } - public static void LogGlobalOperation(LogAggregator logAggregator) + public static void LogGlobalOperation(CountLogAggregator logAggregator) => logAggregator.IncreaseCount(GlobalOperation); - public static void LogActiveFileEnqueue(LogAggregator logAggregator) + public static void LogActiveFileEnqueue(CountLogAggregator logAggregator) => logAggregator.IncreaseCount(ActiveFileEnqueue); - public static void LogWorkItemEnqueue(LogAggregator logAggregator, ProjectId _) + public static void LogWorkItemEnqueue(CountLogAggregator logAggregator, ProjectId _) => logAggregator.IncreaseCount(ProjectEnqueue); public static void LogWorkItemEnqueue( - LogAggregator logAggregator, string language, DocumentId? documentId, InvocationReasons reasons, bool lowPriority, SyntaxPath? activeMember, bool added) + CountLogAggregator logAggregator, string language, DocumentId? documentId, InvocationReasons reasons, bool lowPriority, SyntaxPath? activeMember, bool added) { logAggregator.IncreaseCount(language); logAggregator.IncreaseCount(added ? NewWorkItem : UpdateWorkItem); @@ -183,16 +175,16 @@ public static void LogWorkItemEnqueue( } } - public static void LogHigherPriority(LogAggregator logAggregator, Guid documentId) + public static void LogHigherPriority(CountLogAggregator logAggregator, Guid documentId) { logAggregator.IncreaseCount(HigherPriority); logAggregator.IncreaseCount(ValueTuple.Create(HigherPriority, documentId)); } - public static void LogResetStates(LogAggregator logAggregator) + public static void LogResetStates(CountLogAggregator logAggregator) => logAggregator.IncreaseCount(ResetStates); - public static void LogIncrementalAnalyzerProcessorStatistics(int correlationId, Solution solution, LogAggregator logAggregator, ImmutableArray analyzers) + public static void LogIncrementalAnalyzerProcessorStatistics(int correlationId, Solution solution, CountLogAggregator logAggregator, ImmutableArray analyzers) { Logger.Log(FunctionId.IncrementalAnalyzerProcessor_Shutdown, KeyValueLogMessage.Create(m => { @@ -207,30 +199,23 @@ public static void LogIncrementalAnalyzerProcessorStatistics(int correlationId, if (key is string stringKey) { m[stringKey] = counter.GetCount(); - continue; } - - if (key is ValueTuple propertyNameAndId) + else if (key is ValueTuple propertyNameAndId) { var list = statMap.GetOrAdd(propertyNameAndId.Item1, _ => new List()); list.Add(counter.GetCount()); - continue; } - - throw ExceptionUtilities.Unreachable; + else + { + throw ExceptionUtilities.Unreachable; + } } foreach (var (propertyName, propertyValues) in statMap) { - var result = LogAggregator.GetStatistics(propertyValues); - - m[CreateProperty(propertyName, Max)] = result.Maximum; - m[CreateProperty(propertyName, Min)] = result.Minimum; - m[CreateProperty(propertyName, Median)] = result.Median!.Value; - m[CreateProperty(propertyName, Mean)] = result.Mean; - m[CreateProperty(propertyName, Mode)] = result.Mode!.Value; - m[CreateProperty(propertyName, Range)] = result.Range; - m[CreateProperty(propertyName, Count)] = result.Count; + var result = StatisticResult.FromList(propertyValues); + + result.WriteTelemetryPropertiesTo(m, prefix: propertyName); } })); @@ -250,22 +235,19 @@ private static int GetSolutionHash(Solution solution) return 0; } - private static string CreateProperty(string parent, string child) - => parent + "." + child; - - public static void LogProcessCloseDocument(LogAggregator logAggregator, Guid documentId) + public static void LogProcessCloseDocument(CountLogAggregator logAggregator, Guid documentId) { logAggregator.IncreaseCount(CloseDocument); logAggregator.IncreaseCount(ValueTuple.Create(CloseDocument, documentId)); } - public static void LogProcessOpenDocument(LogAggregator logAggregator, Guid documentId) + public static void LogProcessOpenDocument(CountLogAggregator logAggregator, Guid documentId) { logAggregator.IncreaseCount(OpenDocument); logAggregator.IncreaseCount(ValueTuple.Create(OpenDocument, documentId)); } - public static void LogProcessActiveFileDocument(LogAggregator logAggregator, Guid _, bool processed) + public static void LogProcessActiveFileDocument(CountLogAggregator logAggregator, Guid _, bool processed) { if (processed) { @@ -277,7 +259,7 @@ public static void LogProcessActiveFileDocument(LogAggregator logAggregator, Gui } } - public static void LogProcessDocument(LogAggregator logAggregator, Guid documentId, bool processed) + public static void LogProcessDocument(CountLogAggregator logAggregator, Guid documentId, bool processed) { if (processed) { @@ -291,10 +273,10 @@ public static void LogProcessDocument(LogAggregator logAggregator, Guid document logAggregator.IncreaseCount(ValueTuple.Create(ProcessDocument, documentId)); } - public static void LogProcessDocumentNotExist(LogAggregator logAggregator) + public static void LogProcessDocumentNotExist(CountLogAggregator logAggregator) => logAggregator.IncreaseCount(DocumentNotExist); - public static void LogProcessProject(LogAggregator logAggregator, Guid projectId, bool processed) + public static void LogProcessProject(CountLogAggregator logAggregator, Guid projectId, bool processed) { if (processed) { @@ -308,7 +290,7 @@ public static void LogProcessProject(LogAggregator logAggregator, Guid projectId logAggregator.IncreaseCount(ValueTuple.Create(ProcessProject, projectId)); } - public static void LogProcessProjectNotExist(LogAggregator logAggregator) + public static void LogProcessProjectNotExist(CountLogAggregator logAggregator) => logAggregator.IncreaseCount(ProjectNotExist); } } diff --git a/src/Features/Core/Portable/SolutionCrawler/SolutionCrawlerRegistrationService.cs b/src/Features/Core/Portable/SolutionCrawler/SolutionCrawlerRegistrationService.cs index b5def68057044..18a1e2e3aba98 100644 --- a/src/Features/Core/Portable/SolutionCrawler/SolutionCrawlerRegistrationService.cs +++ b/src/Features/Core/Portable/SolutionCrawler/SolutionCrawlerRegistrationService.cs @@ -62,7 +62,7 @@ public void EnsureRegistration(Workspace workspace, bool initializeLazily) { Contract.ThrowIfNull(workspace.Kind); - var correlationId = LogAggregator.GetNextId(); + var correlationId = CorrelationIdFactory.GetNextId(); lock (_gate) { diff --git a/src/Features/Core/Portable/SolutionCrawler/WorkCoordinator.IncrementalAnalyzerProcessor.cs b/src/Features/Core/Portable/SolutionCrawler/WorkCoordinator.IncrementalAnalyzerProcessor.cs index f4a317aceaad5..b1a6863cc7c35 100644 --- a/src/Features/Core/Portable/SolutionCrawler/WorkCoordinator.IncrementalAnalyzerProcessor.cs +++ b/src/Features/Core/Portable/SolutionCrawler/WorkCoordinator.IncrementalAnalyzerProcessor.cs @@ -13,7 +13,7 @@ using Microsoft.CodeAnalysis.ErrorReporting; using Microsoft.CodeAnalysis.Host; using Microsoft.CodeAnalysis.Internal.Log; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Notification; using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Shared.Extensions; @@ -42,7 +42,11 @@ private partial class IncrementalAnalyzerProcessor // NOTE: IDiagnosticAnalyzerService can be null in test environment. private readonly Lazy _lazyDiagnosticAnalyzerService; - private LogAggregator _logAggregator = new(); + /// + /// The keys in this are either a string or a (string, Guid) tuple. See + /// for what is writing this out. + /// + private CountLogAggregator _logAggregator = new(); public IncrementalAnalyzerProcessor( IAsynchronousOperationListener listener, @@ -150,7 +154,7 @@ private IEnumerable GetOpenDocumentIds() => _registration.Workspace.GetOpenDocumentIds(); private void ResetLogAggregator() - => _logAggregator = new LogAggregator(); + => _logAggregator = new CountLogAggregator(); private void ReportPendingWorkItemCount() { diff --git a/src/Features/Core/Portable/SolutionCrawler/WorkCoordinator.cs b/src/Features/Core/Portable/SolutionCrawler/WorkCoordinator.cs index cf3c7a1f63683..186965e20aeb8 100644 --- a/src/Features/Core/Portable/SolutionCrawler/WorkCoordinator.cs +++ b/src/Features/Core/Portable/SolutionCrawler/WorkCoordinator.cs @@ -24,7 +24,7 @@ internal sealed partial class WorkCoordinator private readonly Registration _registration; private readonly object _gate = new(); - private readonly LogAggregator _logAggregator = new(); + private readonly CountLogAggregator _logAggregator = new(); private readonly IAsynchronousOperationListener _listener; private readonly IDocumentTrackingService _documentTrackingService; private readonly IWorkspaceConfigurationService? _workspaceConfigurationService; @@ -192,7 +192,7 @@ private bool NotOurShutdownToken(OperationCanceledException oce) private void ProcessEvent(WorkspaceChangeEventArgs args, string eventName) { - SolutionCrawlerLogger.LogWorkspaceEvent(_logAggregator, (int)args.Kind); + SolutionCrawlerLogger.LogWorkspaceEvent(_logAggregator, args.Kind); // TODO: add telemetry that record how much it takes to process an event (max, min, average and etc) switch (args.Kind) @@ -211,7 +211,7 @@ private void ProcessEvent(WorkspaceChangeEventArgs args, string eventName) break; case WorkspaceChangeKind.SolutionCleared: - EnqueueFullSolutionEvent(args.OldSolution, InvocationReasons.DocumentRemoved, eventName); + EnqueueFullSolutionEvent(args.OldSolution, InvocationReasons.SolutionRemoved, eventName); break; case WorkspaceChangeKind.ProjectAdded: diff --git a/src/Features/Core/Portable/SpellCheck/AbstractSpellCheckCodeFixProvider.cs b/src/Features/Core/Portable/SpellCheck/AbstractSpellCheckCodeFixProvider.cs index 1d75a665acf27..b9ddd2b508483 100644 --- a/src/Features/Core/Portable/SpellCheck/AbstractSpellCheckCodeFixProvider.cs +++ b/src/Features/Core/Portable/SpellCheck/AbstractSpellCheckCodeFixProvider.cs @@ -13,7 +13,7 @@ using Microsoft.CodeAnalysis.CodeFixes; using Microsoft.CodeAnalysis.Completion; using Microsoft.CodeAnalysis.Host; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Shared.Extensions; using Roslyn.Utilities; @@ -118,7 +118,7 @@ private async Task CreateSpellCheckCodeIssueAsync( // - We believe spell-check should only compare what you have typed to what symbol would be offered here. var options = CompletionOptions.Default with { - HideAdvancedMembers = context.Options.GetOptions(document.Project.LanguageServices).HideAdvancedMembers, + HideAdvancedMembers = context.Options.GetOptions(document.Project.Services).HideAdvancedMembers, SnippetsBehavior = SnippetsRule.NeverInclude, ShowItemsFromUnimportedNamespaces = false, TargetTypedCompletionFilter = false, diff --git a/src/Features/Core/Portable/SpellCheck/AbstractSpellCheckSpanService.cs b/src/Features/Core/Portable/SpellCheck/AbstractSpellCheckSpanService.cs index f8deeb364cd1a..d79e52bf2b657 100644 --- a/src/Features/Core/Portable/SpellCheck/AbstractSpellCheckSpanService.cs +++ b/src/Features/Core/Portable/SpellCheck/AbstractSpellCheckSpanService.cs @@ -7,7 +7,7 @@ using System.Threading.Tasks; using Microsoft.CodeAnalysis.Classification; using Microsoft.CodeAnalysis.Host; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Text; diff --git a/src/Features/Core/Portable/SpellCheck/ISpellCheckingSpanService.cs b/src/Features/Core/Portable/SpellCheck/ISpellCheckingSpanService.cs index fdb5fc764962b..76a654e3c949a 100644 --- a/src/Features/Core/Portable/SpellCheck/ISpellCheckingSpanService.cs +++ b/src/Features/Core/Portable/SpellCheck/ISpellCheckingSpanService.cs @@ -7,7 +7,7 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.Host; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Text; diff --git a/src/Features/Core/Portable/SplitOrMergeIfStatements/AbstractMergeIfStatementsCodeRefactoringProvider.cs b/src/Features/Core/Portable/SplitOrMergeIfStatements/AbstractMergeIfStatementsCodeRefactoringProvider.cs index fca173f6a6c7c..a7076885590f5 100644 --- a/src/Features/Core/Portable/SplitOrMergeIfStatements/AbstractMergeIfStatementsCodeRefactoringProvider.cs +++ b/src/Features/Core/Portable/SplitOrMergeIfStatements/AbstractMergeIfStatementsCodeRefactoringProvider.cs @@ -12,7 +12,7 @@ using System.Threading.Tasks; using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeRefactorings; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Text; diff --git a/src/Features/Core/Portable/SplitOrMergeIfStatements/AbstractSplitIfStatementCodeRefactoringProvider.cs b/src/Features/Core/Portable/SplitOrMergeIfStatements/AbstractSplitIfStatementCodeRefactoringProvider.cs index 8166783bdf94a..29c2b64516154 100644 --- a/src/Features/Core/Portable/SplitOrMergeIfStatements/AbstractSplitIfStatementCodeRefactoringProvider.cs +++ b/src/Features/Core/Portable/SplitOrMergeIfStatements/AbstractSplitIfStatementCodeRefactoringProvider.cs @@ -10,7 +10,7 @@ using System.Threading.Tasks; using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeRefactorings; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Text; diff --git a/src/Features/Core/Portable/SplitOrMergeIfStatements/Consecutive/AbstractMergeConsecutiveIfStatementsCodeRefactoringProvider.cs b/src/Features/Core/Portable/SplitOrMergeIfStatements/Consecutive/AbstractMergeConsecutiveIfStatementsCodeRefactoringProvider.cs index eb4449bc361fd..cf7d664ef7dfb 100644 --- a/src/Features/Core/Portable/SplitOrMergeIfStatements/Consecutive/AbstractMergeConsecutiveIfStatementsCodeRefactoringProvider.cs +++ b/src/Features/Core/Portable/SplitOrMergeIfStatements/Consecutive/AbstractMergeConsecutiveIfStatementsCodeRefactoringProvider.cs @@ -13,7 +13,7 @@ using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.Editing; using Microsoft.CodeAnalysis.Formatting; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Utilities; using Roslyn.Utilities; diff --git a/src/Features/Core/Portable/SplitOrMergeIfStatements/Consecutive/AbstractSplitIntoConsecutiveIfStatementsCodeRefactoringProvider.cs b/src/Features/Core/Portable/SplitOrMergeIfStatements/Consecutive/AbstractSplitIntoConsecutiveIfStatementsCodeRefactoringProvider.cs index 6c776a5f716f0..acede8d3d7e11 100644 --- a/src/Features/Core/Portable/SplitOrMergeIfStatements/Consecutive/AbstractSplitIntoConsecutiveIfStatementsCodeRefactoringProvider.cs +++ b/src/Features/Core/Portable/SplitOrMergeIfStatements/Consecutive/AbstractSplitIntoConsecutiveIfStatementsCodeRefactoringProvider.cs @@ -12,7 +12,7 @@ using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.Editing; using Microsoft.CodeAnalysis.Formatting; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Shared.Extensions; namespace Microsoft.CodeAnalysis.SplitOrMergeIfStatements diff --git a/src/Features/Core/Portable/SplitOrMergeIfStatements/Nested/AbstractMergeNestedIfStatementsCodeRefactoringProvider.cs b/src/Features/Core/Portable/SplitOrMergeIfStatements/Nested/AbstractMergeNestedIfStatementsCodeRefactoringProvider.cs index d1cba7d22384c..6648c85ac1dac 100644 --- a/src/Features/Core/Portable/SplitOrMergeIfStatements/Nested/AbstractMergeNestedIfStatementsCodeRefactoringProvider.cs +++ b/src/Features/Core/Portable/SplitOrMergeIfStatements/Nested/AbstractMergeNestedIfStatementsCodeRefactoringProvider.cs @@ -12,7 +12,7 @@ using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.Editing; using Microsoft.CodeAnalysis.Formatting; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Utilities; using Roslyn.Utilities; diff --git a/src/Features/Core/Portable/SplitOrMergeIfStatements/Nested/AbstractSplitIntoNestedIfStatementsCodeRefactoringProvider.cs b/src/Features/Core/Portable/SplitOrMergeIfStatements/Nested/AbstractSplitIntoNestedIfStatementsCodeRefactoringProvider.cs index c3cdd5403913c..1d7114179a205 100644 --- a/src/Features/Core/Portable/SplitOrMergeIfStatements/Nested/AbstractSplitIntoNestedIfStatementsCodeRefactoringProvider.cs +++ b/src/Features/Core/Portable/SplitOrMergeIfStatements/Nested/AbstractSplitIntoNestedIfStatementsCodeRefactoringProvider.cs @@ -9,7 +9,7 @@ using System.Threading.Tasks; using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.Formatting; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Shared.Extensions; namespace Microsoft.CodeAnalysis.SplitOrMergeIfStatements diff --git a/src/Features/Core/Portable/StackTraceExplorer/StackFrameLocalMethodResolver.cs b/src/Features/Core/Portable/StackTraceExplorer/StackFrameLocalMethodResolver.cs index a91bf6bc5781a..1de299888ed73 100644 --- a/src/Features/Core/Portable/StackTraceExplorer/StackFrameLocalMethodResolver.cs +++ b/src/Features/Core/Portable/StackTraceExplorer/StackFrameLocalMethodResolver.cs @@ -7,7 +7,7 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.EmbeddedLanguages.StackFrame; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Shared.Extensions; namespace Microsoft.CodeAnalysis.StackTraceExplorer diff --git a/src/Features/Core/Portable/StackTraceExplorer/StackTraceExplorerService.cs b/src/Features/Core/Portable/StackTraceExplorer/StackTraceExplorerService.cs index 719ba0d1bc6af..de6e0bb9304bf 100644 --- a/src/Features/Core/Portable/StackTraceExplorer/StackTraceExplorerService.cs +++ b/src/Features/Core/Portable/StackTraceExplorer/StackTraceExplorerService.cs @@ -49,7 +49,7 @@ public StackTraceExplorerService() return null; } - var client = await RemoteHostClient.TryGetClientAsync(solution.Workspace, cancellationToken).ConfigureAwait(false); + var client = await RemoteHostClient.TryGetClientAsync(solution.Services, cancellationToken).ConfigureAwait(false); if (client is not null) { var result = await client.TryInvokeAsync( diff --git a/src/Features/Core/Portable/Structure/BlockStructureServiceWithProviders.cs b/src/Features/Core/Portable/Structure/BlockStructureServiceWithProviders.cs index 68d58fa6d0a96..884334c2b2a67 100644 --- a/src/Features/Core/Portable/Structure/BlockStructureServiceWithProviders.cs +++ b/src/Features/Core/Portable/Structure/BlockStructureServiceWithProviders.cs @@ -8,21 +8,20 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; +using Microsoft.CodeAnalysis.Host; using Microsoft.CodeAnalysis.Host.Mef; -using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.PooledObjects; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Structure { internal abstract class BlockStructureServiceWithProviders : BlockStructureService { - private readonly Workspace _workspace; + private readonly SolutionServices _services; private readonly ImmutableArray _providers; - protected BlockStructureServiceWithProviders(Workspace workspace) + protected BlockStructureServiceWithProviders(SolutionServices services) { - _workspace = workspace; + _services = services; _providers = GetBuiltInProviders().Concat(GetImportedProviders()); } @@ -36,7 +35,7 @@ protected virtual ImmutableArray GetBuiltInProviders() private ImmutableArray GetImportedProviders() { var language = Language; - var mefExporter = (IMefHostExportProvider)_workspace.Services.HostServices; + var mefExporter = _services.ExportProvider; var providers = mefExporter.GetExports() .Where(lz => lz.Metadata.Language == language) diff --git a/src/Features/Core/Portable/SymbolSearch/Windows/IFileDownloaderFactory.cs b/src/Features/Core/Portable/SymbolSearch/Windows/IFileDownloaderFactory.cs new file mode 100644 index 0000000000000..ba845e673513a --- /dev/null +++ b/src/Features/Core/Portable/SymbolSearch/Windows/IFileDownloaderFactory.cs @@ -0,0 +1,22 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.IO; +using System.Threading.Tasks; + +namespace Microsoft.CodeAnalysis.SymbolSearch; + +/// +/// Used so we can mock out the remote control service in unit tests. +/// +internal interface IFileDownloaderFactory +{ + IFileDownloader CreateClient(string hostId, string serverPath, int pollingMinutes); +} + +internal interface IFileDownloader : IDisposable +{ + public Task ReadFileAsync(); // BehaviorOnStale.ReturnStale +} diff --git a/src/Features/Core/Portable/SymbolSearch/Windows/IRemoteControlService.cs b/src/Features/Core/Portable/SymbolSearch/Windows/IRemoteControlService.cs deleted file mode 100644 index 90b59eff551ac..0000000000000 --- a/src/Features/Core/Portable/SymbolSearch/Windows/IRemoteControlService.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 - -using Microsoft.VisualStudio.RemoteControl; - -namespace Microsoft.CodeAnalysis.SymbolSearch -{ - /// - /// Used so we can mock out the remote control service in unit tests. - /// - internal interface IRemoteControlService - { - IRemoteControlClient CreateClient(string hostId, string serverPath, int pollingMinutes); - } -} diff --git a/src/Features/Core/Portable/SymbolSearch/Windows/SymbolSearchUpdateEngine.RemoteControlService.cs b/src/Features/Core/Portable/SymbolSearch/Windows/SymbolSearchUpdateEngine.RemoteControlService.cs deleted file mode 100644 index b4aaf498701b2..0000000000000 --- a/src/Features/Core/Portable/SymbolSearch/Windows/SymbolSearchUpdateEngine.RemoteControlService.cs +++ /dev/null @@ -1,25 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -#nullable disable - -using Microsoft.VisualStudio.RemoteControl; - -namespace Microsoft.CodeAnalysis.SymbolSearch -{ - internal partial class SymbolSearchUpdateEngine - { - private class RemoteControlService : IRemoteControlService - { - public IRemoteControlClient CreateClient(string hostId, string serverPath, int pollingMinutes) - { - // BaseUrl provided by the VS RemoteControl client team. This is URL we are supposed - // to use to publish and access data from. - const string BaseUrl = "https://az700632.vo.msecnd.net/pub"; - - return new RemoteControlClient(hostId, BaseUrl, serverPath, pollingMinutes); - } - } - } -} diff --git a/src/Features/Core/Portable/SymbolSearch/Windows/SymbolSearchUpdateEngine.Update.cs b/src/Features/Core/Portable/SymbolSearch/Windows/SymbolSearchUpdateEngine.Update.cs index d355eed9bf548..56644a35aae5e 100644 --- a/src/Features/Core/Portable/SymbolSearch/Windows/SymbolSearchUpdateEngine.Update.cs +++ b/src/Features/Core/Portable/SymbolSearch/Windows/SymbolSearchUpdateEngine.Update.cs @@ -18,7 +18,6 @@ using Microsoft.CodeAnalysis.AddImport; using Microsoft.CodeAnalysis.Elfie.Model; using Microsoft.CodeAnalysis.Shared.Utilities; -using Microsoft.VisualStudio.RemoteControl; using static System.FormattableString; namespace Microsoft.CodeAnalysis.SymbolSearch @@ -50,7 +49,7 @@ internal partial class SymbolSearchUpdateEngine // mock behavior during tests. private readonly IDelayService _delayService; private readonly IIOService _ioService; - private readonly IRemoteControlService _remoteControlService; + private readonly IFileDownloaderFactory _fileDownloaderFactory; private readonly IPatchService _patchService; private readonly IDatabaseFactoryService _databaseFactoryService; private readonly Func _reportAndSwallowExceptionUnlessCanceled; @@ -502,7 +501,7 @@ private async Task DownloadFileAsync(string serverPath, CancellationTo // minutes ago, then the client will attempt to download the file. // In the interim period null will be returned from client.ReadFile. var pollingMinutes = (int)TimeSpan.FromDays(1).TotalMinutes; - using var client = _service._remoteControlService.CreateClient(HostId, serverPath, pollingMinutes); + using var client = _service._fileDownloaderFactory.CreateClient(HostId, serverPath, pollingMinutes); await LogInfoAsync("Creating download client completed", cancellationToken).ConfigureAwait(false); @@ -527,11 +526,11 @@ private async Task DownloadFileAsync(string serverPath, CancellationTo } /// Returns 'null' if download is not available and caller should keep polling. - private async Task TryDownloadFileAsync(IRemoteControlClient client, CancellationToken cancellationToken) + private async Task TryDownloadFileAsync(IFileDownloader fileDownloader, CancellationToken cancellationToken) { await LogInfoAsync("Read file from client", cancellationToken).ConfigureAwait(false); - using var stream = await client.ReadFileAsync(BehaviorOnStale.ReturnStale).ConfigureAwait(false); + using var stream = await fileDownloader.ReadFileAsync().ConfigureAwait(false); if (stream == null) { diff --git a/src/Features/Core/Portable/SymbolSearch/Windows/SymbolSearchUpdateEngine.cs b/src/Features/Core/Portable/SymbolSearch/Windows/SymbolSearchUpdateEngine.cs index 1859e136220cf..ca84ad9c4539f 100644 --- a/src/Features/Core/Portable/SymbolSearch/Windows/SymbolSearchUpdateEngine.cs +++ b/src/Features/Core/Portable/SymbolSearch/Windows/SymbolSearchUpdateEngine.cs @@ -36,8 +36,8 @@ internal partial class SymbolSearchUpdateEngine : ISymbolSearchUpdateEngine /// /// Don't call directly. Use instead. /// - public SymbolSearchUpdateEngine() - : this(new RemoteControlService(), + public SymbolSearchUpdateEngine(IFileDownloaderFactory fileDownloaderFactory) + : this(fileDownloaderFactory, new DelayService(), new IOService(), new PatchService(), @@ -51,7 +51,7 @@ public SymbolSearchUpdateEngine() /// For testing purposes only. /// internal SymbolSearchUpdateEngine( - IRemoteControlService remoteControlService, + IFileDownloaderFactory fileDownloaderFactory, IDelayService delayService, IIOService ioService, IPatchService patchService, @@ -60,7 +60,7 @@ internal SymbolSearchUpdateEngine( { _delayService = delayService; _ioService = ioService; - _remoteControlService = remoteControlService; + _fileDownloaderFactory = fileDownloaderFactory; _patchService = patchService; _databaseFactoryService = databaseFactoryService; _reportAndSwallowExceptionUnlessCanceled = reportAndSwallowExceptionUnlessCanceled; diff --git a/src/Features/Core/Portable/SymbolSearch/Windows/SymbolSearchUpdateEngineFactory.cs b/src/Features/Core/Portable/SymbolSearch/Windows/SymbolSearchUpdateEngineFactory.cs index 11d96e8c24dea..97a49277ef4de 100644 --- a/src/Features/Core/Portable/SymbolSearch/Windows/SymbolSearchUpdateEngineFactory.cs +++ b/src/Features/Core/Portable/SymbolSearch/Windows/SymbolSearchUpdateEngineFactory.cs @@ -24,6 +24,7 @@ internal static class SymbolSearchUpdateEngineFactory public static async ValueTask CreateEngineAsync( Workspace workspace, ISymbolSearchLogService logService, + IFileDownloaderFactory fileDownloaderFactory, CancellationToken cancellationToken) { var client = await RemoteHostClient.TryGetClientAsync(workspace, cancellationToken).ConfigureAwait(false); @@ -33,16 +34,16 @@ public static async ValueTask CreateEngineAsync( } // Couldn't go out of proc. Just do everything inside the current process. - return CreateEngineInProcess(); + return CreateEngineInProcess(fileDownloaderFactory); } /// /// This returns a No-op engine if called on non-Windows OS, because the backing storage depends on Windows APIs. /// - public static ISymbolSearchUpdateEngine CreateEngineInProcess() + public static ISymbolSearchUpdateEngine CreateEngineInProcess(IFileDownloaderFactory fileDownloaderFactory) { return RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? - new SymbolSearchUpdateEngine() : + new SymbolSearchUpdateEngine(fileDownloaderFactory) : SymbolSearchUpdateNoOpEngine.Instance; } } diff --git a/src/Features/Core/Portable/TodoComments/AbstractTodoCommentsIncrementalAnalyzer.cs b/src/Features/Core/Portable/TodoComments/AbstractTodoCommentsIncrementalAnalyzer.cs index e2440ebf21fe5..c136761c17ba1 100644 --- a/src/Features/Core/Portable/TodoComments/AbstractTodoCommentsIncrementalAnalyzer.cs +++ b/src/Features/Core/Portable/TodoComments/AbstractTodoCommentsIncrementalAnalyzer.cs @@ -4,6 +4,7 @@ using System.Collections.Generic; using System.Collections.Immutable; +using System.Linq; using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.PooledObjects; @@ -15,8 +16,8 @@ namespace Microsoft.CodeAnalysis.TodoComments internal abstract partial class AbstractTodoCommentsIncrementalAnalyzer : IncrementalAnalyzerBase { private readonly object _gate = new(); - private string? _lastTokenList = null; - private ImmutableArray _lastDescriptors = default; + private ImmutableArray _lastTokenList = ImmutableArray.Empty; + private ImmutableArray _lastDescriptors = ImmutableArray.Empty; /// /// Set of documents that we have reported an non-empty set of todo comments for. Used so that we don't bother @@ -45,11 +46,11 @@ public override Task RemoveDocumentAsync(DocumentId documentId, CancellationToke return ReportTodoCommentDataAsync(documentId, ImmutableArray.Empty, cancellationToken).AsTask(); } - private ImmutableArray GetTodoCommentDescriptors(string tokenList) + private ImmutableArray GetTodoCommentDescriptors(ImmutableArray tokenList) { lock (_gate) { - if (tokenList != _lastTokenList) + if (!tokenList.SequenceEqual(_lastTokenList)) { _lastDescriptors = TodoCommentDescriptor.Parse(tokenList); _lastTokenList = tokenList; diff --git a/src/Features/Core/Portable/TodoComments/TodoCommentDescriptor.cs b/src/Features/Core/Portable/TodoComments/TodoCommentDescriptor.cs index 9dc5c5159ff38..4f832edbe7ad4 100644 --- a/src/Features/Core/Portable/TodoComments/TodoCommentDescriptor.cs +++ b/src/Features/Core/Portable/TodoComments/TodoCommentDescriptor.cs @@ -6,7 +6,9 @@ using System.Collections.Immutable; using System.Globalization; +using System.Linq.Expressions; using Microsoft.CodeAnalysis.PooledObjects; +using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.TodoComments { @@ -24,28 +26,18 @@ public TodoCommentDescriptor(string text, int priority) Priority = priority; } - public static ImmutableArray Parse(string data) + public static ImmutableArray Parse(ImmutableArray items) { - if (string.IsNullOrWhiteSpace(data)) - return ImmutableArray.Empty; - - var tuples = data.Split('|'); using var _ = ArrayBuilder.GetInstance(out var result); - foreach (var tuple in tuples) + foreach (var item in items) { - if (string.IsNullOrWhiteSpace(tuple)) - continue; - - var pair = tuple.Split(':'); - - if (pair.Length != 2 || string.IsNullOrWhiteSpace(pair[0])) - continue; - - if (!int.TryParse(pair[1], NumberStyles.None, CultureInfo.InvariantCulture, out var priority)) - continue; - - result.Add(new TodoCommentDescriptor(pair[0].Trim(), priority)); + if (item.Split(':') is [var token, var priorityString] && + !string.IsNullOrWhiteSpace(token) && + int.TryParse(priorityString, NumberStyles.None, CultureInfo.InvariantCulture, out var priority)) + { + result.Add(new TodoCommentDescriptor(token, priority)); + } } return result.ToImmutable(); diff --git a/src/Features/Core/Portable/UnusedReferences/UnusedReferencesRemover.cs b/src/Features/Core/Portable/UnusedReferences/UnusedReferencesRemover.cs index f4692715bd23a..fe45c2edd5348 100644 --- a/src/Features/Core/Portable/UnusedReferences/UnusedReferencesRemover.cs +++ b/src/Features/Core/Portable/UnusedReferences/UnusedReferencesRemover.cs @@ -264,17 +264,15 @@ internal static ImmutableArray GetAllCompilationAssemblies(ReferenceInfo .ToImmutableArray(); } - public static async Task UpdateReferencesAsync( + public static async Task UpdateReferencesAsync( Solution solution, string projectFilePath, ImmutableArray referenceUpdates, CancellationToken cancellationToken) { - var referenceCleanupService = solution.Workspace.Services.GetRequiredService(); + var referenceCleanupService = solution.Services.GetRequiredService(); await ApplyReferenceUpdatesAsync(referenceCleanupService, projectFilePath, referenceUpdates, cancellationToken).ConfigureAwait(true); - - return solution.Workspace.CurrentSolution; } internal static async Task ApplyReferenceUpdatesAsync( diff --git a/src/Features/Core/Portable/UseAutoProperty/AbstractUseAutoPropertyCodeFixProvider.cs b/src/Features/Core/Portable/UseAutoProperty/AbstractUseAutoPropertyCodeFixProvider.cs index ef47debfc221f..2e1831eda5d42 100644 --- a/src/Features/Core/Portable/UseAutoProperty/AbstractUseAutoPropertyCodeFixProvider.cs +++ b/src/Features/Core/Portable/UseAutoProperty/AbstractUseAutoPropertyCodeFixProvider.cs @@ -16,8 +16,9 @@ using Microsoft.CodeAnalysis.Editing; using Microsoft.CodeAnalysis.Formatting; using Microsoft.CodeAnalysis.Formatting.Rules; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Rename; +using Microsoft.CodeAnalysis.Rename.ConflictEngine; using Microsoft.CodeAnalysis.Shared.Extensions; using Roslyn.Utilities; @@ -118,7 +119,7 @@ private async Task ProcessResultAsync(CodeFixContext context, Diagnost linkedFiles.AddRange(fieldDocument.GetLinkedDocumentIds()); linkedFiles.AddRange(propertyDocument.GetLinkedDocumentIds()); - var canEdit = new Dictionary(); + var canEdit = new Dictionary(); // Now, rename all usages of the field to point at the property. Except don't actually // rename the field itself. We want to be able to find it again post rename. @@ -131,16 +132,16 @@ private async Task ProcessResultAsync(CodeFixContext context, Diagnost // same as the property we're trying to get the references pointing to. var filteredLocations = fieldLocations.Filter( - location => location.SourceTree != null && - !location.IntersectsWith(declaratorLocation) && - CanEditDocument(solution, location.SourceTree, linkedFiles, canEdit)); + (documentId, span) => + fieldDocument.Id == documentId && + !span.IntersectsWith(declaratorLocation.SourceSpan) && + CanEditDocument(solution, documentId, linkedFiles, canEdit)); var resolution = await filteredLocations.ResolveConflictsAsync( - propertySymbol.Name, - nonConflictSymbols: ImmutableHashSet.Create(propertySymbol), - cancellationToken).ConfigureAwait(false); + fieldSymbol, propertySymbol.Name, + nonConflictSymbolKeys: ImmutableArray.Create(propertySymbol.GetSymbolKey(cancellationToken)), cancellationToken).ConfigureAwait(false); - Contract.ThrowIfTrue(resolution.ErrorMessage != null); + Contract.ThrowIfFalse(resolution.IsSuccessful); solution = resolution.NewSolution; @@ -206,7 +207,7 @@ private async Task ProcessResultAsync(CodeFixContext context, Diagnost // Same file. Have to do this in a slightly complicated fashion. var declaratorTreeRoot = await fieldDocument.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false); - var editor = new SyntaxEditor(declaratorTreeRoot, fieldDocument.Project.Solution.Workspace.Services); + var editor = new SyntaxEditor(declaratorTreeRoot, fieldDocument.Project.Solution.Services); editor.ReplaceNode(property, updatedProperty); editor.RemoveNode(nodeToRemove, syntaxRemoveOptions); @@ -262,17 +263,18 @@ private static bool WillRemoveFirstFieldInTypeDirectlyAboveProperty( } private static bool CanEditDocument( - Solution solution, SyntaxTree sourceTree, + Solution solution, + DocumentId documentId, HashSet linkedDocuments, - Dictionary canEdit) + Dictionary canEdit) { - if (!canEdit.ContainsKey(sourceTree)) + if (!canEdit.ContainsKey(documentId)) { - var document = solution.GetDocument(sourceTree); - canEdit[sourceTree] = document != null && !linkedDocuments.Contains(document.Id); + var document = solution.GetDocument(documentId); + canEdit[documentId] = document != null && !linkedDocuments.Contains(document.Id); } - return canEdit[sourceTree]; + return canEdit[documentId]; } private async Task FormatAsync(SyntaxNode newRoot, Document document, CodeCleanupOptionsProvider fallbackOptions, CancellationToken cancellationToken) @@ -284,11 +286,11 @@ private async Task FormatAsync(SyntaxNode newRoot, Document document } var options = await document.GetSyntaxFormattingOptionsAsync(fallbackOptions, cancellationToken).ConfigureAwait(false); - return Formatter.Format(newRoot, SpecializedFormattingAnnotation, document.Project.Solution.Workspace.Services, options, formattingRules, cancellationToken); + return Formatter.Format(newRoot, SpecializedFormattingAnnotation, document.Project.Solution.Services, options, formattingRules, cancellationToken); } private static bool IsWrittenToOutsideOfConstructorOrProperty( - IFieldSymbol field, RenameLocations renameLocations, TPropertyDeclaration propertyDeclaration, CancellationToken cancellationToken) + IFieldSymbol field, LightweightRenameLocations renameLocations, TPropertyDeclaration propertyDeclaration, CancellationToken cancellationToken) { var constructorNodes = field.ContainingType.GetMembers() .Where(m => m.IsConstructor()) diff --git a/src/Features/Core/Portable/UseNamedArguments/AbstractUseNamedArgumentsCodeRefactoringProvider.cs b/src/Features/Core/Portable/UseNamedArguments/AbstractUseNamedArgumentsCodeRefactoringProvider.cs index f93d8848a66a4..3f84c3ee6b16f 100644 --- a/src/Features/Core/Portable/UseNamedArguments/AbstractUseNamedArgumentsCodeRefactoringProvider.cs +++ b/src/Features/Core/Portable/UseNamedArguments/AbstractUseNamedArgumentsCodeRefactoringProvider.cs @@ -200,7 +200,7 @@ protected AbstractUseNamedArgumentsCodeRefactoringProvider( public sealed override async Task ComputeRefactoringsAsync(CodeRefactoringContext context) { var (document, _, cancellationToken) = context; - if (document.Project.Solution.Workspace.Kind == WorkspaceKind.MiscellaneousFiles) + if (document.Project.Solution.WorkspaceKind == WorkspaceKind.MiscellaneousFiles) { return; } diff --git a/src/Features/Core/Portable/ValueTracking/ValueTracker.FindReferencesProgress.cs b/src/Features/Core/Portable/ValueTracking/ValueTracker.FindReferencesProgress.cs index 742027c03e7a5..951e99858f158 100644 --- a/src/Features/Core/Portable/ValueTracking/ValueTracker.FindReferencesProgress.cs +++ b/src/Features/Core/Portable/ValueTracking/ValueTracker.FindReferencesProgress.cs @@ -5,7 +5,7 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.FindSymbols; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Operations; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Shared.Utilities; diff --git a/src/Features/Core/Portable/ValueTracking/ValueTracker.cs b/src/Features/Core/Portable/ValueTracking/ValueTracker.cs index 3fdea9a7c09e5..412ef3a266010 100644 --- a/src/Features/Core/Portable/ValueTracking/ValueTracker.cs +++ b/src/Features/Core/Portable/ValueTracking/ValueTracker.cs @@ -7,7 +7,7 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.FindSymbols; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Operations; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Text; diff --git a/src/Features/Core/Portable/Workspace/BackgroundCompiler.cs b/src/Features/Core/Portable/Workspace/BackgroundCompiler.cs index f4441a790b03f..56a6e5b53d4f0 100644 --- a/src/Features/Core/Portable/Workspace/BackgroundCompiler.cs +++ b/src/Features/Core/Portable/Workspace/BackgroundCompiler.cs @@ -17,18 +17,11 @@ namespace Microsoft.CodeAnalysis.Host internal sealed class BackgroundCompiler : IDisposable { private Workspace? _workspace; - private readonly AsyncBatchingWorkQueue _workQueue; + private readonly AsyncBatchingWorkQueue _workQueue; [SuppressMessage("CodeQuality", "IDE0052:Remove unread private members", Justification = "Used to keep a strong reference to the built compilations so they are not GC'd")] private readonly ConcurrentSet _mostRecentCompilations = new(); - /// - /// Cancellation series controlling the individual pieces of work added to . Every time - /// we add a new item, we cancel the prior item so that batch can stop as soon as possible and move onto the - /// next batch. - /// - private readonly CancellationSeries _cancellationSeries = new(); - /// /// Token to stop work entirely when this object is disposed. /// @@ -40,7 +33,8 @@ public BackgroundCompiler(Workspace workspace) // make a scheduler that runs on the thread pool var listenerProvider = workspace.Services.GetRequiredService(); - _workQueue = new AsyncBatchingWorkQueue( + + _workQueue = new AsyncBatchingWorkQueue( DelayTimeSpan.NearImmediate, BuildCompilationsForVisibleDocumentsAsync, listenerProvider.GetListener(), @@ -54,7 +48,6 @@ public BackgroundCompiler(Workspace workspace) public void Dispose() { _disposalCancellationSource.Cancel(); - _cancellationSeries.Dispose(); _mostRecentCompilations.Clear(); @@ -78,51 +71,22 @@ private void OnWorkspaceChanged(object? sender, WorkspaceChangeEventArgs args) private void Rebuild() { - // Stop any work on the current batch and create a token for the next batch. - var nextToken = _cancellationSeries.CreateNext(); - _workQueue.AddWork(nextToken); + // Stop any work on the current batch and start the next job. + _workQueue.AddWork(cancelExistingWork: true); } - private async ValueTask BuildCompilationsForVisibleDocumentsAsync( - ImmutableSegmentedList cancellationTokens, CancellationToken disposalToken) - { - using var _ = ArrayBuilder.GetInstance(out var compilations); - - await AddCompilationsForVisibleDocumentsAsync(cancellationTokens, compilations, disposalToken).ConfigureAwait(false); - - _mostRecentCompilations.Clear(); - _mostRecentCompilations.AddRange(compilations); - } - - private async ValueTask AddCompilationsForVisibleDocumentsAsync( - ImmutableSegmentedList cancellationTokens, - ArrayBuilder compilations, - CancellationToken disposalToken) + private async ValueTask BuildCompilationsForVisibleDocumentsAsync(CancellationToken cancellationToken) { var workspace = _workspace; if (workspace is null) return; - // Because we always cancel the previous token prior to queuing new work, there can only be at most one - // actual real cancellation token that is not already canceled. - var cancellationToken = cancellationTokens.SingleOrNull(ct => !ct.IsCancellationRequested); + using var _ = ArrayBuilder.GetInstance(out var compilations); - // if we didn't get an actual non-canceled token back, then this batch was entirely canceled and we have - // nothing to do. - if (cancellationToken is null) - return; + await AddCompilationsForVisibleDocumentsAsync(workspace.CurrentSolution, compilations, cancellationToken).ConfigureAwait(false); - using var source = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken.Value, disposalToken); - try - { - await AddCompilationsForVisibleDocumentsAsync( - workspace.CurrentSolution, compilations, source.Token).ConfigureAwait(false); - } - catch (OperationCanceledException) when (!disposalToken.IsCancellationRequested) - { - // Don't bubble up cancellation to the queue for our own internal cancellation. Just because we decided - // to cancel this batch isn't something the queue should be aware of. - } + _mostRecentCompilations.Clear(); + _mostRecentCompilations.AddRange(compilations); } private static async ValueTask AddCompilationsForVisibleDocumentsAsync( @@ -132,7 +96,7 @@ private static async ValueTask AddCompilationsForVisibleDocumentsAsync( { cancellationToken.ThrowIfCancellationRequested(); - var trackingService = solution.Workspace.Services.GetRequiredService(); + var trackingService = solution.Services.GetRequiredService(); var visibleProjectIds = trackingService.GetVisibleDocuments().Select(d => d.ProjectId).ToSet(); var activeProjectId = trackingService.TryGetActiveDocument()?.ProjectId; diff --git a/src/Features/Core/Portable/Workspace/CompileTimeSolutionProvider.cs b/src/Features/Core/Portable/Workspace/CompileTimeSolutionProvider.cs index ab31487eb3266..e3d582d8ead93 100644 --- a/src/Features/Core/Portable/Workspace/CompileTimeSolutionProvider.cs +++ b/src/Features/Core/Portable/Workspace/CompileTimeSolutionProvider.cs @@ -8,6 +8,7 @@ using System.Diagnostics; using System.IO; using System.Linq; +using System.Runtime.CompilerServices; using System.Text; using System.Threading; using System.Threading.Tasks; @@ -44,20 +45,18 @@ public Factory() private const string RazorSourceGeneratorTypeName = "Microsoft.NET.Sdk.Razor.SourceGenerators.RazorSourceGenerator"; private static readonly string s_razorSourceGeneratorFileNamePrefix = Path.Combine(RazorSourceGeneratorAssemblyName, RazorSourceGeneratorTypeName); - private readonly Workspace _workspace; - private readonly object _gate = new(); /// - /// Cached compile time solution corresponding to the + /// Cached compile-time solution corresponding to an existing design-time solution. /// - private (int DesignTimeSolutionVersion, BranchId DesignTimeSolutionBranch, Solution CompileTimeSolution)? _primaryBranchCompileTimeCache; +#if NETCOREAPP + private readonly ConditionalWeakTable _designTimeToCompileTimeSolution = new(); +#else + private ConditionalWeakTable _designTimeToCompileTimeSolution = new(); +#endif - /// - /// Cached compile time solution for a forked branch. This is used primarily by LSP cases where - /// we fork the workspace solution and request diagnostics for the forked solution. - /// - private (int DesignTimeSolutionVersion, BranchId DesignTimeSolutionBranch, Solution CompileTimeSolution)? _forkedBranchCompileTimeCache; + private Solution? _lastCompileTimeSolution; public CompileTimeSolutionProvider(Workspace workspace) { @@ -67,12 +66,15 @@ public CompileTimeSolutionProvider(Workspace workspace) { lock (_gate) { - _primaryBranchCompileTimeCache = null; - _forkedBranchCompileTimeCache = null; +#if NETCOREAPP + _designTimeToCompileTimeSolution.Clear(); +#else + _designTimeToCompileTimeSolution = new(); +#endif + _lastCompileTimeSolution = null; } } }; - _workspace = workspace; } private static bool IsRazorAnalyzerConfig(TextDocumentState documentState) @@ -82,32 +84,30 @@ public Solution GetCompileTimeSolution(Solution designTimeSolution) { lock (_gate) { - var cachedCompileTimeSolution = GetCachedCompileTimeSolution(designTimeSolution); + _designTimeToCompileTimeSolution.TryGetValue(designTimeSolution, out var cachedCompileTimeSolution); // Design time solution hasn't changed since we calculated the last compile-time solution: if (cachedCompileTimeSolution != null) - { return cachedCompileTimeSolution; - } - using var _1 = ArrayBuilder.GetInstance(out var configIdsToRemove); - using var _2 = ArrayBuilder.GetInstance(out var documentIdsToRemove); + var staleSolution = _lastCompileTimeSolution; + var compileTimeSolution = designTimeSolution; - foreach (var (_, projectState) in designTimeSolution.State.ProjectStates) + foreach (var (_, projectState) in compileTimeSolution.State.ProjectStates) { - var anyConfigs = false; + using var _1 = ArrayBuilder.GetInstance(out var configIdsToRemove); + using var _2 = ArrayBuilder.GetInstance(out var documentIdsToRemove); foreach (var (_, configState) in projectState.AnalyzerConfigDocumentStates.States) { if (IsRazorAnalyzerConfig(configState)) { configIdsToRemove.Add(configState.Id); - anyConfigs = true; } } // only remove design-time only documents when source-generated ones replace them - if (anyConfigs) + if (configIdsToRemove.Count > 0) { foreach (var (_, documentState) in projectState.DocumentStates.States) { @@ -116,49 +116,27 @@ public Solution GetCompileTimeSolution(Solution designTimeSolution) documentIdsToRemove.Add(documentState.Id); } } + + compileTimeSolution = compileTimeSolution + .RemoveAnalyzerConfigDocuments(configIdsToRemove.ToImmutable()) + .RemoveDocuments(documentIdsToRemove.ToImmutable()); + + if (staleSolution is not null) + { + var existingStaleProject = staleSolution.GetProject(projectState.Id); + if (existingStaleProject is not null) + compileTimeSolution = compileTimeSolution.WithCachedSourceGeneratorState(projectState.Id, existingStaleProject); + } } } - var compileTimeSolution = designTimeSolution - .RemoveAnalyzerConfigDocuments(configIdsToRemove.ToImmutable()) - .RemoveDocuments(documentIdsToRemove.ToImmutable()); - - UpdateCachedCompileTimeSolution(designTimeSolution, compileTimeSolution); + compileTimeSolution = _designTimeToCompileTimeSolution.GetValue(designTimeSolution, _ => compileTimeSolution); + _lastCompileTimeSolution = compileTimeSolution; return compileTimeSolution; } } - private Solution? GetCachedCompileTimeSolution(Solution designTimeSolution) - { - // If the design time solution is for the primary branch, retrieve the last cached solution for it. - // Otherwise this is a forked solution, so retrieve the last forked compile time solution we calculated. - var cachedCompileTimeSolution = designTimeSolution.BranchId == _workspace.PrimaryBranchId ? _primaryBranchCompileTimeCache : _forkedBranchCompileTimeCache; - - // Verify that the design time solution has not changed since the last calculated compile time solution and that - // the design time solution branch matches the branch of the design time solution we calculated the compile time solution for. - if (cachedCompileTimeSolution != null - && designTimeSolution.WorkspaceVersion == cachedCompileTimeSolution.Value.DesignTimeSolutionVersion - && designTimeSolution.BranchId == cachedCompileTimeSolution.Value.DesignTimeSolutionBranch) - { - return cachedCompileTimeSolution.Value.CompileTimeSolution; - } - - return null; - } - - private void UpdateCachedCompileTimeSolution(Solution designTimeSolution, Solution compileTimeSolution) - { - if (designTimeSolution.BranchId == _workspace.PrimaryBranchId) - { - _primaryBranchCompileTimeCache = (designTimeSolution.WorkspaceVersion, designTimeSolution.BranchId, compileTimeSolution); - } - else - { - _forkedBranchCompileTimeCache = (designTimeSolution.WorkspaceVersion, designTimeSolution.BranchId, compileTimeSolution); - } - } - // Copied from // https://github.com/dotnet/sdk/blob/main/src/RazorSdk/SourceGenerators/RazorSourceGenerator.Helpers.cs#L32 private static string GetIdentifierFromPath(string filePath) diff --git a/src/Features/Core/Portable/Workspace/MiscellaneousFileUtilities.cs b/src/Features/Core/Portable/Workspace/MiscellaneousFileUtilities.cs index 73ce15439c8eb..e35a4d8a4ea30 100644 --- a/src/Features/Core/Portable/Workspace/MiscellaneousFileUtilities.cs +++ b/src/Features/Core/Portable/Workspace/MiscellaneousFileUtilities.cs @@ -18,7 +18,7 @@ internal static ProjectInfo CreateMiscellaneousProjectInfoForDocument( string filePath, TextLoader textLoader, LanguageInformation languageInformation, - HostWorkspaceServices services, + SolutionServices services, ImmutableArray metadataReferences) { var fileExtension = PathUtilities.GetExtension(filePath); @@ -71,7 +71,7 @@ internal static ProjectInfo CreateMiscellaneousProjectInfoForDocument( // Do not inline this to avoid loading Microsoft.CodeAnalysis.Scripting unless a script file is opened in the workspace. [MethodImpl(MethodImplOptions.NoInlining)] - private static CompilationOptions GetCompilationOptionsWithScriptReferenceResolvers(HostWorkspaceServices services, CompilationOptions compilationOptions, string filePath) + private static CompilationOptions GetCompilationOptionsWithScriptReferenceResolvers(SolutionServices services, CompilationOptions compilationOptions, string filePath) { var metadataService = services.GetRequiredService(); diff --git a/src/Features/Core/Portable/Wrapping/AbstractCodeActionComputer.cs b/src/Features/Core/Portable/Wrapping/AbstractCodeActionComputer.cs index 597bc7130a7a7..72620386d28ca 100644 --- a/src/Features/Core/Portable/Wrapping/AbstractCodeActionComputer.cs +++ b/src/Features/Core/Portable/Wrapping/AbstractCodeActionComputer.cs @@ -93,6 +93,7 @@ protected string GetIndentationAfter(SyntaxNodeOrToken nodeOrToken, FormattingOp var newSourceText = OriginalSourceText.WithChanges(new TextChange(new TextSpan(nodeOrToken.Span.End, 0), newLine)); newSourceText = newSourceText.WithChanges( new TextChange(TextSpan.FromBounds(nodeOrToken.Span.End + newLine.Length, newSourceText.Length), "")); + var newDocument = OriginalDocument.WithText(newSourceText); // The only auto-formatting option that's relevant is indent style. Others only control behavior on typing. @@ -100,8 +101,12 @@ protected string GetIndentationAfter(SyntaxNodeOrToken nodeOrToken, FormattingOp var indentationService = Wrapper.IndentationService; var originalLineNumber = newSourceText.Lines.GetLineFromPosition(nodeOrToken.Span.End).LineNumber; + + // TODO: should be async https://github.com/dotnet/roslyn/issues/61998 + var newParsedDocument = ParsedDocument.CreateSynchronously(newDocument, CancellationToken); + var desiredIndentation = indentationService.GetIndentation( - newDocument, originalLineNumber + 1, + newParsedDocument, originalLineNumber + 1, indentationOptions, CancellationToken); diff --git a/src/Features/Core/Portable/Wrapping/AbstractWrappingCodeRefactoringProvider.cs b/src/Features/Core/Portable/Wrapping/AbstractWrappingCodeRefactoringProvider.cs index 883445ffdd276..94b9c53458916 100644 --- a/src/Features/Core/Portable/Wrapping/AbstractWrappingCodeRefactoringProvider.cs +++ b/src/Features/Core/Portable/Wrapping/AbstractWrappingCodeRefactoringProvider.cs @@ -45,7 +45,7 @@ public override async Task ComputeRefactoringsAsync(CodeRefactoringContext conte var token = root.FindToken(position); var configOptions = await document.GetAnalyzerConfigOptionsAsync(cancellationToken).ConfigureAwait(false); - var options = GetWrappingOptions(configOptions, context.Options.GetOptions(document.Project.LanguageServices)); + var options = GetWrappingOptions(configOptions, context.Options.GetOptions(document.Project.Services)); foreach (var node in token.GetRequiredParent().AncestorsAndSelf()) { diff --git a/src/Features/Core/Portable/Wrapping/BinaryExpression/AbstractBinaryExpressionWrapper.cs b/src/Features/Core/Portable/Wrapping/BinaryExpression/AbstractBinaryExpressionWrapper.cs index 45bb422126ba5..78deff9e9e31e 100644 --- a/src/Features/Core/Portable/Wrapping/BinaryExpression/AbstractBinaryExpressionWrapper.cs +++ b/src/Features/Core/Portable/Wrapping/BinaryExpression/AbstractBinaryExpressionWrapper.cs @@ -2,21 +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.Collections.Generic; using System.Collections.Immutable; using System.Threading; using System.Threading.Tasks; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.Indentation; +using Microsoft.CodeAnalysis.LanguageService; +using Microsoft.CodeAnalysis.Operations; using Microsoft.CodeAnalysis.PooledObjects; - +using Microsoft.CodeAnalysis.Precedence; +using Roslyn.Utilities; #if DEBUG using System.Diagnostics; #endif namespace Microsoft.CodeAnalysis.Wrapping.BinaryExpression { - using Microsoft.CodeAnalysis.Indentation; - using Microsoft.CodeAnalysis.Precedence; - internal abstract partial class AbstractBinaryExpressionWrapper : AbstractSyntaxWrapper where TBinaryExpressionSyntax : SyntaxNode { @@ -103,19 +104,30 @@ private ImmutableArray GetExpressionsAndOperators( private void AddExpressionsAndOperators( PrecedenceKind precedence, SyntaxNode expr, ArrayBuilder result) { - if (expr is TBinaryExpressionSyntax && - precedence == _precedenceService.GetPrecedenceKind(expr)) - { - _syntaxFacts.GetPartsOfBinaryExpression( - expr, out var left, out var opToken, out var right); - AddExpressionsAndOperators(precedence, left, result); - result.Add(opToken); - AddExpressionsAndOperators(precedence, right, result); - } - else + // In-order traverse which visit the left child -> operator in the binary expression -> right child + using var pooledStack = SharedPools.Default>().GetPooledObject(); + var stack = pooledStack.Object; + stack.Push(expr); + + while (!stack.IsEmpty()) { - result.Add(expr); + var currentNodeOrToken = stack.Pop(); + if (currentNodeOrToken.IsNode && IsValidBinaryExpression(precedence, currentNodeOrToken.AsNode())) + { + _syntaxFacts.GetPartsOfBinaryExpression(currentNodeOrToken.AsNode()!, out var left, out var opToken, out var right); + // We are visiting the tree In-order, so push the node in a reverse order. + stack.Push(right); + stack.Push(opToken); + stack.Push(left); + } + else + { + result.Add(currentNodeOrToken); + } } + + bool IsValidBinaryExpression(PrecedenceKind precedence, SyntaxNode? node) + => node is TBinaryExpressionSyntax && precedence == _precedenceService.GetPrecedenceKind(node); } } } diff --git a/src/Features/Core/Portable/Wrapping/ChainedExpression/AbstractChainedExpressionWrapper.cs b/src/Features/Core/Portable/Wrapping/ChainedExpression/AbstractChainedExpressionWrapper.cs index cd346692eedd7..ea0ff6dd48bd0 100644 --- a/src/Features/Core/Portable/Wrapping/ChainedExpression/AbstractChainedExpressionWrapper.cs +++ b/src/Features/Core/Portable/Wrapping/ChainedExpression/AbstractChainedExpressionWrapper.cs @@ -7,7 +7,7 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.Indentation; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.PooledObjects; namespace Microsoft.CodeAnalysis.Wrapping.ChainedExpression @@ -230,13 +230,11 @@ pieces[index] is var piece && private static ImmutableArray GetSubRange( ArrayBuilder pieces, int start, int end) { - using var resultDisposer = ArrayBuilder.GetInstance(end - start, out var result); + using var _ = ArrayBuilder.GetInstance(end - start, out var result); for (var i = start; i < end; i++) - { result.Add(pieces[i]); - } - return result.ToImmutable(); + return result.ToImmutableAndClear(); } private bool IsDecomposableChainPart(SyntaxNode? node) diff --git a/src/Features/Core/Portable/Wrapping/SeparatedSyntaxList/AbstractSeparatedSyntaxListWrapper.cs b/src/Features/Core/Portable/Wrapping/SeparatedSyntaxList/AbstractSeparatedSyntaxListWrapper.cs index cdc655e517918..22f34e39b9b84 100644 --- a/src/Features/Core/Portable/Wrapping/SeparatedSyntaxList/AbstractSeparatedSyntaxListWrapper.cs +++ b/src/Features/Core/Portable/Wrapping/SeparatedSyntaxList/AbstractSeparatedSyntaxListWrapper.cs @@ -52,7 +52,7 @@ protected abstract bool PositionIsApplicable( Document document, int position, SyntaxNode declaration, SyntaxWrappingOptions options, bool containsSyntaxError, CancellationToken cancellationToken) { var listSyntax = TryGetApplicableList(declaration); - if (listSyntax == null) + if (listSyntax == null || listSyntax.Span.IsEmpty) return null; var root = await document.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false); diff --git a/src/Features/Core/Portable/xlf/FeaturesResources.cs.xlf b/src/Features/Core/Portable/xlf/FeaturesResources.cs.xlf index 48dbc643daf63..48ea31d4bf0c9 100644 --- a/src/Features/Core/Portable/xlf/FeaturesResources.cs.xlf +++ b/src/Features/Core/Portable/xlf/FeaturesResources.cs.xlf @@ -625,6 +625,11 @@ Ujistěte se, že specifikátor tt použijete pro jazyky, pro které je nezbytn Odstranění {0} vyžaduje restartování aplikace. + + Deleting {0} requires restarting the application because is not supported by the runtime. + Deleting {0} requires restarting the application because is not supported by the runtime. + + Deleting captured variable '{0}' requires restarting the application. Odstranění zachycené proměnné {0} vyžaduje restartování aplikace. @@ -710,6 +715,11 @@ Ujistěte se, že specifikátor tt použijete pro jazyky, pro které je nezbytn Extrahovat základní třídu... + + Extract base record... + Extract base record... + {Locked="record"} "record" is a language construct for C# and should not be localized. + Extract interface... Extrahovat rozhraní... @@ -1315,6 +1325,16 @@ Ujistěte se, že specifikátor tt použijete pro jazyky, pro které je nezbytn Povýšit členy na základní typ... + + Pull selected members up + Pull selected members up + + + + Pull selected members up to {0} + Pull selected members up to {0} + + Quantifier {x,y} following nothing Před kvantifikátorem {x,y} není nic uvedeno. @@ -2525,6 +2545,11 @@ Pozitivní kontrolní výrazy zpětného vyhledávání s nulovou délkou se obv Nahradit podmíněný výraz pomocí příkazů + + required + required + Used in the object initializer completion. + Resolve conflict markers Vyřešit značky konfliktů @@ -2880,16 +2905,6 @@ Pozitivní kontrolní výrazy zpětného vyhledávání s nulovou délkou se obv Aktualizace variance {0} vyžaduje restartování aplikace. - - Use block body for lambda expressions - Pro lambda výrazy používat text bloku - - - - Use expression body for lambda expressions - Používat text výrazu pro lambda výrazy - - Value: Hodnota: @@ -3326,6 +3341,11 @@ Pokud se specifikátor formátu H použije bez dalších specifikátorů vlastn code + + Console.WriteLine + Console.WriteLine + + date separator oddělovač data @@ -3462,6 +3482,11 @@ Specifikátor standardního formátu f představuje kombinaci vzorů dlouhého d obecná přetížení + + if statement + if statement + + in {0} ({1} - {2}) v {0} ({1}–{2}) @@ -3980,16 +4005,6 @@ Chcete pokračovat? {1}. - - Simplify Names - Zjednodušit názvy - - - - Simplify Member Access - Zjednodušit přístup ke členům - - Remove qualification Odebrat kvalifikaci diff --git a/src/Features/Core/Portable/xlf/FeaturesResources.de.xlf b/src/Features/Core/Portable/xlf/FeaturesResources.de.xlf index 4be7ed50ce0e6..d91e753e9ba75 100644 --- a/src/Features/Core/Portable/xlf/FeaturesResources.de.xlf +++ b/src/Features/Core/Portable/xlf/FeaturesResources.de.xlf @@ -625,6 +625,11 @@ Stellen Sie sicher, dass Sie den Bezeichner "tt" für Sprachen verwenden, für d Das Löschen von {0} erfordert einen Neustart der Anwendung. + + Deleting {0} requires restarting the application because is not supported by the runtime. + Deleting {0} requires restarting the application because is not supported by the runtime. + + Deleting captured variable '{0}' requires restarting the application. Das Löschen der erfassten Variable „{0}“ erfordert einen Neustart der Anwendung. @@ -710,6 +715,11 @@ Stellen Sie sicher, dass Sie den Bezeichner "tt" für Sprachen verwenden, für d Basisklasse extrahieren... + + Extract base record... + Extract base record... + {Locked="record"} "record" is a language construct for C# and should not be localized. + Extract interface... Schnittstelle extrahieren... @@ -1315,6 +1325,16 @@ Stellen Sie sicher, dass Sie den Bezeichner "tt" für Sprachen verwenden, für d Member zum Basistyp ziehen... + + Pull selected members up + Pull selected members up + + + + Pull selected members up to {0} + Pull selected members up to {0} + + Quantifier {x,y} following nothing Quantifizierer {x,y} nach nichts. @@ -2525,6 +2545,11 @@ Positive Lookbehindassertionen mit Nullbreite werden normalerweise am Anfang reg Bedingter Ausdruck durch Anweisungen ersetzen + + required + required + Used in the object initializer completion. + Resolve conflict markers Konfliktmarkierungen auflösen @@ -2880,16 +2905,6 @@ Positive Lookbehindassertionen mit Nullbreite werden normalerweise am Anfang reg Das Aktualisieren der Abweichung von {0} erfordert einen Neustart der Anwendung. - - Use block body for lambda expressions - Blocktextkörper für Lambdaausdrücke verwenden - - - - Use expression body for lambda expressions - Ausdruckskörper für Lambdaausdrücke verwenden - - Value: Wert: @@ -3326,6 +3341,11 @@ Bei Verwendung des Formatbezeichners "H" ohne weitere benutzerdefinierte Formatb Code + + Console.WriteLine + Console.WriteLine + + date separator Datumstrennzeichen @@ -3462,6 +3482,11 @@ Der Standardformatbezeichner "f" repräsentiert eine Kombination aus den Mustern generische Überladungen + + if statement + if statement + + in {0} ({1} - {2}) in {0} ({1}–{2}) @@ -3980,16 +4005,6 @@ Möchten Sie fortfahren? "{1}". - - Simplify Names - Namen vereinfachen - - - - Simplify Member Access - Memberzugriff vereinfachen - - Remove qualification Qualifizierung entfernen diff --git a/src/Features/Core/Portable/xlf/FeaturesResources.es.xlf b/src/Features/Core/Portable/xlf/FeaturesResources.es.xlf index 5631260cef771..657219189ca1b 100644 --- a/src/Features/Core/Portable/xlf/FeaturesResources.es.xlf +++ b/src/Features/Core/Portable/xlf/FeaturesResources.es.xlf @@ -625,6 +625,11 @@ Asegúrese de usar el especificador "tt" para los idiomas para los que es necesa Para eliminar {0} es necesario reiniciar la aplicación. + + Deleting {0} requires restarting the application because is not supported by the runtime. + Deleting {0} requires restarting the application because is not supported by the runtime. + + Deleting captured variable '{0}' requires restarting the application. Para eliminar la variable capturada "{0}" se requiere reiniciar la aplicación. @@ -710,6 +715,11 @@ Asegúrese de usar el especificador "tt" para los idiomas para los que es necesa Extraer clase base... + + Extract base record... + Extract base record... + {Locked="record"} "record" is a language construct for C# and should not be localized. + Extract interface... Extraer interfaz... @@ -1315,6 +1325,16 @@ Asegúrese de usar el especificador "tt" para los idiomas para los que es necesa Extraer miembros hasta el tipo de base... + + Pull selected members up + Pull selected members up + + + + Pull selected members up to {0} + Pull selected members up to {0} + + Quantifier {x,y} following nothing Cuantificador {x, y} después de nada @@ -2525,6 +2545,11 @@ Las aserciones de búsqueda retrasada (lookbehind) positivas de ancho cero se us Reemplazar expresión condicional con instrucciones + + required + required + Used in the object initializer completion. + Resolve conflict markers Resolver los marcadores de conflicto @@ -2880,16 +2905,6 @@ Las aserciones de búsqueda retrasada (lookbehind) positivas de ancho cero se us Al actualizar la varianza de {0} se requiere reiniciar la aplicación. - - Use block body for lambda expressions - Usar cuerpo del bloque para las expresiones lambda - - - - Use expression body for lambda expressions - Usar órgano de expresión para expresiones lambda - - Value: Valor: @@ -3326,6 +3341,11 @@ Si el especificador de formato "H" se usa sin otros especificadores de formato p código + + Console.WriteLine + Console.WriteLine + + date separator separador de fecha @@ -3462,6 +3482,11 @@ El especificador de formato estándar "f" representa una combinación de los pat sobrecargas genéricas + + if statement + if statement + + in {0} ({1} - {2}) en {0} ({1} - {2}) @@ -3980,16 +4005,6 @@ Do you want to continue? '{1}'. - - Simplify Names - Simplificar nombres - - - - Simplify Member Access - Simplificar acceso de miembros - - Remove qualification Quitar cualificación diff --git a/src/Features/Core/Portable/xlf/FeaturesResources.fr.xlf b/src/Features/Core/Portable/xlf/FeaturesResources.fr.xlf index 3bf7484e9c919..f9735c64cc2f8 100644 --- a/src/Features/Core/Portable/xlf/FeaturesResources.fr.xlf +++ b/src/Features/Core/Portable/xlf/FeaturesResources.fr.xlf @@ -625,6 +625,11 @@ Veillez à utiliser le spécificateur "tt" pour les langues où il est nécessai La suppression de {0} requiert le redémarrage de l’application. + + Deleting {0} requires restarting the application because is not supported by the runtime. + Deleting {0} requires restarting the application because is not supported by the runtime. + + Deleting captured variable '{0}' requires restarting the application. La suppression de la variable capturée « {0} » requiert le redémarrage de l’application. @@ -710,6 +715,11 @@ Veillez à utiliser le spécificateur "tt" pour les langues où il est nécessai Extraire la classe de base... + + Extract base record... + Extract base record... + {Locked="record"} "record" is a language construct for C# and should not be localized. + Extract interface... Extraire l'interface... @@ -1315,6 +1325,16 @@ Veillez à utiliser le spécificateur "tt" pour les langues où il est nécessai Tirer les membres jusqu'au type de base... + + Pull selected members up + Pull selected members up + + + + Pull selected members up to {0} + Pull selected members up to {0} + + Quantifier {x,y} following nothing Le quantificateur {x,y} ne suit rien @@ -2525,6 +2545,11 @@ Les assertions arrière positives de largeur nulle sont généralement utilisée Remplacer l’expression conditionnelle par des instructions + + required + required + Used in the object initializer completion. + Resolve conflict markers Résoudre les marqueurs de conflit @@ -2880,16 +2905,6 @@ Les assertions arrière positives de largeur nulle sont généralement utilisée La mise à jour de la variance de {0} requiert le redémarrage de l’application. - - Use block body for lambda expressions - Utiliser le corps de bloc pour les expressions lambda - - - - Use expression body for lambda expressions - Utiliser le corps d'expression pour les expressions lambda - - Value: Valeur : @@ -3326,6 +3341,11 @@ Si le spécificateur de format "H" est utilisé sans autres spécificateurs de f code + + Console.WriteLine + Console.WriteLine + + date separator séparateur de date @@ -3462,6 +3482,11 @@ Le spécificateur de format standard "f" représente une combinaison des modèle surcharges génériques + + if statement + if statement + + in {0} ({1} - {2}) dans {0} ({1} - {2}) @@ -3980,16 +4005,6 @@ Voulez-vous continuer ? '{1}'. - - Simplify Names - Simplifier les noms - - - - Simplify Member Access - Simplifier l'accès au membre - - Remove qualification Supprimer une qualification diff --git a/src/Features/Core/Portable/xlf/FeaturesResources.it.xlf b/src/Features/Core/Portable/xlf/FeaturesResources.it.xlf index 9e117385245ce..770e4d47e562c 100644 --- a/src/Features/Core/Portable/xlf/FeaturesResources.it.xlf +++ b/src/Features/Core/Portable/xlf/FeaturesResources.it.xlf @@ -625,6 +625,11 @@ Assicurarsi di usare l'identificatore "tt" per le lingue per le quali è necessa Se si elimina {0}, è necessario riavviare l'applicazione. + + Deleting {0} requires restarting the application because is not supported by the runtime. + Deleting {0} requires restarting the application because is not supported by the runtime. + + Deleting captured variable '{0}' requires restarting the application. Se si elimina la variabile catturata '{0}', è necessario riavviare l'applicazione. @@ -710,6 +715,11 @@ Assicurarsi di usare l'identificatore "tt" per le lingue per le quali è necessa Estrai classe di base... + + Extract base record... + Extract base record... + {Locked="record"} "record" is a language construct for C# and should not be localized. + Extract interface... Estrai interfaccia... @@ -1315,6 +1325,16 @@ Assicurarsi di usare l'identificatore "tt" per le lingue per le quali è necessa Esegui pull dei membri fino al tipo di base... + + Pull selected members up + Pull selected members up + + + + Pull selected members up to {0} + Pull selected members up to {0} + + Quantifier {x,y} following nothing Il quantificatore {x,y} non segue alcun elemento @@ -2525,6 +2545,11 @@ Le asserzioni lookbehind positive di larghezza zero vengono usate in genere all' Sostituisci espressione condizionale con istruzioni + + required + required + Used in the object initializer completion. + Resolve conflict markers Risolvi gli indicatori di conflitto @@ -2880,16 +2905,6 @@ Le asserzioni lookbehind positive di larghezza zero vengono usate in genere all' Se si aggiorna la varianza di {0}, è necessario riavviare l'applicazione. - - Use block body for lambda expressions - Usa il corpo del blocco per le espressioni lambda - - - - Use expression body for lambda expressions - Usa il corpo dell'espressione per le espressioni lambda - - Value: Valore: @@ -3326,6 +3341,11 @@ Se l'identificatore di formato "H" viene usato senza altri identificatori di for codice + + Console.WriteLine + Console.WriteLine + + date separator Separatore di data @@ -3462,6 +3482,11 @@ L'identificatore di formato standard "f" rappresenta una combinazione degli sche overload generici + + if statement + if statement + + in {0} ({1} - {2}) in {0} ({1} - {2}) @@ -3980,16 +4005,6 @@ Continuare? '{1}'. - - Simplify Names - Semplifica nomi - - - - Simplify Member Access - Semplifica accesso membri - - Remove qualification Rimuovi qualificazione diff --git a/src/Features/Core/Portable/xlf/FeaturesResources.ja.xlf b/src/Features/Core/Portable/xlf/FeaturesResources.ja.xlf index 54982f274ac6f..77a18c7d4875e 100644 --- a/src/Features/Core/Portable/xlf/FeaturesResources.ja.xlf +++ b/src/Features/Core/Portable/xlf/FeaturesResources.ja.xlf @@ -625,6 +625,11 @@ Make sure to use the "tt" specifier for languages for which it's necessary to ma {0} を削除すると、アプリケーションを再起動する必要があります。 + + Deleting {0} requires restarting the application because is not supported by the runtime. + Deleting {0} requires restarting the application because is not supported by the runtime. + + Deleting captured variable '{0}' requires restarting the application. キャプチャした変数 '{0}' を削除するには、アプリケーションを再起動する必要があります。 @@ -710,6 +715,11 @@ Make sure to use the "tt" specifier for languages for which it's necessary to ma 基底クラスの抽出... + + Extract base record... + Extract base record... + {Locked="record"} "record" is a language construct for C# and should not be localized. + Extract interface... インターフェイスの抽出... @@ -1315,6 +1325,16 @@ Make sure to use the "tt" specifier for languages for which it's necessary to ma 基本型のメンバーをプル... + + Pull selected members up + Pull selected members up + + + + Pull selected members up to {0} + Pull selected members up to {0} + + Quantifier {x,y} following nothing 量指定子 {x,y} の前に何もありません @@ -2525,6 +2545,11 @@ Zero-width positive lookbehind assertions are typically used at the beginning of 条件式をステートメントに置き換える + + required + required + Used in the object initializer completion. + Resolve conflict markers 競合マーカーの解決 @@ -2880,16 +2905,6 @@ Zero-width positive lookbehind assertions are typically used at the beginning of {0} の変性を更新するには、アプリケーションを再起動する必要があります。 - - Use block body for lambda expressions - ラムダ式にブロック本体を使用する - - - - Use expression body for lambda expressions - ラムダ式に式本体を使用する - - Value: 値: @@ -3326,6 +3341,11 @@ If the "H" format specifier is used without other custom format specifiers, it's コード + + Console.WriteLine + Console.WriteLine + + date separator 日付の区切り記号 @@ -3462,6 +3482,11 @@ The "f" standard format specifier represents a combination of the long date ("D" ジェネリック オーバーロード + + if statement + if statement + + in {0} ({1} - {2}) {0} ({1} - {2}) 内 @@ -3980,16 +4005,6 @@ Do you want to continue? '{1}'。 - - Simplify Names - 名前を単純化します - - - - Simplify Member Access - メンバー アクセスを単純化します - - Remove qualification 修飾子を削除 diff --git a/src/Features/Core/Portable/xlf/FeaturesResources.ko.xlf b/src/Features/Core/Portable/xlf/FeaturesResources.ko.xlf index 72c0ceeaf17a2..e0562cdc6c0ba 100644 --- a/src/Features/Core/Portable/xlf/FeaturesResources.ko.xlf +++ b/src/Features/Core/Portable/xlf/FeaturesResources.ko.xlf @@ -625,6 +625,11 @@ Make sure to use the "tt" specifier for languages for which it's necessary to ma {0}을(를) 삭제하려면 애플리케이션을 다시 시작해야 합니다. + + Deleting {0} requires restarting the application because is not supported by the runtime. + Deleting {0} requires restarting the application because is not supported by the runtime. + + Deleting captured variable '{0}' requires restarting the application. 캡처된 변수 '{0}'을(를) 삭제하려면 응용 프로그램을 다시 시작해야 합니다. @@ -710,6 +715,11 @@ Make sure to use the "tt" specifier for languages for which it's necessary to ma 기본 클래스 추출... + + Extract base record... + Extract base record... + {Locked="record"} "record" is a language construct for C# and should not be localized. + Extract interface... 인터페이스 추출... @@ -1315,6 +1325,16 @@ Make sure to use the "tt" specifier for languages for which it's necessary to ma 기본 형식까지 멤버를 풀... + + Pull selected members up + Pull selected members up + + + + Pull selected members up to {0} + Pull selected members up to {0} + + Quantifier {x,y} following nothing 수량자 {x,y} 앞에 아무 것도 없습니다. @@ -2525,6 +2545,11 @@ Zero-width positive lookbehind assertions are typically used at the beginning of 조건식을 명령문으로 바꾸기 + + required + required + Used in the object initializer completion. + Resolve conflict markers 충돌 표식 확인 @@ -2880,16 +2905,6 @@ Zero-width positive lookbehind assertions are typically used at the beginning of {0}의 분산을 업데이트하려면 응용 프로그램을 다시 시작해야 합니다. - - Use block body for lambda expressions - 람다 식에 블록 본문 사용 - - - - Use expression body for lambda expressions - 람다 식에 식 본문 사용 - - Value: 값: @@ -3326,6 +3341,11 @@ If the "H" format specifier is used without other custom format specifiers, it's 코드 + + Console.WriteLine + Console.WriteLine + + date separator 날짜 구분 기호 @@ -3462,6 +3482,11 @@ The "f" standard format specifier represents a combination of the long date ("D" 제네릭 오버로드 + + if statement + if statement + + in {0} ({1} - {2}) {0}({1} - {2})에서 @@ -3980,16 +4005,6 @@ Do you want to continue? '{1}' - - Simplify Names - 이름 단순화 - - - - Simplify Member Access - 멤버 액세스 단순화 - - Remove qualification 한정자 제거 diff --git a/src/Features/Core/Portable/xlf/FeaturesResources.pl.xlf b/src/Features/Core/Portable/xlf/FeaturesResources.pl.xlf index 69fbc765ec112..489fbffa72b5f 100644 --- a/src/Features/Core/Portable/xlf/FeaturesResources.pl.xlf +++ b/src/Features/Core/Portable/xlf/FeaturesResources.pl.xlf @@ -625,6 +625,11 @@ Pamiętaj, aby nie używać specyfikatora „tt” dla wszystkich języków, w k Usunięcie elementu {0} wymaga ponownego uruchomienia aplikacji. + + Deleting {0} requires restarting the application because is not supported by the runtime. + Deleting {0} requires restarting the application because is not supported by the runtime. + + Deleting captured variable '{0}' requires restarting the application. Usuwanie przechwyconej zmiennej "{0}" wymaga ponownego uruchomienia aplikacji. @@ -710,6 +715,11 @@ Pamiętaj, aby nie używać specyfikatora „tt” dla wszystkich języków, w k Wyodrębnij klasę bazową... + + Extract base record... + Extract base record... + {Locked="record"} "record" is a language construct for C# and should not be localized. + Extract interface... Wyodrębnij interfejs... @@ -1315,6 +1325,16 @@ Pamiętaj, aby nie używać specyfikatora „tt” dla wszystkich języków, w k Ściągnij składowe aż do typu bazowego... + + Pull selected members up + Pull selected members up + + + + Pull selected members up to {0} + Pull selected members up to {0} + + Quantifier {x,y} following nothing Nic nie występuje przed kwantyfikatorem {x,y} @@ -2525,6 +2545,11 @@ Pozytywne asercje wsteczne o zerowej szerokości są zwykle używane na początk Zamień wyrażenie warunkowe na instrukcje + + required + required + Used in the object initializer completion. + Resolve conflict markers Rozwiąż znaczniki konfliktów @@ -2880,16 +2905,6 @@ Pozytywne asercje wsteczne o zerowej szerokości są zwykle używane na początk Aktualizowanie odchylenia elementu {0} wymaga ponownego uruchomienia aplikacji. - - Use block body for lambda expressions - Użyj treści bloku dla wyrażeń lambda - - - - Use expression body for lambda expressions - Użyj treści wyrażenia dla wyrażeń lambda - - Value: Wartość: @@ -3326,6 +3341,11 @@ Jeśli specyfikator formatu „H” zostanie użyty bez innych indywidualnych sp kod + + Console.WriteLine + Console.WriteLine + + date separator separator daty @@ -3462,6 +3482,11 @@ Standardowy specyfikator formatu „f” reprezentuje połączenie wzorców dłu przeciążenia ogólne + + if statement + if statement + + in {0} ({1} - {2}) w {0} ({1} — {2}) @@ -3980,16 +4005,6 @@ Czy chcesz kontynuować? „{1}”. - - Simplify Names - Uprość nazwy - - - - Simplify Member Access - Uprość dostęp do składowej - - Remove qualification Usuń kwalifikacje diff --git a/src/Features/Core/Portable/xlf/FeaturesResources.pt-BR.xlf b/src/Features/Core/Portable/xlf/FeaturesResources.pt-BR.xlf index 445d9a01307cd..ca026e88f643d 100644 --- a/src/Features/Core/Portable/xlf/FeaturesResources.pt-BR.xlf +++ b/src/Features/Core/Portable/xlf/FeaturesResources.pt-BR.xlf @@ -625,6 +625,11 @@ Verifique se o especificador "tt" foi usado para idiomas para os quais é necess A exclusão de {0} requer o reinício do aplicativo. + + Deleting {0} requires restarting the application because is not supported by the runtime. + Deleting {0} requires restarting the application because is not supported by the runtime. + + Deleting captured variable '{0}' requires restarting the application. Excluir a variável capturada '{0}' requer a reinicialização do aplicativo. @@ -710,6 +715,11 @@ Verifique se o especificador "tt" foi usado para idiomas para os quais é necess Extrair a classe base... + + Extract base record... + Extract base record... + {Locked="record"} "record" is a language construct for C# and should not be localized. + Extract interface... Extrair a interface... @@ -1315,6 +1325,16 @@ Verifique se o especificador "tt" foi usado para idiomas para os quais é necess Efetuar pull de membros até o tipo base... + + Pull selected members up + Pull selected members up + + + + Pull selected members up to {0} + Pull selected members up to {0} + + Quantifier {x,y} following nothing Nada precede o quantificador {x,y} @@ -2525,6 +2545,11 @@ As declarações de lookbehind positivas de largura zero normalmente são usadas Substituir expressão condicional por instruções + + required + required + Used in the object initializer completion. + Resolve conflict markers Resolver marcadores de conflitos @@ -2880,16 +2905,6 @@ As declarações de lookbehind positivas de largura zero normalmente são usadas Atualizar a variação de {0} requer a reinicialização do aplicativo. - - Use block body for lambda expressions - Usar o corpo do bloco para expressões lambda - - - - Use expression body for lambda expressions - Usar corpo da expressão para expressões lambda - - Value: Valor: @@ -3326,6 +3341,11 @@ Se o especificador de formato "H" for usado sem outros especificadores de format código + + Console.WriteLine + Console.WriteLine + + date separator separador de data @@ -3462,6 +3482,11 @@ O especificador de formato padrão "f" representa uma combinação de padrões d sobrecargas genéricas + + if statement + if statement + + in {0} ({1} - {2}) em {0} ({1} – {2}) @@ -3980,16 +4005,6 @@ Deseja continuar? '{1}'. - - Simplify Names - Simplificar Nomes - - - - Simplify Member Access - Simplificar o Acesso de Membro - - Remove qualification Remover qualificação diff --git a/src/Features/Core/Portable/xlf/FeaturesResources.ru.xlf b/src/Features/Core/Portable/xlf/FeaturesResources.ru.xlf index f5f8806a764b8..6e933479e9838 100644 --- a/src/Features/Core/Portable/xlf/FeaturesResources.ru.xlf +++ b/src/Features/Core/Portable/xlf/FeaturesResources.ru.xlf @@ -625,6 +625,11 @@ Make sure to use the "tt" specifier for languages for which it's necessary to ma Для удаления {0} требуется перезапустить приложение. + + Deleting {0} requires restarting the application because is not supported by the runtime. + Deleting {0} requires restarting the application because is not supported by the runtime. + + Deleting captured variable '{0}' requires restarting the application. Для удаления зафиксированной переменной "{0}" требуется перезапустить приложение. @@ -710,6 +715,11 @@ Make sure to use the "tt" specifier for languages for which it's necessary to ma Извлечь базовый класс... + + Extract base record... + Extract base record... + {Locked="record"} "record" is a language construct for C# and should not be localized. + Extract interface... Извлечение интерфейса… @@ -1315,6 +1325,16 @@ Make sure to use the "tt" specifier for languages for which it's necessary to ma Извлечь элементы до базового типа... + + Pull selected members up + Pull selected members up + + + + Pull selected members up to {0} + Pull selected members up to {0} + + Quantifier {x,y} following nothing Отсутствуют элементы перед квантификатором {x,y} @@ -2525,6 +2545,11 @@ Zero-width positive lookbehind assertions are typically used at the beginning of Заменить условное выражение операторами + + required + required + Used in the object initializer completion. + Resolve conflict markers Разрешение меток конфликтов @@ -2880,16 +2905,6 @@ Zero-width positive lookbehind assertions are typically used at the beginning of Для обновления расхождения {0} требуется перезапустить приложение. - - Use block body for lambda expressions - Использовать тело блока для лямбда-выражений - - - - Use expression body for lambda expressions - Использовать тело выражения для лямбда-выражений - - Value: Значение: @@ -3326,6 +3341,11 @@ If the "H" format specifier is used without other custom format specifiers, it's код + + Console.WriteLine + Console.WriteLine + + date separator разделитель компонентов даты @@ -3462,6 +3482,11 @@ The "f" standard format specifier represents a combination of the long date ("D" универсальные перегрузки + + if statement + if statement + + in {0} ({1} - {2}) в {0} ({1} — {2}) @@ -3980,16 +4005,6 @@ Do you want to continue? "{1}". - - Simplify Names - Упрощение имен - - - - Simplify Member Access - Упрощение доступа для членов - - Remove qualification Удалить квалификацию diff --git a/src/Features/Core/Portable/xlf/FeaturesResources.tr.xlf b/src/Features/Core/Portable/xlf/FeaturesResources.tr.xlf index 9a46f51d0b590..f7ed9f1358257 100644 --- a/src/Features/Core/Portable/xlf/FeaturesResources.tr.xlf +++ b/src/Features/Core/Portable/xlf/FeaturesResources.tr.xlf @@ -625,6 +625,11 @@ AM ve PM arasındaki farkın korunmasının gerekli olduğu diller için "tt" be {0} öğesinin silinmesi, uygulamanın yeniden başlatılmasını gerektirir. + + Deleting {0} requires restarting the application because is not supported by the runtime. + Deleting {0} requires restarting the application because is not supported by the runtime. + + Deleting captured variable '{0}' requires restarting the application. Yakalanan '{0}' değişkenini silmek, uygulamanın yeniden başlatılmasını gerektirir. @@ -710,6 +715,11 @@ AM ve PM arasındaki farkın korunmasının gerekli olduğu diller için "tt" be Temel sınıfı ayıkla... + + Extract base record... + Extract base record... + {Locked="record"} "record" is a language construct for C# and should not be localized. + Extract interface... Arabirimi ayıkla... @@ -1315,6 +1325,16 @@ AM ve PM arasındaki farkın korunmasının gerekli olduğu diller için "tt" be Üyeleri temel türe çek... + + Pull selected members up + Pull selected members up + + + + Pull selected members up to {0} + Pull selected members up to {0} + + Quantifier {x,y} following nothing Niceleyici {x, y} hiçbir şeyi takip etmiyor @@ -2525,6 +2545,11 @@ Sıfır genişlikli pozitif geri yönlü onaylamalar genellikle normal ifadeleri Koşullu ifadeyi deyimlerle değiştirin + + required + required + Used in the object initializer completion. + Resolve conflict markers Çakışma işaretçilerini çözümle @@ -2880,16 +2905,6 @@ Sıfır genişlikli pozitif geri yönlü onaylamalar genellikle normal ifadeleri {0} varyansını güncelleştirmek, uygulamanın yeniden başlatılmasını gerektirir. - - Use block body for lambda expressions - Lambda ifadeleri için blok vücut kullanımı - - - - Use expression body for lambda expressions - Lambda ifadeleri için ifade vücut kullanımı - - Value: Değer: @@ -3326,6 +3341,11 @@ If the "H" format specifier is used without other custom format specifiers, it's kod + + Console.WriteLine + Console.WriteLine + + date separator tarih ayırıcısı @@ -3462,6 +3482,11 @@ The "f" standard format specifier represents a combination of the long date ("D" genel aşırı yüklemeler + + if statement + if statement + + in {0} ({1} - {2}) {0} ({1}-{2}) içinde @@ -3980,16 +4005,6 @@ Devam etmek istiyor musunuz? '{1}'. - - Simplify Names - Adları Basitleştir - - - - Simplify Member Access - Üye Erişimini Basitleştir - - Remove qualification Nitelemeyi kaldır diff --git a/src/Features/Core/Portable/xlf/FeaturesResources.zh-Hans.xlf b/src/Features/Core/Portable/xlf/FeaturesResources.zh-Hans.xlf index e3e87ff546b55..e66b6e5de9fe0 100644 --- a/src/Features/Core/Portable/xlf/FeaturesResources.zh-Hans.xlf +++ b/src/Features/Core/Portable/xlf/FeaturesResources.zh-Hans.xlf @@ -625,6 +625,11 @@ Make sure to use the "tt" specifier for languages for which it's necessary to ma 删除 {0} 需要重启应用程序。 + + Deleting {0} requires restarting the application because is not supported by the runtime. + Deleting {0} requires restarting the application because is not supported by the runtime. + + Deleting captured variable '{0}' requires restarting the application. 删除捕获的变量“{0}”需要重新启动应用程序。 @@ -710,6 +715,11 @@ Make sure to use the "tt" specifier for languages for which it's necessary to ma 提取基类... + + Extract base record... + Extract base record... + {Locked="record"} "record" is a language construct for C# and should not be localized. + Extract interface... 提取接口... @@ -1315,6 +1325,16 @@ Make sure to use the "tt" specifier for languages for which it's necessary to ma 将成员拉到基类... + + Pull selected members up + Pull selected members up + + + + Pull selected members up to {0} + Pull selected members up to {0} + + Quantifier {x,y} following nothing 限定符 {x,y} 前没有任何内容 @@ -2525,6 +2545,11 @@ Zero-width positive lookbehind assertions are typically used at the beginning of 将条件表达式替换为语句 + + required + required + Used in the object initializer completion. + Resolve conflict markers 解决冲突标记 @@ -2880,16 +2905,6 @@ Zero-width positive lookbehind assertions are typically used at the beginning of 更新 {0} 的差异需要重新启动应用程序。 - - Use block body for lambda expressions - 对 lambda 表达式使用块主体 - - - - Use expression body for lambda expressions - 对 lambda 表达式使用表达式正文 - - Value: 值: @@ -3326,6 +3341,11 @@ If the "H" format specifier is used without other custom format specifiers, it's 代码 + + Console.WriteLine + Console.WriteLine + + date separator 日期分隔符 @@ -3462,6 +3482,11 @@ The "f" standard format specifier represents a combination of the long date ("D" 多个泛型重载 + + if statement + if statement + + in {0} ({1} - {2}) 在 {0} ({1} - {2}) @@ -3980,16 +4005,6 @@ Do you want to continue? “{1}”。 - - Simplify Names - 简化名称 - - - - Simplify Member Access - 简化成员访问 - - Remove qualification 删除限定 diff --git a/src/Features/Core/Portable/xlf/FeaturesResources.zh-Hant.xlf b/src/Features/Core/Portable/xlf/FeaturesResources.zh-Hant.xlf index 70f6299a30025..ee05b903a2005 100644 --- a/src/Features/Core/Portable/xlf/FeaturesResources.zh-Hant.xlf +++ b/src/Features/Core/Portable/xlf/FeaturesResources.zh-Hant.xlf @@ -625,6 +625,11 @@ Make sure to use the "tt" specifier for languages for which it's necessary to ma 刪除 {0} 需要重新啟動應用程式。 + + Deleting {0} requires restarting the application because is not supported by the runtime. + Deleting {0} requires restarting the application because is not supported by the runtime. + + Deleting captured variable '{0}' requires restarting the application. 刪除擷取到的變數 '{0}' 需要重新啟動應用程式。 @@ -710,6 +715,11 @@ Make sure to use the "tt" specifier for languages for which it's necessary to ma 擷取基底類別... + + Extract base record... + Extract base record... + {Locked="record"} "record" is a language construct for C# and should not be localized. + Extract interface... 擷取介面... @@ -1315,6 +1325,16 @@ Make sure to use the "tt" specifier for languages for which it's necessary to ma 將成員提取直到基底類型... + + Pull selected members up + Pull selected members up + + + + Pull selected members up to {0} + Pull selected members up to {0} + + Quantifier {x,y} following nothing 數量詞 {x,y} 前面沒有任何項目 @@ -2525,6 +2545,11 @@ Zero-width positive lookbehind assertions are typically used at the beginning of 以陳述式取代條件運算式 + + required + required + Used in the object initializer completion. + Resolve conflict markers 解決衝突標記 @@ -2880,16 +2905,6 @@ Zero-width positive lookbehind assertions are typically used at the beginning of 更新 {0} 的差異需要重新啟動應用程式。 - - Use block body for lambda expressions - 使用 Lambda 運算式的區塊主體 - - - - Use expression body for lambda expressions - 使用 Lambda 運算式的運算式主體 - - Value: 值: @@ -3326,6 +3341,11 @@ If the "H" format specifier is used without other custom format specifiers, it's 代碼 + + Console.WriteLine + Console.WriteLine + + date separator 日期分隔符號 @@ -3462,6 +3482,11 @@ The "f" standard format specifier represents a combination of the long date ("D" 泛型多載 + + if statement + if statement + + in {0} ({1} - {2}) 在 {0} ({1} - {2}) @@ -3980,16 +4005,6 @@ Do you want to continue? '{1}'。 - - Simplify Names - 簡化名稱 - - - - Simplify Member Access - 簡化成員存取 - - Remove qualification 移除限定性條件 diff --git a/src/Features/LanguageServer/Protocol/Features/CodeCleanup/AbstractCodeCleanupService.cs b/src/Features/LanguageServer/Protocol/Features/CodeCleanup/AbstractCodeCleanupService.cs index 77d84a1a2d9a2..f50a73b526723 100644 --- a/src/Features/LanguageServer/Protocol/Features/CodeCleanup/AbstractCodeCleanupService.cs +++ b/src/Features/LanguageServer/Protocol/Features/CodeCleanup/AbstractCodeCleanupService.cs @@ -181,7 +181,7 @@ private async Task ApplyCodeFixesForSpecificDiagnosticIdAsync(Document return document; } - var fixAllService = document.Project.Solution.Workspace.Services.GetRequiredService(); + var fixAllService = document.Project.Solution.Services.GetRequiredService(); var solution = await fixAllService.GetFixAllChangedSolutionAsync( new FixAllContext(fixCollection.FixAllState, progressTracker, cancellationToken)).ConfigureAwait(false); diff --git a/src/Features/LanguageServer/Protocol/Features/CodeFixes/CodeFixService.cs b/src/Features/LanguageServer/Protocol/Features/CodeFixes/CodeFixService.cs index 8506b92f9c976..5e8391b3bd496 100644 --- a/src/Features/LanguageServer/Protocol/Features/CodeFixes/CodeFixService.cs +++ b/src/Features/LanguageServer/Protocol/Features/CodeFixes/CodeFixService.cs @@ -20,6 +20,7 @@ using Microsoft.CodeAnalysis.ErrorLogger; using Microsoft.CodeAnalysis.ErrorReporting; using Microsoft.CodeAnalysis.Extensions; +using Microsoft.CodeAnalysis.Host; using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.Internal.Log; using Microsoft.CodeAnalysis.PooledObjects; @@ -193,7 +194,7 @@ public async IAsyncEnumerable StreamFixesAsync( } // TODO (https://github.com/dotnet/roslyn/issues/4932): Don't restrict CodeFixes in Interactive - if (document.Project.Solution.Workspace.Kind != WorkspaceKind.Interactive && includeSuppressionFixes) + if (document.Project.Solution.WorkspaceKind != WorkspaceKind.Interactive && includeSuppressionFixes) { // Ensure that we do not register duplicate configuration fixes. using var _2 = PooledHashSet.GetInstance(out var registeredConfigurationFixTitles); @@ -290,7 +291,7 @@ public async Task ApplyCodeFixesForSpecificDiagnosticIdAsync( return document; } - var fixAllService = document.Project.Solution.Workspace.Services.GetRequiredService(); + var fixAllService = document.Project.Solution.Services.GetRequiredService(); var solution = await fixAllService.GetFixAllChangedSolutionAsync( new FixAllContext(fixCollection.FixAllState, progressTracker, cancellationToken)).ConfigureAwait(false); @@ -302,7 +303,7 @@ private bool TryGetWorkspaceFixersMap(Document document, [NotNullWhen(true)] out { if (_lazyWorkspaceFixersMap == null) { - var workspaceFixersMap = GetFixerPerLanguageMap(document.Project.Solution.Workspace); + var workspaceFixersMap = GetFixerPerLanguageMap(document.Project.Solution.Services); Interlocked.CompareExchange(ref _lazyWorkspaceFixersMap, workspaceFixersMap, null); } @@ -313,7 +314,7 @@ private bool TryGetWorkspaceFixersPriorityMap(Document document, [NotNullWhen(tr { if (_lazyFixerPriorityMap == null) { - var fixersPriorityByLanguageMap = GetFixerPriorityPerLanguageMap(document.Project.Solution.Workspace); + var fixersPriorityByLanguageMap = GetFixerPriorityPerLanguageMap(document.Project.Solution.Services); Interlocked.CompareExchange(ref _lazyFixerPriorityMap, fixersPriorityByLanguageMap, null); } @@ -322,7 +323,7 @@ private bool TryGetWorkspaceFixersPriorityMap(Document document, [NotNullWhen(tr private bool TryGetWorkspaceFixer( Lazy lazyFixer, - Workspace workspace, + SolutionServices services, bool logExceptionWithInfoBar, [NotNullWhen(returnValue: true)] out CodeFixProvider? fixer) { @@ -337,7 +338,7 @@ private bool TryGetWorkspaceFixer( // Log exception and show info bar, if needed. if (logExceptionWithInfoBar) { - var errorReportingService = workspace.Services.GetRequiredService(); + var errorReportingService = services.GetRequiredService(); var message = lazyFixer.Metadata.Name != null ? string.Format(FeaturesResources.Error_creating_instance_of_CodeFixProvider_0, lazyFixer.Metadata.Name) : FeaturesResources.Error_creating_instance_of_CodeFixProvider; @@ -383,7 +384,7 @@ private async IAsyncEnumerable StreamFixesAsync( yield break; // TODO (https://github.com/dotnet/roslyn/issues/4932): Don't restrict CodeFixes in Interactive - var isInteractive = document.Project.Solution.Workspace.Kind == WorkspaceKind.Interactive; + var isInteractive = document.Project.Solution.WorkspaceKind == WorkspaceKind.Interactive; // gather CodeFixProviders for all distinct diagnostics found for current span using var _1 = PooledDictionary diagnostics)>>.GetInstance(out var fixerToRangesAndDiagnostics); @@ -423,7 +424,7 @@ private async IAsyncEnumerable StreamFixesAsync( if (TryGetWorkspaceFixersPriorityMap(document, out var fixersForLanguage)) allFixers = allFixers.Sort(new FixerComparer(allFixers, fixersForLanguage.Value)); - var extensionManager = document.Project.Solution.Workspace.Services.GetService(); + var extensionManager = document.Project.Solution.Services.GetService(); // Run each CodeFixProvider to gather individual CodeFixes for reported diagnostics. // Ensure that no diagnostic has registered code actions from different code fix providers with same equivalance key. @@ -673,7 +674,7 @@ await diagnosticsWithSameSpan.OrderByDescending(d => d.Severity) return null; } - var extensionManager = document.Project.Solution.Workspace.Services.GetRequiredService(); + var extensionManager = document.Project.Solution.Services.GetRequiredService(); var fixes = await extensionManager.PerformFunctionAsync(fixer, () => getFixes(diagnostics), defaultValue: ImmutableArray.Empty).ConfigureAwait(false); @@ -787,10 +788,10 @@ private static ImmutableArray GetAndTestFixableDiagnosticIds(CodeFixProv } private ImmutableDictionary>>> GetFixerPerLanguageMap( - Workspace workspace) + SolutionServices services) { var fixerMap = ImmutableDictionary.Create>>>(); - var extensionManager = workspace.Services.GetService(); + var extensionManager = services.GetService(); foreach (var (diagnosticId, lazyFixers) in _fixersPerLanguageMap) { var lazyMap = new Lazy>>(() => @@ -799,7 +800,7 @@ private ImmutableDictionary GetConfigurationFixProviders(Im } } - private ImmutableDictionary>> GetFixerPriorityPerLanguageMap(Workspace workspace) + private ImmutableDictionary>> GetFixerPriorityPerLanguageMap(SolutionServices services) { var languageMap = ImmutableDictionary.CreateBuilder>>(); foreach (var (diagnosticId, lazyFixers) in _fixersPerLanguageMap) @@ -863,7 +864,7 @@ private ImmutableDictionary> GetProjectFixers(Project project) { // TODO (https://github.com/dotnet/roslyn/issues/4932): Don't restrict CodeFixes in Interactive - return project.Solution.Workspace.Kind == WorkspaceKind.Interactive + return project.Solution.WorkspaceKind == WorkspaceKind.Interactive ? ImmutableDictionary>.Empty : _projectFixersMap.GetValue(project.AnalyzerReferences, _ => ComputeProjectFixers(project)); } private ImmutableDictionary> ComputeProjectFixers(Project project) { - var extensionManager = project.Solution.Workspace.Services.GetService(); + var extensionManager = project.Solution.Services.GetService(); using var _ = PooledDictionary>.GetInstance(out var builder); var codeFixProviders = ProjectCodeFixProvider.GetExtensions(project); diff --git a/src/Features/LanguageServer/Protocol/Features/Diagnostics/DiagnosticAnalyzerService.cs b/src/Features/LanguageServer/Protocol/Features/Diagnostics/DiagnosticAnalyzerService.cs index b447b8757f2e0..b951abb33b2ea 100644 --- a/src/Features/LanguageServer/Protocol/Features/Diagnostics/DiagnosticAnalyzerService.cs +++ b/src/Features/LanguageServer/Protocol/Features/Diagnostics/DiagnosticAnalyzerService.cs @@ -44,9 +44,10 @@ internal partial class DiagnosticAnalyzerService : IDiagnosticAnalyzerService public DiagnosticAnalyzerService( IDiagnosticUpdateSourceRegistrationService registrationService, IAsynchronousOperationListenerProvider listenerProvider, + DiagnosticAnalyzerInfoCache.SharedGlobalCache globalCache, IGlobalOptionService globalOptions) { - AnalyzerInfoCache = new DiagnosticAnalyzerInfoCache(); + AnalyzerInfoCache = globalCache.AnalyzerInfoCache; Listener = listenerProvider.GetListener(FeatureAttribute.DiagnosticService); GlobalOptions = globalOptions; diff --git a/src/Features/LanguageServer/Protocol/Features/Diagnostics/DiagnosticAnalyzerService_IncrementalAnalyzer.cs b/src/Features/LanguageServer/Protocol/Features/Diagnostics/DiagnosticAnalyzerService_IncrementalAnalyzer.cs index 4a8469a9ee997..4bb863a34fdbd 100644 --- a/src/Features/LanguageServer/Protocol/Features/Diagnostics/DiagnosticAnalyzerService_IncrementalAnalyzer.cs +++ b/src/Features/LanguageServer/Protocol/Features/Diagnostics/DiagnosticAnalyzerService_IncrementalAnalyzer.cs @@ -49,7 +49,7 @@ private DiagnosticIncrementalAnalyzer CreateIncrementalAnalyzerCallback(Workspac // subscribe to active context changed event for new workspace workspace.DocumentActiveContextChanged += OnDocumentActiveContextChanged; - return new DiagnosticIncrementalAnalyzer(this, LogAggregator.GetNextId(), workspace, AnalyzerInfoCache); + return new DiagnosticIncrementalAnalyzer(this, CorrelationIdFactory.GetNextId(), workspace, AnalyzerInfoCache); } private void OnDocumentActiveContextChanged(object? sender, DocumentActiveContextChangedEventArgs e) diff --git a/src/Features/LanguageServer/Protocol/Features/Diagnostics/DiagnosticDataExtensions.cs b/src/Features/LanguageServer/Protocol/Features/Diagnostics/DiagnosticDataExtensions.cs new file mode 100644 index 0000000000000..e9ba59a06e62e --- /dev/null +++ b/src/Features/LanguageServer/Protocol/Features/Diagnostics/DiagnosticDataExtensions.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 Microsoft.CodeAnalysis.ErrorReporting; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.IO; +using System.Runtime.Serialization.Json; +using System.Text; +using System; +using Microsoft.CodeAnalysis.Diagnostics; +using System.Diagnostics.CodeAnalysis; + +namespace Microsoft.CodeAnalysis.LanguageServer.Features.Diagnostics; +internal static class DiagnosticDataExtensions +{ + internal static bool TryGetUnnecessaryDataLocations(this DiagnosticData diagnosticData, [NotNullWhen(true)] out ImmutableArray? unnecessaryLocations) + { + // If there are 'unnecessary' locations specified in the property bag, use those instead of the main diagnostic location. + if (diagnosticData.TryGetUnnecessaryLocationIndices(out var unnecessaryIndices)) + { + using var _ = PooledObjects.ArrayBuilder.GetInstance(out var locationsToTag); + + foreach (var index in GetLocationIndices(unnecessaryIndices)) + locationsToTag.Add(diagnosticData.AdditionalLocations[index]); + + unnecessaryLocations = locationsToTag.ToImmutable(); + return true; + } + + unnecessaryLocations = null; + return false; + + static IEnumerable GetLocationIndices(string indicesProperty) + { + try + { + using var stream = new MemoryStream(Encoding.UTF8.GetBytes(indicesProperty)); + var serializer = new DataContractJsonSerializer(typeof(IEnumerable)); + var result = serializer.ReadObject(stream) as IEnumerable; + return result ?? Array.Empty(); + } + catch (Exception e) when (FatalError.ReportAndCatch(e)) + { + return ImmutableArray.Empty; + } + } + } + + internal static bool TryGetUnnecessaryLocationIndices( + this DiagnosticData diagnosticData, [NotNullWhen(true)] out string? unnecessaryIndices) + { + unnecessaryIndices = null; + + return diagnosticData.AdditionalLocations.Length > 0 + && diagnosticData.Properties != null + && diagnosticData.Properties.TryGetValue(WellKnownDiagnosticTags.Unnecessary, out unnecessaryIndices) + && unnecessaryIndices != null; + } +} diff --git a/src/Features/LanguageServer/Protocol/Features/Diagnostics/DiagnosticService.cs b/src/Features/LanguageServer/Protocol/Features/Diagnostics/DiagnosticService.cs index 156f271f631b1..19cb071f9d85e 100644 --- a/src/Features/LanguageServer/Protocol/Features/Diagnostics/DiagnosticService.cs +++ b/src/Features/LanguageServer/Protocol/Features/Diagnostics/DiagnosticService.cs @@ -34,19 +34,14 @@ internal partial class DiagnosticService : IDiagnosticService private readonly EventListenerTracker _eventListenerTracker; - public IGlobalOptionService GlobalOptions { get; } - private ImmutableHashSet _updateSources; [ImportingConstructor] [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] public DiagnosticService( - IGlobalOptionService globalOptions, IAsynchronousOperationListenerProvider listenerProvider, [ImportMany] IEnumerable> eventListeners) { - GlobalOptions = globalOptions; - // we use registry service rather than doing MEF import since MEF import method can have race issue where // update source gets created before aggregator - diagnostic service - is created and we will lose events fired before // the aggregator is created. @@ -211,10 +206,6 @@ private void OnCleared(object sender, EventArgs e) RaiseDiagnosticsCleared((IDiagnosticUpdateSource)sender); } - [Obsolete] - ImmutableArray IDiagnosticService.GetDiagnostics(Workspace workspace, ProjectId projectId, DocumentId documentId, object id, bool includeSuppressedDiagnostics, CancellationToken cancellationToken) - => GetPushDiagnosticsAsync(workspace, projectId, documentId, id, includeSuppressedDiagnostics, GlobalOptions.GetDiagnosticMode(InternalDiagnosticsOptions.NormalDiagnosticMode), cancellationToken).AsTask().WaitAndGetResult_CanCallOnBackground(cancellationToken); - public ValueTask> GetPullDiagnosticsAsync(Workspace workspace, ProjectId projectId, DocumentId documentId, object id, bool includeSuppressedDiagnostics, DiagnosticMode diagnosticMode, CancellationToken cancellationToken) => GetDiagnosticsAsync(workspace, projectId, documentId, id, includeSuppressedDiagnostics, forPullDiagnostics: true, diagnosticMode, cancellationToken); diff --git a/src/Features/LanguageServer/Protocol/Features/Diagnostics/DocumentAnalysisExecutor.cs b/src/Features/LanguageServer/Protocol/Features/Diagnostics/DocumentAnalysisExecutor.cs index ab65a11d7bc48..73568d9abe412 100644 --- a/src/Features/LanguageServer/Protocol/Features/Diagnostics/DocumentAnalysisExecutor.cs +++ b/src/Features/LanguageServer/Protocol/Features/Diagnostics/DocumentAnalysisExecutor.cs @@ -11,7 +11,7 @@ using System.Threading.Tasks; using Microsoft.CodeAnalysis.ErrorReporting; using Microsoft.CodeAnalysis.Internal.Log; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Text; @@ -56,6 +56,9 @@ public DocumentAnalysisExecutor( public DocumentAnalysisScope AnalysisScope { get; } + public DocumentAnalysisExecutor With(DocumentAnalysisScope analysisScope) + => new(analysisScope, _compilationWithAnalyzers, _diagnosticAnalyzerRunner, _logPerformanceInfo, _onAnalysisException); + /// /// Return all local diagnostics (syntax, semantic) that belong to given document for the given analyzer by calculating them. /// @@ -153,10 +156,15 @@ public async Task> ComputeDiagnosticsAsync(Diagnosti // Remap diagnostic locations, if required. diagnostics = await RemapDiagnosticLocationsIfRequiredAsync(textDocument, diagnostics, cancellationToken).ConfigureAwait(false); + if (span.HasValue) + { + diagnostics = diagnostics.WhereAsArray(d => !d.HasTextSpan || span.Value.IntersectsWith(d.GetTextSpan())); + } + #if DEBUG var diags = await diagnostics.ToDiagnosticsAsync(textDocument.Project, cancellationToken).ConfigureAwait(false); Debug.Assert(diags.Length == CompilationWithAnalyzers.GetEffectiveDiagnostics(diags, _compilationWithAnalyzers.Compilation).Count()); - //Debug.Assert(diagnostics.Length == diags.ConvertToLocalDiagnostics(textDocument, span).Count()); + Debug.Assert(diagnostics.Length == ConvertToLocalDiagnostics(diags, textDocument, span).Count()); #endif return diagnostics; @@ -172,9 +180,9 @@ private async Task> RemapDiagnosticLocatio } // Check if IWorkspaceVenusSpanMappingService is present for remapping. - var diagnosticSpanMappingService = textDocument.Project.Solution.Workspace.Services.GetService(); + var diagnosticSpanMappingService = textDocument.Project.Solution.Services.GetService(); if (diagnosticSpanMappingService == null) { return diagnostics; @@ -376,7 +384,7 @@ private static async Task> RemapDiagnosticLocatio builder.Add(DiagnosticData.Create(diagnostic, textDocument)); } - return builder.ToImmutable(); + return builder.ToImmutableAndClear(); } } } diff --git a/src/Features/LanguageServer/Protocol/Features/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer.ActiveFileState.cs b/src/Features/LanguageServer/Protocol/Features/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer.ActiveFileState.cs index c0e883f65fc2e..0f0c1c9798fd5 100644 --- a/src/Features/LanguageServer/Protocol/Features/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer.ActiveFileState.cs +++ b/src/Features/LanguageServer/Protocol/Features/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer.ActiveFileState.cs @@ -14,6 +14,8 @@ internal partial class DiagnosticIncrementalAnalyzer /// private sealed class ActiveFileState { + private readonly object _gate = new(); + // file state this is for public readonly DocumentId DocumentId; @@ -24,39 +26,59 @@ private sealed class ActiveFileState public ActiveFileState(DocumentId documentId) => DocumentId = documentId; - public bool IsEmpty => _syntax.Items.IsEmpty && _semantic.Items.IsEmpty; + public bool IsEmpty + { + get + { + lock (_gate) + { + return _syntax.Items.IsEmpty && _semantic.Items.IsEmpty; + } + } + } public void ResetVersion() { - // reset version of cached data so that we can recalculate new data (ex, OnDocumentReset) - _syntax = new DocumentAnalysisData(VersionStamp.Default, _syntax.Items); - _semantic = new DocumentAnalysisData(VersionStamp.Default, _semantic.Items); + lock (_gate) + { + // reset version of cached data so that we can recalculate new data (ex, OnDocumentReset) + _syntax = new DocumentAnalysisData(VersionStamp.Default, _syntax.Items); + _semantic = new DocumentAnalysisData(VersionStamp.Default, _semantic.Items); + } } public DocumentAnalysisData GetAnalysisData(AnalysisKind kind) - => kind switch + { + lock (_gate) { - AnalysisKind.Syntax => _syntax, - AnalysisKind.Semantic => _semantic, - _ => throw ExceptionUtilities.UnexpectedValue(kind) - }; + 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); - switch (kind) + lock (_gate) { - case AnalysisKind.Syntax: - _syntax = data; - return; + switch (kind) + { + case AnalysisKind.Syntax: + _syntax = data; + return; - case AnalysisKind.Semantic: - _semantic = data; - return; + case AnalysisKind.Semantic: + _semantic = data; + return; - default: - throw ExceptionUtilities.UnexpectedValue(kind); + default: + throw ExceptionUtilities.UnexpectedValue(kind); + } } } } diff --git a/src/Features/LanguageServer/Protocol/Features/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer.CompilationManager.cs b/src/Features/LanguageServer/Protocol/Features/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer.CompilationManager.cs index 577abb2d62d3b..c137c22c1bdce 100644 --- a/src/Features/LanguageServer/Protocol/Features/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer.CompilationManager.cs +++ b/src/Features/LanguageServer/Protocol/Features/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer.CompilationManager.cs @@ -27,12 +27,19 @@ internal partial class DiagnosticIncrementalAnalyzer var ideOptions = AnalyzerService.GlobalOptions.GetIdeAnalyzerOptions(project); - if (_projectCompilationsWithAnalyzers.TryGetValue(project, out var compilationWithAnalyzers) && - ((WorkspaceAnalyzerOptions)compilationWithAnalyzers!.AnalysisOptions.Options!).IdeOptions == ideOptions) + if (_projectCompilationsWithAnalyzers.TryGetValue(project, out var compilationWithAnalyzers)) { - // we have cached one, return that. - AssertAnalyzers(compilationWithAnalyzers, stateSets); - return compilationWithAnalyzers; + // We may have cached a null entry if we determiend that there are no actual analyzers to run. + if (compilationWithAnalyzers is null) + { + return null; + } + else if (((WorkspaceAnalyzerOptions)compilationWithAnalyzers.AnalysisOptions.Options!).IdeOptions == ideOptions) + { + // we have cached one, return that. + AssertAnalyzers(compilationWithAnalyzers, stateSets); + return compilationWithAnalyzers; + } } // Create driver that holds onto compilation and associated analyzers diff --git a/src/Features/LanguageServer/Protocol/Features/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer.IncrementalMemberEditAnalyzer.cs b/src/Features/LanguageServer/Protocol/Features/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer.IncrementalMemberEditAnalyzer.cs new file mode 100644 index 0000000000000..c1a4f2944f239 --- /dev/null +++ b/src/Features/LanguageServer/Protocol/Features/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer.IncrementalMemberEditAnalyzer.cs @@ -0,0 +1,381 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Diagnostics; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.LanguageService; +using Microsoft.CodeAnalysis.PooledObjects; +using Microsoft.CodeAnalysis.Shared.Extensions; +using Microsoft.CodeAnalysis.SolutionCrawler; +using Microsoft.CodeAnalysis.Text; +using Roslyn.Utilities; + +namespace Microsoft.CodeAnalysis.Diagnostics.EngineV2 +{ + internal partial class DiagnosticIncrementalAnalyzer + { + /// + /// This type performs incremental analysis in presence of edits to only a single member inside a document. + /// For typing scenarios where we are continuously editing a method body, we can optimize the full + /// document diagnostic computation by doing the following: + /// 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 all the old diagnostics for the edited member node in a prior document snapshot + /// with the newly computed 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. + /// + private sealed partial class IncrementalMemberEditAnalyzer + { + /// + /// Weak reference to the last document snapshot for which full document diagnostics + /// were computed and saved. + /// + private readonly WeakReference _lastDocumentWithCachedDiagnostics = new(null); + + public void UpdateDocumentWithCachedDiagnostics(Document document) + => _lastDocumentWithCachedDiagnostics.SetTarget(document); + + public async Task>> ComputeDiagnosticsAsync( + DocumentAnalysisExecutor executor, + ImmutableArray stateSets, + VersionStamp version, + Func>> computeAnalyzerDiagnosticsAsync, + Func>>> computeDiagnosticsNonIncrementallyAsync, + CancellationToken cancellationToken) + { + var analysisScope = executor.AnalysisScope; + + // We should be asked to perform incremental analysis only for full document diagnostics computation. + Debug.Assert(!analysisScope.Span.HasValue); + + // Ensure that only the analyzers that support incremental span-based analysis are provided. + Debug.Assert(stateSets.All(stateSet => stateSet.Analyzer.SupportsSpanBasedSemanticDiagnosticAnalysis())); + + var document = (Document)analysisScope.TextDocument; + var root = await document.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false); + var changedMemberAndIdAndSpansAndDocument = await TryGetChangedMemberAsync(document, root, cancellationToken).ConfigureAwait(false); + if (changedMemberAndIdAndSpansAndDocument == null) + { + // This is not a member-edit scenario, so compute full document diagnostics + // without incremental analysis. + return await computeDiagnosticsNonIncrementallyAsync(executor, cancellationToken).ConfigureAwait(false); + } + + var (changedMember, changedMemberId, newMemberSpans, oldDocument) = changedMemberAndIdAndSpansAndDocument.Value; + + try + { + var oldDocumentVersion = await GetDiagnosticVersionAsync(oldDocument.Project, cancellationToken).ConfigureAwait(false); + + using var _1 = ArrayBuilder<(DiagnosticAnalyzer, DocumentAnalysisData)>.GetInstance(out var spanBasedAnalyzers); + using var _2 = ArrayBuilder<(DiagnosticAnalyzer, DocumentAnalysisData)>.GetInstance(out var documentBasedAnalyzers); + (DiagnosticAnalyzer analyzer, DocumentAnalysisData existingData, bool spanBased)? compilerAnalyzerData = null; + foreach (var stateSet in stateSets) + { + // 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 = stateSet.GetOrCreateActiveFileState(document.Id); + var existingData = state.GetAnalysisData(analysisScope.Kind); + if (oldDocumentVersion == existingData.Version) + { + if (!compilerAnalyzerData.HasValue && stateSet.Analyzer.IsCompilerAnalyzer()) + compilerAnalyzerData = (stateSet.Analyzer, existingData, spanBased: true); + else + spanBasedAnalyzers.Add((stateSet.Analyzer, existingData)); + } + else + { + if (!compilerAnalyzerData.HasValue && stateSet.Analyzer.IsCompilerAnalyzer()) + compilerAnalyzerData = (stateSet.Analyzer, DocumentAnalysisData.Empty, spanBased: false); + else + documentBasedAnalyzers.Add((stateSet.Analyzer, DocumentAnalysisData.Empty)); + } + } + + if (spanBasedAnalyzers.Count == 0 && (!compilerAnalyzerData.HasValue || !compilerAnalyzerData.Value.spanBased)) + { + // No incremental span based-analysis to be performed. + return await computeDiagnosticsNonIncrementallyAsync(executor, cancellationToken).ConfigureAwait(false); + } + + // Get or create the member spans for all member nodes in the old document. + var oldMemberSpans = await GetOrCreateMemberSpansAsync(oldDocument, oldDocumentVersion, cancellationToken).ConfigureAwait(false); + + // Execute all the analyzers, starting with compiler analyzer first, followed by span-based analyzers + // and finally document-based analyzers. + using var _ = PooledDictionary>.GetInstance(out var builder); + await ExecuteCompilerAnalyzerAsync(compilerAnalyzerData, oldMemberSpans, builder).ConfigureAwait(false); + await ExecuteSpanBasedAnalyzersAsync(spanBasedAnalyzers, oldMemberSpans, builder).ConfigureAwait(false); + await ExecuteDocumentBasedAnalyzersAsync(documentBasedAnalyzers, oldMemberSpans, builder).ConfigureAwait(false); + return builder.ToImmutableDictionary(); + } + finally + { + // Finally, save the current member spans in the latest document so that the + // diagnostic computation for any subsequent member-only edits can be done incrementally. + SaveMemberSpans(document.Id, version, newMemberSpans); + } + + async Task ExecuteCompilerAnalyzerAsync( + (DiagnosticAnalyzer analyzer, DocumentAnalysisData existingData, bool spanBased)? compilerAnalyzerData, + ImmutableArray oldMemberSpans, + PooledDictionary> builder) + { + if (!compilerAnalyzerData.HasValue) + return; + + var (analyzer, existingData, spanBased) = compilerAnalyzerData.Value; + var span = spanBased ? changedMember.FullSpan : (TextSpan?)null; + executor = executor.With(analysisScope.WithSpan(span)); + var analyzerAndExistingData = SpecializedCollections.SingletonEnumerable((analyzer, existingData)); + await ExecuteAnalyzersAsync(executor, analyzerAndExistingData, oldMemberSpans, builder).ConfigureAwait(false); + } + + async Task ExecuteSpanBasedAnalyzersAsync( + ArrayBuilder<(DiagnosticAnalyzer, DocumentAnalysisData)> analyzersAndExistingData, + ImmutableArray oldMemberSpans, + PooledDictionary> builder) + { + if (analyzersAndExistingData.Count == 0) + return; + + executor = executor.With(analysisScope.WithSpan(changedMember.FullSpan)); + await ExecuteAnalyzersAsync(executor, analyzersAndExistingData, oldMemberSpans, builder).ConfigureAwait(false); + } + + async Task ExecuteDocumentBasedAnalyzersAsync( + ArrayBuilder<(DiagnosticAnalyzer, DocumentAnalysisData)> analyzersAndExistingData, + ImmutableArray oldMemberSpans, + PooledDictionary> builder) + { + if (analyzersAndExistingData.Count == 0) + return; + + executor = executor.With(analysisScope.WithSpan(null)); + await ExecuteAnalyzersAsync(executor, analyzersAndExistingData, oldMemberSpans, builder).ConfigureAwait(false); + } + + async Task ExecuteAnalyzersAsync( + DocumentAnalysisExecutor executor, + IEnumerable<(DiagnosticAnalyzer, DocumentAnalysisData)> analyzersAndExistingData, + ImmutableArray oldMemberSpans, + PooledDictionary> builder) + { + var analysisScope = executor.AnalysisScope; + + Debug.Assert(changedMember != null); + Debug.Assert(analysisScope.Kind == AnalysisKind.Semantic); + + foreach (var (analyzer, existingData) in analyzersAndExistingData) + { + var diagnostics = await computeAnalyzerDiagnosticsAsync(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, existingData, analyzer, + executor, changedMember, changedMemberId, + oldMemberSpans, computeAnalyzerDiagnosticsAsync, cancellationToken).ConfigureAwait(false); + } + + builder.Add(analyzer, diagnostics); + } + } + } + + private async Task<(SyntaxNode changedMember, int changedMemberId, ImmutableArray memberSpans, Document lastDocument)?> TryGetChangedMemberAsync( + Document document, + SyntaxNode root, + CancellationToken cancellationToken) + { + if (!_lastDocumentWithCachedDiagnostics.TryGetTarget(out var lastDocument) + || lastDocument?.Id != document.Id) + { + return null; + } + + var documentDifferenceService = document.GetRequiredLanguageService(); + var differenceResult = await documentDifferenceService.GetDifferenceAsync(lastDocument, document, cancellationToken).ConfigureAwait(false); + if (differenceResult?.ChangedMember is not { } changedMember) + { + return null; + } + + var syntaxFacts = document.GetRequiredLanguageService(); + var members = syntaxFacts.GetMethodLevelMembers(root); + var memberSpans = members.SelectAsArray(member => member.FullSpan); + var changedMemberId = members.IndexOf(changedMember); + 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); + Debug.Assert(diagnostics.All(d => !d.HasTextSpan || changedMember.FullSpan.IntersectsWith(d.GetTextSpan()))); + + // 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. + if (TryGetUpdatedDocumentDiagnostics(existingData, oldMemberSpans, diagnostics, changedMember.SyntaxTree, 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, 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.HasTextSpan) + { + resultBuilder.Add(diagnostic); + continue; + } + + var diagnosticSpan = diagnostic.GetTextSpan(); + 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.SourceSpan.HasValue && l.SourceSpan.Value.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.SourceSpan.HasValue && oldSpan.End > l.SourceSpan.Value.Start)) + { + updatedDiagnostics = default; + return false; + } + + resultBuilder.Add(UpdateLocations(diagnostic, tree, 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, 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) + { + // Do not need to update additional locations without source span + if (!location.SourceSpan.HasValue) + return location; + + var diagnosticSpan = location.SourceSpan.Value; + var start = Math.Min(Math.Max(diagnosticSpan.Start + delta, 0), tree.Length); + var newSpan = new TextSpan(start, start >= tree.Length ? 0 : diagnosticSpan.Length); + return location.WithSpan(newSpan, tree); + } + } + } + } + } +} diff --git a/src/Features/LanguageServer/Protocol/Features/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer.IncrementalMemberEditAnalyzer_MemberSpans.cs b/src/Features/LanguageServer/Protocol/Features/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer.IncrementalMemberEditAnalyzer_MemberSpans.cs new file mode 100644 index 0000000000000..0cf8570ac3410 --- /dev/null +++ b/src/Features/LanguageServer/Protocol/Features/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer.IncrementalMemberEditAnalyzer_MemberSpans.cs @@ -0,0 +1,62 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .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.LanguageService; +using Microsoft.CodeAnalysis.Shared.Extensions; +using Microsoft.CodeAnalysis.Text; +using Roslyn.Utilities; + +namespace Microsoft.CodeAnalysis.Diagnostics.EngineV2 +{ + internal partial class DiagnosticIncrementalAnalyzer + { + private sealed partial class IncrementalMemberEditAnalyzer + { + /// + /// Spans of member nodes for incremental analysis. + /// + private readonly record struct MemberSpans(DocumentId DocumentId, VersionStamp Version, ImmutableArray Spans); + + private readonly object _gate = new(); + private MemberSpans _savedMemberSpans; + + private async Task> GetOrCreateMemberSpansAsync(Document document, VersionStamp version, CancellationToken cancellationToken) + { + lock (_gate) + { + if (_savedMemberSpans.DocumentId == document.Id && _savedMemberSpans.Version == version) + return _savedMemberSpans.Spans; + } + + var memberSpans = await CreateMemberSpansAsync(document, version, cancellationToken).ConfigureAwait(false); + + lock (_gate) + { + _savedMemberSpans = new MemberSpans(document.Id, version, memberSpans); + } + + return memberSpans; + + static async Task> CreateMemberSpansAsync(Document document, VersionStamp version, CancellationToken cancellationToken) + { + var service = document.GetRequiredLanguageService(); + var root = await document.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false); + var members = service.GetMethodLevelMembers(root); + return members.SelectAsArray(m => m.FullSpan); + } + } + + private void SaveMemberSpans(DocumentId documentId, VersionStamp version, ImmutableArray memberSpans) + { + lock (_gate) + { + _savedMemberSpans = new MemberSpans(documentId, version, memberSpans); + } + } + } + } +} diff --git a/src/Features/LanguageServer/Protocol/Features/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer.ProjectState.cs b/src/Features/LanguageServer/Protocol/Features/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer.ProjectState.cs index ccb246f172ac1..5457e602fbace 100644 --- a/src/Features/LanguageServer/Protocol/Features/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer.ProjectState.cs +++ b/src/Features/LanguageServer/Protocol/Features/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer.ProjectState.cs @@ -206,7 +206,7 @@ public async ValueTask SaveToInMemoryStorageAsync(Project project, DiagnosticAna // 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.Workspace.Services.GetService()?.Options.EnableOpeningSourceGeneratedFiles == true) + && project.Solution.Services.GetService()?.Options.EnableOpeningSourceGeneratedFiles == true) { document = await project.GetSourceGeneratedDocumentAsync(documentId, CancellationToken.None).ConfigureAwait(false); } @@ -256,7 +256,7 @@ public async ValueTask MergeAsync(ActiveFileState state, TextDocument document, // keep from build flag if full analysis is off var fromBuild = fullAnalysis ? false : lastResult.FromBuild; - var languageServices = document.Project.LanguageServices; + var languageServices = document.Project.Services; var simplifierOptions = (languageServices.GetService() != null) ? globalOptions.GetSimplifierOptions(languageServices) : null; var openFileOnlyAnalyzer = _owner.Analyzer.IsOpenFileOnly(simplifierOptions); diff --git a/src/Features/LanguageServer/Protocol/Features/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer.cs b/src/Features/LanguageServer/Protocol/Features/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer.cs index 89bf1b1f00c9d..cb621104e078c 100644 --- a/src/Features/LanguageServer/Protocol/Features/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer.cs +++ b/src/Features/LanguageServer/Protocol/Features/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer.cs @@ -33,6 +33,7 @@ internal partial class DiagnosticIncrementalAnalyzer : IIncrementalAnalyzer private readonly StateManager _stateManager; private readonly InProcOrRemoteHostAnalyzerRunner _diagnosticAnalyzerRunner; private readonly IDocumentTrackingService _documentTrackingService; + private readonly IncrementalMemberEditAnalyzer _incrementalMemberEditAnalyzer = new(); #if NETSTANDARD private ConditionalWeakTable _projectCompilationsWithAnalyzers = new(); diff --git a/src/Features/LanguageServer/Protocol/Features/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer_GetDiagnostics.cs b/src/Features/LanguageServer/Protocol/Features/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer_GetDiagnostics.cs index 9fa626514040f..12bf16266848a 100644 --- a/src/Features/LanguageServer/Protocol/Features/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer_GetDiagnostics.cs +++ b/src/Features/LanguageServer/Protocol/Features/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer_GetDiagnostics.cs @@ -207,7 +207,7 @@ private static async Task> GetProjectStateDiagnos // file doesn't exist in current solution var document = await project.Solution.GetDocumentAsync( documentId, - includeSourceGenerated: project.Solution.Workspace.Services.GetService()?.Options.EnableOpeningSourceGeneratedFiles == true, + includeSourceGenerated: project.Solution.Services.GetService()?.Options.EnableOpeningSourceGeneratedFiles == true, cancellationToken).ConfigureAwait(false); if (document == null) diff --git a/src/Features/LanguageServer/Protocol/Features/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer_GetDiagnosticsForSpan.cs b/src/Features/LanguageServer/Protocol/Features/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer_GetDiagnosticsForSpan.cs index 0c2bb8bfc7ad7..d04be1792830f 100644 --- a/src/Features/LanguageServer/Protocol/Features/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer_GetDiagnosticsForSpan.cs +++ b/src/Features/LanguageServer/Protocol/Features/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer_GetDiagnosticsForSpan.cs @@ -159,16 +159,16 @@ public async Task TryGetAsync(ArrayBuilder list, Cancellat var containsFullResult = true; // 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 _2 = ArrayBuilder.GetInstance(out var semanticSpanBasedAnalyzers); - using var _3 = ArrayBuilder.GetInstance(out var semanticDocumentBasedAnalyzers); + using var _1 = ArrayBuilder.GetInstance(out var syntaxAnalyzers); + using var _2 = ArrayBuilder.GetInstance(out var semanticSpanBasedAnalyzers); + using var _3 = ArrayBuilder.GetInstance(out var semanticDocumentBasedAnalyzers); foreach (var stateSet in _stateSets) { if (!ShouldIncludeAnalyzer(stateSet.Analyzer, _shouldIncludeDiagnostic, _owner)) continue; if (!await TryAddCachedDocumentDiagnosticsAsync(stateSet, AnalysisKind.Syntax, list, cancellationToken).ConfigureAwait(false)) - syntaxAnalyzers.Add(stateSet.Analyzer); + syntaxAnalyzers.Add(stateSet); if (!await TryAddCachedDocumentDiagnosticsAsync(stateSet, AnalysisKind.Semantic, list, cancellationToken).ConfigureAwait(false)) { @@ -181,15 +181,15 @@ public async Task TryGetAsync(ArrayBuilder list, Cancellat else { var stateSets = spanBased ? semanticSpanBasedAnalyzers : semanticDocumentBasedAnalyzers; - stateSets.Add(stateSet.Analyzer); + stateSets.Add(stateSet); } } } // Compute diagnostics for non-cached state sets. - await ComputeDocumentDiagnosticsAsync(syntaxAnalyzers.ToImmutable(), AnalysisKind.Syntax, _range, list, cancellationToken).ConfigureAwait(false); - await ComputeDocumentDiagnosticsAsync(semanticSpanBasedAnalyzers.ToImmutable(), AnalysisKind.Semantic, _range, list, cancellationToken).ConfigureAwait(false); - await ComputeDocumentDiagnosticsAsync(semanticDocumentBasedAnalyzers.ToImmutable(), AnalysisKind.Semantic, span: null, list, cancellationToken).ConfigureAwait(false); + await ComputeDocumentDiagnosticsAsync(syntaxAnalyzers.ToImmutable(), AnalysisKind.Syntax, _range, list, supportsSpanBasedAnalysis: false, cancellationToken).ConfigureAwait(false); + await ComputeDocumentDiagnosticsAsync(semanticSpanBasedAnalyzers.ToImmutable(), AnalysisKind.Semantic, _range, list, supportsSpanBasedAnalysis: true, cancellationToken).ConfigureAwait(false); + await ComputeDocumentDiagnosticsAsync(semanticDocumentBasedAnalyzers.ToImmutable(), AnalysisKind.Semantic, span: null, list, supportsSpanBasedAnalysis: false, cancellationToken).ConfigureAwait(false); // If we are blocked for data, then we should always have full result. Debug.Assert(!_blockForData || containsFullResult); @@ -265,35 +265,99 @@ private async Task TryAddCachedDocumentDiagnosticsAsync( } private async Task ComputeDocumentDiagnosticsAsync( - ImmutableArray analyzers, + ImmutableArray stateSets, AnalysisKind kind, TextSpan? span, - ArrayBuilder list, + ArrayBuilder builder, + bool supportsSpanBasedAnalysis, CancellationToken cancellationToken) { - analyzers = analyzers.WhereAsArray(a => MatchesPriority(a)); + Debug.Assert(!supportsSpanBasedAnalysis || kind == AnalysisKind.Semantic); + Debug.Assert(!supportsSpanBasedAnalysis || stateSets.All(stateSet => stateSet.Analyzer.SupportsSpanBasedSemanticDiagnosticAnalysis())); + + stateSets = stateSets.WhereAsArray(s => MatchesPriority(s.Analyzer)); - if (analyzers.IsEmpty) + if (stateSets.IsEmpty) return; + var analyzers = stateSets.SelectAsArray(stateSet => stateSet.Analyzer); var analysisScope = new DocumentAnalysisScope(_document, span, analyzers, kind); var executor = new DocumentAnalysisExecutor(analysisScope, _compilationWithAnalyzers, _owner._diagnosticAnalyzerRunner, logPerformanceInfo: false); - foreach (var analyzer in analyzers) + var version = await GetDiagnosticVersionAsync(_document.Project, cancellationToken).ConfigureAwait(false); + + // If we are computing full document diagnostics, and the provided analyzers + // support span based analysis, we will attempt to perform incremental + // member edit analysis. + // This analysis is currently guarded with 'IncrementalMemberEditAnalysisFeatureFlag' + var incrementalAnalysis = !span.HasValue + && supportsSpanBasedAnalysis + && _document.SupportsSyntaxTree + && _owner.GlobalOptions.GetOption(DiagnosticOptionsStorage.IncrementalMemberEditAnalysisFeatureFlag); + + ImmutableDictionary> diagnosticsMap; + if (incrementalAnalysis) + { + diagnosticsMap = await _owner._incrementalMemberEditAnalyzer.ComputeDiagnosticsAsync( + executor, + stateSets, + version, + ComputeDocumentDiagnosticsForAnalyzerCoreAsync, + ComputeDocumentDiagnosticsCoreAsync, + cancellationToken).ConfigureAwait(false); + } + else + { + diagnosticsMap = await ComputeDocumentDiagnosticsCoreAsync(executor, cancellationToken).ConfigureAwait(false); + } + + foreach (var stateSet in stateSets) { - cancellationToken.ThrowIfCancellationRequested(); + var diagnostics = diagnosticsMap[stateSet.Analyzer]; + builder.AddRange(diagnostics.Where(ShouldInclude)); - var analyzerTypeName = analyzer.GetType().Name; - using (_addOperationScope?.Invoke(analyzerTypeName)) - using (_addOperationScope is object ? RoslynEventSource.LogInformationalBlock(FunctionId.DiagnosticAnalyzerService_GetDiagnosticsForSpanAsync, analyzerTypeName, cancellationToken) : default) + // Cache the computed diagnostics if they were computed for the entire document. + if (!span.HasValue) { - var dx = await executor.ComputeDiagnosticsAsync(analyzer, cancellationToken).ConfigureAwait(false); - if (dx != null) - { - // no state yet - list.AddRange(dx.Where(ShouldInclude)); - } + var state = stateSet.GetOrCreateActiveFileState(_document.Id); + var data = new DocumentAnalysisData(version, diagnostics); + state.Save(executor.AnalysisScope.Kind, data); } } + + if (incrementalAnalysis) + _owner._incrementalMemberEditAnalyzer.UpdateDocumentWithCachedDiagnostics(_document); + } + + private async Task>> ComputeDocumentDiagnosticsCoreAsync( + DocumentAnalysisExecutor executor, + CancellationToken cancellationToken) + { + using var _ = PooledDictionary>.GetInstance(out var builder); + foreach (var analyzer in executor.AnalysisScope.Analyzers) + { + var diagnostics = await ComputeDocumentDiagnosticsForAnalyzerCoreAsync(analyzer, executor, cancellationToken).ConfigureAwait(false); + builder.Add(analyzer, diagnostics); + } + + return builder.ToImmutableDictionary(); + } + + private async Task> ComputeDocumentDiagnosticsForAnalyzerCoreAsync( + DiagnosticAnalyzer analyzer, + DocumentAnalysisExecutor executor, + CancellationToken cancellationToken) + { + cancellationToken.ThrowIfCancellationRequested(); + + var analyzerTypeName = analyzer.GetType().Name; + var document = executor.AnalysisScope.TextDocument; + + using (_addOperationScope?.Invoke(analyzerTypeName)) + using (_addOperationScope is object ? RoslynEventSource.LogInformationalBlock(FunctionId.DiagnosticAnalyzerService_GetDiagnosticsForSpanAsync, analyzerTypeName, cancellationToken) : default) + { + var diagnostics = await executor.ComputeDiagnosticsAsync(analyzer, cancellationToken).ConfigureAwait(false); + return diagnostics?.ToImmutableArrayOrEmpty() ?? ImmutableArray.Empty; + } } private bool MatchesPriority(DiagnosticAnalyzer analyzer) diff --git a/src/Features/LanguageServer/Protocol/Features/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer_IncrementalAnalyzer.cs b/src/Features/LanguageServer/Protocol/Features/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer_IncrementalAnalyzer.cs index 580473cd337ed..212328a535447 100644 --- a/src/Features/LanguageServer/Protocol/Features/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer_IncrementalAnalyzer.cs +++ b/src/Features/LanguageServer/Protocol/Features/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer_IncrementalAnalyzer.cs @@ -90,7 +90,7 @@ private async Task AnalyzeDocumentForKindAsync(TextDocument document, AnalysisKi { var analysisScope = new DocumentAnalysisScope(document, span: null, nonCachedStateSets.SelectAsArray(s => s.Analyzer), kind); var executor = new DocumentAnalysisExecutor(analysisScope, compilationWithAnalyzers, _diagnosticAnalyzerRunner, logPerformanceInfo: true, onAnalysisException: OnAnalysisException); - var logTelemetry = GlobalOptions.GetOption(DiagnosticOptions.LogTelemetryForBackgroundAnalyzerExecution); + var logTelemetry = GlobalOptions.GetOption(DiagnosticOptionsStorage.LogTelemetryForBackgroundAnalyzerExecution); foreach (var stateSet in nonCachedStateSets) { var computedData = await ComputeDocumentAnalysisDataAsync(executor, stateSet, logTelemetry, cancellationToken).ConfigureAwait(false); @@ -564,7 +564,7 @@ private async Task RaiseProjectDiagnosticsCreatedAsync(Project project, StateSet // 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.Workspace.Services.GetService()?.Options.EnableOpeningSourceGeneratedFiles == true) + && project.Solution.Services.GetService()?.Options.EnableOpeningSourceGeneratedFiles == true) { document = await project.GetSourceGeneratedDocumentAsync(documentId, cancellationToken).ConfigureAwait(false); } diff --git a/src/Features/LanguageServer/Protocol/Features/Diagnostics/IDiagnosticService.cs b/src/Features/LanguageServer/Protocol/Features/Diagnostics/IDiagnosticService.cs index ba294bd07fd50..8169798ba0c72 100644 --- a/src/Features/LanguageServer/Protocol/Features/Diagnostics/IDiagnosticService.cs +++ b/src/Features/LanguageServer/Protocol/Features/Diagnostics/IDiagnosticService.cs @@ -15,8 +15,6 @@ namespace Microsoft.CodeAnalysis.Diagnostics /// internal interface IDiagnosticService { - IGlobalOptionService GlobalOptions { get; } - /// /// Event to get notified as new diagnostics are discovered by IDiagnosticUpdateSource /// @@ -25,24 +23,6 @@ internal interface IDiagnosticService /// event EventHandler DiagnosticsUpdated; - /// - /// This call is equivalent to passing in . - /// - [Obsolete("Legacy overload for TypeScript. Use GetPullDiagnostics or GetPushDiagnostics instead.", error: false)] - ImmutableArray GetDiagnostics( - Workspace workspace, ProjectId? projectId, DocumentId? documentId, object? id, bool includeSuppressedDiagnostics, CancellationToken cancellationToken); - - /// - /// Get current diagnostics stored in IDiagnosticUpdateSource. - /// - /// Option controlling if pull diagnostics are allowed for the client. The - /// only provides diagnostics for either push or pull purposes (but not both). - /// If the caller's desired purpose doesn't match the option value, then this will return nothing, otherwise it - /// will return the requested diagnostics. - ValueTask> GetPullDiagnosticsAsync( - Workspace workspace, ProjectId? projectId, DocumentId? documentId, object? id, bool includeSuppressedDiagnostics, - DiagnosticMode diagnosticMode, CancellationToken cancellationToken); - /// /// Get current diagnostics stored in IDiagnosticUpdateSource. /// @@ -55,8 +35,7 @@ ValueTask> GetPushDiagnosticsAsync( DiagnosticMode diagnosticMode, CancellationToken cancellationToken); /// - /// Get current buckets storing our grouped diagnostics. Specific buckets can be retrieved by calling . + /// Get current buckets storing our grouped diagnostics. /// /// Option controlling if pull diagnostics are allowed for the client. The /// only provides diagnostics for either push or pull purposes (but not both). @@ -67,8 +46,7 @@ ImmutableArray GetPullDiagnosticBuckets( DiagnosticMode diagnosticMode, CancellationToken cancellationToken); /// - /// Get current buckets storing our grouped diagnostics. Specific buckets can be retrieved by calling . + /// Get current buckets storing our grouped diagnostics. /// /// Option controlling if pull diagnostics are allowed for the client. The only provides diagnostics for either push or pull purposes (but not both). If diff --git a/src/Features/LanguageServer/Protocol/Features/Diagnostics/IDiagnosticServiceExtensions.cs b/src/Features/LanguageServer/Protocol/Features/Diagnostics/IDiagnosticServiceExtensions.cs deleted file mode 100644 index 1cf00faa3df8d..0000000000000 --- a/src/Features/LanguageServer/Protocol/Features/Diagnostics/IDiagnosticServiceExtensions.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.Collections.Immutable; -using System.Threading; -using System.Threading.Tasks; -using Microsoft.CodeAnalysis.PooledObjects; -using Roslyn.Utilities; - -namespace Microsoft.CodeAnalysis.Diagnostics -{ - internal static class IDiagnosticServiceExtensions - { - public static ValueTask> GetPullDiagnosticsAsync(this IDiagnosticService service, DiagnosticBucket bucket, bool includeSuppressedDiagnostics, DiagnosticMode diagnosticMode, CancellationToken cancellationToken) - => service.GetPullDiagnosticsAsync(bucket.Workspace, bucket.ProjectId, bucket.DocumentId, bucket.Id, includeSuppressedDiagnostics, diagnosticMode, cancellationToken); - - public static ValueTask> GetPushDiagnosticsAsync(this IDiagnosticService service, DiagnosticBucket bucket, bool includeSuppressedDiagnostics, DiagnosticMode diagnosticMode, CancellationToken cancellationToken) - => service.GetPushDiagnosticsAsync(bucket.Workspace, bucket.ProjectId, bucket.DocumentId, bucket.Id, includeSuppressedDiagnostics, diagnosticMode, cancellationToken); - - public static ValueTask> GetPushDiagnosticsAsync( - this IDiagnosticService service, - Document document, - bool includeSuppressedDiagnostics, - DiagnosticMode diagnosticMode, - CancellationToken cancellationToken) - { - return service.GetPushDiagnosticsAsync(document.Project.Solution.Workspace, document.Project.Id, document.Id, id: null, includeSuppressedDiagnostics, diagnosticMode, cancellationToken); - } - - public static ValueTask> GetPullDiagnosticsAsync( - this IDiagnosticService service, - Document document, - bool includeSuppressedDiagnostics, - DiagnosticMode diagnosticMode, - CancellationToken cancellationToken) - { - return service.GetPullDiagnosticsAsync(document.Project.Solution.Workspace, document.Project.Id, document.Id, id: null, includeSuppressedDiagnostics, diagnosticMode, cancellationToken); - } - } -} diff --git a/src/Features/LanguageServer/Protocol/Features/Options/AddImportPlacementOptionsStorage.cs b/src/Features/LanguageServer/Protocol/Features/Options/AddImportPlacementOptionsStorage.cs index 0f32537520e84..a43e2f198fab8 100644 --- a/src/Features/LanguageServer/Protocol/Features/Options/AddImportPlacementOptionsStorage.cs +++ b/src/Features/LanguageServer/Protocol/Features/Options/AddImportPlacementOptionsStorage.cs @@ -17,8 +17,8 @@ internal interface IAddImportPlacementOptionsStorage : ILanguageService internal static class AddImportPlacementOptionsStorage { public static ValueTask GetAddImportPlacementOptionsAsync(this Document document, IGlobalOptionService globalOptions, CancellationToken cancellationToken) - => document.GetAddImportPlacementOptionsAsync(globalOptions.GetAddImportPlacementOptions(document.Project.LanguageServices), cancellationToken); + => document.GetAddImportPlacementOptionsAsync(globalOptions.GetAddImportPlacementOptions(document.Project.Services), cancellationToken); - public static AddImportPlacementOptions GetAddImportPlacementOptions(this IGlobalOptionService globalOptions, HostLanguageServices languageServices) + public static AddImportPlacementOptions GetAddImportPlacementOptions(this IGlobalOptionService globalOptions, LanguageServices languageServices) => languageServices.GetRequiredService().GetOptions(globalOptions); } diff --git a/src/Features/LanguageServer/Protocol/Features/Options/BlockStructureOptionsStorage.cs b/src/Features/LanguageServer/Protocol/Features/Options/BlockStructureOptionsStorage.cs index e12c0f69c8554..5416070de84c6 100644 --- a/src/Features/LanguageServer/Protocol/Features/Options/BlockStructureOptionsStorage.cs +++ b/src/Features/LanguageServer/Protocol/Features/Options/BlockStructureOptionsStorage.cs @@ -9,7 +9,7 @@ namespace Microsoft.CodeAnalysis.Structure; internal static class BlockStructureOptionsStorage { public static BlockStructureOptions GetBlockStructureOptions(this IGlobalOptionService globalOptions, Project project) - => GetBlockStructureOptions(globalOptions, project.Language, isMetadataAsSource: project.Solution.Workspace.Kind == WorkspaceKind.MetadataAsSource); + => GetBlockStructureOptions(globalOptions, project.Language, isMetadataAsSource: project.Solution.WorkspaceKind == WorkspaceKind.MetadataAsSource); public static BlockStructureOptions GetBlockStructureOptions(this IGlobalOptionService globalOptions, string language, bool isMetadataAsSource) => new() diff --git a/src/Features/LanguageServer/Protocol/Features/Options/CodeActionOptionsStorage.cs b/src/Features/LanguageServer/Protocol/Features/Options/CodeActionOptionsStorage.cs index f2edcf9f4f9d7..eb7be81e03229 100644 --- a/src/Features/LanguageServer/Protocol/Features/Options/CodeActionOptionsStorage.cs +++ b/src/Features/LanguageServer/Protocol/Features/Options/CodeActionOptionsStorage.cs @@ -22,7 +22,7 @@ internal static class CodeActionOptionsStorage public static readonly PerLanguageOption2 WrappingColumn = new("FormattingOptions", "WrappingColumn", CodeActionOptions.DefaultWrappingColumn); - public static CodeActionOptions GetCodeActionOptions(this IGlobalOptionService globalOptions, HostLanguageServices languageServices) + public static CodeActionOptions GetCodeActionOptions(this IGlobalOptionService globalOptions, LanguageServices languageServices) => new( cleanupOptions: globalOptions.GetCodeCleanupOptions(languageServices), codeGenerationOptions: globalOptions.GetCodeGenerationOptions(languageServices), diff --git a/src/Features/LanguageServer/Protocol/Features/Options/CodeCleanupOptionsStorage.cs b/src/Features/LanguageServer/Protocol/Features/Options/CodeCleanupOptionsStorage.cs index 9db899dda6381..148aacc336ccb 100644 --- a/src/Features/LanguageServer/Protocol/Features/Options/CodeCleanupOptionsStorage.cs +++ b/src/Features/LanguageServer/Protocol/Features/Options/CodeCleanupOptionsStorage.cs @@ -16,9 +16,9 @@ namespace Microsoft.CodeAnalysis.CodeCleanup; internal static class CodeCleanupOptionsStorage { public static ValueTask GetCodeCleanupOptionsAsync(this Document document, IGlobalOptionService globalOptions, CancellationToken cancellationToken) - => document.GetCodeCleanupOptionsAsync(globalOptions.GetCodeCleanupOptions(document.Project.LanguageServices), cancellationToken); + => document.GetCodeCleanupOptionsAsync(globalOptions.GetCodeCleanupOptions(document.Project.Services), cancellationToken); - public static CodeCleanupOptions GetCodeCleanupOptions(this IGlobalOptionService globalOptions, HostLanguageServices languageServices) + public static CodeCleanupOptions GetCodeCleanupOptions(this IGlobalOptionService globalOptions, LanguageServices languageServices) => new( globalOptions.GetSyntaxFormattingOptions(languageServices), globalOptions.GetSimplifierOptions(languageServices)) diff --git a/src/Features/LanguageServer/Protocol/Features/Options/CodeGenerationOptionsStorage.cs b/src/Features/LanguageServer/Protocol/Features/Options/CodeGenerationOptionsStorage.cs index 58a41a595d1c3..e935a82ab7fc4 100644 --- a/src/Features/LanguageServer/Protocol/Features/Options/CodeGenerationOptionsStorage.cs +++ b/src/Features/LanguageServer/Protocol/Features/Options/CodeGenerationOptionsStorage.cs @@ -21,10 +21,10 @@ internal interface ICodeGenerationOptionsStorage : ILanguageService internal static class CodeGenerationOptionsStorage { public static ValueTask GetCodeGenerationOptionsAsync(this Document document, IGlobalOptionService globalOptions, CancellationToken cancellationToken) - => document.GetCodeGenerationOptionsAsync(globalOptions.GetCodeGenerationOptions(document.Project.LanguageServices), cancellationToken); + => document.GetCodeGenerationOptionsAsync(globalOptions.GetCodeGenerationOptions(document.Project.Services), cancellationToken); public static ValueTask GetCleanCodeGenerationOptionsAsync(this Document document, IGlobalOptionService globalOptions, CancellationToken cancellationToken) - => document.GetCleanCodeGenerationOptionsAsync(globalOptions.GetCleanCodeGenerationOptions(document.Project.LanguageServices), cancellationToken); + => document.GetCleanCodeGenerationOptionsAsync(globalOptions.GetCleanCodeGenerationOptions(document.Project.Services), cancellationToken); public static CodeGenerationOptions.CommonOptions GetCommonCodeGenerationOptions(this IGlobalOptionService globalOptions, string language) => new() @@ -32,12 +32,12 @@ public static CodeGenerationOptions.CommonOptions GetCommonCodeGenerationOptions NamingStyle = globalOptions.GetNamingStylePreferences(language) }; - public static CodeGenerationOptions GetCodeGenerationOptions(this IGlobalOptionService globalOptions, HostLanguageServices languageServices) + public static CodeGenerationOptions GetCodeGenerationOptions(this IGlobalOptionService globalOptions, LanguageServices languageServices) => languageServices.GetRequiredService().GetOptions(globalOptions); - public static CodeAndImportGenerationOptions GetCodeAndImportGenerationOptions(this IGlobalOptionService globalOptions, HostLanguageServices languageServices) + public static CodeAndImportGenerationOptions GetCodeAndImportGenerationOptions(this IGlobalOptionService globalOptions, LanguageServices languageServices) => new(globalOptions.GetCodeGenerationOptions(languageServices), globalOptions.GetAddImportPlacementOptions(languageServices)); - public static CleanCodeGenerationOptions GetCleanCodeGenerationOptions(this IGlobalOptionService globalOptions, HostLanguageServices languageServices) + public static CleanCodeGenerationOptions GetCleanCodeGenerationOptions(this IGlobalOptionService globalOptions, LanguageServices languageServices) => new(globalOptions.GetCodeGenerationOptions(languageServices), globalOptions.GetCodeCleanupOptions(languageServices)); } diff --git a/src/Features/LanguageServer/Protocol/Features/Options/CodeStyleOptionsStorage.cs b/src/Features/LanguageServer/Protocol/Features/Options/CodeStyleOptionsStorage.cs index 3d02d3c650b76..5bddc86c403d0 100644 --- a/src/Features/LanguageServer/Protocol/Features/Options/CodeStyleOptionsStorage.cs +++ b/src/Features/LanguageServer/Protocol/Features/Options/CodeStyleOptionsStorage.cs @@ -21,7 +21,7 @@ internal interface ICodeStyleOptionsStorage : ILanguageService internal static class CodeStyleOptionsStorage { - public static IdeCodeStyleOptions GetCodeStyleOptions(this IGlobalOptionService globalOptions, HostLanguageServices languageServices) + public static IdeCodeStyleOptions GetCodeStyleOptions(this IGlobalOptionService globalOptions, LanguageServices languageServices) => languageServices.GetRequiredService().GetOptions(globalOptions); public static IdeCodeStyleOptions.CommonOptions GetCommonCodeStyleOptions(this IGlobalOptionService globalOptions, string language) @@ -30,7 +30,7 @@ public static IdeCodeStyleOptions.CommonOptions GetCommonCodeStyleOptions(this I PreferObjectInitializer = globalOptions.GetOption(CodeStyleOptions2.PreferObjectInitializer, language), PreferCollectionInitializer = globalOptions.GetOption(CodeStyleOptions2.PreferCollectionInitializer, language), PreferSimplifiedBooleanExpressions = globalOptions.GetOption(CodeStyleOptions2.PreferSimplifiedBooleanExpressions, language), - OperatorPlacementWhenWrapping = globalOptions.GetOption(CodeStyleOptions2.OperatorPlacementWhenWrapping, language), + OperatorPlacementWhenWrapping = globalOptions.GetOption(CodeStyleOptions2.OperatorPlacementWhenWrapping), PreferCoalesceExpression = globalOptions.GetOption(CodeStyleOptions2.PreferCoalesceExpression, language), PreferNullPropagation = globalOptions.GetOption(CodeStyleOptions2.PreferNullPropagation, language), PreferExplicitTupleNames = globalOptions.GetOption(CodeStyleOptions2.PreferExplicitTupleNames, language), @@ -49,7 +49,7 @@ public static IdeCodeStyleOptions.CommonOptions GetCommonCodeStyleOptions(this I OtherBinaryParentheses = globalOptions.GetOption(CodeStyleOptions2.OtherBinaryParentheses, language), RelationalBinaryParentheses = globalOptions.GetOption(CodeStyleOptions2.RelationalBinaryParentheses, language), OtherParentheses = globalOptions.GetOption(CodeStyleOptions2.OtherParentheses, language), - ForEachExplicitCastInSource = globalOptions.GetOption(CodeStyleOptions2.ForEachExplicitCastInSource, language), + ForEachExplicitCastInSource = globalOptions.GetOption(CodeStyleOptions2.ForEachExplicitCastInSource), PreferNamespaceAndFolderMatchStructure = globalOptions.GetOption(CodeStyleOptions2.PreferNamespaceAndFolderMatchStructure, language), AllowMultipleBlankLines = globalOptions.GetOption(CodeStyleOptions2.AllowMultipleBlankLines, language), AllowStatementImmediatelyAfterBlock = globalOptions.GetOption(CodeStyleOptions2.AllowStatementImmediatelyAfterBlock, language), diff --git a/src/Features/LanguageServer/Protocol/Features/Options/CompletionOptionsStorage.cs b/src/Features/LanguageServer/Protocol/Features/Options/CompletionOptionsStorage.cs index 86fe016f831e9..e12ebce56e77b 100644 --- a/src/Features/LanguageServer/Protocol/Features/Options/CompletionOptionsStorage.cs +++ b/src/Features/LanguageServer/Protocol/Features/Options/CompletionOptionsStorage.cs @@ -3,6 +3,7 @@ // See the LICENSE file in the project root for more information. using Microsoft.CodeAnalysis.CodeStyle; +using Microsoft.CodeAnalysis.Completion.Providers.Snippets; using Microsoft.CodeAnalysis.Options; namespace Microsoft.CodeAnalysis.Completion; @@ -27,7 +28,9 @@ public static CompletionOptions GetCompletionOptions(this IGlobalOptionService o ProvideRegexCompletions = options.GetOption(ProvideRegexCompletions, language), ForceExpandedCompletionIndexCreation = options.GetOption(ForceExpandedCompletionIndexCreation), UpdateImportCompletionCacheInBackground = options.GetOption(UpdateImportCompletionCacheInBackground), - NamingStyleFallbackOptions = options.GetNamingStylePreferences(language) + NamingStyleFallbackOptions = options.GetNamingStylePreferences(language), + ShowNewSnippetExperience = options.GetOption(ShowNewSnippetExperience, language), + SnippetCompletion = options.GetOption(ShowNewSnippetExperienceFeatureFlag) }; // feature flags @@ -40,11 +43,17 @@ public static CompletionOptions GetCompletionOptions(this IGlobalOptionService o CompletionOptions.Default.UnnamedSymbolCompletionDisabled, new FeatureFlagStorageLocation("Roslyn.UnnamedSymbolCompletionDisabled")); - // This is serialized by the Visual Studio-specific LanguageSettingsPersister - public static readonly PerLanguageOption2 HideAdvancedMembers = new(nameof(CompletionOptions), nameof(HideAdvancedMembers), CompletionOptions.Default.HideAdvancedMembers); + public static readonly Option2 ShowNewSnippetExperienceFeatureFlag = new(nameof(CompletionOptions), nameof(ShowNewSnippetExperienceFeatureFlag), + CompletionOptions.Default.SnippetCompletion, + new FeatureFlagStorageLocation("Roslyn.SnippetCompletion")); - // This is serialized by the Visual Studio-specific LanguageSettingsPersister - public static readonly PerLanguageOption2 TriggerOnTyping = new(nameof(CompletionOptions), nameof(TriggerOnTyping), CompletionOptions.Default.TriggerOnTyping); + public static readonly PerLanguageOption2 HideAdvancedMembers = new( + "CompletionOptions", "HideAdvancedMembers", CompletionOptions.Default.HideAdvancedMembers, + new RoamingProfileStorageLocation("TextEditor.%LANGUAGE%.Hide Advanced Auto List Members")); + + public static readonly PerLanguageOption2 TriggerOnTyping = new( + "CompletionOptions", "TriggerOnTyping", CompletionOptions.Default.TriggerOnTyping, + new RoamingProfileStorageLocation("TextEditor.%LANGUAGE%.Auto List Members")); public static readonly PerLanguageOption2 TriggerOnTypingLetters = new(nameof(CompletionOptions), nameof(TriggerOnTypingLetters), CompletionOptions.Default.TriggerOnTypingLetters, storageLocation: new RoamingProfileStorageLocation("TextEditor.%LANGUAGE%.Specific.TriggerOnTypingLetters")); @@ -99,4 +108,8 @@ public static readonly Option2 UpdateImportCompletionCacheInBackground nameof(ProvideDateAndTimeCompletions), CompletionOptions.Default.ProvideDateAndTimeCompletions, storageLocation: new RoamingProfileStorageLocation("TextEditor.%LANGUAGE%.Specific.ProvideDateAndTimeCompletions")); + + public static readonly PerLanguageOption2 ShowNewSnippetExperience + = new(nameof(CompletionOptions), nameof(ShowNewSnippetExperience), CompletionOptions.Default.ShowNewSnippetExperience, + storageLocation: new RoamingProfileStorageLocation("TextEditor.%LANGUAGE%.Specific.ShowNewSnippetExperience")); } diff --git a/src/Features/LanguageServer/Protocol/Features/Options/DiagnosticModeExtensions.cs b/src/Features/LanguageServer/Protocol/Features/Options/DiagnosticModeExtensions.cs index 1a5ef527389ae..e3f727145d68f 100644 --- a/src/Features/LanguageServer/Protocol/Features/Options/DiagnosticModeExtensions.cs +++ b/src/Features/LanguageServer/Protocol/Features/Options/DiagnosticModeExtensions.cs @@ -16,7 +16,7 @@ public static DiagnosticMode GetDiagnosticMode(this IGlobalOptionService globalO // If the workspace diagnostic mode is set to Default, defer to the feature flag service. if (diagnosticModeOption == DiagnosticMode.Default) { - return globalOptions.GetOption(DiagnosticOptions.LspPullDiagnosticsFeatureFlag) ? DiagnosticMode.Pull : DiagnosticMode.Push; + return globalOptions.GetOption(DiagnosticOptionsStorage.LspPullDiagnosticsFeatureFlag) ? DiagnosticMode.Pull : DiagnosticMode.Push; } // Otherwise, defer to the workspace+option to determine what mode we're in. diff --git a/src/Features/Core/Portable/Diagnostics/DiagnosticOptions.cs b/src/Features/LanguageServer/Protocol/Features/Options/DiagnosticOptionsStorage.cs similarity index 76% rename from src/Features/Core/Portable/Diagnostics/DiagnosticOptions.cs rename to src/Features/LanguageServer/Protocol/Features/Options/DiagnosticOptionsStorage.cs index 1422e927ed734..e82b41277c016 100644 --- a/src/Features/Core/Portable/Diagnostics/DiagnosticOptions.cs +++ b/src/Features/LanguageServer/Protocol/Features/Options/DiagnosticOptionsStorage.cs @@ -11,7 +11,7 @@ namespace Microsoft.CodeAnalysis.Diagnostics { - internal sealed class DiagnosticOptions + internal sealed class DiagnosticOptionsStorage { private const string FeatureName = "DiagnosticOptions"; @@ -19,6 +19,10 @@ internal sealed class DiagnosticOptions FeatureName, nameof(LspPullDiagnosticsFeatureFlag), defaultValue: false, new FeatureFlagStorageLocation("Lsp.PullDiagnostics")); + public static readonly Option2 IncrementalMemberEditAnalysisFeatureFlag = new( + FeatureName, nameof(IncrementalMemberEditAnalysisFeatureFlag), defaultValue: false, + new FeatureFlagStorageLocation("Roslyn.IncrementalMemberEditAnalysis")); + public static readonly Option2 LogTelemetryForBackgroundAnalyzerExecution = new( FeatureName, nameof(LogTelemetryForBackgroundAnalyzerExecution), defaultValue: false, new FeatureFlagStorageLocation($"Roslyn.LogTelemetryForBackgroundAnalyzerExecution")); diff --git a/src/Features/LanguageServer/Protocol/Features/Options/DocumentationCommentOptionsStorage.cs b/src/Features/LanguageServer/Protocol/Features/Options/DocumentationCommentOptionsStorage.cs index 0ab002c56b994..b8596c9b3ebeb 100644 --- a/src/Features/LanguageServer/Protocol/Features/Options/DocumentationCommentOptionsStorage.cs +++ b/src/Features/LanguageServer/Protocol/Features/Options/DocumentationCommentOptionsStorage.cs @@ -11,15 +11,6 @@ namespace Microsoft.CodeAnalysis.DocumentationComments; internal static class DocumentationCommentOptionsStorage { - public static async ValueTask GetDocumentationCommentOptionsAsync(this Document document, IGlobalOptionService globalOptions, CancellationToken cancellationToken) - { - var lineFormattingOptions = await document.GetLineFormattingOptionsAsync(globalOptions, cancellationToken).ConfigureAwait(false); - return new() - { - LineFormatting = lineFormattingOptions, - AutoXmlDocCommentGeneration = globalOptions.GetOption(AutoXmlDocCommentGeneration, document.Project.Language), - }; - } public static DocumentationCommentOptions GetDocumentationCommentOptions(this IGlobalOptionService globalOptions, LineFormattingOptions lineFormatting, string language) => new() diff --git a/src/Features/LanguageServer/Protocol/Features/Options/ExtractMethodOptionsStorage.cs b/src/Features/LanguageServer/Protocol/Features/Options/ExtractMethodOptionsStorage.cs index b8f6ced181941..b45ea19579de5 100644 --- a/src/Features/LanguageServer/Protocol/Features/Options/ExtractMethodOptionsStorage.cs +++ b/src/Features/LanguageServer/Protocol/Features/Options/ExtractMethodOptionsStorage.cs @@ -21,7 +21,7 @@ public static ExtractMethodOptions GetExtractMethodOptions(this IGlobalOptionSer DontPutOutOrRefOnStruct = globalOptions.GetOption(DontPutOutOrRefOnStruct, language) }; - public static ExtractMethodGenerationOptions GetExtractMethodGenerationOptions(this IGlobalOptionService globalOptions, HostLanguageServices languageServices) + public static ExtractMethodGenerationOptions GetExtractMethodGenerationOptions(this IGlobalOptionService globalOptions, LanguageServices languageServices) => new(globalOptions.GetCodeGenerationOptions(languageServices)) { ExtractOptions = globalOptions.GetExtractMethodOptions(languageServices.Language), @@ -30,7 +30,7 @@ public static ExtractMethodGenerationOptions GetExtractMethodGenerationOptions(t }; public static ValueTask GetExtractMethodGenerationOptionsAsync(this Document document, IGlobalOptionService globalOptions, CancellationToken cancellationToken) - => document.GetExtractMethodGenerationOptionsAsync(globalOptions.GetExtractMethodGenerationOptions(document.Project.LanguageServices), cancellationToken); + => document.GetExtractMethodGenerationOptionsAsync(globalOptions.GetExtractMethodGenerationOptions(document.Project.Services), cancellationToken); public static readonly PerLanguageOption2 DontPutOutOrRefOnStruct = new( "ExtractMethodOptions", "DontPutOutOrRefOnStruct", ExtractMethodOptions.Default.DontPutOutOrRefOnStruct, diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Options/FeatureFlagStorageLocation.cs b/src/Features/LanguageServer/Protocol/Features/Options/FeatureFlagStorageLocation.cs similarity index 100% rename from src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Options/FeatureFlagStorageLocation.cs rename to src/Features/LanguageServer/Protocol/Features/Options/FeatureFlagStorageLocation.cs diff --git a/src/Features/LanguageServer/Protocol/Features/Options/GlobalCodeActionOptionsProvider.cs b/src/Features/LanguageServer/Protocol/Features/Options/GlobalCodeActionOptionsProvider.cs index 68356e1e08160..cc4b322a28d0f 100644 --- a/src/Features/LanguageServer/Protocol/Features/Options/GlobalCodeActionOptionsProvider.cs +++ b/src/Features/LanguageServer/Protocol/Features/Options/GlobalCodeActionOptionsProvider.cs @@ -42,40 +42,40 @@ public sealed class Provider : public Provider(IGlobalOptionService globalOptions) => _globalOptions = globalOptions; - CodeActionOptions CodeActionOptionsProvider.GetOptions(HostLanguageServices languageService) - => _globalOptions.GetCodeActionOptions(languageService); + CodeActionOptions CodeActionOptionsProvider.GetOptions(LanguageServices languageServices) + => _globalOptions.GetCodeActionOptions(languageServices); - ValueTask OptionsProvider.GetOptionsAsync(HostLanguageServices languageServices, CancellationToken cancellationToken) + ValueTask OptionsProvider.GetOptionsAsync(LanguageServices languageServices, CancellationToken cancellationToken) => ValueTaskFactory.FromResult(_globalOptions.GetLineFormattingOptions(languageServices.Language)); - ValueTask OptionsProvider.GetOptionsAsync(HostLanguageServices languageServices, CancellationToken cancellationToken) + ValueTask OptionsProvider.GetOptionsAsync(LanguageServices languageServices, CancellationToken cancellationToken) => ValueTaskFactory.FromResult(_globalOptions.GetDocumentFormattingOptions(languageServices.Language)); - ValueTask OptionsProvider.GetOptionsAsync(HostLanguageServices languageServices, CancellationToken cancellationToken) + ValueTask OptionsProvider.GetOptionsAsync(LanguageServices languageServices, CancellationToken cancellationToken) => ValueTaskFactory.FromResult(_globalOptions.GetSyntaxFormattingOptions(languageServices)); - ValueTask OptionsProvider.GetOptionsAsync(HostLanguageServices languageServices, CancellationToken cancellationToken) + ValueTask OptionsProvider.GetOptionsAsync(LanguageServices languageServices, CancellationToken cancellationToken) => ValueTaskFactory.FromResult(_globalOptions.GetSimplifierOptions(languageServices)); - ValueTask OptionsProvider.GetOptionsAsync(HostLanguageServices languageServices, CancellationToken cancellationToken) + ValueTask OptionsProvider.GetOptionsAsync(LanguageServices languageServices, CancellationToken cancellationToken) => ValueTaskFactory.FromResult(_globalOptions.GetAddImportPlacementOptions(languageServices)); - ValueTask OptionsProvider.GetOptionsAsync(HostLanguageServices languageServices, CancellationToken cancellationToken) + ValueTask OptionsProvider.GetOptionsAsync(LanguageServices languageServices, CancellationToken cancellationToken) => ValueTaskFactory.FromResult(_globalOptions.GetOrganizeImportsOptions(languageServices.Language)); - ValueTask OptionsProvider.GetOptionsAsync(HostLanguageServices languageServices, CancellationToken cancellationToken) + ValueTask OptionsProvider.GetOptionsAsync(LanguageServices languageServices, CancellationToken cancellationToken) => ValueTaskFactory.FromResult(_globalOptions.GetCodeCleanupOptions(languageServices)); - ValueTask OptionsProvider.GetOptionsAsync(HostLanguageServices languageServices, CancellationToken cancellationToken) + ValueTask OptionsProvider.GetOptionsAsync(LanguageServices languageServices, CancellationToken cancellationToken) => ValueTaskFactory.FromResult(_globalOptions.GetCodeGenerationOptions(languageServices)); - ValueTask OptionsProvider.GetOptionsAsync(HostLanguageServices languageServices, CancellationToken cancellationToken) + ValueTask OptionsProvider.GetOptionsAsync(LanguageServices languageServices, CancellationToken cancellationToken) => ValueTaskFactory.FromResult(_globalOptions.GetNamingStylePreferences(languageServices.Language)); - ValueTask OptionsProvider.GetOptionsAsync(HostLanguageServices languageServices, CancellationToken cancellationToken) + ValueTask OptionsProvider.GetOptionsAsync(LanguageServices languageServices, CancellationToken cancellationToken) => ValueTaskFactory.FromResult(_globalOptions.GetCleanCodeGenerationOptions(languageServices)); - ValueTask OptionsProvider.GetOptionsAsync(HostLanguageServices languageServices, CancellationToken cancellationToken) + ValueTask OptionsProvider.GetOptionsAsync(LanguageServices languageServices, CancellationToken cancellationToken) => ValueTaskFactory.FromResult(_globalOptions.GetCodeAndImportGenerationOptions(languageServices)); } } diff --git a/src/Features/LanguageServer/Protocol/Features/Options/IdeAnalyzerOptionsStorage.cs b/src/Features/LanguageServer/Protocol/Features/Options/IdeAnalyzerOptionsStorage.cs index 34315d5287236..cbda788e10eb9 100644 --- a/src/Features/LanguageServer/Protocol/Features/Options/IdeAnalyzerOptionsStorage.cs +++ b/src/Features/LanguageServer/Protocol/Features/Options/IdeAnalyzerOptionsStorage.cs @@ -15,9 +15,9 @@ namespace Microsoft.CodeAnalysis.Diagnostics; internal static class IdeAnalyzerOptionsStorage { public static IdeAnalyzerOptions GetIdeAnalyzerOptions(this IGlobalOptionService globalOptions, Project project) - => GetIdeAnalyzerOptions(globalOptions, project.LanguageServices); + => GetIdeAnalyzerOptions(globalOptions, project.Services); - public static IdeAnalyzerOptions GetIdeAnalyzerOptions(this IGlobalOptionService globalOptions, HostLanguageServices languageServices) + public static IdeAnalyzerOptions GetIdeAnalyzerOptions(this IGlobalOptionService globalOptions, LanguageServices languageServices) { var language = languageServices.Language; var supportsLanguageSpecificOptions = languageServices.GetService() != null; @@ -25,10 +25,6 @@ public static IdeAnalyzerOptions GetIdeAnalyzerOptions(this IGlobalOptionService return new() { CrashOnAnalyzerException = globalOptions.GetOption(CrashOnAnalyzerException), - FadeOutUnusedImports = globalOptions.GetOption(FadeOutUnusedImports, language), - FadeOutUnreachableCode = globalOptions.GetOption(FadeOutUnreachableCode, language), - FadeOutComplexObjectInitialization = globalOptions.GetOption(FadeOutComplexObjectInitialization, language), - FadeOutComplexCollectionInitialization = globalOptions.GetOption(FadeOutComplexCollectionInitialization, language), ReportInvalidPlaceholdersInStringDotFormatCalls = globalOptions.GetOption(ReportInvalidPlaceholdersInStringDotFormatCalls, language), ReportInvalidRegexPatterns = globalOptions.GetOption(ReportInvalidRegexPatterns, language), ReportInvalidJsonPatterns = globalOptions.GetOption(ReportInvalidJsonPatterns, language), @@ -43,22 +39,6 @@ public static IdeAnalyzerOptions GetIdeAnalyzerOptions(this IGlobalOptionService "InternalDiagnosticsOptions", "CrashOnAnalyzerException", IdeAnalyzerOptions.CommonDefault.CrashOnAnalyzerException, storageLocation: new LocalUserProfileStorageLocation(@"Roslyn\Internal\Diagnostics\CrashOnAnalyzerException")); - public static readonly PerLanguageOption2 FadeOutUnusedImports = new( - "FadingOptions", "FadeOutUnusedImports", IdeAnalyzerOptions.CommonDefault.FadeOutUnusedImports, - storageLocation: new RoamingProfileStorageLocation($"TextEditor.%LANGUAGE%.Specific.FadeOutUnusedImports")); - - public static readonly PerLanguageOption2 FadeOutUnreachableCode = new( - "FadingOptions", "FadeOutUnreachableCode", IdeAnalyzerOptions.CommonDefault.FadeOutUnreachableCode, - storageLocation: new RoamingProfileStorageLocation($"TextEditor.%LANGUAGE%.Specific.FadeOutUnreachableCode")); - - public static readonly PerLanguageOption2 FadeOutComplexObjectInitialization = new( - "CodeStyleOptions", "PreferObjectInitializer_FadeOutCode", IdeAnalyzerOptions.CommonDefault.FadeOutComplexObjectInitialization, - storageLocation: new RoamingProfileStorageLocation("TextEditor.%LANGUAGE%.Specific.PreferObjectInitializer_FadeOutCode")); - - internal static readonly PerLanguageOption2 FadeOutComplexCollectionInitialization = new( - "CodeStyleOptions", "PreferCollectionInitializer_FadeOutCode", IdeAnalyzerOptions.CommonDefault.FadeOutComplexCollectionInitialization, - storageLocation: new RoamingProfileStorageLocation("TextEditor.%LANGUAGE%.Specific.PreferCollectionInitializer_FadeOutCode")); - public static PerLanguageOption2 ReportInvalidPlaceholdersInStringDotFormatCalls = new("ValidateFormatStringOption", "ReportInvalidPlaceholdersInStringDotFormatCalls", diff --git a/src/Features/LanguageServer/Protocol/Features/Options/ImplementTypeOptionsStorage.cs b/src/Features/LanguageServer/Protocol/Features/Options/ImplementTypeOptionsStorage.cs index 016a156d0fa38..7aebf1fd2fc51 100644 --- a/src/Features/LanguageServer/Protocol/Features/Options/ImplementTypeOptionsStorage.cs +++ b/src/Features/LanguageServer/Protocol/Features/Options/ImplementTypeOptionsStorage.cs @@ -17,7 +17,7 @@ public static ImplementTypeOptions GetImplementTypeOptions(this IGlobalOptionSer PropertyGenerationBehavior = globalOptions.GetOption(PropertyGenerationBehavior, language) }; - public static ImplementTypeGenerationOptions GetImplementTypeGenerationOptions(this IGlobalOptionService globalOptions, HostLanguageServices languageServices) + public static ImplementTypeGenerationOptions GetImplementTypeGenerationOptions(this IGlobalOptionService globalOptions, LanguageServices languageServices) => new(globalOptions.GetImplementTypeOptions(languageServices.Language), globalOptions.CreateProvider()); diff --git a/src/Features/LanguageServer/Protocol/Features/Options/MetadataAsSourceOptionsStorage.cs b/src/Features/LanguageServer/Protocol/Features/Options/MetadataAsSourceOptionsStorage.cs index 67840effb2c08..24125b6566d9a 100644 --- a/src/Features/LanguageServer/Protocol/Features/Options/MetadataAsSourceOptionsStorage.cs +++ b/src/Features/LanguageServer/Protocol/Features/Options/MetadataAsSourceOptionsStorage.cs @@ -12,11 +12,12 @@ namespace Microsoft.CodeAnalysis.MetadataAsSource; internal static class MetadataAsSourceOptionsStorage { - public static MetadataAsSourceOptions GetMetadataAsSourceOptions(this IGlobalOptionService globalOptions, HostLanguageServices languageServices) + public static MetadataAsSourceOptions GetMetadataAsSourceOptions(this IGlobalOptionService globalOptions, LanguageServices languageServices) => new(GenerationOptions: globalOptions.GetCleanCodeGenerationOptions(languageServices)) { NavigateToDecompiledSources = globalOptions.GetOption(NavigateToDecompiledSources), AlwaysUseDefaultSymbolServers = globalOptions.GetOption(AlwaysUseDefaultSymbolServers), + NavigateToSourceLinkAndEmbeddedSources = globalOptions.GetOption(NavigateToSourceLinkAndEmbeddedSources), }; public static Option2 NavigateToDecompiledSources = @@ -26,4 +27,8 @@ public static MetadataAsSourceOptions GetMetadataAsSourceOptions(this IGlobalOpt public static Option2 AlwaysUseDefaultSymbolServers = new("FeatureOnOffOptions", "AlwaysUseDefaultSymbolServers", defaultValue: true, storageLocation: new RoamingProfileStorageLocation($"TextEditor.AlwaysUseDefaultSymbolServers")); + + public static Option2 NavigateToSourceLinkAndEmbeddedSources = + new("FeatureOnOffOptions", "NavigateToSourceLinkAndEmbeddedSources", defaultValue: true, + storageLocation: new RoamingProfileStorageLocation($"TextEditor.NavigateToSourceLinkAndEmbeddedSources")); } diff --git a/src/Features/LanguageServer/Protocol/Features/Options/SimplifierOptionsStorage.cs b/src/Features/LanguageServer/Protocol/Features/Options/SimplifierOptionsStorage.cs index c1546e9bded13..2ccf516cc379e 100644 --- a/src/Features/LanguageServer/Protocol/Features/Options/SimplifierOptionsStorage.cs +++ b/src/Features/LanguageServer/Protocol/Features/Options/SimplifierOptionsStorage.cs @@ -18,9 +18,9 @@ internal interface ISimplifierOptionsStorage : ILanguageService internal static class SimplifierOptionsStorage { public static ValueTask GetSimplifierOptionsAsync(this Document document, IGlobalOptionService globalOptions, CancellationToken cancellationToken) - => document.GetSimplifierOptionsAsync(globalOptions.GetSimplifierOptions(document.Project.LanguageServices), cancellationToken); + => document.GetSimplifierOptionsAsync(globalOptions.GetSimplifierOptions(document.Project.Services), cancellationToken); - public static SimplifierOptions GetSimplifierOptions(this IGlobalOptionService globalOptions, HostLanguageServices languageServices) + public static SimplifierOptions GetSimplifierOptions(this IGlobalOptionService globalOptions, LanguageServices languageServices) => languageServices.GetRequiredService().GetOptions(globalOptions); public static SimplifierOptions.CommonOptions GetCommonSimplifierOptions(this IGlobalOptionService globalOptions, string language) diff --git a/src/Features/LanguageServer/Protocol/Features/Options/SyntaxFormattingOptionsStorage.cs b/src/Features/LanguageServer/Protocol/Features/Options/SyntaxFormattingOptionsStorage.cs index 816cb2c28b511..0a3d609a1edf4 100644 --- a/src/Features/LanguageServer/Protocol/Features/Options/SyntaxFormattingOptionsStorage.cs +++ b/src/Features/LanguageServer/Protocol/Features/Options/SyntaxFormattingOptionsStorage.cs @@ -30,9 +30,9 @@ public static SyntaxFormattingOptions.CommonOptions GetCommonSyntaxFormattingOpt }; public static ValueTask GetSyntaxFormattingOptionsAsync(this Document document, IGlobalOptionService globalOptions, CancellationToken cancellationToken) - => document.GetSyntaxFormattingOptionsAsync(globalOptions.GetSyntaxFormattingOptions(document.Project.LanguageServices), cancellationToken); + => document.GetSyntaxFormattingOptionsAsync(globalOptions.GetSyntaxFormattingOptions(document.Project.Services), cancellationToken); - public static SyntaxFormattingOptions GetSyntaxFormattingOptions(this IGlobalOptionService globalOptions, HostLanguageServices languageServices) + public static SyntaxFormattingOptions GetSyntaxFormattingOptions(this IGlobalOptionService globalOptions, LanguageServices languageServices) => languageServices.GetRequiredService().GetOptions(globalOptions); } diff --git a/src/Features/LanguageServer/Protocol/Features/TodoComments/TodoCommentOptionsStorage.cs b/src/Features/LanguageServer/Protocol/Features/TodoComments/TodoCommentOptionsStorage.cs index db83f4e8dda48..98d500f302525 100644 --- a/src/Features/LanguageServer/Protocol/Features/TodoComments/TodoCommentOptionsStorage.cs +++ b/src/Features/LanguageServer/Protocol/Features/TodoComments/TodoCommentOptionsStorage.cs @@ -2,15 +2,24 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +using System.Collections.Generic; +using System.Collections.Immutable; using Microsoft.CodeAnalysis.Options; namespace Microsoft.CodeAnalysis.TodoComments { internal static class TodoCommentOptionsStorage { - public static readonly Option2 TokenList = new("TodoCommentOptions", "TokenList", TodoCommentOptions.Default.TokenList); + public static readonly Option2> TokenList = new( + "TodoCommentOptions", + "TokenList", + TodoCommentOptions.Default.TokenList, + new RoamingProfileStorageLocation("Microsoft.VisualStudio.ErrorListPkg.Shims.TaskListOptions.CommentTokens")); public static TodoCommentOptions GetTodoCommentOptions(this IGlobalOptionService globalOptions) - => new(globalOptions.GetOption(TokenList) ?? TodoCommentOptions.Default.TokenList); + => new() + { + TokenList = globalOptions.GetOption(TokenList) + }; } } diff --git a/src/Features/LanguageServer/Protocol/Features/TodoComments/TodoCommentsListener.cs b/src/Features/LanguageServer/Protocol/Features/TodoComments/TodoCommentsListener.cs index aea37bfe2a6a1..c74297d4ef5fc 100644 --- a/src/Features/LanguageServer/Protocol/Features/TodoComments/TodoCommentsListener.cs +++ b/src/Features/LanguageServer/Protocol/Features/TodoComments/TodoCommentsListener.cs @@ -23,7 +23,7 @@ internal sealed class TodoCommentsListener : ITodoCommentsListener, IDisposable { private readonly CancellationToken _disposalToken; private readonly IGlobalOptionService _globalOptions; - private readonly HostWorkspaceServices _services; + private readonly SolutionServices _services; private readonly IAsynchronousOperationListener _asyncListener; private readonly Action, ImmutableArray> _onTodoCommentsUpdated; private readonly ConcurrentDictionary> _documentToInfos = new(); @@ -41,7 +41,7 @@ internal sealed class TodoCommentsListener : ITodoCommentsListener, IDisposable public TodoCommentsListener( IGlobalOptionService globalOptions, - HostWorkspaceServices services, + SolutionServices services, IAsynchronousOperationListenerProvider asynchronousOperationListenerProvider, Action, ImmutableArray> onTodoCommentsUpdated, CancellationToken disposalToken) diff --git a/src/Features/LanguageServer/Protocol/Features/UnifiedSuggestions/UnifiedSuggestedActionSet.cs b/src/Features/LanguageServer/Protocol/Features/UnifiedSuggestions/UnifiedSuggestedActionSet.cs index ca4d99cfea496..fa593e7edc71f 100644 --- a/src/Features/LanguageServer/Protocol/Features/UnifiedSuggestions/UnifiedSuggestedActionSet.cs +++ b/src/Features/LanguageServer/Protocol/Features/UnifiedSuggestions/UnifiedSuggestedActionSet.cs @@ -13,6 +13,8 @@ namespace Microsoft.CodeAnalysis.UnifiedSuggestions /// internal class UnifiedSuggestedActionSet { + public Solution OriginalSolution { get; } + public string? CategoryName { get; } public ImmutableArray Actions { get; } @@ -24,12 +26,14 @@ internal class UnifiedSuggestedActionSet public TextSpan? ApplicableToSpan { get; } public UnifiedSuggestedActionSet( + Solution originalSolution, string? categoryName, ImmutableArray actions, object? title, UnifiedSuggestedActionSetPriority priority, TextSpan? applicableToSpan) { + OriginalSolution = originalSolution; CategoryName = categoryName; Actions = actions; Title = title; diff --git a/src/Features/LanguageServer/Protocol/Features/UnifiedSuggestions/UnifiedSuggestedActionsSource.cs b/src/Features/LanguageServer/Protocol/Features/UnifiedSuggestions/UnifiedSuggestedActionsSource.cs index b922ed7c4b78a..1c457f94a056d 100644 --- a/src/Features/LanguageServer/Protocol/Features/UnifiedSuggestions/UnifiedSuggestedActionsSource.cs +++ b/src/Features/LanguageServer/Protocol/Features/UnifiedSuggestions/UnifiedSuggestedActionsSource.cs @@ -42,6 +42,8 @@ public static async ValueTask> GetFilt Func addOperationScope, CancellationToken cancellationToken) { + var originalSolution = document.Project.Solution; + // Intentionally switch to a threadpool thread to compute fixes. We do not want to accidentally // run any of this on the UI thread and potentially allow any code to take a dependency on that. var fixes = await Task.Run(() => codeFixService.GetFixesAsync( @@ -54,7 +56,7 @@ public static async ValueTask> GetFilt cancellationToken), cancellationToken).ConfigureAwait(false); var filteredFixes = fixes.WhereAsArray(c => c.Fixes.Length > 0); - var organizedFixes = await OrganizeFixesAsync(workspace, filteredFixes, cancellationToken).ConfigureAwait(false); + var organizedFixes = await OrganizeFixesAsync(workspace, originalSolution, filteredFixes, cancellationToken).ConfigureAwait(false); return organizedFixes; } @@ -64,6 +66,7 @@ public static async ValueTask> GetFilt /// private static async Task> OrganizeFixesAsync( Workspace workspace, + Solution originalSolution, ImmutableArray fixCollections, CancellationToken cancellationToken) { @@ -71,10 +74,10 @@ private static async Task> OrganizeFix using var _ = ArrayBuilder.GetInstance(out var order); // First group fixes by diagnostic and priority. - await GroupFixesAsync(workspace, fixCollections, map, order, cancellationToken).ConfigureAwait(false); + await GroupFixesAsync(workspace, originalSolution, fixCollections, map, order, cancellationToken).ConfigureAwait(false); // Then prioritize between the groups. - var prioritizedFixes = PrioritizeFixGroups(map.ToImmutable(), order.ToImmutable(), workspace); + var prioritizedFixes = PrioritizeFixGroups(originalSolution, map.ToImmutable(), order.ToImmutable(), workspace); return prioritizedFixes; } @@ -83,17 +86,19 @@ private static async Task> OrganizeFix /// private static async Task GroupFixesAsync( Workspace workspace, + Solution originalSolution, ImmutableArray fixCollections, IDictionary> map, ArrayBuilder order, CancellationToken cancellationToken) { foreach (var fixCollection in fixCollections) - await ProcessFixCollectionAsync(workspace, map, order, fixCollection, cancellationToken).ConfigureAwait(false); + await ProcessFixCollectionAsync(workspace, originalSolution, map, order, fixCollection, cancellationToken).ConfigureAwait(false); } private static async Task ProcessFixCollectionAsync( Workspace workspace, + Solution originalSolution, IDictionary> map, ArrayBuilder order, CodeFixCollection fixCollection, @@ -105,11 +110,11 @@ private static async Task ProcessFixCollectionAsync( var nonSupressionCodeFixes = fixes.WhereAsArray(f => !IsTopLevelSuppressionAction(f.Action)); var supressionCodeFixes = fixes.WhereAsArray(f => IsTopLevelSuppressionAction(f.Action)); - await AddCodeActionsAsync(workspace, map, order, fixCollection, GetFixAllSuggestedActionSetAsync, nonSupressionCodeFixes).ConfigureAwait(false); + await AddCodeActionsAsync(workspace, originalSolution, map, order, fixCollection, GetFixAllSuggestedActionSetAsync, nonSupressionCodeFixes).ConfigureAwait(false); // Add suppression fixes to the end of a given SuggestedActionSet so that they // always show up last in a group. - await AddCodeActionsAsync(workspace, map, order, fixCollection, GetFixAllSuggestedActionSetAsync, supressionCodeFixes).ConfigureAwait(false); + await AddCodeActionsAsync(workspace, originalSolution, map, order, fixCollection, GetFixAllSuggestedActionSetAsync, supressionCodeFixes).ConfigureAwait(false); return; @@ -118,38 +123,42 @@ private static async Task ProcessFixCollectionAsync( => GetUnifiedFixAllSuggestedActionSetAsync( codeAction, fixCount, fixCollection.FixAllState, fixCollection.SupportedScopes, fixCollection.FirstDiagnostic, - workspace, cancellationToken); + workspace, originalSolution, cancellationToken); } private static async Task AddCodeActionsAsync( - Workspace workspace, IDictionary> map, - ArrayBuilder order, CodeFixCollection fixCollection, + Workspace workspace, + Solution originalSolution, + IDictionary> map, + ArrayBuilder order, + CodeFixCollection fixCollection, Func> getFixAllSuggestedActionSetAsync, ImmutableArray codeFixes) { foreach (var fix in codeFixes) { - var unifiedSuggestedAction = await GetUnifiedSuggestedActionAsync(fix.Action, fix).ConfigureAwait(false); + var unifiedSuggestedAction = await GetUnifiedSuggestedActionAsync(originalSolution, fix.Action, fix).ConfigureAwait(false); AddFix(fix, unifiedSuggestedAction, map, order); } return; // Local functions - async Task GetUnifiedSuggestedActionAsync(CodeAction action, CodeFix fix) + async Task GetUnifiedSuggestedActionAsync(Solution originalSolution, CodeAction action, CodeFix fix) { if (action.NestedCodeActions.Length > 0) { using var _ = ArrayBuilder.GetInstance(action.NestedCodeActions.Length, out var unifiedNestedActions); foreach (var nestedAction in action.NestedCodeActions) { - var unifiedNestedAction = await GetUnifiedSuggestedActionAsync(nestedAction, fix).ConfigureAwait(false); + var unifiedNestedAction = await GetUnifiedSuggestedActionAsync(originalSolution, nestedAction, fix).ConfigureAwait(false); unifiedNestedActions.Add(unifiedNestedAction); } var set = new UnifiedSuggestedActionSet( + originalSolution, categoryName: null, - actions: unifiedNestedActions.ToImmutable(), + actions: unifiedNestedActions.ToImmutableAndClear(), title: null, priority: GetUnifiedSuggestedActionSetPriority(action.Priority), applicableToSpan: fix.PrimaryDiagnostic.Location.SourceSpan); @@ -204,6 +213,7 @@ static CodeFixGroupKey GetGroupKey(CodeFix fix) ImmutableArray supportedScopes, Diagnostic firstDiagnostic, Workspace workspace, + Solution originalSolution, CancellationToken cancellationToken) { if (fixAllState == null) @@ -244,6 +254,7 @@ static CodeFixGroupKey GetGroupKey(CodeFix fix) } return new UnifiedSuggestedActionSet( + originalSolution, categoryName: null, actions: fixAllSuggestedActions.ToImmutable(), title: CodeFixesResources.Fix_all_occurrences_in, @@ -264,6 +275,7 @@ static CodeFixGroupKey GetGroupKey(CodeFix fix) /// always show up last after all other fixes (and refactorings) for the selected line of code. /// private static ImmutableArray PrioritizeFixGroups( + Solution originalSolution, ImmutableDictionary> map, ImmutableArray order, Workspace workspace) @@ -277,11 +289,11 @@ private static ImmutableArray PrioritizeFixGroups( var actions = map[groupKey]; var nonSuppressionActions = actions.Where(a => !IsTopLevelSuppressionAction(a.OriginalCodeAction)).ToImmutableArray(); - AddUnifiedSuggestedActionsSet(nonSuppressionActions, groupKey, nonSuppressionSets); + AddUnifiedSuggestedActionsSet(originalSolution, nonSuppressionActions, groupKey, nonSuppressionSets); var suppressionActions = actions.Where(a => IsTopLevelSuppressionAction(a.OriginalCodeAction) && !IsBulkConfigurationAction(a.OriginalCodeAction)).ToImmutableArray(); - AddUnifiedSuggestedActionsSet(suppressionActions, groupKey, suppressionSets); + AddUnifiedSuggestedActionsSet(originalSolution, suppressionActions, groupKey, suppressionSets); bulkConfigurationActions.AddRange(actions.Where(a => IsBulkConfigurationAction(a.OriginalCodeAction))); } @@ -292,6 +304,7 @@ private static ImmutableArray PrioritizeFixGroups( if (bulkConfigurationActions.Count > 0) { var bulkConfigurationSet = new UnifiedSuggestedActionSet( + originalSolution, UnifiedPredefinedSuggestedActionCategoryNames.CodeFix, bulkConfigurationActions.ToImmutable(), title: null, @@ -314,6 +327,7 @@ private static ImmutableArray PrioritizeFixGroups( // to get the span and category for the new top level suggested action. var (span, category) = CombineSpansAndCategory(suppressionSets); var wrappingSet = new UnifiedSuggestedActionSet( + originalSolution, category, actions: ImmutableArray.Create(wrappingSuggestedAction), title: CodeFixesResources.Suppress_or_Configure_issues, @@ -368,6 +382,7 @@ private static ImmutableArray PrioritizeFixGroups( } private static void AddUnifiedSuggestedActionsSet( + Solution originalSolution, ImmutableArray actions, CodeFixGroupKey groupKey, ArrayBuilder sets) @@ -380,7 +395,7 @@ private static void AddUnifiedSuggestedActionsSet( Debug.Assert(groupKey.Item1.HasTextSpan); var category = GetFixCategory(groupKey.Item1.Severity); sets.Add(new UnifiedSuggestedActionSet( - category, group.ToImmutableArray(), title: null, priority, applicableToSpan: groupKey.Item1.GetTextSpan())); + originalSolution, category, group.ToImmutableArray(), title: null, priority, applicableToSpan: groupKey.Item1.GetTextSpan())); } } @@ -438,7 +453,7 @@ public static async Task> GetFilterAnd orderedRefactorings.Add(orderedRefactoring); } - return orderedRefactorings.ToImmutable(); + return orderedRefactorings.ToImmutableAndClear(); } private static ImmutableArray FilterOnAnyThread( @@ -491,6 +506,8 @@ private static async Task OrganizeRefactoringsAsync( CodeRefactoring refactoring, CancellationToken cancellationToken) { + var originalSolution = document.Project.Solution; + using var _ = ArrayBuilder.GetInstance(out var refactoringSuggestedActions); foreach (var (action, applicableToSpan) in refactoring.CodeActions) @@ -509,6 +526,7 @@ private static async Task OrganizeRefactoringsAsync( // and therefore the complexity of determining the closest one isn't worth the benefit // of slightly more correct orderings in certain edge cases. return new UnifiedSuggestedActionSet( + originalSolution, UnifiedPredefinedSuggestedActionCategoryNames.Refactoring, actions: actions, title: null, @@ -528,8 +546,9 @@ async Task GetUnifiedSuggestedActionSetAsync(CodeAction } var set = new UnifiedSuggestedActionSet( + originalSolution, categoryName: null, - actions: nestedActions.ToImmutable(), + actions: nestedActions.ToImmutableAndClear(), title: null, priority: GetUnifiedSuggestedActionSetPriority(codeAction.Priority), applicableToSpan: applicableToSpan); @@ -577,6 +596,8 @@ async Task GetUnifiedSuggestedActionSetAsync(CodeAction return null; } + var originalSolution = document.Project.Solution; + using var fixAllSuggestedActionsDisposer = ArrayBuilder.GetInstance(out var fixAllSuggestedActions); foreach (var scope in fixAllProviderInfo.SupportedScopes) { @@ -601,6 +622,7 @@ async Task GetUnifiedSuggestedActionSetAsync(CodeAction } return new UnifiedSuggestedActionSet( + originalSolution, categoryName: null, actions: fixAllSuggestedActions.ToImmutable(), title: CodeFixesResources.Fix_all_occurrences_in, @@ -698,7 +720,7 @@ private static ImmutableArray OrderActionSets( private static UnifiedSuggestedActionSet WithPriority( UnifiedSuggestedActionSet set, UnifiedSuggestedActionSetPriority priority) - => new(set.CategoryName, set.Actions, set.Title, priority, set.ApplicableToSpan); + => new(set.OriginalSolution, set.CategoryName, set.Actions, set.Title, priority, set.ApplicableToSpan); private static ImmutableArray InlineActionSetsIfDesirable( ImmutableArray actionSets, @@ -731,6 +753,7 @@ private static UnifiedSuggestedActionSet InlineActions(UnifiedSuggestedActionSet } return new UnifiedSuggestedActionSet( + actionSet.OriginalSolution, actionSet.CategoryName, newActions.ToImmutable(), actionSet.Title, @@ -770,7 +793,7 @@ private static ImmutableArray FilterActionSetsByTitle return actions.Count == 0 ? null - : new UnifiedSuggestedActionSet(set.CategoryName, actions.ToImmutable(), set.Title, set.Priority, set.ApplicableToSpan); + : new UnifiedSuggestedActionSet(set.OriginalSolution, set.CategoryName, actions.ToImmutable(), set.Title, set.Priority, set.ApplicableToSpan); } } } diff --git a/src/Features/LanguageServer/Protocol/Handler/Breakpoints/ValidateBreakableRangeHandler.cs b/src/Features/LanguageServer/Protocol/Handler/Breakpoints/ValidateBreakableRangeHandler.cs index 1a7afe412bd34..984a31d60283a 100644 --- a/src/Features/LanguageServer/Protocol/Handler/Breakpoints/ValidateBreakableRangeHandler.cs +++ b/src/Features/LanguageServer/Protocol/Handler/Breakpoints/ValidateBreakableRangeHandler.cs @@ -38,7 +38,7 @@ public ValidateBreakableRangeHandler() var text = await document.GetTextAsync(cancellationToken).ConfigureAwait(false); var span = ProtocolConversions.RangeToTextSpan(request.Range, text); - var breakpointService = document.Project.LanguageServices.GetRequiredService(); + var breakpointService = document.Project.Services.GetRequiredService(); if (span.Length > 0) { diff --git a/src/Features/LanguageServer/Protocol/Handler/Definitions/AbstractGoToDefinitionHandler.cs b/src/Features/LanguageServer/Protocol/Handler/Definitions/AbstractGoToDefinitionHandler.cs index 11636129c02ed..b039215ed03ea 100644 --- a/src/Features/LanguageServer/Protocol/Handler/Definitions/AbstractGoToDefinitionHandler.cs +++ b/src/Features/LanguageServer/Protocol/Handler/Definitions/AbstractGoToDefinitionHandler.cs @@ -70,7 +70,7 @@ public AbstractGoToDefinitionHandler(IMetadataAsSourceFileService metadataAsSour { if (!typeOnly || symbol is ITypeSymbol) { - var options = _globalOptions.GetMetadataAsSourceOptions(document.Project.LanguageServices); + var options = _globalOptions.GetMetadataAsSourceOptions(document.Project.Services); var declarationFile = await _metadataAsSourceFileService.GetGeneratedFileAsync(document.Project, symbol, signaturesOnly: false, options, cancellationToken).ConfigureAwait(false); var linePosSpan = declarationFile.IdentifierLocation.GetLineSpan().Span; diff --git a/src/Features/LanguageServer/Protocol/Handler/Diagnostics/AbstractPullDiagnosticHandler.cs b/src/Features/LanguageServer/Protocol/Handler/Diagnostics/AbstractPullDiagnosticHandler.cs index f0ec470cf56cb..f70fd2a5ac995 100644 --- a/src/Features/LanguageServer/Protocol/Handler/Diagnostics/AbstractPullDiagnosticHandler.cs +++ b/src/Features/LanguageServer/Protocol/Handler/Diagnostics/AbstractPullDiagnosticHandler.cs @@ -8,12 +8,10 @@ using System.Threading.Tasks; using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.EditAndContinue; -using Microsoft.CodeAnalysis.Host; +using Microsoft.CodeAnalysis.LanguageServer.Features.Diagnostics; using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.PooledObjects; -using Microsoft.CodeAnalysis.Text; using Microsoft.VisualStudio.LanguageServer.Protocol; -using Microsoft.VisualStudio.Text; using Roslyn.Utilities; using LSP = Microsoft.VisualStudio.LanguageServer.Protocol; @@ -254,7 +252,7 @@ private async Task ComputeAndReportCurrentDiagnosticsAsync( context.TraceInformation($"Found {diagnostics.Length} diagnostics for {diagnosticSource.GetUri()}"); foreach (var diagnostic in diagnostics) - result.Add(ConvertDiagnostic(diagnosticSource, diagnostic, clientCapabilities)); + result.AddRange(ConvertDiagnostic(diagnosticSource, diagnostic, clientCapabilities)); return CreateReport(new LSP.TextDocumentIdentifier { Uri = diagnosticSource.GetUri() }, result.ToArray(), resultId); } @@ -273,37 +271,57 @@ private void HandleRemovedDocuments(RequestContext context, ImmutableArray ConvertDiagnostic(IDiagnosticSource diagnosticSource, DiagnosticData diagnosticData, ClientCapabilities capabilities) { - Contract.ThrowIfNull(diagnosticData.Message, $"Got a document diagnostic that did not have a {nameof(diagnosticData.Message)}"); - var project = diagnosticSource.GetProject(); + var diagnostic = CreateLspDiagnostic(diagnosticData, project, capabilities); - if (!capabilities.HasVisualStudioLspCapability()) + // Check if we need to handle the unnecessary tag (fading). + if (!diagnosticData.CustomTags.Contains(WellKnownDiagnosticTags.Unnecessary)) { - var diagnostic = CreateBaseLspDiagnostic(); - return diagnostic; + return ImmutableArray.Create(diagnostic); } - else + + // DiagnosticId supports fading, check if the corresponding VS option is turned on. + if (!SupportsFadingOption(diagnosticData)) { - var vsDiagnostic = CreateBaseLspDiagnostic(); - vsDiagnostic.DiagnosticType = diagnosticData.Category; - vsDiagnostic.Projects = new[] - { - new VSDiagnosticProjectInformation - { - ProjectIdentifier = project.Id.Id.ToString(), - ProjectName = project.Name, - }, - }; + return ImmutableArray.Create(diagnostic); + } - return vsDiagnostic; + // Check to see if there are specific locations marked to fade. + if (!diagnosticData.TryGetUnnecessaryDataLocations(out var unnecessaryLocations)) + { + // There are no specific fading locations, just mark the whole diagnostic span as unnecessary. + // We should always have at least one tag (build or intellisense error). + Contract.ThrowIfNull(diagnostic.Tags, $"diagnostic {diagnostic.Identifier} was missing tags"); + diagnostic.Tags = diagnostic.Tags.Append(DiagnosticTag.Unnecessary); + return ImmutableArray.Create(diagnostic); } - // We can just use VSDiagnostic as it doesn't have any default properties set that - // would get automatically serialized. - LSP.VSDiagnostic CreateBaseLspDiagnostic() + // Roslyn produces unnecessary diagnostics by using additional locations, however LSP doesn't support tagging + // additional locations separately. Instead we just create multiple hidden diagnostics for unnecessary squiggling. + using var _ = ArrayBuilder.GetInstance(out var diagnosticsBuilder); + diagnosticsBuilder.Add(diagnostic); + foreach (var location in unnecessaryLocations) { + var additionalDiagnostic = CreateLspDiagnostic(diagnosticData, project, capabilities); + additionalDiagnostic.Severity = LSP.DiagnosticSeverity.Hint; + additionalDiagnostic.Range = GetRange(location); + additionalDiagnostic.Tags = new DiagnosticTag[] { DiagnosticTag.Unnecessary, VSDiagnosticTags.HiddenInEditor, VSDiagnosticTags.HiddenInErrorList, VSDiagnosticTags.SuppressEditorToolTip }; + diagnosticsBuilder.Add(additionalDiagnostic); + } + + return diagnosticsBuilder.ToImmutableArray(); + + LSP.VSDiagnostic CreateLspDiagnostic( + DiagnosticData diagnosticData, + Project project, + ClientCapabilities capabilities) + { + Contract.ThrowIfNull(diagnosticData.Message, $"Got a document diagnostic that did not have a {nameof(diagnosticData.Message)}"); + + // We can just use VSDiagnostic as it doesn't have any default properties set that + // would get automatically serialized. var diagnostic = new LSP.VSDiagnostic { Source = "Roslyn", @@ -313,22 +331,29 @@ LSP.VSDiagnostic CreateBaseLspDiagnostic() Severity = ConvertDiagnosticSeverity(diagnosticData.Severity), Tags = ConvertTags(diagnosticData), }; - var range = GetRange(diagnosticData.DataLocation); - if (range != null) + if (diagnosticData.DataLocation != null) { - diagnostic.Range = range; + diagnostic.Range = GetRange(diagnosticData.DataLocation); + } + + if (capabilities.HasVisualStudioLspCapability()) + { + diagnostic.DiagnosticType = diagnosticData.Category; + diagnostic.Projects = new[] + { + new VSDiagnosticProjectInformation + { + ProjectIdentifier = project.Id.Id.ToString(), + ProjectName = project.Name, + }, + }; } return diagnostic; } - static Range? GetRange(DiagnosticDataLocation? dataLocation) + static LSP.Range GetRange(DiagnosticDataLocation dataLocation) { - if (dataLocation == null) - { - return null; - } - // We currently do not map diagnostics spans as // 1. Razor handles span mapping for razor files on their side. // 2. LSP does not allow us to report document pull diagnostics for a different file path. @@ -337,7 +362,7 @@ LSP.VSDiagnostic CreateBaseLspDiagnostic() // We also do not adjust the diagnostic locations to ensure they are in bounds because we've // explicitly requested up to date diagnostics as of the snapshot we were passed in. - return new Range + return new LSP.Range { Start = new Position { @@ -391,13 +416,21 @@ protected static DiagnosticTag[] ConvertTags(DiagnosticData diagnosticData, bool ? VSDiagnosticTags.BuildError : VSDiagnosticTags.IntellisenseError); - if (diagnosticData.CustomTags.Contains(WellKnownDiagnosticTags.Unnecessary)) - result.Add(DiagnosticTag.Unnecessary); - if (diagnosticData.CustomTags.Contains(WellKnownDiagnosticTags.EditAndContinue)) result.Add(VSDiagnosticTags.EditAndContinueError); return result.ToArray(); } + + private bool SupportsFadingOption(DiagnosticData diagnosticData) + { + if (IDEDiagnosticIdToOptionMappingHelper.TryGetMappedFadingOption(diagnosticData.Id, out var fadingOption)) + { + Contract.ThrowIfNull(diagnosticData.Language, $"diagnostic {diagnosticData.Id} is missing a language"); + return GlobalOptions.GetOption(fadingOption, diagnosticData.Language); + } + + return true; + } } } diff --git a/src/Features/LanguageServer/Protocol/Handler/Diagnostics/Experimental/ExperimentalDiagnosticsTypes.cs b/src/Features/LanguageServer/Protocol/Handler/Diagnostics/Experimental/ExperimentalDiagnosticsTypes.cs index b8e1dbb2c82b4..2c11b6380ace0 100644 --- a/src/Features/LanguageServer/Protocol/Handler/Diagnostics/Experimental/ExperimentalDiagnosticsTypes.cs +++ b/src/Features/LanguageServer/Protocol/Handler/Diagnostics/Experimental/ExperimentalDiagnosticsTypes.cs @@ -17,7 +17,7 @@ namespace Microsoft.CodeAnalysis.LanguageServer.Handler.Diagnostics.Experimental // A document diagnostic partial report is defined as having the first literal send = DocumentDiagnosticReport (aka the sumtype of changed / unchanged) followed // by n DocumentDiagnosticPartialResult literals. // See https://github.com/microsoft/vscode-languageserver-node/blob/main/protocol/src/common/proposed.diagnostics.md#textDocument_diagnostic -using DocumentDiagnosticPartialReport = SumType, DocumentDiagnosticPartialResult>; +using DocumentDiagnosticPartialReport = SumType; internal class DocumentDiagnosticParams : IPartialResultParams { diff --git a/src/Features/LanguageServer/Protocol/Handler/Diagnostics/Experimental/ExperimentalDocumentPullDiagnosticsHandler.cs b/src/Features/LanguageServer/Protocol/Handler/Diagnostics/Experimental/ExperimentalDocumentPullDiagnosticsHandler.cs index 09e8281c94063..349b4c2899dfb 100644 --- a/src/Features/LanguageServer/Protocol/Handler/Diagnostics/Experimental/ExperimentalDocumentPullDiagnosticsHandler.cs +++ b/src/Features/LanguageServer/Protocol/Handler/Diagnostics/Experimental/ExperimentalDocumentPullDiagnosticsHandler.cs @@ -22,7 +22,7 @@ namespace Microsoft.CodeAnalysis.LanguageServer.Handler.Diagnostics.Experimental // A document diagnostic partial report is defined as having the first literal send = DocumentDiagnosticReport (aka the sumtype of changed / unchanged) followed // by n DocumentDiagnosticPartialResult literals. // See https://github.com/microsoft/vscode-languageserver-node/blob/main/protocol/src/common/proposed.diagnostics.md#textDocument_diagnostic -using DocumentDiagnosticPartialReport = SumType, DocumentDiagnosticPartialResult>; +using DocumentDiagnosticPartialReport = SumType; [Method(ExperimentalMethods.TextDocumentDiagnostic)] internal class ExperimentalDocumentPullDiagnosticsHandler : AbstractPullDiagnosticHandler @@ -57,7 +57,12 @@ protected override DocumentDiagnosticPartialReport CreateUnchangedReport(TextDoc var progressValues = progress.GetValues(); if (progressValues != null && progressValues.Length > 0) { - return progressValues.Single().First; + if (progressValues.Single().TryGetFirst(out var value)) + { + return value; + } + + return progressValues.Single().Second; } return null; diff --git a/src/Features/LanguageServer/Protocol/Handler/Diagnostics/WorkspacePullDiagnosticHandler.cs b/src/Features/LanguageServer/Protocol/Handler/Diagnostics/WorkspacePullDiagnosticHandler.cs index a7c3a714d8e5e..7204c2bc8d6fe 100644 --- a/src/Features/LanguageServer/Protocol/Handler/Diagnostics/WorkspacePullDiagnosticHandler.cs +++ b/src/Features/LanguageServer/Protocol/Handler/Diagnostics/WorkspacePullDiagnosticHandler.cs @@ -89,7 +89,7 @@ internal static async ValueTask> GetWorkspaceP var solution = context.Solution; - var documentTrackingService = solution.Workspace.Services.GetRequiredService(); + var documentTrackingService = solution.Services.GetRequiredService(); // Collect all the documents from the solution in the order we'd like to get diagnostics for. This will // prioritize the files from currently active projects, but then also include all other docs in all projects @@ -133,7 +133,7 @@ async Task AddDocumentsAndProject(Project? project, ImmutableArray suppo // If all features are enabled for source generated documents, make sure they are included when FSA is on or a file in the project is open. // This is done because for either scenario we've already run generators, so there shouldn't be much cost in getting the diagnostics. - if ((isFSAOn || isOpen) && solution.Workspace.Services.GetService()?.Options.EnableOpeningSourceGeneratedFiles == true) + if ((isFSAOn || isOpen) && solution.Services.GetService()?.Options.EnableOpeningSourceGeneratedFiles == true) { var sourceGeneratedDocuments = await project.GetSourceGeneratedDocumentsAsync(cancellationToken).ConfigureAwait(false); documents = documents.AddRange(sourceGeneratedDocuments); diff --git a/src/Features/LanguageServer/Protocol/Handler/FoldingRanges/FoldingRangesHandler.cs b/src/Features/LanguageServer/Protocol/Handler/FoldingRanges/FoldingRangesHandler.cs index bcc7614fc33fa..683fe991822cc 100644 --- a/src/Features/LanguageServer/Protocol/Handler/FoldingRanges/FoldingRangesHandler.cs +++ b/src/Features/LanguageServer/Protocol/Handler/FoldingRanges/FoldingRangesHandler.cs @@ -40,7 +40,7 @@ public FoldingRangesHandler(IGlobalOptionService globalOptions) if (document == null) return null; - var blockStructureService = document.Project.LanguageServices.GetService(); + var blockStructureService = document.Project.Services.GetService(); if (blockStructureService == null) { return Array.Empty(); @@ -59,7 +59,7 @@ public FoldingRangesHandler(IGlobalOptionService globalOptions) public static FoldingRange[] GetFoldingRanges( SyntaxTree syntaxTree, - HostLanguageServices languageServices, + LanguageServices languageServices, in BlockStructureOptions options, CancellationToken cancellationToken) { diff --git a/src/Features/LanguageServer/Protocol/Handler/Formatting/AbstractFormatDocumentHandlerBase.cs b/src/Features/LanguageServer/Protocol/Handler/Formatting/AbstractFormatDocumentHandlerBase.cs index fefd619a35bb3..bfcbab1398bce 100644 --- a/src/Features/LanguageServer/Protocol/Handler/Formatting/AbstractFormatDocumentHandlerBase.cs +++ b/src/Features/LanguageServer/Protocol/Handler/Formatting/AbstractFormatDocumentHandlerBase.cs @@ -43,7 +43,7 @@ internal abstract class AbstractFormatDocumentHandlerBase(); diff --git a/src/Features/LanguageServer/Protocol/Handler/Formatting/FormatDocumentOnTypeHandler.cs b/src/Features/LanguageServer/Protocol/Handler/Formatting/FormatDocumentOnTypeHandler.cs index 69203f3d12d96..71550efcdceee 100644 --- a/src/Features/LanguageServer/Protocol/Handler/Formatting/FormatDocumentOnTypeHandler.cs +++ b/src/Features/LanguageServer/Protocol/Handler/Formatting/FormatDocumentOnTypeHandler.cs @@ -55,7 +55,7 @@ public FormatDocumentOnTypeHandler(IGlobalOptionService globalOptions) return Array.Empty(); } - var formattingService = document.Project.LanguageServices.GetRequiredService(); + var formattingService = document.Project.Services.GetRequiredService(); var documentSyntax = await ParsedDocument.CreateAsync(document, cancellationToken).ConfigureAwait(false); if (!formattingService.ShouldFormatOnTypedCharacter(documentSyntax, request.Character[0], position, cancellationToken)) diff --git a/src/Features/LanguageServer/Protocol/Handler/InlineCompletions/InlineCompletionsHandler.cs b/src/Features/LanguageServer/Protocol/Handler/InlineCompletions/InlineCompletionsHandler.cs index ae05e9304d4d0..3664c209edda7 100644 --- a/src/Features/LanguageServer/Protocol/Handler/InlineCompletions/InlineCompletionsHandler.cs +++ b/src/Features/LanguageServer/Protocol/Handler/InlineCompletions/InlineCompletionsHandler.cs @@ -12,7 +12,7 @@ using Microsoft.CodeAnalysis.Formatting; using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.Indentation; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Shared.Collections; @@ -147,7 +147,7 @@ private static async Task GetFormattedLspSnippetAsync( var root = await originalDocument.WithText(documentWithSnippetText).GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false); var spanToFormat = TextSpan.FromBounds(textChange.Span.Start, snippetEndPosition); - var formattingChanges = Formatter.GetFormattedTextChanges(root, spanToFormat, originalDocument.Project.Solution.Workspace.Services, formattingOptions, cancellationToken: cancellationToken) + var formattingChanges = Formatter.GetFormattedTextChanges(root, spanToFormat, originalDocument.Project.Solution.Services, formattingOptions, cancellationToken: cancellationToken) ?.ToImmutableArray() ?? ImmutableArray.Empty; var formattedText = documentWithSnippetText.WithChanges(formattingChanges); diff --git a/src/Features/LanguageServer/Protocol/Handler/OnAutoInsert/OnAutoInsertHandler.cs b/src/Features/LanguageServer/Protocol/Handler/OnAutoInsert/OnAutoInsertHandler.cs index a3d39b50891f7..9a00da65a639f 100644 --- a/src/Features/LanguageServer/Protocol/Handler/OnAutoInsert/OnAutoInsertHandler.cs +++ b/src/Features/LanguageServer/Protocol/Handler/OnAutoInsert/OnAutoInsertHandler.cs @@ -146,7 +146,7 @@ public OnAutoInsertHandler( } var (service, context) = serviceAndContext.Value; - var postReturnEdit = await service.GetTextChangeAfterReturnAsync(context, options, cancellationToken).ConfigureAwait(false); + var postReturnEdit = service.GetTextChangeAfterReturn(context, options, cancellationToken); if (postReturnEdit == null) { return null; @@ -235,9 +235,11 @@ static string GetTextChangeTextWithCaretAtLocation(SourceText sourceText, TextCh _ => throw new ArgumentException($"Language {document.Project.Language} is not recognized for OnAutoInsert") }; + var parsedDocument = await ParsedDocument.CreateAsync(document, cancellationToken).ConfigureAwait(false); + foreach (var service in servicesForDocument) { - var context = await service.GetCompletedBraceContextAsync(document, caretLocation, cancellationToken).ConfigureAwait(false); + var context = service.GetCompletedBraceContext(parsedDocument, caretLocation); if (context != null) { return (service, context.Value); diff --git a/src/Features/LanguageServer/Protocol/Handler/PullHandlers/VersionedPullCache`2.cs b/src/Features/LanguageServer/Protocol/Handler/PullHandlers/VersionedPullCache`2.cs index ef9bab461fcf2..a368994df0b06 100644 --- a/src/Features/LanguageServer/Protocol/Handler/PullHandlers/VersionedPullCache`2.cs +++ b/src/Features/LanguageServer/Protocol/Handler/PullHandlers/VersionedPullCache`2.cs @@ -126,7 +126,7 @@ public VersionedPullCache(string uniqueKey) private static async Task IsFullyLoadedAsync(Solution solution, CancellationToken cancellationToken) { - var workspaceStatusService = solution.Workspace.Services.GetRequiredService(); + var workspaceStatusService = solution.Services.GetRequiredService(); var isFullyLoaded = await workspaceStatusService.IsFullyLoadedAsync(cancellationToken).ConfigureAwait(false); return isFullyLoaded; } diff --git a/src/Features/LanguageServer/Protocol/Handler/RequestTelemetryLogger.cs b/src/Features/LanguageServer/Protocol/Handler/RequestTelemetryLogger.cs index e53c233f0caa2..1f6cd5520feb6 100644 --- a/src/Features/LanguageServer/Protocol/Handler/RequestTelemetryLogger.cs +++ b/src/Features/LanguageServer/Protocol/Handler/RequestTelemetryLogger.cs @@ -24,7 +24,7 @@ internal sealed class RequestTelemetryLogger : IDisposable, ILspService /// /// Histogram to aggregate the time in queue metrics. /// - private readonly HistogramLogAggregator _queuedDurationLogAggregator; + private readonly HistogramLogAggregator _queuedDurationLogAggregator; /// /// Histogram to aggregate total request duration metrics. @@ -34,7 +34,7 @@ internal sealed class RequestTelemetryLogger : IDisposable, ILspService /// This provides highly detailed buckets when duration is in MS, but less detailed /// when the duration is in terms of seconds or minutes. /// - private readonly HistogramLogAggregator _requestDurationLogAggregator; + private readonly HistogramLogAggregator _requestDurationLogAggregator; /// /// Store request counters in a concurrent dictionary as non-mutating LSP requests can @@ -42,9 +42,9 @@ internal sealed class RequestTelemetryLogger : IDisposable, ILspService /// private readonly ConcurrentDictionary _requestCounters; - private readonly LogAggregator _findDocumentResults; + private readonly CountLogAggregator _findDocumentResults; - private readonly LogAggregator _usedForkedSolutionCounter; + private readonly CountLogAggregator _usedForkedSolutionCounter; private int _disposed; @@ -57,11 +57,11 @@ public RequestTelemetryLogger(string serverTypeName) // Buckets queued duration into 10ms buckets with the last bucket starting at 1000ms. // Queue times are relatively short and fall under 50ms, so tracking past 1000ms is not useful. - _queuedDurationLogAggregator = new HistogramLogAggregator(bucketSize: 10, maxBucketValue: 1000); + _queuedDurationLogAggregator = new HistogramLogAggregator(bucketSize: 10, maxBucketValue: 1000); // Since this is a log based histogram, these are appropriate bucket sizes for the log data. // A bucket at 1 corresponds to ~26ms, while the max bucket value corresponds to ~17minutes - _requestDurationLogAggregator = new HistogramLogAggregator(bucketSize: 1, maxBucketValue: 40); + _requestDurationLogAggregator = new HistogramLogAggregator(bucketSize: 1, maxBucketValue: 40); } public void UpdateFindDocumentTelemetryData(bool success, string? workspaceKind) @@ -87,10 +87,10 @@ public void UpdateTelemetryData( { // Find the bucket corresponding to the queued duration and update the count of durations in that bucket. // This is not broken down per method as time in queue is not specific to an LSP method. - _queuedDurationLogAggregator.IncreaseCount(QueuedDurationKey, Convert.ToDecimal(queuedDuration.TotalMilliseconds)); + _queuedDurationLogAggregator.LogTime(QueuedDurationKey, queuedDuration); // Store the request time metrics per LSP method. - _requestDurationLogAggregator.IncreaseCount(methodName, Convert.ToDecimal(ComputeLogValue(requestDuration.TotalMilliseconds))); + _requestDurationLogAggregator.IncreaseCount(methodName, (int)ComputeLogValue(requestDuration.TotalMilliseconds)); _requestCounters.GetOrAdd(methodName, (_) => new Counter()).IncrementCount(result); } diff --git a/src/Features/LanguageServer/Protocol/Handler/SpellCheck/WorkspaceSpellCheckHandler.cs b/src/Features/LanguageServer/Protocol/Handler/SpellCheck/WorkspaceSpellCheckHandler.cs index 772d4a58e32cb..2686656b13d75 100644 --- a/src/Features/LanguageServer/Protocol/Handler/SpellCheck/WorkspaceSpellCheckHandler.cs +++ b/src/Features/LanguageServer/Protocol/Handler/SpellCheck/WorkspaceSpellCheckHandler.cs @@ -40,7 +40,7 @@ protected override ImmutableArray GetOrderedDocuments(RequestContext c var solution = context.Solution; - var documentTrackingService = solution.Workspace.Services.GetRequiredService(); + var documentTrackingService = solution.Services.GetRequiredService(); // Collect all the documents from the solution in the order we'd like to get spans for. This will // prioritize the files from currently active projects, but then also include all other docs in all diff --git a/src/Features/LanguageServer/Protocol/Workspaces/LspMiscellaneousFilesWorkspace.cs b/src/Features/LanguageServer/Protocol/Workspaces/LspMiscellaneousFilesWorkspace.cs index b8ba6a8e3305d..1cc824c529c35 100644 --- a/src/Features/LanguageServer/Protocol/Workspaces/LspMiscellaneousFilesWorkspace.cs +++ b/src/Features/LanguageServer/Protocol/Workspaces/LspMiscellaneousFilesWorkspace.cs @@ -63,7 +63,7 @@ public LspMiscellaneousFilesWorkspace() : base(MefHostServices.DefaultHost, Work var sourceTextLoader = new SourceTextLoader(documentText, uriAbsolutePath); - var projectInfo = MiscellaneousFileUtilities.CreateMiscellaneousProjectInfoForDocument(uri.AbsolutePath, sourceTextLoader, languageInformation, Services, ImmutableArray.Empty); + var projectInfo = MiscellaneousFileUtilities.CreateMiscellaneousProjectInfoForDocument(uri.AbsolutePath, sourceTextLoader, languageInformation, Services.SolutionServices, ImmutableArray.Empty); OnProjectAdded(projectInfo); var id = projectInfo.Documents.Single().Id; diff --git a/src/Features/LanguageServer/Protocol/Workspaces/LspWorkspaceManager.cs b/src/Features/LanguageServer/Protocol/Workspaces/LspWorkspaceManager.cs index 0ee06fb6d8d99..ab7dc2da605af 100644 --- a/src/Features/LanguageServer/Protocol/Workspaces/LspWorkspaceManager.cs +++ b/src/Features/LanguageServer/Protocol/Workspaces/LspWorkspaceManager.cs @@ -157,7 +157,7 @@ public void UpdateTrackedDocument(Uri uri, SourceText newSourceText) // Ensure we have the latest lsp solutions var updatedSolutions = await GetLspSolutionsAsync(cancellationToken).ConfigureAwait(false); - var (hostWorkspaceSolution, isForked) = updatedSolutions.FirstOrDefault(lspSolution => lspSolution.Solution.Workspace.Kind == _hostWorkspaceKind); + var (hostWorkspaceSolution, isForked) = updatedSolutions.FirstOrDefault(lspSolution => lspSolution.Solution.WorkspaceKind == _hostWorkspaceKind); _requestTelemetryLogger.UpdateUsedForkedSolutionCounter(isForked); return hostWorkspaceSolution; @@ -184,7 +184,7 @@ public void UpdateTrackedDocument(Uri uri, SourceText newSourceText) var document = documents.FindDocumentInProjectContext(textDocumentIdentifier); // Record metadata on how we got this document. - var workspaceKind = document.Project.Solution.Workspace.Kind; + var workspaceKind = document.Project.Solution.WorkspaceKind; _requestTelemetryLogger.UpdateFindDocumentTelemetryData(success: true, workspaceKind); _requestTelemetryLogger.UpdateUsedForkedSolutionCounter(isForked); _logger.TraceInformation($"{document.FilePath} found in workspace {workspaceKind}"); @@ -194,7 +194,7 @@ public void UpdateTrackedDocument(Uri uri, SourceText newSourceText) } // We didn't find the document in any workspace, record a telemetry notification that we did not find it. - var searchedWorkspaceKinds = string.Join(";", lspSolutions.SelectAsArray(lspSolution => lspSolution.Solution.Workspace.Kind)); + var searchedWorkspaceKinds = string.Join(";", lspSolutions.SelectAsArray(lspSolution => lspSolution.Solution.WorkspaceKind)); _logger.TraceError($"Could not find '{uri}'. Searched {searchedWorkspaceKinds}"); _requestTelemetryLogger.UpdateFindDocumentTelemetryData(success: false, workspaceKind: null); @@ -293,7 +293,7 @@ private async Task DoesAllTextMatchWorkspaceSolutionAsync(ImmutableDiction if (!isTextEquivalent) { - _logger.TraceWarning($"Text for {uriInWorkspace} did not match document text {firstDocument.Id} in workspace's {firstDocument.Project.Solution.Workspace.Kind} current solution"); + _logger.TraceWarning($"Text for {uriInWorkspace} did not match document text {firstDocument.Id} in workspace's {firstDocument.Project.Solution.WorkspaceKind} current solution"); return false; } } diff --git a/src/Features/LanguageServer/Protocol/Workspaces/LspWorkspaceRegistrationEventListener.cs b/src/Features/LanguageServer/Protocol/Workspaces/LspWorkspaceRegistrationEventListener.cs index bb6a32b966e1b..c2059f850b4ee 100644 --- a/src/Features/LanguageServer/Protocol/Workspaces/LspWorkspaceRegistrationEventListener.cs +++ b/src/Features/LanguageServer/Protocol/Workspaces/LspWorkspaceRegistrationEventListener.cs @@ -11,7 +11,7 @@ namespace Microsoft.CodeAnalysis.LanguageServer; // Specify the VS workspaces we know we need (host, misc, metadata as source) and MSBuild for VSCode. [ExportEventListener(WellKnownEventListeners.Workspace, WorkspaceKind.Host, WorkspaceKind.MiscellaneousFiles, WorkspaceKind.MetadataAsSource, WorkspaceKind.MSBuild, WorkspaceKind.Interactive), Shared] -internal class LspWorkspaceRegistrationEventListener : IEventListener +internal class LspWorkspaceRegistrationEventListener : IEventListener, IEventListenerStoppable { private readonly LspWorkspaceRegistrationService _lspWorkspaceRegistrationService; @@ -26,5 +26,10 @@ public void StartListening(Workspace workspace, object _) { _lspWorkspaceRegistrationService.Register(workspace); } + + public void StopListening(Workspace workspace) + { + _lspWorkspaceRegistrationService.Deregister(workspace); + } } diff --git a/src/Features/LanguageServer/Protocol/Workspaces/LspWorkspaceRegistrationService.cs b/src/Features/LanguageServer/Protocol/Workspaces/LspWorkspaceRegistrationService.cs index 4fcddcd1ef579..8f780f47730df 100644 --- a/src/Features/LanguageServer/Protocol/Workspaces/LspWorkspaceRegistrationService.cs +++ b/src/Features/LanguageServer/Protocol/Workspaces/LspWorkspaceRegistrationService.cs @@ -43,6 +43,15 @@ public virtual void Register(Workspace workspace) workspace.WorkspaceChanged += OnLspWorkspaceChanged; } + public void Deregister(Workspace workspace) + { + workspace.WorkspaceChanged -= OnLspWorkspaceChanged; + lock (_gate) + { + _registrations = _registrations.Remove(workspace); + } + } + private void OnLspWorkspaceChanged(object? sender, WorkspaceChangeEventArgs e) { LspSolutionChanged?.Invoke(this, e); @@ -56,6 +65,8 @@ public void Dispose() { workspace.WorkspaceChanged -= OnLspWorkspaceChanged; } + + _registrations = _registrations.Clear(); } } diff --git a/src/Features/LanguageServer/ProtocolUnitTests/Completion/CompletionResolveTests.cs b/src/Features/LanguageServer/ProtocolUnitTests/Completion/CompletionResolveTests.cs index 41e4b6a8ae057..80f6d3ef3745d 100644 --- a/src/Features/LanguageServer/ProtocolUnitTests/Completion/CompletionResolveTests.cs +++ b/src/Features/LanguageServer/ProtocolUnitTests/Completion/CompletionResolveTests.cs @@ -12,7 +12,7 @@ using Microsoft.CodeAnalysis.Completion; using Microsoft.CodeAnalysis.Host; using Microsoft.CodeAnalysis.LanguageServer.Handler; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Text; using Microsoft.VisualStudio.LanguageServer.Protocol; @@ -181,7 +181,7 @@ class B : A var selectedItem = CodeAnalysis.Completion.CompletionItem.Create(displayText: "M"); var textEdit = await CompletionResolveHandler.GenerateTextEditAsync( - document, new TestCaretOutOfScopeCompletionService(document.Project.Solution.Workspace), selectedItem, snippetsSupported: true, CancellationToken.None).ConfigureAwait(false); + document, new TestCaretOutOfScopeCompletionService(testLspServer.TestWorkspace.Services.SolutionServices), selectedItem, snippetsSupported: true, CancellationToken.None).ConfigureAwait(false); Assert.Equal(@"public override void M() { @@ -431,7 +431,7 @@ private static T ConvertToClientCompletionItem(T serverCompletionItem) where private class TestCaretOutOfScopeCompletionService : CompletionService { - public TestCaretOutOfScopeCompletionService(Workspace workspace) : base(workspace) + public TestCaretOutOfScopeCompletionService(SolutionServices services) : base(services) { } @@ -459,7 +459,7 @@ public override Task GetChangeAsync( return Task.FromResult(CompletionChange.Create(textChange, newPosition: 0)); } - internal override bool ShouldTriggerCompletion(Project project, HostLanguageServices languageServices, SourceText text, int caretPosition, CompletionTrigger trigger, CodeAnalysis.Completion.CompletionOptions options, OptionSet passthroughOptions, ImmutableHashSet roles = null) + internal override bool ShouldTriggerCompletion(Project project, LanguageServices languageServices, SourceText text, int caretPosition, CompletionTrigger trigger, CodeAnalysis.Completion.CompletionOptions options, OptionSet passthroughOptions, ImmutableHashSet roles = null) => false; internal override CompletionRules GetRules(CodeAnalysis.Completion.CompletionOptions options) diff --git a/src/Features/LanguageServer/ProtocolUnitTests/Diagnostics/AbstractPullDiagnosticTestsBase.cs b/src/Features/LanguageServer/ProtocolUnitTests/Diagnostics/AbstractPullDiagnosticTestsBase.cs index dba7b0c11c168..3f00f0bdf8bf0 100644 --- a/src/Features/LanguageServer/ProtocolUnitTests/Diagnostics/AbstractPullDiagnosticTestsBase.cs +++ b/src/Features/LanguageServer/ProtocolUnitTests/Diagnostics/AbstractPullDiagnosticTestsBase.cs @@ -8,6 +8,8 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; +using Microsoft.CodeAnalysis.CSharp.RemoveUnnecessaryImports; +using Microsoft.CodeAnalysis.CSharp.RemoveUnnecessaryParentheses; using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces; using Microsoft.CodeAnalysis.LanguageServer.Handler; @@ -25,12 +27,24 @@ namespace Microsoft.CodeAnalysis.LanguageServer.UnitTests.Diagnostics { - using DocumentDiagnosticPartialReport = SumType, DocumentDiagnosticPartialResult>; + using DocumentDiagnosticPartialReport = SumType; public abstract class AbstractPullDiagnosticTestsBase : AbstractLanguageServerProtocolTests { - private protected override TestAnalyzerReferenceByLanguage TestAnalyzerReferences => new(DiagnosticExtensions.GetCompilerDiagnosticAnalyzersMap() - .Add(InternalLanguageNames.TypeScript, ImmutableArray.Create(new MockTypescriptDiagnosticAnalyzer()))); + private protected override TestAnalyzerReferenceByLanguage TestAnalyzerReferences + { + get + { + var builder = ImmutableDictionary.CreateBuilder>(); + builder.Add(LanguageNames.CSharp, ImmutableArray.Create( + DiagnosticExtensions.GetCompilerDiagnosticAnalyzer(LanguageNames.CSharp), + new CSharpRemoveUnnecessaryImportsDiagnosticAnalyzer(), + new CSharpRemoveUnnecessaryExpressionParenthesesDiagnosticAnalyzer())); + builder.Add(LanguageNames.VisualBasic, ImmutableArray.Create(DiagnosticExtensions.GetCompilerDiagnosticAnalyzer(LanguageNames.VisualBasic))); + builder.Add(InternalLanguageNames.TypeScript, ImmutableArray.Create(new MockTypescriptDiagnosticAnalyzer())); + return new(builder.ToImmutableDictionary()); + } + } protected override TestComposition Composition => base.Composition.AddParts(typeof(MockTypescriptDiagnosticAnalyzer)); diff --git a/src/Features/LanguageServer/ProtocolUnitTests/Diagnostics/PullDiagnosticTests.cs b/src/Features/LanguageServer/ProtocolUnitTests/Diagnostics/PullDiagnosticTests.cs index 4669c384bf3b3..79b529a2a7bf8 100644 --- a/src/Features/LanguageServer/ProtocolUnitTests/Diagnostics/PullDiagnosticTests.cs +++ b/src/Features/LanguageServer/ProtocolUnitTests/Diagnostics/PullDiagnosticTests.cs @@ -7,8 +7,10 @@ using System.Collections.Immutable; using System.Composition; using System.Linq; +using System.ServiceModel.Syndication; using System.Threading; using System.Threading.Tasks; +using Microsoft.CodeAnalysis.CodeStyle; using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.EditAndContinue; using Microsoft.CodeAnalysis.Editor.Test; @@ -99,7 +101,7 @@ public async Task TestNoDocumentDiagnosticsForOpenFilesIfDefaultAndFeatureFlagOf await OpenDocumentAsync(testLspServer, document); // Ensure we get no diagnostics when feature flag is off. - testLspServer.TestWorkspace.GlobalOptions.SetGlobalOption(new OptionKey(DiagnosticOptions.LspPullDiagnosticsFeatureFlag), false); + testLspServer.TestWorkspace.GlobalOptions.SetGlobalOption(new OptionKey(DiagnosticOptionsStorage.LspPullDiagnosticsFeatureFlag), false); await Assert.ThrowsAsync(async () => await RunGetDocumentPullDiagnosticsAsync(testLspServer, document.GetURI(), useVSDiagnostics)); } @@ -117,7 +119,7 @@ public async Task TestDocumentDiagnosticsForOpenFilesIfDefaultAndFeatureFlagOn(b var document = testLspServer.GetCurrentSolution().Projects.Single().Documents.Single(); await OpenDocumentAsync(testLspServer, document); - testLspServer.TestWorkspace.GlobalOptions.SetGlobalOption(new OptionKey(DiagnosticOptions.LspPullDiagnosticsFeatureFlag), true); + testLspServer.TestWorkspace.GlobalOptions.SetGlobalOption(new OptionKey(DiagnosticOptionsStorage.LspPullDiagnosticsFeatureFlag), true); var results = await RunGetDocumentPullDiagnosticsAsync(testLspServer, document.GetURI(), useVSDiagnostics); Assert.Equal("CS1513", results.Single().Diagnostics.Single().Code); @@ -529,6 +531,97 @@ public async Task TestDocumentDiagnosticsIncludesSourceGeneratorDiagnostics(bool Assert.Equal(DiagnosticProducingGenerator.Descriptor.Id, diagnostic.Code); } + [Theory, CombinatorialData] + public async Task TestDocumentDiagnosticsWithFadingOptionOn(bool useVSDiagnostics) + { + var markup = +@" +{|first:using System.Linq; +using System.Threading;|} +class A +{ +}"; + using var testLspServer = await CreateTestWorkspaceWithDiagnosticsAsync(markup, BackgroundAnalysisScope.OpenFiles, useVSDiagnostics); + var firstLocation = testLspServer.GetLocations("first").Single().Range; + testLspServer.TestWorkspace.GlobalOptions.SetGlobalOption(new OptionKey(FadingOptions.FadeOutUnusedImports, LanguageNames.CSharp), true); + + var document = testLspServer.GetCurrentSolution().Projects.Single().Documents.Single(); + + await OpenDocumentAsync(testLspServer, document); + + var results = await RunGetDocumentPullDiagnosticsAsync( + testLspServer, document.GetURI(), useVSDiagnostics); + + // We should have an unnecessary diagnostic marking all the usings. + Assert.True(results.Single().Diagnostics![0].Tags!.Contains(DiagnosticTag.Unnecessary)); + Assert.Equal(firstLocation, results.Single().Diagnostics![1].Range); + + // We should have a regular diagnostic marking all the usings that doesn't fade. + Assert.False(results.Single().Diagnostics![1].Tags!.Contains(DiagnosticTag.Unnecessary)); + Assert.Equal(firstLocation, results.Single().Diagnostics![1].Range); + } + + [Theory, CombinatorialData] + public async Task TestDocumentDiagnosticsWithFadingOptionOff(bool useVSDiagnostics) + { + var markup = +@" +{|first:using System.Linq; +using System.Threading;|} +class A +{ +}"; + using var testLspServer = await CreateTestWorkspaceWithDiagnosticsAsync(markup, BackgroundAnalysisScope.OpenFiles, useVSDiagnostics); + var firstLocation = testLspServer.GetLocations("first").Single().Range; + testLspServer.TestWorkspace.GlobalOptions.SetGlobalOption(new OptionKey(FadingOptions.FadeOutUnusedImports, LanguageNames.CSharp), false); + + var document = testLspServer.GetCurrentSolution().Projects.Single().Documents.Single(); + + await OpenDocumentAsync(testLspServer, document); + + var results = await RunGetDocumentPullDiagnosticsAsync( + testLspServer, document.GetURI(), useVSDiagnostics); + + Assert.All(results.Single().Diagnostics, d => Assert.False(d.Tags!.Contains(DiagnosticTag.Unnecessary))); + } + + [Theory, CombinatorialData] + public async Task TestDocumentDiagnosticsWithNotConfigurableFading(bool useVSDiagnostics) + { + var markup = +@"class A +{ + void M() + { + _ = {|line:{|open:(|}1 + 2 +|} + 3 + 4{|close:)|}; + } +}"; + using var testLspServer = await CreateTestWorkspaceWithDiagnosticsAsync(markup, BackgroundAnalysisScope.OpenFiles, useVSDiagnostics); + var openLocation = testLspServer.GetLocations("open").Single().Range; + var closeLocation = testLspServer.GetLocations("close").Single().Range; + var lineLocation = testLspServer.GetLocations("line").Single().Range; + + var document = testLspServer.GetCurrentSolution().Projects.Single().Documents.Single(); + + await OpenDocumentAsync(testLspServer, document); + + var results = await RunGetDocumentPullDiagnosticsAsync( + testLspServer, document.GetURI(), useVSDiagnostics); + + // The first line should have a diagnostic on it that is not marked as unnecessary. + Assert.False(results.Single().Diagnostics![0].Tags!.Contains(DiagnosticTag.Unnecessary)); + Assert.Equal(lineLocation, results.Single().Diagnostics![0].Range); + + // The open paren should have an unnecessary diagnostic. + Assert.True(results.Single().Diagnostics![1].Tags!.Contains(DiagnosticTag.Unnecessary)); + Assert.Equal(openLocation, results.Single().Diagnostics![1].Range); + + // The close paren should have an unnecessary diagnostic. + Assert.True(results.Single().Diagnostics![2].Tags!.Contains(DiagnosticTag.Unnecessary)); + Assert.Equal(closeLocation, results.Single().Diagnostics![2].Range); + } + #endregion #region Workspace Diagnostics diff --git a/src/Features/LanguageServer/ProtocolUnitTests/Hover/HoverTests.cs b/src/Features/LanguageServer/ProtocolUnitTests/Hover/HoverTests.cs index 9127740b2806d..53e371d2ed53c 100644 --- a/src/Features/LanguageServer/ProtocolUnitTests/Hover/HoverTests.cs +++ b/src/Features/LanguageServer/ProtocolUnitTests/Hover/HoverTests.cs @@ -262,7 +262,7 @@ [link text](https://google.com) var results = await RunGetHoverAsync( testLspServer, expectedLocation).ConfigureAwait(false); - Assert.Equal(expectedMarkdown, results.Contents.Third.Value); + Assert.Equal(expectedMarkdown, results.Contents.Value.Fourth.Value); } [Fact] @@ -329,7 +329,7 @@ a string var results = await RunGetHoverAsync( testLspServer, expectedLocation).ConfigureAwait(false); - Assert.Equal(expectedText, results.Contents.Third.Value); + Assert.Equal(expectedText, results.Contents.Value.Fourth.Value); } [Fact] @@ -383,7 +383,7 @@ void A.AMethod(int i) var results = await RunGetHoverAsync( testLspServer, expectedLocation).ConfigureAwait(false); - Assert.Equal(expectedMarkdown, results.Contents.Third.Value); + Assert.Equal(expectedMarkdown, results.Contents.Value.Fourth.Value); } private static async Task RunGetHoverAsync( @@ -395,7 +395,7 @@ void A.AMethod(int i) CreateTextDocumentPositionParams(caret, projectContext), CancellationToken.None); } - private void VerifyVSContent(LSP.Hover hover, string expectedContent) + private static void VerifyVSContent(LSP.Hover hover, string expectedContent) { var vsHover = Assert.IsType(hover); var containerElement = (ContainerElement)vsHover.RawContent; @@ -406,7 +406,7 @@ private void VerifyVSContent(LSP.Hover hover, string expectedContent) Assert.Equal(expectedContent, content); } - private void GetClassifiedTextElements(ContainerElement container, ArrayBuilder classifiedTextElements) + private static void GetClassifiedTextElements(ContainerElement container, ArrayBuilder classifiedTextElements) { foreach (var element in container.Elements) { diff --git a/src/Features/LanguageServer/ProtocolUnitTests/Miscellaneous/LspMiscellaneousFilesWorkspaceTests.cs b/src/Features/LanguageServer/ProtocolUnitTests/Miscellaneous/LspMiscellaneousFilesWorkspaceTests.cs index 1ad0348068637..9829c4e06afe2 100644 --- a/src/Features/LanguageServer/ProtocolUnitTests/Miscellaneous/LspMiscellaneousFilesWorkspaceTests.cs +++ b/src/Features/LanguageServer/ProtocolUnitTests/Miscellaneous/LspMiscellaneousFilesWorkspaceTests.cs @@ -65,7 +65,7 @@ void M() await testLspServer.InsertTextAsync(looseFileUri, (0, 0, source)).ConfigureAwait(false); var caret = new LSP.Location { Range = new() { Start = new(0, 6), End = new(0, 7) }, Uri = looseFileUri }; var hover = await RunGetHoverAsync(testLspServer, caret).ConfigureAwait(false); - Assert.Contains("class A", hover.Contents.Third.Value); + Assert.Contains("class A", hover.Contents!.Value.Fourth.Value); await AssertFileInMiscWorkspaceAsync(testLspServer, looseFileUri).ConfigureAwait(false); } diff --git a/src/Features/LanguageServer/ProtocolUnitTests/Workspaces/LspWorkspaceRegistrationServiceTests.cs b/src/Features/LanguageServer/ProtocolUnitTests/Workspaces/LspWorkspaceRegistrationServiceTests.cs new file mode 100644 index 0000000000000..01ab6f26a47db --- /dev/null +++ b/src/Features/LanguageServer/ProtocolUnitTests/Workspaces/LspWorkspaceRegistrationServiceTests.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.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Microsoft.VisualStudio.Composition; +using Roslyn.Test.Utilities; +using Xunit; + +namespace Microsoft.CodeAnalysis.LanguageServer.UnitTests.Workspaces; +public class LspWorkspaceRegistrationServiceTests : AbstractLanguageServerProtocolTests +{ + [Fact] + public async Task TestDisposedWorkspaceDeregistered() + { + var markup = ""; + TestWorkspaceRegistrationService registrationService; + using (var testLspServer = await CreateTestLspServerAsync(markup)) + { + registrationService = (TestWorkspaceRegistrationService)testLspServer.TestWorkspace.ExportProvider.GetExportedValue(); + } + + Assert.Empty(registrationService.GetAllRegistrations()); + } +} diff --git a/src/Features/Lsif/Generator/CompilerInvocation.cs b/src/Features/Lsif/Generator/CompilerInvocation.cs index 92557df153a6f..17451f67d4886 100644 --- a/src/Features/Lsif/Generator/CompilerInvocation.cs +++ b/src/Features/Lsif/Generator/CompilerInvocation.cs @@ -19,11 +19,11 @@ namespace Microsoft.CodeAnalysis.LanguageServerIndexFormat.Generator internal class CompilerInvocation { public Compilation Compilation { get; } - public HostLanguageServices LanguageServices { get; } + public LanguageServices LanguageServices { get; } public string ProjectFilePath { get; } public GeneratorOptions Options { get; } - public CompilerInvocation(Compilation compilation, HostLanguageServices languageServices, string projectFilePath, GeneratorOptions options) + public CompilerInvocation(Compilation compilation, LanguageServices languageServices, string projectFilePath, GeneratorOptions options) { Compilation = compilation; LanguageServices = languageServices; @@ -35,14 +35,18 @@ public static async Task CreateFromJsonAsync(string jsonCont { var invocationInfo = JsonConvert.DeserializeObject(jsonContents); Assumes.Present(invocationInfo); + return await CreateFromInvocationInfoAsync(invocationInfo); + } + public static async Task CreateFromInvocationInfoAsync(CompilerInvocationInfo invocationInfo) + { // We will use a Workspace to simplify the creation of the compilation, but will be careful not to return the Workspace instance from this class. // We will still provide the language services which are used by the generator itself, but we don't tie it to a Workspace object so we can // run this as an in-proc source generator if one day desired. var workspace = new AdhocWorkspace(); var languageName = GetLanguageName(invocationInfo); - var languageServices = workspace.Services.GetLanguageServices(languageName); + var languageServices = workspace.Services.GetLanguageServices(languageName).LanguageServices; var mapPath = GetPathMapper(invocationInfo); @@ -180,7 +184,7 @@ static string AddDirectorySuffixIfMissing(string path) /// /// A simple data class that represents the schema for JSON serialization. /// - private sealed class CompilerInvocationInfo + public sealed class CompilerInvocationInfo { #nullable disable // this class is used for deserialization by Newtonsoft.Json, so we don't really need warnings about this class itself diff --git a/src/Features/Lsif/Generator/Generator.cs b/src/Features/Lsif/Generator/Generator.cs index b256826723821..9a3b0fdbac5b3 100644 --- a/src/Features/Lsif/Generator/Generator.cs +++ b/src/Features/Lsif/Generator/Generator.cs @@ -13,7 +13,7 @@ using Microsoft.CodeAnalysis.LanguageServerIndexFormat.Generator.Graph; using Microsoft.CodeAnalysis.LanguageServerIndexFormat.Generator.ResultSetTracking; using Microsoft.CodeAnalysis.LanguageServerIndexFormat.Generator.Writing; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Roslyn.Utilities; using Methods = Microsoft.VisualStudio.LanguageServer.Protocol.Methods; @@ -49,7 +49,7 @@ public static Generator CreateAndWriteCapabilitiesVertex(ILsifJsonWriter lsifJso return generator; } - public async Task GenerateForCompilationAsync(Compilation compilation, string projectPath, HostLanguageServices languageServices, GeneratorOptions options) + public async Task GenerateForCompilationAsync(Compilation compilation, string projectPath, LanguageServices languageServices, GeneratorOptions options) { var projectVertex = new Graph.LsifProject(kind: GetLanguageKind(compilation.Language), new Uri(projectPath), _idFactory); _lsifJsonWriter.Write(projectVertex); @@ -118,7 +118,7 @@ public async Task GenerateForCompilationAsync(Compilation compilation, string pr /// private static async Task> GenerateForDocumentAsync( SemanticModel semanticModel, - HostLanguageServices languageServices, + LanguageServices languageServices, GeneratorOptions options, IResultSetTracker topLevelSymbolsResultSetTracker, ILsifJsonWriter lsifJsonWriter, diff --git a/src/Features/Lsif/Generator/GeneratorOptions.cs b/src/Features/Lsif/Generator/GeneratorOptions.cs index 4f008e6c6abe5..1fa2445c6d7fd 100644 --- a/src/Features/Lsif/Generator/GeneratorOptions.cs +++ b/src/Features/Lsif/Generator/GeneratorOptions.cs @@ -2,7 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Structure; namespace Microsoft.CodeAnalysis.LanguageServerIndexFormat.Generator diff --git a/src/Features/Lsif/Generator/Microsoft.CodeAnalysis.LanguageServerIndexFormat.Generator.csproj b/src/Features/Lsif/Generator/Microsoft.CodeAnalysis.LanguageServerIndexFormat.Generator.csproj index c25185b9cafd1..325e42692b09c 100644 --- a/src/Features/Lsif/Generator/Microsoft.CodeAnalysis.LanguageServerIndexFormat.Generator.csproj +++ b/src/Features/Lsif/Generator/Microsoft.CodeAnalysis.LanguageServerIndexFormat.Generator.csproj @@ -47,8 +47,16 @@ + + + + + + + diff --git a/src/Features/Lsif/Generator/Program.cs b/src/Features/Lsif/Generator/Program.cs index 2b98744299bb5..ae114f56522e8 100644 --- a/src/Features/Lsif/Generator/Program.cs +++ b/src/Features/Lsif/Generator/Program.cs @@ -3,6 +3,7 @@ // See the LICENSE file in the project root for more information. using System; +using System.Collections.Immutable; using System.CommandLine; using System.CommandLine.Builder; using System.CommandLine.Invocation; @@ -14,6 +15,7 @@ using Microsoft.Build.Locator; using Microsoft.CodeAnalysis.LanguageServerIndexFormat.Generator.Writing; using Microsoft.CodeAnalysis.MSBuild; +using CompilerInvocationsReader = Microsoft.Build.Logging.StructuredLogger.CompilerInvocationsReader; namespace Microsoft.CodeAnalysis.LanguageServerIndexFormat.Generator { @@ -26,17 +28,18 @@ public static Task Main(string[] args) new Option("--solution", "input solution file") { Argument = new Argument().ExistingOnly() }, new Option("--project", "input project file") { Argument = new Argument().ExistingOnly() }, new Option("--compiler-invocation", "path to a .json file that contains the information for a csc/vbc invocation") { Argument = new Argument().ExistingOnly() }, + new Option("--binlog", "path to a MSBuild binlog that csc/vbc invocations will be extracted from") { Argument = new Argument().ExistingOnly() }, new Option("--output", "file to write the LSIF output to, instead of the console") { Argument = new Argument(defaultValue: () => null).LegalFilePathsOnly() }, new Option("--output-format", "format of LSIF output") { Argument = new Argument(defaultValue: () => LsifFormat.Line) }, new Option("--log", "file to write a log to") { Argument = new Argument(defaultValue: () => null).LegalFilePathsOnly() } }; - generateCommand.Handler = CommandHandler.Create((Func)GenerateAsync); + generateCommand.Handler = CommandHandler.Create((Func)GenerateAsync); return generateCommand.InvokeAsync(args); } - private static async Task GenerateAsync(FileInfo? solution, FileInfo? project, FileInfo? compilerInvocation, string? output, LsifFormat outputFormat, string? log) + private static async Task GenerateAsync(FileInfo? solution, FileInfo? project, FileInfo? compilerInvocation, FileInfo? binLog, string? output, LsifFormat outputFormat, string? log) { // If we have an output file, we'll write to that, else we'll use Console.Out using var outputFile = output != null ? new StreamWriter(output) : null; @@ -53,21 +56,32 @@ private static async Task GenerateAsync(FileInfo? solution, FileInfo? project, F try { // Exactly one of "solution", or "project" or "compilerInvocation" should be specified - if (solution != null && project == null && compilerInvocation == null) + var fileInputs = new[] { solution, project, compilerInvocation, binLog }; + var nonNullFileInputs = fileInputs.Count(p => p is not null); + + if (nonNullFileInputs != 1) + { + throw new Exception("Exactly one of either a solution path, project path or a compiler invocation path should be supplied."); + } + + if (solution != null) { + await LocateAndRegisterMSBuild(logFile); await GenerateFromSolutionAsync(solution, lsifWriter, logFile); } - else if (solution == null && project != null && compilerInvocation == null) + else if (project != null) { + await LocateAndRegisterMSBuild(logFile); await GenerateFromProjectAsync(project, lsifWriter, logFile); } - else if (solution == null && project == null && compilerInvocation != null) + else if (compilerInvocation != null) { await GenerateFromCompilerInvocationAsync(compilerInvocation, lsifWriter, logFile); } else { - throw new Exception("Exactly one of either a solution path, project path or a compiler invocation path should be supplied."); + await LocateAndRegisterMSBuild(logFile); + await GenerateFromBinaryLogAsync(binLog!, lsifWriter, logFile); } } catch (Exception e) @@ -101,8 +115,7 @@ private static async Task LocateAndRegisterMSBuild(TextWriter logFile) private static async Task GenerateFromProjectAsync(FileInfo projectFile, ILsifJsonWriter lsifWriter, TextWriter logFile) { - await LocateAndRegisterMSBuild(logFile); - await GenerateWithMSBuildLocatedAsync( + await GenerateWithMSBuildWorkspaceAsync( projectFile, lsifWriter, logFile, async w => { @@ -113,8 +126,7 @@ await GenerateWithMSBuildLocatedAsync( private static async Task GenerateFromSolutionAsync(FileInfo solutionFile, ILsifJsonWriter lsifWriter, TextWriter logFile) { - await LocateAndRegisterMSBuild(logFile); - await GenerateWithMSBuildLocatedAsync( + await GenerateWithMSBuildWorkspaceAsync( solutionFile, lsifWriter, logFile, w => w.OpenSolutionAsync(solutionFile.FullName)); } @@ -122,7 +134,7 @@ await GenerateWithMSBuildLocatedAsync( // This method can't be loaded until we've registered MSBuild with MSBuildLocator, as otherwise // we load ILogger prematurely which breaks MSBuildLocator. [MethodImpl(MethodImplOptions.NoInlining)] - private static async Task GenerateWithMSBuildLocatedAsync( + private static async Task GenerateWithMSBuildWorkspaceAsync( FileInfo solutionOrProjectFile, ILsifJsonWriter lsifWriter, TextWriter logFile, Func> openAsync) { @@ -153,7 +165,7 @@ private static async Task GenerateWithMSBuildLocatedAsync( await logFile.WriteLineAsync($"Fetch of compilation for {project.FilePath} completed in {compilationCreationStopwatch.Elapsed.ToDisplayString()}."); var generationForProjectStopwatch = Stopwatch.StartNew(); - await lsifGenerator.GenerateForCompilationAsync(compilation, project.FilePath, project.LanguageServices, options); + await lsifGenerator.GenerateForCompilationAsync(compilation, project.FilePath, project.Services, options); generationForProjectStopwatch.Stop(); totalTimeInGenerationPhase += generationForProjectStopwatch.Elapsed; @@ -180,5 +192,34 @@ private static async Task GenerateFromCompilerInvocationAsync(FileInfo compilerI await lsifGenerator.GenerateForCompilationAsync(compilerInvocation.Compilation, compilerInvocation.ProjectFilePath, compilerInvocation.LanguageServices, compilerInvocation.Options); await logFile.WriteLineAsync($"Generation for {compilerInvocation.ProjectFilePath} completed in {generationStopwatch.Elapsed.ToDisplayString()}."); } + + // This method can't be loaded until we've registered MSBuild with MSBuildLocator, as otherwise we might load a type prematurely. + [MethodImpl(MethodImplOptions.NoInlining)] + private static async Task GenerateFromBinaryLogAsync(FileInfo binLog, ILsifJsonWriter lsifWriter, TextWriter logFile) + { + await logFile.WriteLineAsync($"Reading binlog {binLog.FullName}..."); + var msbuildInvocations = CompilerInvocationsReader.ReadInvocations(binLog.FullName).ToImmutableArray(); + + await logFile.WriteLineAsync($"Load of the binlog complete; {msbuildInvocations.Length} invocations were found."); + + var lsifGenerator = Generator.CreateAndWriteCapabilitiesVertex(lsifWriter); + + foreach (var msbuildInvocation in msbuildInvocations) + { + // Convert from the MSBuild "CompilerInvocation" type to our type that we use for our JSON-input mode already. + var invocationInfo = new CompilerInvocation.CompilerInvocationInfo + { + Arguments = msbuildInvocation.CommandLineArguments, + ProjectFilePath = msbuildInvocation.ProjectFilePath, + Tool = msbuildInvocation.Language == Microsoft.Build.Logging.StructuredLogger.CompilerInvocation.CSharp ? "csc" : "vbc" + }; + + var compilerInvocation = await CompilerInvocation.CreateFromInvocationInfoAsync(invocationInfo); + + var generationStopwatch = Stopwatch.StartNew(); + await lsifGenerator.GenerateForCompilationAsync(compilerInvocation.Compilation, compilerInvocation.ProjectFilePath, compilerInvocation.LanguageServices, compilerInvocation.Options); + await logFile.WriteLineAsync($"Generation for {compilerInvocation.ProjectFilePath} completed in {generationStopwatch.Elapsed.ToDisplayString()}."); + } + } } } diff --git a/src/Features/Lsif/GeneratorTest/HoverTests.vb b/src/Features/Lsif/GeneratorTest/HoverTests.vb index f8f4c2488e949..598b303738b9c 100644 --- a/src/Features/Lsif/GeneratorTest/HoverTests.vb +++ b/src/Features/Lsif/GeneratorTest/HoverTests.vb @@ -37,7 +37,7 @@ class C Dim rangeVertex = Await lsif.GetSelectedRangeAsync() Dim resultSetVertex = lsif.GetLinkedVertices(Of Graph.ResultSet)(rangeVertex, "next").Single() Dim hoverVertex = lsif.GetLinkedVertices(Of Graph.HoverResult)(resultSetVertex, Methods.TextDocumentHoverName).SingleOrDefault() - Dim hoverMarkupContent = DirectCast(hoverVertex.Result.Contents.Value, MarkupContent) + Dim hoverMarkupContent = DirectCast(hoverVertex.Result.Contents.Value.Fourth, MarkupContent) Dim expectedHoverContents As String Select Case code @@ -94,7 +94,7 @@ class C Dim rangeVertex = Await lsif.GetSelectedRangeAsync() Dim resultSetVertex = lsif.GetLinkedVertices(Of Graph.ResultSet)(rangeVertex, "next").Single() Dim hoverVertex = lsif.GetLinkedVertices(Of Graph.HoverResult)(resultSetVertex, Methods.TextDocumentHoverName).SingleOrDefault() - Dim hoverMarkupContent = DirectCast(hoverVertex.Result.Contents.Value, MarkupContent) + Dim hoverMarkupContent = DirectCast(hoverVertex.Result.Contents.Value.Fourth, MarkupContent) Dim expectedHoverContents As String Select Case code @@ -160,7 +160,7 @@ class C End If Next - Dim hoverMarkupContent = DirectCast(hoverVertex.Result.Contents.Value, MarkupContent) + Dim hoverMarkupContent = DirectCast(hoverVertex.Result.Contents.Value.Fourth, MarkupContent) Assert.Equal(MarkupKind.PlainText, hoverMarkupContent.Kind) Assert.Equal("class System.String" + Environment.NewLine, hoverMarkupContent.Value) End Function diff --git a/src/Features/Lsif/GeneratorTest/Utilities/TestLsifOutput.vb b/src/Features/Lsif/GeneratorTest/Utilities/TestLsifOutput.vb index 643b46cdf3c05..939464005eac2 100644 --- a/src/Features/Lsif/GeneratorTest/Utilities/TestLsifOutput.vb +++ b/src/Features/Lsif/GeneratorTest/Utilities/TestLsifOutput.vb @@ -35,7 +35,7 @@ Namespace Microsoft.CodeAnalysis.LanguageServerIndexFormat.Generator.UnitTests.U ' Assert we don't have any errors to prevent any typos in the tests Assert.Empty(compilation.GetDiagnostics().Where(Function(d) d.Severity = DiagnosticSeverity.Error)) - Await lsifGenerator.GenerateForCompilationAsync(compilation, project.FilePath, project.LanguageServices, GeneratorOptions.Default) + Await lsifGenerator.GenerateForCompilationAsync(compilation, project.FilePath, project.Services, GeneratorOptions.Default) Next End Function diff --git a/src/Features/VisualBasic/Portable/AddImport/VisualBasicAddImportFeatureService.vb b/src/Features/VisualBasic/Portable/AddImport/VisualBasicAddImportFeatureService.vb index ba19c8c027d2e..35aa5d41d3a07 100644 --- a/src/Features/VisualBasic/Portable/AddImport/VisualBasicAddImportFeatureService.vb +++ b/src/Features/VisualBasic/Portable/AddImport/VisualBasicAddImportFeatureService.vb @@ -11,7 +11,7 @@ Imports Microsoft.CodeAnalysis.Diagnostics Imports Microsoft.CodeAnalysis.Editing Imports Microsoft.CodeAnalysis.Formatting Imports Microsoft.CodeAnalysis.Host.Mef -Imports Microsoft.CodeAnalysis.LanguageServices +Imports Microsoft.CodeAnalysis.LanguageService Imports Microsoft.CodeAnalysis.Simplification Imports Microsoft.CodeAnalysis.VisualBasic.Syntax diff --git a/src/Features/VisualBasic/Portable/BraceCompletion/AbstractVisualBasicBraceCompletionService.vb b/src/Features/VisualBasic/Portable/BraceCompletion/AbstractVisualBasicBraceCompletionService.vb index 5f868cdb8f98a..cd07e75bf3889 100644 --- a/src/Features/VisualBasic/Portable/BraceCompletion/AbstractVisualBasicBraceCompletionService.vb +++ b/src/Features/VisualBasic/Portable/BraceCompletion/AbstractVisualBasicBraceCompletionService.vb @@ -3,8 +3,8 @@ ' See the LICENSE file in the project root for more information. Imports Microsoft.CodeAnalysis.BraceCompletion -Imports Microsoft.CodeAnalysis.LanguageServices -Imports Microsoft.CodeAnalysis.VisualBasic.LanguageServices +Imports Microsoft.CodeAnalysis.LanguageService +Imports Microsoft.CodeAnalysis.VisualBasic.LanguageService Namespace Microsoft.CodeAnalysis.VisualBasic.BraceCompletion Friend MustInherit Class AbstractVisualBasicBraceCompletionService diff --git a/src/Features/VisualBasic/Portable/BraceCompletion/BracketBraceCompletionService.vb b/src/Features/VisualBasic/Portable/BraceCompletion/BracketBraceCompletionService.vb index 768ccbd1cca6e..1b050659914f2 100644 --- a/src/Features/VisualBasic/Portable/BraceCompletion/BracketBraceCompletionService.vb +++ b/src/Features/VisualBasic/Portable/BraceCompletion/BracketBraceCompletionService.vb @@ -7,10 +7,10 @@ Imports System.Threading Imports Microsoft.CodeAnalysis Imports Microsoft.CodeAnalysis.BraceCompletion Imports Microsoft.CodeAnalysis.Host.Mef -Imports Microsoft.CodeAnalysis.LanguageServices +Imports Microsoft.CodeAnalysis.LanguageService Imports Microsoft.CodeAnalysis.Text Imports Microsoft.CodeAnalysis.VisualBasic -Imports Microsoft.CodeAnalysis.VisualBasic.LanguageServices +Imports Microsoft.CodeAnalysis.VisualBasic.LanguageService Imports Microsoft.CodeAnalysis.VisualBasic.Syntax Namespace Microsoft.CodeAnalysis.VisualBasic.BraceCompletion @@ -27,8 +27,8 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.BraceCompletion Protected Overrides ReadOnly Property OpeningBrace As Char = Bracket.OpenCharacter Protected Overrides ReadOnly Property ClosingBrace As Char = Bracket.CloseCharacter - Public Overrides Function AllowOverTypeAsync(context As BraceCompletionContext, cancellationToken As CancellationToken) As Task(Of Boolean) - Return AllowOverTypeInUserCodeWithValidClosingTokenAsync(context, cancellationToken) + Public Overrides Function AllowOverType(context As BraceCompletionContext, cancellationToken As CancellationToken) As Boolean + Return AllowOverTypeInUserCodeWithValidClosingToken(context, cancellationToken) End Function Protected Overrides Function IsValidOpeningBraceToken(token As SyntaxToken) As Boolean diff --git a/src/Features/VisualBasic/Portable/BraceCompletion/CurlyBraceCompletionService.vb b/src/Features/VisualBasic/Portable/BraceCompletion/CurlyBraceCompletionService.vb index f70a15678af9f..c650e77006045 100644 --- a/src/Features/VisualBasic/Portable/BraceCompletion/CurlyBraceCompletionService.vb +++ b/src/Features/VisualBasic/Portable/BraceCompletion/CurlyBraceCompletionService.vb @@ -23,16 +23,16 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.BraceCompletion Protected Overrides ReadOnly Property OpeningBrace As Char = CurlyBrace.OpenCharacter Protected Overrides ReadOnly Property ClosingBrace As Char = CurlyBrace.CloseCharacter - Public Overrides Function AllowOverTypeAsync(context As BraceCompletionContext, cancellationToken As CancellationToken) As Task(Of Boolean) - Return AllowOverTypeInUserCodeWithValidClosingTokenAsync(context, cancellationToken) + Public Overrides Function AllowOverType(context As BraceCompletionContext, cancellationToken As CancellationToken) As Boolean + Return AllowOverTypeInUserCodeWithValidClosingToken(context, cancellationToken) End Function - Public Overrides Async Function CanProvideBraceCompletionAsync(brace As Char, openingPosition As Integer, document As Document, cancellationToken As CancellationToken) As Task(Of Boolean) - If OpeningBrace = brace And Await InterpolationBraceCompletionService.IsPositionInInterpolationContextAsync(document, openingPosition, cancellationToken).ConfigureAwait(False) Then + Public Overrides Function CanProvideBraceCompletion(brace As Char, openingPosition As Integer, document As ParsedDocument, cancellationToken As CancellationToken) As Boolean + If OpeningBrace = brace And InterpolationBraceCompletionService.IsPositionInInterpolationContext(document, openingPosition) Then Return False End If - Return Await MyBase.CanProvideBraceCompletionAsync(brace, openingPosition, document, cancellationToken).ConfigureAwait(False) + Return MyBase.CanProvideBraceCompletion(brace, openingPosition, document, cancellationToken) End Function Protected Overrides Function IsValidOpeningBraceToken(token As SyntaxToken) As Boolean diff --git a/src/Features/VisualBasic/Portable/BraceCompletion/InterpolatedStringBraceCompletionService.vb b/src/Features/VisualBasic/Portable/BraceCompletion/InterpolatedStringBraceCompletionService.vb index f481e109ae032..74272722ad892 100644 --- a/src/Features/VisualBasic/Portable/BraceCompletion/InterpolatedStringBraceCompletionService.vb +++ b/src/Features/VisualBasic/Portable/BraceCompletion/InterpolatedStringBraceCompletionService.vb @@ -29,12 +29,12 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.BraceCompletion Return IsValidOpeningBraceToken(token) AndAlso token.Span.End - 1 = position End Function - Public Overrides Function AllowOverTypeAsync(context As BraceCompletionContext, cancellationToken As CancellationToken) As Task(Of Boolean) - Return AllowOverTypeWithValidClosingTokenAsync(context, cancellationToken) + Public Overrides Function AllowOverType(context As BraceCompletionContext, cancellationToken As CancellationToken) As Boolean + Return AllowOverTypeWithValidClosingToken(context) End Function - Public Overrides Async Function CanProvideBraceCompletionAsync(brace As Char, openingPosition As Integer, document As Document, cancellationToken As CancellationToken) As Task(Of Boolean) - Return OpeningBrace = brace And Await IsPositionInInterpolatedStringContextAsync(document, openingPosition, cancellationToken).ConfigureAwait(False) + Public Overrides Function CanProvideBraceCompletion(brace As Char, openingPosition As Integer, document As ParsedDocument, cancellationToken As CancellationToken) As Boolean + Return OpeningBrace = brace And IsPositionInInterpolatedStringContext(document, openingPosition) End Function Protected Overrides Function IsValidOpeningBraceToken(token As SyntaxToken) As Boolean @@ -45,15 +45,13 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.BraceCompletion Return token.IsKind(SyntaxKind.DoubleQuoteToken) End Function - Public Shared Async Function IsPositionInInterpolatedStringContextAsync(document As Document, position As Integer, cancellationToken As CancellationToken) As Task(Of Boolean) + Public Shared Function IsPositionInInterpolatedStringContext(document As ParsedDocument, position As Integer) As Boolean If position = 0 Then Return False End If - Dim text = Await document.GetTextAsync(cancellationToken).ConfigureAwait(False) - ' Position can be in an interpolated string if the preceding character is a $ - Return text(position - 1) = "$"c + Return document.Text(position - 1) = "$"c End Function End Class End Namespace diff --git a/src/Features/VisualBasic/Portable/BraceCompletion/InterpolationBraceCompletionService.vb b/src/Features/VisualBasic/Portable/BraceCompletion/InterpolationBraceCompletionService.vb index fcf0b759b0e36..8b32312ce4f55 100644 --- a/src/Features/VisualBasic/Portable/BraceCompletion/InterpolationBraceCompletionService.vb +++ b/src/Features/VisualBasic/Portable/BraceCompletion/InterpolationBraceCompletionService.vb @@ -28,12 +28,12 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.BraceCompletion Return IsValidOpeningBraceToken(token) End Function - Public Overrides Function AllowOverTypeAsync(context As BraceCompletionContext, cancellationToken As CancellationToken) As Task(Of Boolean) - Return AllowOverTypeWithValidClosingTokenAsync(context, cancellationToken) + Public Overrides Function AllowOverType(context As BraceCompletionContext, cancellationToken As CancellationToken) As Boolean + Return AllowOverTypeWithValidClosingToken(context) End Function - Public Overrides Async Function CanProvideBraceCompletionAsync(brace As Char, openingPosition As Integer, document As Document, cancellationToken As CancellationToken) As Task(Of Boolean) - Return OpeningBrace = brace And Await IsPositionInInterpolationContextAsync(document, openingPosition, cancellationToken).ConfigureAwait(False) + Public Overrides Function CanProvideBraceCompletion(brace As Char, openingPosition As Integer, document As ParsedDocument, cancellationToken As CancellationToken) As Boolean + Return OpeningBrace = brace And IsPositionInInterpolationContext(document, openingPosition) End Function Protected Overrides Function IsValidOpeningBraceToken(token As SyntaxToken) As Boolean @@ -45,7 +45,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.BraceCompletion Return token.IsKind(SyntaxKind.CloseBraceToken) End Function - Public Shared Async Function IsPositionInInterpolationContextAsync(document As Document, position As Integer, cancellationToken As CancellationToken) As Task(Of Boolean) + Public Shared Function IsPositionInInterpolationContext(document As ParsedDocument, position As Integer) As Boolean If position = 0 Then Return False End If @@ -53,14 +53,13 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.BraceCompletion ' First, check to see if the character to the left of the position is an open curly. ' If it is, we shouldn't complete because the user may be trying to escape a curly. ' E.g. they are trying to type $"{{" - If (Await CouldEscapePreviousOpenBraceAsync("{"c, position, document, cancellationToken).ConfigureAwait(False)) Then + If CouldEscapePreviousOpenBrace("{"c, position, document.Text) Then Return False End If ' Next, check to see if the token we're typing is part of an existing interpolated string. ' - Dim root = Await document.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(False) - Dim token = root.FindTokenOnRightOfPosition(position) + Dim token = document.Root.FindTokenOnRightOfPosition(position) If Not token.Span.IntersectsWith(position) Then Return False diff --git a/src/Features/VisualBasic/Portable/BraceCompletion/LessAndGreaterThanCompletionService.vb b/src/Features/VisualBasic/Portable/BraceCompletion/LessAndGreaterThanCompletionService.vb index 0ccf0ff748621..e39e024003fd1 100644 --- a/src/Features/VisualBasic/Portable/BraceCompletion/LessAndGreaterThanCompletionService.vb +++ b/src/Features/VisualBasic/Portable/BraceCompletion/LessAndGreaterThanCompletionService.vb @@ -43,8 +43,8 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.BraceCompletion Return True End Function - Public Overrides Function AllowOverTypeAsync(context As BraceCompletionContext, cancellationToken As CancellationToken) As Task(Of Boolean) - Return AllowOverTypeInUserCodeWithValidClosingTokenAsync(context, cancellationToken) + Public Overrides Function AllowOverType(context As BraceCompletionContext, cancellationToken As CancellationToken) As Boolean + Return AllowOverTypeInUserCodeWithValidClosingToken(context, cancellationToken) End Function End Class End Namespace diff --git a/src/Features/VisualBasic/Portable/BraceCompletion/ParenthesisBraceCompletionService.vb b/src/Features/VisualBasic/Portable/BraceCompletion/ParenthesisBraceCompletionService.vb index 52acc51bc5c31..639f282a35fa1 100644 --- a/src/Features/VisualBasic/Portable/BraceCompletion/ParenthesisBraceCompletionService.vb +++ b/src/Features/VisualBasic/Portable/BraceCompletion/ParenthesisBraceCompletionService.vb @@ -51,8 +51,8 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.BraceCompletion Return True End Function - Public Overrides Function AllowOverTypeAsync(context As BraceCompletionContext, cancellationToken As CancellationToken) As Task(Of Boolean) - Return AllowOverTypeInUserCodeWithValidClosingTokenAsync(context, cancellationToken) + Public Overrides Function AllowOverType(context As BraceCompletionContext, cancellationToken As CancellationToken) As Boolean + Return AllowOverTypeInUserCodeWithValidClosingToken(context, cancellationToken) End Function End Class End Namespace diff --git a/src/Features/VisualBasic/Portable/BraceCompletion/StringLiteralBraceCompletionService.vb b/src/Features/VisualBasic/Portable/BraceCompletion/StringLiteralBraceCompletionService.vb index 4828a56dec3a3..6b3aa54ba318e 100644 --- a/src/Features/VisualBasic/Portable/BraceCompletion/StringLiteralBraceCompletionService.vb +++ b/src/Features/VisualBasic/Portable/BraceCompletion/StringLiteralBraceCompletionService.vb @@ -23,16 +23,16 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.BraceCompletion Protected Overrides ReadOnly Property OpeningBrace As Char = DoubleQuote.OpenCharacter Protected Overrides ReadOnly Property ClosingBrace As Char = DoubleQuote.CloseCharacter - Public Overrides Function AllowOverTypeAsync(context As BraceCompletionContext, cancellationToken As CancellationToken) As Task(Of Boolean) - Return AllowOverTypeWithValidClosingTokenAsync(context, cancellationToken) + Public Overrides Function AllowOverType(context As BraceCompletionContext, cancellationToken As CancellationToken) As Boolean + Return AllowOverTypeWithValidClosingToken(context) End Function - Public Overrides Async Function CanProvideBraceCompletionAsync(brace As Char, openingPosition As Integer, document As Document, cancellationToken As CancellationToken) As Task(Of Boolean) - If (OpeningBrace = brace And Await InterpolatedStringBraceCompletionService.IsPositionInInterpolatedStringContextAsync(document, openingPosition, cancellationToken).ConfigureAwait(False)) Then + Public Overrides Function CanProvideBraceCompletion(brace As Char, openingPosition As Integer, document As ParsedDocument, cancellationToken As CancellationToken) As Boolean + If OpeningBrace = brace And InterpolatedStringBraceCompletionService.IsPositionInInterpolatedStringContext(document, openingPosition) Then Return False End If - Return Await MyBase.CanProvideBraceCompletionAsync(brace, openingPosition, document, cancellationToken).ConfigureAwait(False) + Return MyBase.CanProvideBraceCompletion(brace, openingPosition, document, cancellationToken) End Function Protected Overrides Function IsValidOpeningBraceToken(token As SyntaxToken) As Boolean diff --git a/src/EditorFeatures/VisualBasic/BraceMatching/AbstractVisualBasicBraceMatcher.vb b/src/Features/VisualBasic/Portable/BraceMatching/AbstractVisualBasicBraceMatcher.vb similarity index 91% rename from src/EditorFeatures/VisualBasic/BraceMatching/AbstractVisualBasicBraceMatcher.vb rename to src/Features/VisualBasic/Portable/BraceMatching/AbstractVisualBasicBraceMatcher.vb index 91141ae17e88a..44daa7be88c67 100644 --- a/src/EditorFeatures/VisualBasic/BraceMatching/AbstractVisualBasicBraceMatcher.vb +++ b/src/Features/VisualBasic/Portable/BraceMatching/AbstractVisualBasicBraceMatcher.vb @@ -4,7 +4,7 @@ Imports Microsoft.CodeAnalysis.BraceMatching -Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.BraceMatching +Namespace Microsoft.CodeAnalysis.VisualBasic.BraceMatching Friend Class AbstractVisualBasicBraceMatcher Inherits AbstractBraceMatcher diff --git a/src/EditorFeatures/VisualBasic/BraceMatching/InterpolatedStringBraceMatcher.vb b/src/Features/VisualBasic/Portable/BraceMatching/InterpolatedStringBraceMatcher.vb similarity index 89% rename from src/EditorFeatures/VisualBasic/BraceMatching/InterpolatedStringBraceMatcher.vb rename to src/Features/VisualBasic/Portable/BraceMatching/InterpolatedStringBraceMatcher.vb index 647e6d44a6c9a..cbcb87dc9b2d3 100644 --- a/src/EditorFeatures/VisualBasic/BraceMatching/InterpolatedStringBraceMatcher.vb +++ b/src/Features/VisualBasic/Portable/BraceMatching/InterpolatedStringBraceMatcher.vb @@ -2,16 +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. -Imports System.ComponentModel.Composition +Imports System.Composition Imports System.Threading -Imports System.Threading.Tasks +Imports Microsoft.CodeAnalysis.BraceMatching Imports Microsoft.CodeAnalysis.Host.Mef Imports Microsoft.CodeAnalysis.Text Imports Microsoft.CodeAnalysis.VisualBasic.Syntax -Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.BraceMatching - - +Namespace Microsoft.CodeAnalysis.VisualBasic.BraceMatching + Friend Class InterpolatedStringBraceMatcher Implements IBraceMatcher diff --git a/src/EditorFeatures/VisualBasic/BraceMatching/LessThanGreaterThanBraceMatcher.vb b/src/Features/VisualBasic/Portable/BraceMatching/LessThanGreaterThanBraceMatcher.vb similarity index 85% rename from src/EditorFeatures/VisualBasic/BraceMatching/LessThanGreaterThanBraceMatcher.vb rename to src/Features/VisualBasic/Portable/BraceMatching/LessThanGreaterThanBraceMatcher.vb index 312c8d8b2aa84..e211b6e159d1d 100644 --- a/src/EditorFeatures/VisualBasic/BraceMatching/LessThanGreaterThanBraceMatcher.vb +++ b/src/Features/VisualBasic/Portable/BraceMatching/LessThanGreaterThanBraceMatcher.vb @@ -2,11 +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.ComponentModel.Composition +Imports System.Composition +Imports Microsoft.CodeAnalysis.BraceMatching Imports Microsoft.CodeAnalysis.Host.Mef -Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.BraceMatching - +Namespace Microsoft.CodeAnalysis.VisualBasic.BraceMatching + Friend Class LessThanGreaterThanBraceMatcher Inherits AbstractVisualBasicBraceMatcher diff --git a/src/EditorFeatures/VisualBasic/BraceMatching/OpenCloseBraceBraceMatcher.vb b/src/Features/VisualBasic/Portable/BraceMatching/OpenCloseBraceBraceMatcher.vb similarity index 75% rename from src/EditorFeatures/VisualBasic/BraceMatching/OpenCloseBraceBraceMatcher.vb rename to src/Features/VisualBasic/Portable/BraceMatching/OpenCloseBraceBraceMatcher.vb index 14ca5bda6829a..066c85498858e 100644 --- a/src/EditorFeatures/VisualBasic/BraceMatching/OpenCloseBraceBraceMatcher.vb +++ b/src/Features/VisualBasic/Portable/BraceMatching/OpenCloseBraceBraceMatcher.vb @@ -2,11 +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.ComponentModel.Composition +Imports System.Composition +Imports Microsoft.CodeAnalysis.BraceMatching Imports Microsoft.CodeAnalysis.Host.Mef -Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.BraceMatching - +Namespace Microsoft.CodeAnalysis.VisualBasic.BraceMatching + Friend Class OpenCloseBraceBraceMatcher Inherits AbstractVisualBasicBraceMatcher diff --git a/src/EditorFeatures/VisualBasic/BraceMatching/OpenCloseParenBraceMatcher.vb b/src/Features/VisualBasic/Portable/BraceMatching/OpenCloseParenBraceMatcher.vb similarity index 75% rename from src/EditorFeatures/VisualBasic/BraceMatching/OpenCloseParenBraceMatcher.vb rename to src/Features/VisualBasic/Portable/BraceMatching/OpenCloseParenBraceMatcher.vb index 53d4ced627d6d..5ac58ac66274f 100644 --- a/src/EditorFeatures/VisualBasic/BraceMatching/OpenCloseParenBraceMatcher.vb +++ b/src/Features/VisualBasic/Portable/BraceMatching/OpenCloseParenBraceMatcher.vb @@ -2,11 +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.ComponentModel.Composition +Imports System.Composition +Imports Microsoft.CodeAnalysis.BraceMatching Imports Microsoft.CodeAnalysis.Host.Mef -Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.BraceMatching - +Namespace Microsoft.CodeAnalysis.VisualBasic.BraceMatching + Friend Class OpenCloseParenBraceMatcher Inherits AbstractVisualBasicBraceMatcher diff --git a/src/EditorFeatures/VisualBasic/BraceMatching/StringLiteralBraceMatcher.vb b/src/Features/VisualBasic/Portable/BraceMatching/StringLiteralBraceMatcher.vb similarity index 88% rename from src/EditorFeatures/VisualBasic/BraceMatching/StringLiteralBraceMatcher.vb rename to src/Features/VisualBasic/Portable/BraceMatching/StringLiteralBraceMatcher.vb index 2a974bfc107f9..1f6565b1082e9 100644 --- a/src/EditorFeatures/VisualBasic/BraceMatching/StringLiteralBraceMatcher.vb +++ b/src/Features/VisualBasic/Portable/BraceMatching/StringLiteralBraceMatcher.vb @@ -2,14 +2,14 @@ ' The .NET Foundation licenses this file to you under the MIT license. ' See the LICENSE file in the project root for more information. -Imports System.ComponentModel.Composition +Imports System.Composition Imports System.Threading -Imports System.Threading.Tasks +Imports Microsoft.CodeAnalysis.BraceMatching Imports Microsoft.CodeAnalysis.Host.Mef Imports Microsoft.CodeAnalysis.Text -Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.BraceMatching - +Namespace Microsoft.CodeAnalysis.VisualBasic.BraceMatching + Friend Class StringLiteralBraceMatcher Implements IBraceMatcher diff --git a/src/EditorFeatures/VisualBasic/BraceMatching/VisualBasicDirectiveTriviaBraceMatcher.vb b/src/Features/VisualBasic/Portable/BraceMatching/VisualBasicDirectiveTriviaBraceMatcher.vb similarity index 91% rename from src/EditorFeatures/VisualBasic/BraceMatching/VisualBasicDirectiveTriviaBraceMatcher.vb rename to src/Features/VisualBasic/Portable/BraceMatching/VisualBasicDirectiveTriviaBraceMatcher.vb index 6f44b0de70dfa..b612a9882fd3a 100644 --- a/src/EditorFeatures/VisualBasic/BraceMatching/VisualBasicDirectiveTriviaBraceMatcher.vb +++ b/src/Features/VisualBasic/Portable/BraceMatching/VisualBasicDirectiveTriviaBraceMatcher.vb @@ -2,15 +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. -Imports System.ComponentModel.Composition +Imports System.Composition Imports System.Threading +Imports Microsoft.CodeAnalysis.BraceMatching Imports Microsoft.CodeAnalysis.Host.Mef Imports Microsoft.CodeAnalysis.Text Imports Microsoft.CodeAnalysis.VisualBasic.Syntax -Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.BraceMatching - - +Namespace Microsoft.CodeAnalysis.VisualBasic.BraceMatching + Friend Class VisualBasicDirectiveTriviaBraceMatcher Inherits AbstractDirectiveTriviaBraceMatcher(Of DirectiveTriviaSyntax, IfDirectiveTriviaSyntax, IfDirectiveTriviaSyntax, diff --git a/src/EditorFeatures/VisualBasic/BraceMatching/VisualBasicEmbeddedLanguageBraceMatcher.vb b/src/Features/VisualBasic/Portable/BraceMatching/VisualBasicEmbeddedLanguageBraceMatcher.vb similarity index 81% rename from src/EditorFeatures/VisualBasic/BraceMatching/VisualBasicEmbeddedLanguageBraceMatcher.vb rename to src/Features/VisualBasic/Portable/BraceMatching/VisualBasicEmbeddedLanguageBraceMatcher.vb index 7f87e385ee92d..adafee5d81f2f 100644 --- a/src/EditorFeatures/VisualBasic/BraceMatching/VisualBasicEmbeddedLanguageBraceMatcher.vb +++ b/src/Features/VisualBasic/Portable/BraceMatching/VisualBasicEmbeddedLanguageBraceMatcher.vb @@ -2,15 +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. -Imports System.ComponentModel.Composition +Imports System.Composition Imports Microsoft.CodeAnalysis.BraceMatching Imports Microsoft.CodeAnalysis.EmbeddedLanguages Imports Microsoft.CodeAnalysis.Host.Mef Imports Microsoft.CodeAnalysis.VisualBasic.EmbeddedLanguages.LanguageServices -Imports Microsoft.CodeAnalysis.VisualBasic.LanguageServices +Imports Microsoft.CodeAnalysis.VisualBasic.LanguageService -Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.BraceMatching - +Namespace Microsoft.CodeAnalysis.VisualBasic.BraceMatching + Friend Class VisualBasicEmbeddedLanguageBraceMatcher Inherits AbstractEmbeddedLanguageBraceMatcher diff --git a/src/Features/VisualBasic/Portable/ChangeSignature/VisualBasicChangeSignatureService.vb b/src/Features/VisualBasic/Portable/ChangeSignature/VisualBasicChangeSignatureService.vb index ce65e2060dbc7..77d27484a232c 100644 --- a/src/Features/VisualBasic/Portable/ChangeSignature/VisualBasicChangeSignatureService.vb +++ b/src/Features/VisualBasic/Portable/ChangeSignature/VisualBasicChangeSignatureService.vb @@ -12,10 +12,10 @@ Imports Microsoft.CodeAnalysis.FindSymbols Imports Microsoft.CodeAnalysis.Formatting Imports Microsoft.CodeAnalysis.Formatting.Rules Imports Microsoft.CodeAnalysis.Host.Mef -Imports Microsoft.CodeAnalysis.LanguageServices +Imports Microsoft.CodeAnalysis.LanguageService Imports Microsoft.CodeAnalysis.PooledObjects Imports Microsoft.CodeAnalysis.VisualBasic.CodeGeneration -Imports Microsoft.CodeAnalysis.VisualBasic.LanguageServices +Imports Microsoft.CodeAnalysis.VisualBasic.LanguageService Imports Microsoft.CodeAnalysis.VisualBasic.Syntax Imports Microsoft.CodeAnalysis.VisualBasic.SyntaxFactory diff --git a/src/Features/VisualBasic/Portable/CodeFixes/GenerateEvent/GenerateEventCodeFixProvider.vb b/src/Features/VisualBasic/Portable/CodeFixes/GenerateEvent/GenerateEventCodeFixProvider.vb index 25e61ae3edfa1..c4f207d21b477 100644 --- a/src/Features/VisualBasic/Portable/CodeFixes/GenerateEvent/GenerateEventCodeFixProvider.vb +++ b/src/Features/VisualBasic/Portable/CodeFixes/GenerateEvent/GenerateEventCodeFixProvider.vb @@ -10,7 +10,7 @@ Imports Microsoft.CodeAnalysis.CodeActions Imports Microsoft.CodeAnalysis.CodeFixes Imports Microsoft.CodeAnalysis.CodeGeneration Imports Microsoft.CodeAnalysis.FindSymbols -Imports Microsoft.CodeAnalysis.LanguageServices +Imports Microsoft.CodeAnalysis.LanguageService Imports Microsoft.CodeAnalysis.VisualBasic.Syntax Namespace Microsoft.CodeAnalysis.VisualBasic.CodeFixes.GenerateEvent @@ -125,8 +125,8 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.CodeFixes.GenerateEvent fallbackOptions As CodeAndImportGenerationOptionsProvider, cancellationToken As CancellationToken) As Task(Of CodeAction) - Dim codeGenService = document.Project.Solution.Workspace.Services.GetLanguageServices(targetType.Language).GetService(Of ICodeGenerationService) - Dim syntaxFactService = document.Project.Solution.Workspace.Services.GetLanguageServices(targetType.Language).GetService(Of ISyntaxFactsService) + Dim codeGenService = document.Project.Solution.Services.GetLanguageServices(targetType.Language).GetService(Of ICodeGenerationService) + Dim syntaxFactService = document.Project.Solution.Services.GetLanguageServices(targetType.Language).GetService(Of ISyntaxFactsService) Dim eventHandlerName As String = actualEventName + "Handler" Dim existingSymbols = Await DeclarationFinder.FindSourceDeclarationsWithNormalQueryAsync( @@ -267,7 +267,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.CodeFixes.GenerateEvent Return Nothing End If - Dim codeGenService = document.Project.Solution.Workspace.Services.GetLanguageServices(targetType.Language).GetService(Of ICodeGenerationService) + Dim codeGenService = document.Project.Solution.Services.GetLanguageServices(targetType.Language).GetService(Of ICodeGenerationService) Dim actualEventName = node.Right.Identifier.ValueText @@ -377,7 +377,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.CodeFixes.GenerateEvent Return Nothing End If - Dim codeGenService = document.Project.Solution.Workspace.Services.GetLanguageServices(originalTargetType.Language).GetService(Of ICodeGenerationService) + Dim codeGenService = document.Project.Solution.Services.GetLanguageServices(originalTargetType.Language).GetService(Of ICodeGenerationService) ' Let's bind the method declaration so we can get its parameters. Dim boundMethod = semanticModel.GetDeclaredSymbol(handlesClauseItem.GetAncestor(Of MethodStatementSyntax)(), cancellationToken) diff --git a/src/Features/VisualBasic/Portable/CodeFixes/OverloadBase/OverloadBaseCodeFixProvider.AddKeywordAction.vb b/src/Features/VisualBasic/Portable/CodeFixes/OverloadBase/OverloadBaseCodeFixProvider.AddKeywordAction.vb index 8735c1d6103b2..7c00a8abc3ddc 100644 --- a/src/Features/VisualBasic/Portable/CodeFixes/OverloadBase/OverloadBaseCodeFixProvider.AddKeywordAction.vb +++ b/src/Features/VisualBasic/Portable/CodeFixes/OverloadBase/OverloadBaseCodeFixProvider.AddKeywordAction.vb @@ -74,7 +74,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.CodeFixes.OverloadBase Dim cleanupService = document.GetLanguageService(Of ICodeCleanerService) If cleanupService IsNot Nothing AndAlso newNode IsNot Nothing Then - Dim services = document.Project.Solution.Workspace.Services + Dim services = document.Project.Solution.Services newNode = Await cleanupService.CleanupAsync(newNode, ImmutableArray.Create(newNode.Span), options, services, cleanupService.GetDefaultProviders(), cancellationToken).ConfigureAwait(False) End If diff --git a/src/Features/VisualBasic/Portable/CodeFixes/Suppression/VisualBasicSuppressionCodeFixProvider.vb b/src/Features/VisualBasic/Portable/CodeFixes/Suppression/VisualBasicSuppressionCodeFixProvider.vb index bafe833e5ac81..a91c330364e8c 100644 --- a/src/Features/VisualBasic/Portable/CodeFixes/Suppression/VisualBasicSuppressionCodeFixProvider.vb +++ b/src/Features/VisualBasic/Portable/CodeFixes/Suppression/VisualBasicSuppressionCodeFixProvider.vb @@ -118,7 +118,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.CodeFixes.Suppression targetSymbol As ISymbol, suppressMessageAttribute As INamedTypeSymbol, diagnostic As Diagnostic, - services As HostWorkspaceServices, + services As SolutionServices, options As SyntaxFormattingOptions, addImportsService As IAddImportsService, cancellationToken As CancellationToken) As SyntaxNode diff --git a/src/Features/VisualBasic/Portable/CodeLens/VisualBasicDisplayInfoService.vb b/src/Features/VisualBasic/Portable/CodeLens/VisualBasicDisplayInfoService.vb index 311060d12143e..1b75eec917fe9 100644 --- a/src/Features/VisualBasic/Portable/CodeLens/VisualBasicDisplayInfoService.vb +++ b/src/Features/VisualBasic/Portable/CodeLens/VisualBasicDisplayInfoService.vb @@ -5,7 +5,7 @@ Imports System.Composition Imports System.Globalization Imports Microsoft.CodeAnalysis.CodeLens Imports Microsoft.CodeAnalysis.Host.Mef -Imports Microsoft.CodeAnalysis.VisualBasic.LanguageServices +Imports Microsoft.CodeAnalysis.VisualBasic.LanguageService Imports Microsoft.CodeAnalysis.VisualBasic.Syntax Namespace Microsoft.CodeAnalysis.VisualBasic.CodeLens diff --git a/src/Features/VisualBasic/Portable/CodeRefactorings/InlineMethod/VisualBasicInlineMethodRefactoringProvider.vb b/src/Features/VisualBasic/Portable/CodeRefactorings/InlineMethod/VisualBasicInlineMethodRefactoringProvider.vb index dff559e23541a..633ef1b30927b 100644 --- a/src/Features/VisualBasic/Portable/CodeRefactorings/InlineMethod/VisualBasicInlineMethodRefactoringProvider.vb +++ b/src/Features/VisualBasic/Portable/CodeRefactorings/InlineMethod/VisualBasicInlineMethodRefactoringProvider.vb @@ -7,7 +7,7 @@ Imports Microsoft.CodeAnalysis.CodeRefactorings Imports Microsoft.CodeAnalysis.Host.Mef Imports Microsoft.CodeAnalysis.InlineMethod Imports Microsoft.CodeAnalysis.VisualBasic.CodeGeneration -Imports Microsoft.CodeAnalysis.VisualBasic.LanguageServices +Imports Microsoft.CodeAnalysis.VisualBasic.LanguageService Imports Microsoft.CodeAnalysis.VisualBasic.Syntax Namespace Microsoft.CodeAnalysis.VisualBasic.CodeRefactorings.InlineTemporary diff --git a/src/Features/VisualBasic/Portable/CodeRefactorings/InlineTemporary/VisualBasicInlineTemporaryCodeRefactoringProvider.vb b/src/Features/VisualBasic/Portable/CodeRefactorings/InlineTemporary/VisualBasicInlineTemporaryCodeRefactoringProvider.vb index a3043da8e5451..b3d2fe3492f9e 100644 --- a/src/Features/VisualBasic/Portable/CodeRefactorings/InlineTemporary/VisualBasicInlineTemporaryCodeRefactoringProvider.vb +++ b/src/Features/VisualBasic/Portable/CodeRefactorings/InlineTemporary/VisualBasicInlineTemporaryCodeRefactoringProvider.vb @@ -30,8 +30,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.CodeRefactorings.InlineTemporary Dim document = context.Document Dim cancellationToken = context.CancellationToken - Dim workspace = document.Project.Solution.Workspace - If workspace.Kind = WorkspaceKind.MiscellaneousFiles Then + If document.Project.Solution.WorkspaceKind = WorkspaceKind.MiscellaneousFiles Then Return End If @@ -183,7 +182,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.CodeRefactorings.InlineTemporary updatedDocument = Await updatedDocument.ReplaceNodesAsync( topMostStatements, Function(o, n) - Return Simplifier.Expand(DirectCast(n, StatementSyntax), semanticModel, document.Project.Solution.Workspace, cancellationToken:=cancellationToken) + Return Simplifier.Expand(DirectCast(n, StatementSyntax), semanticModel, document.Project.Solution.Services, cancellationToken:=cancellationToken) End Function, cancellationToken).ConfigureAwait(False) diff --git a/src/Features/VisualBasic/Portable/CodeRefactorings/MoveStaticMembers/VisualBasicMoveStaticMembersRefactoringProvider.vb b/src/Features/VisualBasic/Portable/CodeRefactorings/MoveStaticMembers/VisualBasicMoveStaticMembersRefactoringProvider.vb index 042ddb09fc9cc..59231341cad84 100644 --- a/src/Features/VisualBasic/Portable/CodeRefactorings/MoveStaticMembers/VisualBasicMoveStaticMembersRefactoringProvider.vb +++ b/src/Features/VisualBasic/Portable/CodeRefactorings/MoveStaticMembers/VisualBasicMoveStaticMembersRefactoringProvider.vb @@ -2,6 +2,7 @@ ' The .NET Foundation licenses this file to you under the MIT license. ' See the LICENSE file in the project root for more information. +Imports System.Collections.Immutable Imports System.Composition Imports Microsoft.CodeAnalysis.CodeRefactorings Imports Microsoft.CodeAnalysis.Host.Mef @@ -18,7 +19,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.CodeRefactorings.MoveStaticMembers MyBase.New() End Sub - Protected Overrides Async Function GetSelectedNodeAsync(context As CodeRefactoringContext) As Task(Of SyntaxNode) + Protected Overrides Async Function GetSelectedNodesAsync(context As CodeRefactoringContext) As Task(Of ImmutableArray(Of SyntaxNode)) Return Await GetSelectedMemberDeclarationAsync(context).ConfigureAwait(False) End Function End Class diff --git a/src/Features/VisualBasic/Portable/CodeRefactorings/NodeSelectionHelpers.vb b/src/Features/VisualBasic/Portable/CodeRefactorings/NodeSelectionHelpers.vb index e82b062351c20..991393f13620a 100644 --- a/src/Features/VisualBasic/Portable/CodeRefactorings/NodeSelectionHelpers.vb +++ b/src/Features/VisualBasic/Portable/CodeRefactorings/NodeSelectionHelpers.vb @@ -2,24 +2,54 @@ ' The .NET Foundation licenses this file to you under the MIT license. ' See the LICENSE file in the project root for more information. +Imports System.Collections.Immutable +Imports System.Threading Imports Microsoft.CodeAnalysis.CodeRefactorings +Imports Microsoft.CodeAnalysis.Text +Imports Microsoft.CodeAnalysis.VisualBasic.LanguageService Imports Microsoft.CodeAnalysis.VisualBasic.Syntax Namespace Microsoft.CodeAnalysis.VisualBasic.CodeRefactorings Friend Module NodeSelectionHelpers - Friend Async Function GetSelectedMemberDeclarationAsync(context As CodeRefactoringContext) As Task(Of SyntaxNode) - Dim methodMember = Await context.TryGetRelevantNodeAsync(Of MethodBaseSyntax)().ConfigureAwait(False) - If methodMember IsNot Nothing Then - Return methodMember + Friend Async Function GetSelectedMemberDeclarationAsync(context As CodeRefactoringContext) As Task(Of ImmutableArray(Of SyntaxNode)) + Dim document As Document = context.Document + Dim span As TextSpan = context.Span + Dim cancellationToken As CancellationToken = context.CancellationToken + If span.IsEmpty Then + ' MethodBaseSyntax also includes properties + Dim methodMember = Await context.TryGetRelevantNodeAsync(Of MethodBaseSyntax)().ConfigureAwait(False) + If methodMember IsNot Nothing Then + Return ImmutableArray.Create(Of SyntaxNode)(methodMember) + End If + ' Gets field variable declarations (not including the keywords like Public/Shared, etc), which are not methods + Dim fieldDeclaration = Await context.TryGetRelevantNodeAsync(Of FieldDeclarationSyntax).ConfigureAwait(False) + If fieldDeclaration Is Nothing Then + ' Gets the identifier + type of the field itself (ex. TestField As Integer), since it is nested in the variable declaration + ' And so the token's parent is not a variable declaration + Dim modifiedIdentifier = Await context.TryGetRelevantNodeAsync(Of ModifiedIdentifierSyntax).ConfigureAwait(False) + If modifiedIdentifier Is Nothing Then + Return ImmutableArray(Of SyntaxNode).Empty + Else + Return ImmutableArray.Create(Of SyntaxNode)(modifiedIdentifier) + End If + Else + ' Field declarations can contain multiple variables (each of which are a "member") + Return fieldDeclaration.Declarators.SelectMany(Function(vds) vds.Names).Cast(Of SyntaxNode).AsImmutable() + End If + Else + ' if the span is non-empty, then we get potentially multiple members + ' Note: even though this method handles the empty span case, we don't use it because it doesn't correctly + ' pick up on keywords before the declaration, such as "public static int". + ' We could potentially use it for every case if that behavior changes + Dim tree = Await document.GetSyntaxTreeAsync(cancellationToken).ConfigureAwait(False) + Dim selectedMembers = Await VisualBasicSelectedMembers.Instance. + GetSelectedMembersAsync(tree, span, allowPartialSelection:=True, cancellationToken).ConfigureAwait(False) + If selectedMembers.OfType(Of IncompleteMemberSyntax)().Any() Then + Return ImmutableArray(Of SyntaxNode).Empty + Else + Return selectedMembers + End If End If - ' Gets field variable declarations (not including the keywords like Public/Shared, etc), which are not methods - Dim fieldDeclaration = Await context.TryGetRelevantNodeAsync(Of FieldDeclarationSyntax).ConfigureAwait(False) - If fieldDeclaration IsNot Nothing Then - Return fieldDeclaration - End If - ' Gets the identifier + type of the field itself (ex. TestField As Integer), since it is nested in the variable declaration - ' And so the token's parent is not a variable declaration - Return Await context.TryGetRelevantNodeAsync(Of ModifiedIdentifierSyntax).ConfigureAwait(False) End Function End Module End Namespace diff --git a/src/Features/VisualBasic/Portable/CodeRefactorings/SyncNamespace/VisualBasicChangeNamespaceService.vb b/src/Features/VisualBasic/Portable/CodeRefactorings/SyncNamespace/VisualBasicChangeNamespaceService.vb index 7e01e49b961ee..41fd0cc2fa77b 100644 --- a/src/Features/VisualBasic/Portable/CodeRefactorings/SyncNamespace/VisualBasicChangeNamespaceService.vb +++ b/src/Features/VisualBasic/Portable/CodeRefactorings/SyncNamespace/VisualBasicChangeNamespaceService.vb @@ -7,7 +7,7 @@ Imports System.Composition Imports System.Threading Imports Microsoft.CodeAnalysis.ChangeNamespace Imports Microsoft.CodeAnalysis.Host.Mef -Imports Microsoft.CodeAnalysis.LanguageServices +Imports Microsoft.CodeAnalysis.LanguageService Imports Microsoft.CodeAnalysis.Text Imports Microsoft.CodeAnalysis.VisualBasic.Syntax diff --git a/src/Features/VisualBasic/Portable/CodeRefactorings/VisualBasicRefactoringHelpersService.vb b/src/Features/VisualBasic/Portable/CodeRefactorings/VisualBasicRefactoringHelpersService.vb index cc3751d63a846..d28d345c993c9 100644 --- a/src/Features/VisualBasic/Portable/CodeRefactorings/VisualBasicRefactoringHelpersService.vb +++ b/src/Features/VisualBasic/Portable/CodeRefactorings/VisualBasicRefactoringHelpersService.vb @@ -6,8 +6,8 @@ Imports System.Composition Imports Microsoft.CodeAnalysis.CodeRefactorings Imports Microsoft.CodeAnalysis.VisualBasic.Syntax Imports Microsoft.CodeAnalysis.Host.Mef -Imports Microsoft.CodeAnalysis.LanguageServices -Imports Microsoft.CodeAnalysis.VisualBasic.LanguageServices +Imports Microsoft.CodeAnalysis.LanguageService +Imports Microsoft.CodeAnalysis.VisualBasic.LanguageService Imports Microsoft.CodeAnalysis.Text Namespace Microsoft.CodeAnalysis.VisualBasic.CodeRefactorings diff --git a/src/Features/VisualBasic/Portable/Completion/CompletionProviders/AwaitCompletionProvider.vb b/src/Features/VisualBasic/Portable/Completion/CompletionProviders/AwaitCompletionProvider.vb index 9d4aa9700e331..0ac470ca48992 100644 --- a/src/Features/VisualBasic/Portable/Completion/CompletionProviders/AwaitCompletionProvider.vb +++ b/src/Features/VisualBasic/Portable/Completion/CompletionProviders/AwaitCompletionProvider.vb @@ -8,7 +8,7 @@ Imports System.Threading Imports Microsoft.CodeAnalysis.Completion Imports Microsoft.CodeAnalysis.Completion.Providers Imports Microsoft.CodeAnalysis.Host.Mef -Imports Microsoft.CodeAnalysis.VisualBasic.LanguageServices +Imports Microsoft.CodeAnalysis.VisualBasic.LanguageService Imports Microsoft.CodeAnalysis.VisualBasic.Syntax Namespace Microsoft.CodeAnalysis.VisualBasic.Completion.Providers diff --git a/src/Features/VisualBasic/Portable/Completion/CompletionProviders/CompletionListTagCompletionProvider.vb b/src/Features/VisualBasic/Portable/Completion/CompletionProviders/CompletionListTagCompletionProvider.vb index cfcc954bb3720..94535476a7321 100644 --- a/src/Features/VisualBasic/Portable/Completion/CompletionProviders/CompletionListTagCompletionProvider.vb +++ b/src/Features/VisualBasic/Portable/Completion/CompletionProviders/CompletionListTagCompletionProvider.vb @@ -8,7 +8,7 @@ Imports System.Threading Imports Microsoft.CodeAnalysis.Completion Imports Microsoft.CodeAnalysis.Completion.Providers Imports Microsoft.CodeAnalysis.Host.Mef -Imports Microsoft.CodeAnalysis.LanguageServices +Imports Microsoft.CodeAnalysis.LanguageService Imports Microsoft.CodeAnalysis.Options Imports Microsoft.CodeAnalysis.VisualBasic.Extensions.ContextQuery diff --git a/src/Features/VisualBasic/Portable/Completion/CompletionProviders/CrefCompletionProvider.vb b/src/Features/VisualBasic/Portable/Completion/CompletionProviders/CrefCompletionProvider.vb index 7a0d7646a291e..a83357a703978 100644 --- a/src/Features/VisualBasic/Portable/Completion/CompletionProviders/CrefCompletionProvider.vb +++ b/src/Features/VisualBasic/Portable/Completion/CompletionProviders/CrefCompletionProvider.vb @@ -111,7 +111,6 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Completion.Providers End If Dim semanticModel = Await document.ReuseExistingSpeculativeModelAsync(parentNode, cancellationToken).ConfigureAwait(False) - Dim workspace = document.Project.Solution.Workspace Dim symbols = GetSymbols(token, semanticModel, cancellationToken) Return (token, semanticModel, symbols.ToImmutableArray()) diff --git a/src/Features/VisualBasic/Portable/Completion/CompletionProviders/EnumCompletionProvider.vb b/src/Features/VisualBasic/Portable/Completion/CompletionProviders/EnumCompletionProvider.vb index c6396b252a75d..53652808f13f9 100644 --- a/src/Features/VisualBasic/Portable/Completion/CompletionProviders/EnumCompletionProvider.vb +++ b/src/Features/VisualBasic/Portable/Completion/CompletionProviders/EnumCompletionProvider.vb @@ -8,7 +8,7 @@ Imports System.Threading Imports Microsoft.CodeAnalysis.Completion Imports Microsoft.CodeAnalysis.Completion.Providers Imports Microsoft.CodeAnalysis.Host.Mef -Imports Microsoft.CodeAnalysis.LanguageServices +Imports Microsoft.CodeAnalysis.LanguageService Imports Microsoft.CodeAnalysis.Options Imports Microsoft.CodeAnalysis.Text Imports Microsoft.CodeAnalysis.VisualBasic.Extensions.ContextQuery diff --git a/src/Features/VisualBasic/Portable/Completion/CompletionProviders/ImportCompletionProvider/TypeImportCompletionServiceFactory.vb b/src/Features/VisualBasic/Portable/Completion/CompletionProviders/ImportCompletionProvider/TypeImportCompletionServiceFactory.vb index 3fd4715c9b057..583f92982649d 100644 --- a/src/Features/VisualBasic/Portable/Completion/CompletionProviders/ImportCompletionProvider/TypeImportCompletionServiceFactory.vb +++ b/src/Features/VisualBasic/Portable/Completion/CompletionProviders/ImportCompletionProvider/TypeImportCompletionServiceFactory.vb @@ -19,14 +19,14 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Completion.Providers End Sub Public Function CreateLanguageService(languageServices As HostLanguageServices) As ILanguageService Implements ILanguageServiceFactory.CreateLanguageService - Return New BasicTypeImportCompletionService(languageServices.WorkspaceServices.Workspace) + Return New BasicTypeImportCompletionService(languageServices.LanguageServices.SolutionServices) End Function Private Class BasicTypeImportCompletionService Inherits AbstractTypeImportCompletionService - Public Sub New(workspace As Workspace) - MyBase.New(workspace) + Public Sub New(services As SolutionServices) + MyBase.New(services) End Sub Protected Overrides ReadOnly Property GenericTypeSuffix As String diff --git a/src/Features/VisualBasic/Portable/Completion/CompletionProviders/NamedParameterCompletionProvider.vb b/src/Features/VisualBasic/Portable/Completion/CompletionProviders/NamedParameterCompletionProvider.vb index c5de5d420de74..299e34f010c3a 100644 --- a/src/Features/VisualBasic/Portable/Completion/CompletionProviders/NamedParameterCompletionProvider.vb +++ b/src/Features/VisualBasic/Portable/Completion/CompletionProviders/NamedParameterCompletionProvider.vb @@ -13,7 +13,7 @@ Imports Microsoft.CodeAnalysis.VisualBasic.Extensions.ContextQuery Imports Microsoft.CodeAnalysis.ErrorReporting Imports System.Composition Imports Microsoft.CodeAnalysis.Host.Mef -Imports Microsoft.CodeAnalysis.LanguageServices +Imports Microsoft.CodeAnalysis.LanguageService Namespace Microsoft.CodeAnalysis.VisualBasic.Completion.Providers diff --git a/src/Features/VisualBasic/Portable/Completion/KeywordRecommenders/Expressions/TrueFalseKeywordRecommender.vb b/src/Features/VisualBasic/Portable/Completion/KeywordRecommenders/Expressions/TrueFalseKeywordRecommender.vb index 6e46d663df6c3..be6c2af122a03 100644 --- a/src/Features/VisualBasic/Portable/Completion/KeywordRecommenders/Expressions/TrueFalseKeywordRecommender.vb +++ b/src/Features/VisualBasic/Portable/Completion/KeywordRecommenders/Expressions/TrueFalseKeywordRecommender.vb @@ -5,7 +5,7 @@ Imports System.Collections.Immutable Imports System.Threading Imports Microsoft.CodeAnalysis.Completion.Providers -Imports Microsoft.CodeAnalysis.LanguageServices +Imports Microsoft.CodeAnalysis.LanguageService Imports Microsoft.CodeAnalysis.VisualBasic.Extensions.ContextQuery Namespace Microsoft.CodeAnalysis.VisualBasic.Completion.KeywordRecommenders.Expressions diff --git a/src/Features/VisualBasic/Portable/Completion/VisualBasicCompletionService.vb b/src/Features/VisualBasic/Portable/Completion/VisualBasicCompletionService.vb index 97eebf32c3f2f..8886d7639d290 100644 --- a/src/Features/VisualBasic/Portable/Completion/VisualBasicCompletionService.vb +++ b/src/Features/VisualBasic/Portable/Completion/VisualBasicCompletionService.vb @@ -26,7 +26,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Completion End Sub Public Function CreateLanguageService(languageServices As HostLanguageServices) As ILanguageService Implements ILanguageServiceFactory.CreateLanguageService - Return New VisualBasicCompletionService(languageServices.WorkspaceServices.Workspace) + Return New VisualBasicCompletionService(languageServices.LanguageServices.SolutionServices) End Function End Class @@ -36,8 +36,8 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Completion defaultCommitCharacters:=CompletionRules.Default.DefaultCommitCharacters, defaultEnterKeyRule:=EnterKeyRule.Always) - Private Sub New(workspace As Workspace) - MyBase.New(workspace) + Private Sub New(services As SolutionServices) + MyBase.New(services) End Sub Public Overrides ReadOnly Property Language As String @@ -105,7 +105,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Completion End Function Private Function GetChangeText(item As CompletionItem) As String - Dim provider = TryCast(GetProvider(item), CommonCompletionProvider) + Dim provider = TryCast(GetProvider(item, project:=Nothing), CommonCompletionProvider) If provider IsNot Nothing Then ' TODO: Document Is Not available in this code path.. what about providers that need to reconstruct information before producing text? Dim result = provider.GetTextChangeAsync(Nothing, item, Nothing, CancellationToken.None).Result diff --git a/src/Features/VisualBasic/Portable/ConflictMarkerResolution/VisualBasicResolveConflictMarkerCodeFixProvider.vb b/src/Features/VisualBasic/Portable/ConflictMarkerResolution/VisualBasicResolveConflictMarkerCodeFixProvider.vb index 23eeb3bf45be6..216c0b0a8ce8c 100644 --- a/src/Features/VisualBasic/Portable/ConflictMarkerResolution/VisualBasicResolveConflictMarkerCodeFixProvider.vb +++ b/src/Features/VisualBasic/Portable/ConflictMarkerResolution/VisualBasicResolveConflictMarkerCodeFixProvider.vb @@ -6,7 +6,7 @@ Imports System.Composition Imports Microsoft.CodeAnalysis.CodeFixes Imports Microsoft.CodeAnalysis.ConflictMarkerResolution Imports Microsoft.CodeAnalysis.Host.Mef -Imports Microsoft.CodeAnalysis.VisualBasic.LanguageServices +Imports Microsoft.CodeAnalysis.VisualBasic.LanguageService Namespace Microsoft.CodeAnalysis.VisualBasic.ConflictMarkerResolution diff --git a/src/Features/VisualBasic/Portable/ConvertIfToSwitch/VisualBasicConvertIfToSwitchCodeRefactoringProvider.Analyzer.vb b/src/Features/VisualBasic/Portable/ConvertIfToSwitch/VisualBasicConvertIfToSwitchCodeRefactoringProvider.Analyzer.vb index eb688de664d28..03aebb896975e 100644 --- a/src/Features/VisualBasic/Portable/ConvertIfToSwitch/VisualBasicConvertIfToSwitchCodeRefactoringProvider.Analyzer.vb +++ b/src/Features/VisualBasic/Portable/ConvertIfToSwitch/VisualBasicConvertIfToSwitchCodeRefactoringProvider.Analyzer.vb @@ -2,7 +2,7 @@ ' The .NET Foundation licenses this file to you under the MIT license. ' See the LICENSE file in the project root for more information. -Imports Microsoft.CodeAnalysis.LanguageServices +Imports Microsoft.CodeAnalysis.LanguageService Imports Microsoft.CodeAnalysis.Operations Imports Microsoft.CodeAnalysis.VisualBasic.Syntax diff --git a/src/Features/VisualBasic/Portable/ConvertIfToSwitch/VisualBasicConvertIfToSwitchCodeRefactoringProvider.vb b/src/Features/VisualBasic/Portable/ConvertIfToSwitch/VisualBasicConvertIfToSwitchCodeRefactoringProvider.vb index d7a8e6a8346f2..a9f89204d0578 100644 --- a/src/Features/VisualBasic/Portable/ConvertIfToSwitch/VisualBasicConvertIfToSwitchCodeRefactoringProvider.vb +++ b/src/Features/VisualBasic/Portable/ConvertIfToSwitch/VisualBasicConvertIfToSwitchCodeRefactoringProvider.vb @@ -6,7 +6,7 @@ Imports System.Composition Imports System.Diagnostics.CodeAnalysis Imports Microsoft.CodeAnalysis.CodeRefactorings Imports Microsoft.CodeAnalysis.ConvertIfToSwitch -Imports Microsoft.CodeAnalysis.LanguageServices +Imports Microsoft.CodeAnalysis.LanguageService Imports Microsoft.CodeAnalysis.VisualBasic.Syntax Namespace Microsoft.CodeAnalysis.VisualBasic.ConvertIfToSwitch diff --git a/src/Features/VisualBasic/Portable/Debugging/LocationInfoGetter.vb b/src/Features/VisualBasic/Portable/Debugging/LocationInfoGetter.vb index c9c6ce1cd2a4e..7ff6248c0933a 100644 --- a/src/Features/VisualBasic/Portable/Debugging/LocationInfoGetter.vb +++ b/src/Features/VisualBasic/Portable/Debugging/LocationInfoGetter.vb @@ -4,7 +4,7 @@ Imports System.Threading Imports Microsoft.CodeAnalysis.Debugging -Imports Microsoft.CodeAnalysis.LanguageServices +Imports Microsoft.CodeAnalysis.LanguageService Imports Microsoft.CodeAnalysis.VisualBasic.Syntax Namespace Microsoft.CodeAnalysis.VisualBasic.Debugging diff --git a/src/Features/VisualBasic/Portable/Diagnostics/Analyzers/VisualBasicPreferFrameworkTypeDiagnosticAnalyzer.vb b/src/Features/VisualBasic/Portable/Diagnostics/Analyzers/VisualBasicPreferFrameworkTypeDiagnosticAnalyzer.vb index 22fb495b16238..b4c78d866b879 100644 --- a/src/Features/VisualBasic/Portable/Diagnostics/Analyzers/VisualBasicPreferFrameworkTypeDiagnosticAnalyzer.vb +++ b/src/Features/VisualBasic/Portable/Diagnostics/Analyzers/VisualBasicPreferFrameworkTypeDiagnosticAnalyzer.vb @@ -25,10 +25,6 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Diagnostics.Analyzers Return Not KeywordMatchesTypeName(node.Keyword.Kind()) End Function - Protected Overrides Function GetLanguageName() As String - Return LanguageNames.VisualBasic - End Function - ''' ''' Returns true, if the VB language keyword for predefined type matches its ''' actual framework type name. diff --git a/src/Features/VisualBasic/Portable/Diagnostics/Analyzers/VisualBasicSimplifyTypeNamesDiagnosticAnalyzer.vb b/src/Features/VisualBasic/Portable/Diagnostics/Analyzers/VisualBasicSimplifyTypeNamesDiagnosticAnalyzer.vb index 16d720c1804de..d5be2fb88f02e 100644 --- a/src/Features/VisualBasic/Portable/Diagnostics/Analyzers/VisualBasicSimplifyTypeNamesDiagnosticAnalyzer.vb +++ b/src/Features/VisualBasic/Portable/Diagnostics/Analyzers/VisualBasicSimplifyTypeNamesDiagnosticAnalyzer.vb @@ -113,9 +113,5 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.CodeFixes.SimplifyTypeNames Return True End Function - - Protected Overrides Function GetLanguageName() As String - Return LanguageNames.VisualBasic - End Function End Class End Namespace diff --git a/src/Features/VisualBasic/Portable/DocumentHighlighting/VisualBasicDocumentHighlightsService.vb b/src/Features/VisualBasic/Portable/DocumentHighlighting/VisualBasicDocumentHighlightsService.vb index 280a9004efa96..1c1aa7f687196 100644 --- a/src/Features/VisualBasic/Portable/DocumentHighlighting/VisualBasicDocumentHighlightsService.vb +++ b/src/Features/VisualBasic/Portable/DocumentHighlighting/VisualBasicDocumentHighlightsService.vb @@ -7,7 +7,7 @@ Imports Microsoft.CodeAnalysis.DocumentHighlighting Imports Microsoft.CodeAnalysis.EmbeddedLanguages Imports Microsoft.CodeAnalysis.Host.Mef Imports Microsoft.CodeAnalysis.VisualBasic.EmbeddedLanguages.LanguageServices -Imports Microsoft.CodeAnalysis.VisualBasic.LanguageServices +Imports Microsoft.CodeAnalysis.VisualBasic.LanguageService Namespace Microsoft.CodeAnalysis.VisualBasic.DocumentHighlighting diff --git a/src/Features/VisualBasic/Portable/EditAndContinue/SyntaxUtilities.vb b/src/Features/VisualBasic/Portable/EditAndContinue/SyntaxUtilities.vb index aa1fad44f9caa..1a32f1eb74d9e 100644 --- a/src/Features/VisualBasic/Portable/EditAndContinue/SyntaxUtilities.vb +++ b/src/Features/VisualBasic/Portable/EditAndContinue/SyntaxUtilities.vb @@ -132,6 +132,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.EditAndContinue Public Shared Function HasBackingField(propertyDeclaration As SyntaxNode) As Boolean Return propertyDeclaration.IsKind(SyntaxKind.PropertyStatement) AndAlso + Not propertyDeclaration.Parent.IsKind(SyntaxKind.PropertyBlock) AndAlso Not DirectCast(propertyDeclaration, PropertyStatementSyntax).Modifiers.Any(SyntaxKind.MustOverrideKeyword) End Function diff --git a/src/Features/VisualBasic/Portable/EditAndContinue/VisualBasicEditAndContinueAnalyzer.vb b/src/Features/VisualBasic/Portable/EditAndContinue/VisualBasicEditAndContinueAnalyzer.vb index 73c827cb1bf01..a7f180f98b0de 100644 --- a/src/Features/VisualBasic/Portable/EditAndContinue/VisualBasicEditAndContinueAnalyzer.vb +++ b/src/Features/VisualBasic/Portable/EditAndContinue/VisualBasicEditAndContinueAnalyzer.vb @@ -1043,14 +1043,15 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.EditAndContinue Return node.Parent.FirstAncestorOrSelf(Of TypeBlockSyntax)() ' TODO: EnbumBlock? End Function - Friend Overrides Function TryGetAssociatedMemberDeclaration(node As SyntaxNode, ByRef declaration As SyntaxNode) As Boolean + Friend Overrides Function TryGetAssociatedMemberDeclaration(node As SyntaxNode, editKind As EditKind, ByRef declaration As SyntaxNode) As Boolean If node.IsKind(SyntaxKind.Parameter, SyntaxKind.TypeParameter) Then Contract.ThrowIfFalse(node.IsParentKind(SyntaxKind.ParameterList, SyntaxKind.TypeParameterList)) declaration = node.Parent.Parent Return True End If - If node.IsParentKind(SyntaxKind.PropertyBlock, SyntaxKind.EventBlock) Then + ' We allow deleting event and property accessors, so don't associate them + If editKind <> EditKind.Delete AndAlso node.IsParentKind(SyntaxKind.PropertyBlock, SyntaxKind.EventBlock) Then declaration = node.Parent Return True End If diff --git a/src/Features/VisualBasic/Portable/EmbeddedLanguages/Classification/VisualBasicEmbeddedLanguageClassificationServiceFactory.vb b/src/Features/VisualBasic/Portable/EmbeddedLanguages/Classification/VisualBasicEmbeddedLanguageClassificationServiceFactory.vb index 20666ab326602..0692399e98e22 100644 --- a/src/Features/VisualBasic/Portable/EmbeddedLanguages/Classification/VisualBasicEmbeddedLanguageClassificationServiceFactory.vb +++ b/src/Features/VisualBasic/Portable/EmbeddedLanguages/Classification/VisualBasicEmbeddedLanguageClassificationServiceFactory.vb @@ -7,7 +7,7 @@ Imports Microsoft.CodeAnalysis.Classification Imports Microsoft.CodeAnalysis.EmbeddedLanguages Imports Microsoft.CodeAnalysis.Host.Mef Imports Microsoft.CodeAnalysis.VisualBasic.EmbeddedLanguages.LanguageServices -Imports Microsoft.CodeAnalysis.VisualBasic.LanguageServices +Imports Microsoft.CodeAnalysis.VisualBasic.LanguageService Namespace Microsoft.CodeAnalysis.VisualBasic.Classification diff --git a/src/Features/VisualBasic/Portable/EmbeddedLanguages/VisualBasicEmbeddedLanguagesProvider.vb b/src/Features/VisualBasic/Portable/EmbeddedLanguages/VisualBasicEmbeddedLanguagesProvider.vb index af1287feed94c..25524d719e0f4 100644 --- a/src/Features/VisualBasic/Portable/EmbeddedLanguages/VisualBasicEmbeddedLanguagesProvider.vb +++ b/src/Features/VisualBasic/Portable/EmbeddedLanguages/VisualBasicEmbeddedLanguagesProvider.vb @@ -7,7 +7,7 @@ Imports Microsoft.CodeAnalysis.EmbeddedLanguages Imports Microsoft.CodeAnalysis.Host.Mef Imports Microsoft.CodeAnalysis.VisualBasic.EmbeddedLanguages.VirtualChars Imports Microsoft.CodeAnalysis.VisualBasic.Features.EmbeddedLanguages -Imports Microsoft.CodeAnalysis.VisualBasic.LanguageServices +Imports Microsoft.CodeAnalysis.VisualBasic.LanguageService Namespace Microsoft.CodeAnalysis.VisualBasic.EmbeddedLanguages.LanguageServices diff --git a/src/Features/VisualBasic/Portable/ExtractMethod/VisualBasicMethodExtractor.TriviaResult.vb b/src/Features/VisualBasic/Portable/ExtractMethod/VisualBasicMethodExtractor.TriviaResult.vb index 07a41d56af3ef..83e7359a7a83a 100644 --- a/src/Features/VisualBasic/Portable/ExtractMethod/VisualBasicMethodExtractor.TriviaResult.vb +++ b/src/Features/VisualBasic/Portable/ExtractMethod/VisualBasicMethodExtractor.TriviaResult.vb @@ -13,7 +13,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.ExtractMethod Inherits TriviaResult Public Shared Async Function ProcessAsync(selectionResult As SelectionResult, cancellationToken As CancellationToken) As Task(Of VisualBasicTriviaResult) - Dim preservationService = selectionResult.SemanticDocument.Document.Project.LanguageServices.GetService(Of ISyntaxTriviaService)() + Dim preservationService = selectionResult.SemanticDocument.Document.Project.Services.GetService(Of ISyntaxTriviaService)() Dim root = selectionResult.SemanticDocument.Root Dim result = preservationService.SaveTriviaAroundSelection(root, selectionResult.FinalSpan) diff --git a/src/Features/VisualBasic/Portable/ExtractMethod/VisualBasicSelectionResult.vb b/src/Features/VisualBasic/Portable/ExtractMethod/VisualBasicSelectionResult.vb index e84e3d1aec908..779f2e823f358 100644 --- a/src/Features/VisualBasic/Portable/ExtractMethod/VisualBasicSelectionResult.vb +++ b/src/Features/VisualBasic/Portable/ExtractMethod/VisualBasicSelectionResult.vb @@ -5,11 +5,11 @@ Imports System.Threading Imports Microsoft.CodeAnalysis Imports Microsoft.CodeAnalysis.ExtractMethod -Imports Microsoft.CodeAnalysis.LanguageServices +Imports Microsoft.CodeAnalysis.LanguageService Imports Microsoft.CodeAnalysis.Options Imports Microsoft.CodeAnalysis.Text Imports Microsoft.CodeAnalysis.VisualBasic -Imports Microsoft.CodeAnalysis.VisualBasic.LanguageServices +Imports Microsoft.CodeAnalysis.VisualBasic.LanguageService Imports Microsoft.CodeAnalysis.VisualBasic.Symbols Imports Microsoft.CodeAnalysis.VisualBasic.Syntax diff --git a/src/Features/VisualBasic/Portable/ExtractMethod/VisualBasicSelectionValidator.vb b/src/Features/VisualBasic/Portable/ExtractMethod/VisualBasicSelectionValidator.vb index 7b0d6de815cc8..bbd1920e1578e 100644 --- a/src/Features/VisualBasic/Portable/ExtractMethod/VisualBasicSelectionValidator.vb +++ b/src/Features/VisualBasic/Portable/ExtractMethod/VisualBasicSelectionValidator.vb @@ -8,7 +8,7 @@ Imports Microsoft.CodeAnalysis.ExtractMethod Imports Microsoft.CodeAnalysis.Options Imports Microsoft.CodeAnalysis.Text Imports Microsoft.CodeAnalysis.VisualBasic -Imports Microsoft.CodeAnalysis.VisualBasic.LanguageServices +Imports Microsoft.CodeAnalysis.VisualBasic.LanguageService Imports Microsoft.CodeAnalysis.VisualBasic.Syntax Namespace Microsoft.CodeAnalysis.VisualBasic.ExtractMethod diff --git a/src/Features/VisualBasic/Portable/ExtractMethod/VisualBasicSyntaxTriviaService.vb b/src/Features/VisualBasic/Portable/ExtractMethod/VisualBasicSyntaxTriviaService.vb index 6e953405308f2..d842859e01178 100644 --- a/src/Features/VisualBasic/Portable/ExtractMethod/VisualBasicSyntaxTriviaService.vb +++ b/src/Features/VisualBasic/Portable/ExtractMethod/VisualBasicSyntaxTriviaService.vb @@ -3,7 +3,7 @@ ' See the LICENSE file in the project root for more information. Imports Microsoft.CodeAnalysis.ExtractMethod -Imports Microsoft.CodeAnalysis.VisualBasic.LanguageServices +Imports Microsoft.CodeAnalysis.VisualBasic.LanguageService Namespace Microsoft.CodeAnalysis.VisualBasic.ExtractMethod Friend Class VisualBasicSyntaxTriviaService diff --git a/src/Features/VisualBasic/Portable/GenerateDefaultConstructors/VisualBasicGenerateDefaultConstructorsService.vb b/src/Features/VisualBasic/Portable/GenerateDefaultConstructors/VisualBasicGenerateDefaultConstructorsService.vb index dd827d9ebd536..24f2988e0397c 100644 --- a/src/Features/VisualBasic/Portable/GenerateDefaultConstructors/VisualBasicGenerateDefaultConstructorsService.vb +++ b/src/Features/VisualBasic/Portable/GenerateDefaultConstructors/VisualBasicGenerateDefaultConstructorsService.vb @@ -6,7 +6,7 @@ Imports System.Composition Imports System.Threading Imports Microsoft.CodeAnalysis.GenerateDefaultConstructors Imports Microsoft.CodeAnalysis.Host.Mef -Imports Microsoft.CodeAnalysis.LanguageServices +Imports Microsoft.CodeAnalysis.LanguageService Imports Microsoft.CodeAnalysis.Text Imports Microsoft.CodeAnalysis.VisualBasic.Syntax diff --git a/src/Features/VisualBasic/Portable/GenerateMember/GenerateParameterizedMember/VisualBasicGenerateMethodService.vb b/src/Features/VisualBasic/Portable/GenerateMember/GenerateParameterizedMember/VisualBasicGenerateMethodService.vb index 5081776b49ce3..27de6db3d16ad 100644 --- a/src/Features/VisualBasic/Portable/GenerateMember/GenerateParameterizedMember/VisualBasicGenerateMethodService.vb +++ b/src/Features/VisualBasic/Portable/GenerateMember/GenerateParameterizedMember/VisualBasicGenerateMethodService.vb @@ -7,7 +7,7 @@ Imports System.Threading Imports Microsoft.CodeAnalysis Imports Microsoft.CodeAnalysis.GenerateMember.GenerateParameterizedMember Imports Microsoft.CodeAnalysis.Host.Mef -Imports Microsoft.CodeAnalysis.LanguageServices +Imports Microsoft.CodeAnalysis.LanguageService Imports Microsoft.CodeAnalysis.VisualBasic.Extensions.ContextQuery Imports Microsoft.CodeAnalysis.VisualBasic.Syntax diff --git a/src/Features/VisualBasic/Portable/GenerateMember/GenerateParameterizedMember/VisualBasicGenerateParameterizedMemberService.vb b/src/Features/VisualBasic/Portable/GenerateMember/GenerateParameterizedMember/VisualBasicGenerateParameterizedMemberService.vb index 279a1e3e2a737..7823eb6fdc4e0 100644 --- a/src/Features/VisualBasic/Portable/GenerateMember/GenerateParameterizedMember/VisualBasicGenerateParameterizedMemberService.vb +++ b/src/Features/VisualBasic/Portable/GenerateMember/GenerateParameterizedMember/VisualBasicGenerateParameterizedMemberService.vb @@ -5,7 +5,7 @@ Imports System.Threading Imports Microsoft.CodeAnalysis Imports Microsoft.CodeAnalysis.CodeGeneration -Imports Microsoft.CodeAnalysis.LanguageServices +Imports Microsoft.CodeAnalysis.LanguageService Imports Microsoft.CodeAnalysis.PooledObjects Imports Microsoft.CodeAnalysis.VisualBasic.Symbols Imports Microsoft.CodeAnalysis.VisualBasic.Syntax @@ -54,7 +54,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.GenerateMember.GenerateMethod Return Me.Document.SemanticModel.Compilation.GetSpecialType(SpecialType.System_String) End Select - Dim typeInference = Document.Project.LanguageServices.GetService(Of ITypeInferenceService)() + Dim typeInference = Document.Project.Services.GetService(Of ITypeInferenceService)() Dim inferredType = typeInference.InferType( Document.SemanticModel, Me.InvocationExpression, objectAsDefault:=True, name:=Me.State.IdentifierToken.ValueText, cancellationToken:=cancellationToken) diff --git a/src/Features/VisualBasic/Portable/GenerateType/VisualBasicGenerateTypeService.vb b/src/Features/VisualBasic/Portable/GenerateType/VisualBasicGenerateTypeService.vb index dc029b8b77b94..3a28e4d6e3bc7 100644 --- a/src/Features/VisualBasic/Portable/GenerateType/VisualBasicGenerateTypeService.vb +++ b/src/Features/VisualBasic/Portable/GenerateType/VisualBasicGenerateTypeService.vb @@ -12,7 +12,7 @@ Imports Microsoft.CodeAnalysis.Formatting Imports Microsoft.CodeAnalysis.GenerateMember.GenerateConstructor Imports Microsoft.CodeAnalysis.GenerateType Imports Microsoft.CodeAnalysis.Host.Mef -Imports Microsoft.CodeAnalysis.LanguageServices +Imports Microsoft.CodeAnalysis.LanguageService Imports Microsoft.CodeAnalysis.Simplification Imports Microsoft.CodeAnalysis.Text Imports Microsoft.CodeAnalysis.Utilities @@ -565,10 +565,6 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.GenerateType Return False End If - If GeneratedTypesMustBePublic(project) Then - Return True - End If - Dim node As SyntaxNode = expression While node IsNot Nothing ' Types in BaseList, Type Constraint or Member Types cannot be of more restricted accessibility than the declaring type diff --git a/src/Features/VisualBasic/Portable/ImplementInterface/VisualBasicImplementInterfaceCodeFixProvider.vb b/src/Features/VisualBasic/Portable/ImplementInterface/VisualBasicImplementInterfaceCodeFixProvider.vb index fb2e2e22bcc78..cc46c9f643c34 100644 --- a/src/Features/VisualBasic/Portable/ImplementInterface/VisualBasicImplementInterfaceCodeFixProvider.vb +++ b/src/Features/VisualBasic/Portable/ImplementInterface/VisualBasicImplementInterfaceCodeFixProvider.vb @@ -62,7 +62,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.ImplementInterface Dim service = document.GetLanguageService(Of IImplementInterfaceService)() Dim actions = service.GetCodeActions( document, - context.Options.GetImplementTypeGenerationOptions(document.Project.LanguageServices), + context.Options.GetImplementTypeGenerationOptions(document.Project.Services), Await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(False), typeNode, cancellationToken) diff --git a/src/Features/VisualBasic/Portable/InitializeParameter/VisualBasicAddParameterCheckCodeRefactoringProvider.vb b/src/Features/VisualBasic/Portable/InitializeParameter/VisualBasicAddParameterCheckCodeRefactoringProvider.vb index 8df095c96b8a2..a178813c0c2d4 100644 --- a/src/Features/VisualBasic/Portable/InitializeParameter/VisualBasicAddParameterCheckCodeRefactoringProvider.vb +++ b/src/Features/VisualBasic/Portable/InitializeParameter/VisualBasicAddParameterCheckCodeRefactoringProvider.vb @@ -9,10 +9,10 @@ Imports Microsoft.CodeAnalysis.CodeGeneration Imports Microsoft.CodeAnalysis.CodeRefactorings Imports Microsoft.CodeAnalysis.Editing Imports Microsoft.CodeAnalysis.InitializeParameter -Imports Microsoft.CodeAnalysis.LanguageServices +Imports Microsoft.CodeAnalysis.LanguageService Imports Microsoft.CodeAnalysis.Options Imports Microsoft.CodeAnalysis.Simplification -Imports Microsoft.CodeAnalysis.VisualBasic.LanguageServices +Imports Microsoft.CodeAnalysis.VisualBasic.LanguageService Imports Microsoft.CodeAnalysis.VisualBasic.Simplification Imports Microsoft.CodeAnalysis.VisualBasic.Syntax diff --git a/src/Features/VisualBasic/Portable/InitializeParameter/VisualBasicInitializeMemberFromParameterCodeRefactoringProvider.vb b/src/Features/VisualBasic/Portable/InitializeParameter/VisualBasicInitializeMemberFromParameterCodeRefactoringProvider.vb index 37cea0039da8c..f57ff76cb10dd 100644 --- a/src/Features/VisualBasic/Portable/InitializeParameter/VisualBasicInitializeMemberFromParameterCodeRefactoringProvider.vb +++ b/src/Features/VisualBasic/Portable/InitializeParameter/VisualBasicInitializeMemberFromParameterCodeRefactoringProvider.vb @@ -7,9 +7,9 @@ Imports System.Diagnostics.CodeAnalysis Imports Microsoft.CodeAnalysis.CodeRefactorings Imports Microsoft.CodeAnalysis.Editing Imports Microsoft.CodeAnalysis.InitializeParameter -Imports Microsoft.CodeAnalysis.LanguageServices +Imports Microsoft.CodeAnalysis.LanguageService Imports Microsoft.CodeAnalysis.Operations -Imports Microsoft.CodeAnalysis.VisualBasic.LanguageServices +Imports Microsoft.CodeAnalysis.VisualBasic.LanguageService Imports Microsoft.CodeAnalysis.VisualBasic.Syntax Namespace Microsoft.CodeAnalysis.VisualBasic.InitializeParameter diff --git a/src/Features/VisualBasic/Portable/InlineHints/VisualBasicInlineParameterNameHintsService.vb b/src/Features/VisualBasic/Portable/InlineHints/VisualBasicInlineParameterNameHintsService.vb index 710bd3fd2a417..dc22808b0ea30 100644 --- a/src/Features/VisualBasic/Portable/InlineHints/VisualBasicInlineParameterNameHintsService.vb +++ b/src/Features/VisualBasic/Portable/InlineHints/VisualBasicInlineParameterNameHintsService.vb @@ -6,7 +6,7 @@ Imports System.Composition Imports System.Threading Imports Microsoft.CodeAnalysis.Host.Mef Imports Microsoft.CodeAnalysis.InlineHints -Imports Microsoft.CodeAnalysis.LanguageServices +Imports Microsoft.CodeAnalysis.LanguageService Imports Microsoft.CodeAnalysis.Options Imports Microsoft.CodeAnalysis.PooledObjects Imports Microsoft.CodeAnalysis.VisualBasic.Syntax diff --git a/src/Features/VisualBasic/Portable/IntroduceVariable/VisualBasicIntroduceParameterCodeRefactoringProvider.vb b/src/Features/VisualBasic/Portable/IntroduceVariable/VisualBasicIntroduceParameterCodeRefactoringProvider.vb index 0c7f03ca1fa12..b8ffe9115df9a 100644 --- a/src/Features/VisualBasic/Portable/IntroduceVariable/VisualBasicIntroduceParameterCodeRefactoringProvider.vb +++ b/src/Features/VisualBasic/Portable/IntroduceVariable/VisualBasicIntroduceParameterCodeRefactoringProvider.vb @@ -5,6 +5,7 @@ Imports System.Composition Imports System.Diagnostics.CodeAnalysis Imports Microsoft.CodeAnalysis.CodeRefactorings +Imports Microsoft.CodeAnalysis.Host.Mef Imports Microsoft.CodeAnalysis.IntroduceVariable Imports Microsoft.CodeAnalysis.VisualBasic.CodeGeneration Imports Microsoft.CodeAnalysis.VisualBasic.Syntax @@ -15,7 +16,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.IntroduceVariable Inherits AbstractIntroduceParameterService(Of ExpressionSyntax, InvocationExpressionSyntax, ObjectCreationExpressionSyntax, IdentifierNameSyntax) - + Public Sub New() End Sub diff --git a/src/Features/VisualBasic/Portable/LanguageServices/VisualBasicStructuralTypeDisplayService.vb b/src/Features/VisualBasic/Portable/LanguageServices/VisualBasicStructuralTypeDisplayService.vb index 924174b5cc078..bc7d9effedecc 100644 --- a/src/Features/VisualBasic/Portable/LanguageServices/VisualBasicStructuralTypeDisplayService.vb +++ b/src/Features/VisualBasic/Portable/LanguageServices/VisualBasicStructuralTypeDisplayService.vb @@ -5,10 +5,10 @@ Imports System.Collections.Immutable Imports System.Composition Imports Microsoft.CodeAnalysis.Host.Mef -Imports Microsoft.CodeAnalysis.LanguageServices +Imports Microsoft.CodeAnalysis.LanguageService Imports Microsoft.CodeAnalysis.PooledObjects Imports Microsoft.CodeAnalysis.VisualBasic -Imports Microsoft.CodeAnalysis.VisualBasic.LanguageServices +Imports Microsoft.CodeAnalysis.VisualBasic.LanguageService Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.LanguageServices diff --git a/src/Features/VisualBasic/Portable/LanguageServices/VisualBasicSymbolDisplayService.SymbolDescriptionBuilder.vb b/src/Features/VisualBasic/Portable/LanguageServices/VisualBasicSymbolDisplayService.SymbolDescriptionBuilder.vb index 5c101ab3b6497..b64bb8f0c6635 100644 --- a/src/Features/VisualBasic/Portable/LanguageServices/VisualBasicSymbolDisplayService.SymbolDescriptionBuilder.vb +++ b/src/Features/VisualBasic/Portable/LanguageServices/VisualBasicSymbolDisplayService.SymbolDescriptionBuilder.vb @@ -6,7 +6,7 @@ Imports System.Collections.Immutable Imports System.Threading Imports Microsoft.CodeAnalysis.Classification Imports Microsoft.CodeAnalysis.Host -Imports Microsoft.CodeAnalysis.LanguageServices +Imports Microsoft.CodeAnalysis.LanguageService Imports Microsoft.CodeAnalysis.VisualBasic Imports Microsoft.CodeAnalysis.VisualBasic.Syntax @@ -29,7 +29,7 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.LanguageServices Public Sub New(semanticModel As SemanticModel, position As Integer, - services As HostWorkspaceServices, + services As SolutionServices, structuralTypeDisplayService As IStructuralTypeDisplayService, options As SymbolDescriptionOptions, cancellationToken As CancellationToken) diff --git a/src/Features/VisualBasic/Portable/LanguageServices/VisualBasicSymbolDisplayService.vb b/src/Features/VisualBasic/Portable/LanguageServices/VisualBasicSymbolDisplayService.vb index 88ca1d076f1fb..b62f4e65b803a 100644 --- a/src/Features/VisualBasic/Portable/LanguageServices/VisualBasicSymbolDisplayService.vb +++ b/src/Features/VisualBasic/Portable/LanguageServices/VisualBasicSymbolDisplayService.vb @@ -5,14 +5,14 @@ Imports System.Threading Imports Microsoft.CodeAnalysis.Classification.Classifiers Imports Microsoft.CodeAnalysis.Host -Imports Microsoft.CodeAnalysis.LanguageServices +Imports Microsoft.CodeAnalysis.LanguageService Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.LanguageServices ' Friend Class VisualBasicSymbolDisplayService Inherits AbstractSymbolDisplayService - Public Sub New(provider As HostLanguageServices) + Public Sub New(provider As Host.LanguageServices) MyBase.New(provider) End Sub @@ -20,7 +20,7 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.LanguageServices position As Integer, options As SymbolDescriptionOptions, cancellationToken As CancellationToken) As AbstractSymbolDescriptionBuilder - Return New SymbolDescriptionBuilder(semanticModel, position, Services.WorkspaceServices, AnonymousTypeDisplayService, options, cancellationToken) + Return New SymbolDescriptionBuilder(semanticModel, position, Services.SolutionServices, AnonymousTypeDisplayService, options, cancellationToken) End Function End Class End Namespace diff --git a/src/Features/VisualBasic/Portable/LanguageServices/VisualBasicSymbolDisplayServiceFactory.vb b/src/Features/VisualBasic/Portable/LanguageServices/VisualBasicSymbolDisplayServiceFactory.vb index 93edb704cd44c..a13cdc67e2d67 100644 --- a/src/Features/VisualBasic/Portable/LanguageServices/VisualBasicSymbolDisplayServiceFactory.vb +++ b/src/Features/VisualBasic/Portable/LanguageServices/VisualBasicSymbolDisplayServiceFactory.vb @@ -5,7 +5,7 @@ Imports System.Composition Imports Microsoft.CodeAnalysis.Host Imports Microsoft.CodeAnalysis.Host.Mef -Imports Microsoft.CodeAnalysis.LanguageServices +Imports Microsoft.CodeAnalysis.LanguageService Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.LanguageServices @@ -18,7 +18,7 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.LanguageServices End Sub Public Function CreateLanguageService(provider As HostLanguageServices) As ILanguageService Implements ILanguageServiceFactory.CreateLanguageService - Return New VisualBasicSymbolDisplayService(provider) + Return New VisualBasicSymbolDisplayService(provider.LanguageServices) End Function End Class End Namespace diff --git a/src/Features/VisualBasic/Portable/NavigationBar/VisualBasicNavigationBarItemService.vb b/src/Features/VisualBasic/Portable/NavigationBar/VisualBasicNavigationBarItemService.vb index f3d89443fe212..c6ccb4d99cce3 100644 --- a/src/Features/VisualBasic/Portable/NavigationBar/VisualBasicNavigationBarItemService.vb +++ b/src/Features/VisualBasic/Portable/NavigationBar/VisualBasicNavigationBarItemService.vb @@ -8,7 +8,7 @@ Imports System.Threading Imports Microsoft.CodeAnalysis Imports Microsoft.CodeAnalysis.ErrorReporting Imports Microsoft.CodeAnalysis.Host.Mef -Imports Microsoft.CodeAnalysis.LanguageServices +Imports Microsoft.CodeAnalysis.LanguageService Imports Microsoft.CodeAnalysis.NavigationBar.RoslynNavigationBarItem Imports Microsoft.CodeAnalysis.PooledObjects Imports Microsoft.CodeAnalysis.Text diff --git a/src/Features/VisualBasic/Portable/QuickInfo/VisualBasicQuickInfoService.vb b/src/Features/VisualBasic/Portable/QuickInfo/VisualBasicQuickInfoService.vb index acf8f78e35c20..e245c1d97cf45 100644 --- a/src/Features/VisualBasic/Portable/QuickInfo/VisualBasicQuickInfoService.vb +++ b/src/Features/VisualBasic/Portable/QuickInfo/VisualBasicQuickInfoService.vb @@ -18,7 +18,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.QuickInfo End Sub Public Function CreateLanguageService(languageServices As HostLanguageServices) As ILanguageService Implements ILanguageServiceFactory.CreateLanguageService - Return New VisualBasicQuickInfoService(languageServices) + Return New VisualBasicQuickInfoService(languageServices.LanguageServices) End Function End Class @@ -26,7 +26,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.QuickInfo Friend Class VisualBasicQuickInfoService Inherits QuickInfoServiceWithProviders - Public Sub New(services As HostLanguageServices) + Public Sub New(services As Host.LanguageServices) MyBase.New(services) End Sub End Class diff --git a/src/Features/VisualBasic/Portable/QuickInfo/VisualBasicSemanticQuickInfoProvider.vb b/src/Features/VisualBasic/Portable/QuickInfo/VisualBasicSemanticQuickInfoProvider.vb index 1d7cc2a47eaa7..25719a98f6989 100644 --- a/src/Features/VisualBasic/Portable/QuickInfo/VisualBasicSemanticQuickInfoProvider.vb +++ b/src/Features/VisualBasic/Portable/QuickInfo/VisualBasicSemanticQuickInfoProvider.vb @@ -9,7 +9,7 @@ Imports System.Threading Imports Microsoft.CodeAnalysis Imports Microsoft.CodeAnalysis.Host Imports Microsoft.CodeAnalysis.Host.Mef -Imports Microsoft.CodeAnalysis.LanguageServices +Imports Microsoft.CodeAnalysis.LanguageService Imports Microsoft.CodeAnalysis.QuickInfo Imports Microsoft.CodeAnalysis.VisualBasic.Syntax Imports Microsoft.CodeAnalysis.VisualBasic.Utilities.IntrinsicOperators @@ -28,7 +28,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.QuickInfo context As QuickInfoContext, token As SyntaxToken) As Task(Of QuickInfoItem) Dim semanticModel = Await context.Document.GetRequiredSemanticModelAsync(context.CancellationToken).ConfigureAwait(False) - Dim services = context.Document.Project.Solution.Workspace.Services + Dim services = context.Document.Project.Solution.Services Dim info = Await BuildQuickInfoAsync(services, semanticModel, token, context.Options, context.CancellationToken).ConfigureAwait(False) If info IsNot Nothing Then Return info @@ -49,7 +49,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.QuickInfo End Function Private Overloads Shared Async Function BuildQuickInfoAsync( - services As HostWorkspaceServices, + services As SolutionServices, semanticModel As SemanticModel, token As SyntaxToken, options As SymbolDescriptionOptions, @@ -161,7 +161,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.QuickInfo End Function Private Overloads Shared Async Function BuildContentAsync( - services As HostWorkspaceServices, + services As SolutionServices, semanticModel As SemanticModel, token As SyntaxToken, declarators As SeparatedSyntaxList(Of VariableDeclaratorSyntax), diff --git a/src/Features/VisualBasic/Portable/RemoveUnusedVariable/VisualBasicRemoveUnusedVariableCodeFixProvider.vb b/src/Features/VisualBasic/Portable/RemoveUnusedVariable/VisualBasicRemoveUnusedVariableCodeFixProvider.vb index ab6247fe46216..1cd9336ac2fe8 100644 --- a/src/Features/VisualBasic/Portable/RemoveUnusedVariable/VisualBasicRemoveUnusedVariableCodeFixProvider.vb +++ b/src/Features/VisualBasic/Portable/RemoveUnusedVariable/VisualBasicRemoveUnusedVariableCodeFixProvider.vb @@ -7,7 +7,7 @@ Imports System.Composition Imports System.Diagnostics.CodeAnalysis Imports Microsoft.CodeAnalysis.CodeFixes Imports Microsoft.CodeAnalysis.Editing -Imports Microsoft.CodeAnalysis.LanguageServices +Imports Microsoft.CodeAnalysis.LanguageService Imports Microsoft.CodeAnalysis.RemoveUnusedVariable Imports Microsoft.CodeAnalysis.VisualBasic.Syntax diff --git a/src/Features/VisualBasic/Portable/ReplaceMethodWithProperty/VisualBasicReplaceMethodWithPropertyService.vb b/src/Features/VisualBasic/Portable/ReplaceMethodWithProperty/VisualBasicReplaceMethodWithPropertyService.vb index 3c35fa6842d6a..fdc25c01e8238 100644 --- a/src/Features/VisualBasic/Portable/ReplaceMethodWithProperty/VisualBasicReplaceMethodWithPropertyService.vb +++ b/src/Features/VisualBasic/Portable/ReplaceMethodWithProperty/VisualBasicReplaceMethodWithPropertyService.vb @@ -10,7 +10,7 @@ Imports Microsoft.CodeAnalysis.Host.Mef Imports Microsoft.CodeAnalysis.Options Imports Microsoft.CodeAnalysis.ReplaceMethodWithProperty Imports Microsoft.CodeAnalysis.VisualBasic.Syntax -Imports Microsoft.CodeAnalysis.VisualBasic.LanguageServices +Imports Microsoft.CodeAnalysis.VisualBasic.LanguageService Imports Microsoft.CodeAnalysis.CodeGeneration Namespace Microsoft.CodeAnalysis.VisualBasic.CodeRefactorings.ReplaceMethodWithProperty diff --git a/src/Features/VisualBasic/Portable/SignatureHelp/AbstractIntrinsicOperatorSignatureHelpProvider.vb b/src/Features/VisualBasic/Portable/SignatureHelp/AbstractIntrinsicOperatorSignatureHelpProvider.vb index 82f39a65c0049..2b8403c71fdc1 100644 --- a/src/Features/VisualBasic/Portable/SignatureHelp/AbstractIntrinsicOperatorSignatureHelpProvider.vb +++ b/src/Features/VisualBasic/Portable/SignatureHelp/AbstractIntrinsicOperatorSignatureHelpProvider.vb @@ -3,7 +3,7 @@ ' See the LICENSE file in the project root for more information. Imports System.Threading -Imports Microsoft.CodeAnalysis.LanguageServices +Imports Microsoft.CodeAnalysis.LanguageService Imports Microsoft.CodeAnalysis.SignatureHelp Imports Microsoft.CodeAnalysis.Text Imports Microsoft.CodeAnalysis.VisualBasic.Utilities.IntrinsicOperators diff --git a/src/Features/VisualBasic/Portable/SignatureHelp/AbstractOrdinaryMethodSignatureHelpProvider.vb b/src/Features/VisualBasic/Portable/SignatureHelp/AbstractOrdinaryMethodSignatureHelpProvider.vb index 246d401cc013b..7ff272a7a8f25 100644 --- a/src/Features/VisualBasic/Portable/SignatureHelp/AbstractOrdinaryMethodSignatureHelpProvider.vb +++ b/src/Features/VisualBasic/Portable/SignatureHelp/AbstractOrdinaryMethodSignatureHelpProvider.vb @@ -3,7 +3,7 @@ ' See the LICENSE file in the project root for more information. Imports Microsoft.CodeAnalysis.DocumentationComments -Imports Microsoft.CodeAnalysis.LanguageServices +Imports Microsoft.CodeAnalysis.LanguageService Imports Microsoft.CodeAnalysis.SignatureHelp Namespace Microsoft.CodeAnalysis.VisualBasic.SignatureHelp diff --git a/src/Features/VisualBasic/Portable/SignatureHelp/AttributeSignatureHelpProvider.vb b/src/Features/VisualBasic/Portable/SignatureHelp/AttributeSignatureHelpProvider.vb index 90d944e141a32..9591aa03588f3 100644 --- a/src/Features/VisualBasic/Portable/SignatureHelp/AttributeSignatureHelpProvider.vb +++ b/src/Features/VisualBasic/Portable/SignatureHelp/AttributeSignatureHelpProvider.vb @@ -7,7 +7,7 @@ Imports System.Threading Imports Microsoft.CodeAnalysis Imports Microsoft.CodeAnalysis.DocumentationComments Imports Microsoft.CodeAnalysis.Host.Mef -Imports Microsoft.CodeAnalysis.LanguageServices +Imports Microsoft.CodeAnalysis.LanguageService Imports Microsoft.CodeAnalysis.SignatureHelp Imports Microsoft.CodeAnalysis.Text Imports Microsoft.CodeAnalysis.VisualBasic.Syntax diff --git a/src/Features/VisualBasic/Portable/SignatureHelp/CollectionInitializerSignatureHelpProvider.vb b/src/Features/VisualBasic/Portable/SignatureHelp/CollectionInitializerSignatureHelpProvider.vb index 0aaa13662d39d..ad09a4440b72b 100644 --- a/src/Features/VisualBasic/Portable/SignatureHelp/CollectionInitializerSignatureHelpProvider.vb +++ b/src/Features/VisualBasic/Portable/SignatureHelp/CollectionInitializerSignatureHelpProvider.vb @@ -6,7 +6,7 @@ Imports System.Composition Imports System.Runtime.InteropServices Imports System.Threading Imports Microsoft.CodeAnalysis.Host.Mef -Imports Microsoft.CodeAnalysis.LanguageServices +Imports Microsoft.CodeAnalysis.LanguageService Imports Microsoft.CodeAnalysis.SignatureHelp Imports Microsoft.CodeAnalysis.Text Imports Microsoft.CodeAnalysis.VisualBasic.Syntax diff --git a/src/Features/VisualBasic/Portable/SignatureHelp/FunctionAggregationSignatureHelpProvider.vb b/src/Features/VisualBasic/Portable/SignatureHelp/FunctionAggregationSignatureHelpProvider.vb index 9a2c0a951093d..4674b7e9a2d0f 100644 --- a/src/Features/VisualBasic/Portable/SignatureHelp/FunctionAggregationSignatureHelpProvider.vb +++ b/src/Features/VisualBasic/Portable/SignatureHelp/FunctionAggregationSignatureHelpProvider.vb @@ -6,7 +6,7 @@ Imports System.Composition Imports System.Threading Imports Microsoft.CodeAnalysis.DocumentationComments Imports Microsoft.CodeAnalysis.Host.Mef -Imports Microsoft.CodeAnalysis.LanguageServices +Imports Microsoft.CodeAnalysis.LanguageService Imports Microsoft.CodeAnalysis.SignatureHelp Imports Microsoft.CodeAnalysis.Text Imports Microsoft.CodeAnalysis.VisualBasic.Syntax diff --git a/src/Features/VisualBasic/Portable/SignatureHelp/GenericNameSignatureHelpProvider.vb b/src/Features/VisualBasic/Portable/SignatureHelp/GenericNameSignatureHelpProvider.vb index 42c4c0759668c..c4b6f087392ac 100644 --- a/src/Features/VisualBasic/Portable/SignatureHelp/GenericNameSignatureHelpProvider.vb +++ b/src/Features/VisualBasic/Portable/SignatureHelp/GenericNameSignatureHelpProvider.vb @@ -6,7 +6,7 @@ Imports System.Composition Imports System.Threading Imports Microsoft.CodeAnalysis.DocumentationComments Imports Microsoft.CodeAnalysis.Host.Mef -Imports Microsoft.CodeAnalysis.LanguageServices +Imports Microsoft.CodeAnalysis.LanguageService Imports Microsoft.CodeAnalysis.SignatureHelp Imports Microsoft.CodeAnalysis.Text Imports Microsoft.CodeAnalysis.VisualBasic.Syntax diff --git a/src/Features/VisualBasic/Portable/SignatureHelp/InvocationExpressionSignatureHelpProvider.DelegateInvoke.vb b/src/Features/VisualBasic/Portable/SignatureHelp/InvocationExpressionSignatureHelpProvider.DelegateInvoke.vb index 9609f135a1cf1..ad65a25624f01 100644 --- a/src/Features/VisualBasic/Portable/SignatureHelp/InvocationExpressionSignatureHelpProvider.DelegateInvoke.vb +++ b/src/Features/VisualBasic/Portable/SignatureHelp/InvocationExpressionSignatureHelpProvider.DelegateInvoke.vb @@ -4,7 +4,7 @@ Imports System.Threading Imports Microsoft.CodeAnalysis.DocumentationComments -Imports Microsoft.CodeAnalysis.LanguageServices +Imports Microsoft.CodeAnalysis.LanguageService Imports Microsoft.CodeAnalysis.SignatureHelp Imports Microsoft.CodeAnalysis.VisualBasic.Syntax diff --git a/src/Features/VisualBasic/Portable/SignatureHelp/InvocationExpressionSignatureHelpProvider.ElementAccess.vb b/src/Features/VisualBasic/Portable/SignatureHelp/InvocationExpressionSignatureHelpProvider.ElementAccess.vb index 5a1e5f7ad3ce2..68d7c384df298 100644 --- a/src/Features/VisualBasic/Portable/SignatureHelp/InvocationExpressionSignatureHelpProvider.ElementAccess.vb +++ b/src/Features/VisualBasic/Portable/SignatureHelp/InvocationExpressionSignatureHelpProvider.ElementAccess.vb @@ -4,7 +4,7 @@ Imports System.Threading Imports Microsoft.CodeAnalysis.DocumentationComments -Imports Microsoft.CodeAnalysis.LanguageServices +Imports Microsoft.CodeAnalysis.LanguageService Imports Microsoft.CodeAnalysis.SignatureHelp Imports Microsoft.CodeAnalysis.VisualBasic.Syntax diff --git a/src/Features/VisualBasic/Portable/SignatureHelp/InvocationExpressionSignatureHelpProvider.vb b/src/Features/VisualBasic/Portable/SignatureHelp/InvocationExpressionSignatureHelpProvider.vb index 435852c85c46c..5b11b8aba83bb 100644 --- a/src/Features/VisualBasic/Portable/SignatureHelp/InvocationExpressionSignatureHelpProvider.vb +++ b/src/Features/VisualBasic/Portable/SignatureHelp/InvocationExpressionSignatureHelpProvider.vb @@ -7,7 +7,7 @@ Imports System.Composition Imports System.Threading Imports Microsoft.CodeAnalysis.DocumentationComments Imports Microsoft.CodeAnalysis.Host.Mef -Imports Microsoft.CodeAnalysis.LanguageServices +Imports Microsoft.CodeAnalysis.LanguageService Imports Microsoft.CodeAnalysis.SignatureHelp Imports Microsoft.CodeAnalysis.Text Imports Microsoft.CodeAnalysis.VisualBasic.Syntax diff --git a/src/Features/VisualBasic/Portable/SignatureHelp/ObjectCreationExpressionSignatureHelpProvider.DelegateType.vb b/src/Features/VisualBasic/Portable/SignatureHelp/ObjectCreationExpressionSignatureHelpProvider.DelegateType.vb index 3e376f9379b10..d64c201550430 100644 --- a/src/Features/VisualBasic/Portable/SignatureHelp/ObjectCreationExpressionSignatureHelpProvider.DelegateType.vb +++ b/src/Features/VisualBasic/Portable/SignatureHelp/ObjectCreationExpressionSignatureHelpProvider.DelegateType.vb @@ -3,7 +3,7 @@ ' See the LICENSE file in the project root for more information. Imports Microsoft.CodeAnalysis.DocumentationComments -Imports Microsoft.CodeAnalysis.LanguageServices +Imports Microsoft.CodeAnalysis.LanguageService Imports Microsoft.CodeAnalysis.SignatureHelp Imports Microsoft.CodeAnalysis.VisualBasic.Syntax diff --git a/src/Features/VisualBasic/Portable/SignatureHelp/ObjectCreationExpressionSignatureHelpProvider.NormalType.vb b/src/Features/VisualBasic/Portable/SignatureHelp/ObjectCreationExpressionSignatureHelpProvider.NormalType.vb index 970f7976881e8..d31c052858f00 100644 --- a/src/Features/VisualBasic/Portable/SignatureHelp/ObjectCreationExpressionSignatureHelpProvider.NormalType.vb +++ b/src/Features/VisualBasic/Portable/SignatureHelp/ObjectCreationExpressionSignatureHelpProvider.NormalType.vb @@ -5,7 +5,7 @@ Imports System.Threading Imports Microsoft.CodeAnalysis Imports Microsoft.CodeAnalysis.DocumentationComments -Imports Microsoft.CodeAnalysis.LanguageServices +Imports Microsoft.CodeAnalysis.LanguageService Imports Microsoft.CodeAnalysis.SignatureHelp Imports Microsoft.CodeAnalysis.VisualBasic.Syntax diff --git a/src/Features/VisualBasic/Portable/SignatureHelp/ObjectCreationExpressionSignatureHelpProvider.vb b/src/Features/VisualBasic/Portable/SignatureHelp/ObjectCreationExpressionSignatureHelpProvider.vb index 4a14fbb26db6b..ffe6401682e03 100644 --- a/src/Features/VisualBasic/Portable/SignatureHelp/ObjectCreationExpressionSignatureHelpProvider.vb +++ b/src/Features/VisualBasic/Portable/SignatureHelp/ObjectCreationExpressionSignatureHelpProvider.vb @@ -6,7 +6,7 @@ Imports System.Composition Imports System.Threading Imports Microsoft.CodeAnalysis.DocumentationComments Imports Microsoft.CodeAnalysis.Host.Mef -Imports Microsoft.CodeAnalysis.LanguageServices +Imports Microsoft.CodeAnalysis.LanguageService Imports Microsoft.CodeAnalysis.SignatureHelp Imports Microsoft.CodeAnalysis.Text Imports Microsoft.CodeAnalysis.VisualBasic.Syntax diff --git a/src/Features/VisualBasic/Portable/SignatureHelp/RaiseEventStatementSignatureHelpProvider.vb b/src/Features/VisualBasic/Portable/SignatureHelp/RaiseEventStatementSignatureHelpProvider.vb index 2917c34662e88..6c99beba8903f 100644 --- a/src/Features/VisualBasic/Portable/SignatureHelp/RaiseEventStatementSignatureHelpProvider.vb +++ b/src/Features/VisualBasic/Portable/SignatureHelp/RaiseEventStatementSignatureHelpProvider.vb @@ -6,7 +6,7 @@ Imports System.Composition Imports System.Threading Imports Microsoft.CodeAnalysis.DocumentationComments Imports Microsoft.CodeAnalysis.Host.Mef -Imports Microsoft.CodeAnalysis.LanguageServices +Imports Microsoft.CodeAnalysis.LanguageService Imports Microsoft.CodeAnalysis.SignatureHelp Imports Microsoft.CodeAnalysis.Text Imports Microsoft.CodeAnalysis.VisualBasic.Syntax diff --git a/src/Features/VisualBasic/Portable/SimplifyThisOrMe/VisualBasicSimplifyThisOrMeDiagnosticAnalyzer.vb b/src/Features/VisualBasic/Portable/SimplifyThisOrMe/VisualBasicSimplifyThisOrMeDiagnosticAnalyzer.vb index 08cb415cba697..570b5b6c5e10a 100644 --- a/src/Features/VisualBasic/Portable/SimplifyThisOrMe/VisualBasicSimplifyThisOrMeDiagnosticAnalyzer.vb +++ b/src/Features/VisualBasic/Portable/SimplifyThisOrMe/VisualBasicSimplifyThisOrMeDiagnosticAnalyzer.vb @@ -3,11 +3,11 @@ ' See the LICENSE file in the project root for more information. Imports Microsoft.CodeAnalysis.Diagnostics -Imports Microsoft.CodeAnalysis.LanguageServices +Imports Microsoft.CodeAnalysis.LanguageService Imports Microsoft.CodeAnalysis.Simplification Imports Microsoft.CodeAnalysis.Simplification.Simplifiers Imports Microsoft.CodeAnalysis.SimplifyThisOrMe -Imports Microsoft.CodeAnalysis.VisualBasic.LanguageServices +Imports Microsoft.CodeAnalysis.VisualBasic.LanguageService Imports Microsoft.CodeAnalysis.VisualBasic.Simplification Imports Microsoft.CodeAnalysis.VisualBasic.Simplification.Simplifiers Imports Microsoft.CodeAnalysis.VisualBasic.Syntax diff --git a/src/Features/VisualBasic/Portable/Structure/Providers/DocumentationCommentStructureProvider.vb b/src/Features/VisualBasic/Portable/Structure/Providers/DocumentationCommentStructureProvider.vb index a820ea14bbdef..fbb1cc3928648 100644 --- a/src/Features/VisualBasic/Portable/Structure/Providers/DocumentationCommentStructureProvider.vb +++ b/src/Features/VisualBasic/Portable/Structure/Providers/DocumentationCommentStructureProvider.vb @@ -6,7 +6,7 @@ Imports System.Threading Imports Microsoft.CodeAnalysis.[Shared].Collections Imports Microsoft.CodeAnalysis.Structure Imports Microsoft.CodeAnalysis.Text -Imports Microsoft.CodeAnalysis.VisualBasic.LanguageServices +Imports Microsoft.CodeAnalysis.VisualBasic.LanguageService Imports Microsoft.CodeAnalysis.VisualBasic.Syntax Namespace Microsoft.CodeAnalysis.VisualBasic.Structure diff --git a/src/Features/VisualBasic/Portable/Structure/VisualBasicBlockStructureService.vb b/src/Features/VisualBasic/Portable/Structure/VisualBasicBlockStructureService.vb index 377481c94497f..17cb58dc0b418 100644 --- a/src/Features/VisualBasic/Portable/Structure/VisualBasicBlockStructureService.vb +++ b/src/Features/VisualBasic/Portable/Structure/VisualBasicBlockStructureService.vb @@ -19,15 +19,15 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Structure End Sub Public Function CreateLanguageService(languageServices As HostLanguageServices) As ILanguageService Implements ILanguageServiceFactory.CreateLanguageService - Return New VisualBasicBlockStructureService(languageServices.WorkspaceServices.Workspace) + Return New VisualBasicBlockStructureService(languageServices.LanguageServices.SolutionServices) End Function End Class Friend Class VisualBasicBlockStructureService Inherits BlockStructureServiceWithProviders - Friend Sub New(workspace As Workspace) - MyBase.New(workspace) + Friend Sub New(services As SolutionServices) + MyBase.New(services) End Sub Public Overrides ReadOnly Property Language As String diff --git a/src/Features/VisualBasic/Portable/Wrapping/BinaryExpression/VisualBasicBinaryExpressionWrapper.vb b/src/Features/VisualBasic/Portable/Wrapping/BinaryExpression/VisualBasicBinaryExpressionWrapper.vb index 24bfad557cad4..bc89ef2544623 100644 --- a/src/Features/VisualBasic/Portable/Wrapping/BinaryExpression/VisualBasicBinaryExpressionWrapper.vb +++ b/src/Features/VisualBasic/Portable/Wrapping/BinaryExpression/VisualBasicBinaryExpressionWrapper.vb @@ -3,7 +3,7 @@ ' See the LICENSE file in the project root for more information. Imports Microsoft.CodeAnalysis.VisualBasic.Indentation -Imports Microsoft.CodeAnalysis.VisualBasic.LanguageServices +Imports Microsoft.CodeAnalysis.VisualBasic.LanguageService Imports Microsoft.CodeAnalysis.VisualBasic.Precedence Imports Microsoft.CodeAnalysis.VisualBasic.Syntax Imports Microsoft.CodeAnalysis.Wrapping.BinaryExpression diff --git a/src/Features/VisualBasic/Portable/Wrapping/ChainedExpression/VisualBasicChainedExpressionWrapper.vb b/src/Features/VisualBasic/Portable/Wrapping/ChainedExpression/VisualBasicChainedExpressionWrapper.vb index 5628e836e983b..bc3e102d4e95b 100644 --- a/src/Features/VisualBasic/Portable/Wrapping/ChainedExpression/VisualBasicChainedExpressionWrapper.vb +++ b/src/Features/VisualBasic/Portable/Wrapping/ChainedExpression/VisualBasicChainedExpressionWrapper.vb @@ -3,7 +3,7 @@ ' See the LICENSE file in the project root for more information. Imports Microsoft.CodeAnalysis.VisualBasic.Indentation -Imports Microsoft.CodeAnalysis.VisualBasic.LanguageServices +Imports Microsoft.CodeAnalysis.VisualBasic.LanguageService Imports Microsoft.CodeAnalysis.VisualBasic.Syntax Imports Microsoft.CodeAnalysis.Wrapping.ChainedExpression diff --git a/src/Features/VisualBasic/Portable/Wrapping/SeparatedSyntaxList/VisualBasicArgumentWrapper.vb b/src/Features/VisualBasic/Portable/Wrapping/SeparatedSyntaxList/VisualBasicArgumentWrapper.vb index b2dac3164d143..58d3e78f30f68 100644 --- a/src/Features/VisualBasic/Portable/Wrapping/SeparatedSyntaxList/VisualBasicArgumentWrapper.vb +++ b/src/Features/VisualBasic/Portable/Wrapping/SeparatedSyntaxList/VisualBasicArgumentWrapper.vb @@ -3,7 +3,7 @@ ' See the LICENSE file in the project root for more information. Imports Microsoft.CodeAnalysis.Text -Imports Microsoft.CodeAnalysis.VisualBasic.LanguageServices +Imports Microsoft.CodeAnalysis.VisualBasic.LanguageService Imports Microsoft.CodeAnalysis.VisualBasic.Syntax Namespace Microsoft.CodeAnalysis.VisualBasic.Wrapping.SeparatedSyntaxList diff --git a/src/Interactive/Host/Interactive/Core/InteractiveHost.cs b/src/Interactive/Host/Interactive/Core/InteractiveHost.cs index c89f4acbc8e50..057de7bb967f2 100644 --- a/src/Interactive/Host/Interactive/Core/InteractiveHost.cs +++ b/src/Interactive/Host/Interactive/Core/InteractiveHost.cs @@ -337,10 +337,7 @@ public async Task ResetAsync(InteractiveHostOptions optio var newService = CreateRemoteService(options, skipInitialization: false); var oldService = Interlocked.Exchange(ref _lazyRemoteService, newService); - if (oldService != null) - { - oldService.Dispose(); - } + oldService?.Dispose(); var initializedService = await TryGetOrCreateRemoteServiceAsync().ConfigureAwait(false); if (initializedService.Service == null) diff --git a/src/Interactive/HostTest/InteractiveHostDesktopTests.cs b/src/Interactive/HostTest/InteractiveHostDesktopTests.cs index 924ea37b7f080..1b49177eecc2e 100644 --- a/src/Interactive/HostTest/InteractiveHostDesktopTests.cs +++ b/src/Interactive/HostTest/InteractiveHostDesktopTests.cs @@ -801,7 +801,7 @@ await Execute(@" AssertEx.AssertEqualToleratingWhitespaceDifferences("", error); AssertEx.AssertEqualToleratingWhitespaceDifferences( -$@"{ string.Format(InteractiveHostResources.Loading_context_from_0, Path.GetFileName(rspFile.Path)) } +$@"{string.Format(InteractiveHostResources.Loading_context_from_0, Path.GetFileName(rspFile.Path))} OK ", output); } @@ -825,11 +825,11 @@ public async Task InitialScript_Error() var error = await ReadErrorOutputToEnd(); var output = await ReadOutputToEnd(); - AssertEx.AssertEqualToleratingWhitespaceDifferences($@"{initFile.Path}(1,3): error CS1002: { CSharpResources.ERR_SemicolonExpected } + AssertEx.AssertEqualToleratingWhitespaceDifferences($@"{initFile.Path}(1,3): error CS1002: {CSharpResources.ERR_SemicolonExpected} ", error); AssertEx.AssertEqualToleratingWhitespaceDifferences($@" -{ string.Format(InteractiveHostResources.Loading_context_from_0, Path.GetFileName(rspFile.Path)) } +{string.Format(InteractiveHostResources.Loading_context_from_0, Path.GetFileName(rspFile.Path))} [System.Diagnostics.Process] ", output); } @@ -851,7 +851,7 @@ public async Task ScriptAndArguments() var error = await ReadErrorOutputToEnd(); Assert.Equal("", error); AssertEx.AssertEqualToleratingWhitespaceDifferences( -$@"{ string.Format(InteractiveHostResources.Loading_context_from_0, Path.GetFileName(rspFile.Path)) } +$@"{string.Format(InteractiveHostResources.Loading_context_from_0, Path.GetFileName(rspFile.Path))} ""a"" ""b"" ""c"" @@ -863,7 +863,7 @@ public async Task Script_NoHostNamespaces() { await Execute("nameof(Microsoft.Missing)"); var error = await ReadErrorOutputToEnd(); - AssertEx.AssertEqualToleratingWhitespaceDifferences($@"(1,8): error CS0234: { string.Format(CSharpResources.ERR_DottedTypeNameNotFoundInNS, "Missing", "Microsoft") }", + AssertEx.AssertEqualToleratingWhitespaceDifferences($@"(1,8): error CS0234: {string.Format(CSharpResources.ERR_DottedTypeNameNotFoundInNS, "Missing", "Microsoft")}", error); var output = await ReadOutputToEnd(); diff --git a/src/Scripting/CSharp/Microsoft.CodeAnalysis.CSharp.Scripting.csproj b/src/Scripting/CSharp/Microsoft.CodeAnalysis.CSharp.Scripting.csproj index 3e4aa0a340a56..c69eb5e942c98 100644 --- a/src/Scripting/CSharp/Microsoft.CodeAnalysis.CSharp.Scripting.csproj +++ b/src/Scripting/CSharp/Microsoft.CodeAnalysis.CSharp.Scripting.csproj @@ -25,6 +25,7 @@ + diff --git a/src/Scripting/CSharpTest.Desktop/CsiTests.cs b/src/Scripting/CSharpTest.Desktop/CsiTests.cs index 973cef7ca0f16..61a392ad2436c 100644 --- a/src/Scripting/CSharpTest.Desktop/CsiTests.cs +++ b/src/Scripting/CSharpTest.Desktop/CsiTests.cs @@ -57,7 +57,7 @@ public void CurrentWorkingDirectory_Change() "); var expected = $@" -{ string.Format(CSharpScriptingResources.LogoLine1, s_compilerVersion) } +{string.Format(CSharpScriptingResources.LogoLine1, s_compilerVersion)} {CSharpScriptingResources.LogoLine2} {ScriptingResources.HelpPrompt} @@ -72,8 +72,8 @@ public void CurrentWorkingDirectory_Change() AssertEx.AssertEqualToleratingWhitespaceDifferences(expected, result.Output); AssertEx.AssertEqualToleratingWhitespaceDifferences($@" -(1,7): error CS1504: { string.Format(CSharpResources.ERR_NoSourceFile, "a.csx", CSharpResources.CouldNotFindFile) } -(1,1): error CS0006: { string.Format(CSharpResources.ERR_NoMetadataFile, "C.dll") } +(1,7): error CS1504: {string.Format(CSharpResources.ERR_NoSourceFile, "a.csx", CSharpResources.CouldNotFindFile)} +(1,1): error CS0006: {string.Format(CSharpResources.ERR_NoMetadataFile, "C.dll")} ", result.Errors); Assert.Equal(0, result.ExitCode); diff --git a/src/Scripting/CSharpTest/CommandLineRunnerTests.cs b/src/Scripting/CSharpTest/CommandLineRunnerTests.cs index 80558f307c04c..0244868a4d42c 100644 --- a/src/Scripting/CSharpTest/CommandLineRunnerTests.cs +++ b/src/Scripting/CSharpTest/CommandLineRunnerTests.cs @@ -28,7 +28,7 @@ public class CommandLineRunnerTests : TestBase { private static readonly string s_compilerVersion = CommonCompiler.GetProductVersion(typeof(CSharpInteractiveCompiler)); - private string LogoAndHelpPrompt => $@"{ string.Format(CSharpScriptingResources.LogoLine1, s_compilerVersion) } + private string LogoAndHelpPrompt => $@"{string.Format(CSharpScriptingResources.LogoLine1, s_compilerVersion)} {CSharpScriptingResources.LogoLine2} {ScriptingResources.HelpPrompt}"; @@ -128,7 +128,7 @@ select x * x . return new int[] {{ 1, 2, 3, 4, 5 }}; . }} «Yellow» -(1,19): warning CS1998: { CSharpResources.WRN_AsyncLacksAwaits } +(1,19): warning CS1998: {CSharpResources.WRN_AsyncLacksAwaits} «Gray» > from x in await GetStuffAsync() . where x > 2 @@ -137,7 +137,7 @@ . select x * x > ", runner.Console.Out.ToString()); AssertEx.AssertEqualToleratingWhitespaceDifferences( - $@"(1,19): warning CS1998: { CSharpResources.WRN_AsyncLacksAwaits }", + $@"(1,19): warning CS1998: {CSharpResources.WRN_AsyncLacksAwaits}", runner.Console.Error.ToString()); } @@ -146,10 +146,10 @@ . select x * x public void TestDisplayResultsWithCurrentUICulture1() { // logoOutput needs to be retrieved before the runner is started, because the runner changes the culture to de-DE. - var logoOutput = $@"{ string.Format(CSharpScriptingResources.LogoLine1, s_compilerVersion) } -{ CSharpScriptingResources.LogoLine2} + var logoOutput = $@"{string.Format(CSharpScriptingResources.LogoLine1, s_compilerVersion)} +{CSharpScriptingResources.LogoLine2} -{ ScriptingResources.HelpPrompt}"; +{ScriptingResources.HelpPrompt}"; var runner = CreateRunner(input: @"using System.Globalization; CultureInfo.DefaultThreadCurrentUICulture = new CultureInfo(""en-GB"", useUserOverride: false) @@ -160,7 +160,7 @@ public void TestDisplayResultsWithCurrentUICulture1() runner.RunInteractive(); AssertEx.AssertEqualToleratingWhitespaceDifferences( -$@"{ logoOutput } +$@"{logoOutput} > using System.Globalization; > CultureInfo.DefaultThreadCurrentUICulture = new CultureInfo(""en-GB"", useUserOverride: false) [en-GB] @@ -179,10 +179,10 @@ public void TestDisplayResultsWithCurrentUICulture1() public void TestDisplayResultsWithCurrentUICulture2() { // logoOutput needs to be retrieved before the runner is started, because the runner changes the culture to de-DE. - var logoOutput = $@"{ string.Format(CSharpScriptingResources.LogoLine1, s_compilerVersion) } -{ CSharpScriptingResources.LogoLine2} + var logoOutput = $@"{string.Format(CSharpScriptingResources.LogoLine1, s_compilerVersion)} +{CSharpScriptingResources.LogoLine2} -{ ScriptingResources.HelpPrompt}"; +{ScriptingResources.HelpPrompt}"; // Tests that DefaultThreadCurrentUICulture is respected and not DefaultThreadCurrentCulture. var runner = CreateRunner(input: @"using System.Globalization; @@ -195,7 +195,7 @@ public void TestDisplayResultsWithCurrentUICulture2() runner.RunInteractive(); AssertEx.AssertEqualToleratingWhitespaceDifferences( -$@"{ logoOutput } +$@"{logoOutput} > using System.Globalization; > CultureInfo.DefaultThreadCurrentUICulture = new CultureInfo(""en-GB"", useUserOverride: false) [en-GB] @@ -325,7 +325,7 @@ public void Args_Interactive2() runner.RunInteractive(); - var error = $@"error CS2001: { string.Format(CSharpResources.ERR_FileNotFound, Path.Combine(AppContext.BaseDirectory, "@arg1"))}"; + var error = $@"error CS2001: {string.Format(CSharpResources.ERR_FileNotFound, Path.Combine(AppContext.BaseDirectory, "@arg1"))}"; AssertEx.AssertEqualToleratingWhitespaceDifferences(error, runner.Console.Out.ToString()); AssertEx.AssertEqualToleratingWhitespaceDifferences(error, runner.Console.Error.ToString()); } @@ -472,7 +472,7 @@ public void Script_NonExistingFile() Assert.Equal(1, runner.RunInteractive()); - var error = $@"error CS2001: { string.Format(CSharpResources.ERR_FileNotFound, Path.Combine(AppContext.BaseDirectory, "a + b")) }"; + var error = $@"error CS2001: {string.Format(CSharpResources.ERR_FileNotFound, Path.Combine(AppContext.BaseDirectory, "a + b"))}"; AssertEx.AssertEqualToleratingWhitespaceDifferences(error, runner.Console.Out.ToString()); AssertEx.AssertEqualToleratingWhitespaceDifferences(error, runner.Console.Error.ToString()); } @@ -485,7 +485,7 @@ public void Help() Assert.Equal(0, runner.RunInteractive()); AssertEx.AssertEqualToleratingWhitespaceDifferences( -$@"{ string.Format(CSharpScriptingResources.LogoLine1, s_compilerVersion) } +$@"{string.Format(CSharpScriptingResources.LogoLine1, s_compilerVersion)} {CSharpScriptingResources.LogoLine2} {CSharpScriptingResources.InteractiveHelp} @@ -526,7 +526,7 @@ public void Script_BadUsings() Assert.Equal(1, runner.RunInteractive()); - var error = $@"error CS0246: { string.Format(CSharpResources.ERR_SingleTypeNameNotFound, "Alpha") }"; + var error = $@"error CS0246: {string.Format(CSharpResources.ERR_SingleTypeNameNotFound, "Alpha")}"; AssertEx.AssertEqualToleratingWhitespaceDifferences(error, runner.Console.Out.ToString()); AssertEx.AssertEqualToleratingWhitespaceDifferences(error, runner.Console.Error.ToString()); } @@ -541,12 +541,12 @@ public void Script_NoHostNamespaces() $@"{LogoAndHelpPrompt} > nameof(Microsoft.Missing) «Red» -(1,8): error CS0234: { string.Format(CSharpResources.ERR_DottedTypeNameNotFoundInNS, "Missing", "Microsoft") } +(1,8): error CS0234: {string.Format(CSharpResources.ERR_DottedTypeNameNotFoundInNS, "Missing", "Microsoft")} «Gray» > ", runner.Console.Out.ToString()); AssertEx.AssertEqualToleratingWhitespaceDifferences( - $"(1,8): error CS0234: { string.Format(CSharpResources.ERR_DottedTypeNameNotFoundInNS, "Missing", "Microsoft") }", + $"(1,8): error CS0234: {string.Format(CSharpResources.ERR_DottedTypeNameNotFoundInNS, "Missing", "Microsoft")}", runner.Console.Error.ToString()); } @@ -683,7 +683,7 @@ public void SourceSearchPaths_Change1() SearchPaths {{ }} > #load ""a.csx"" «Red» -(1,7): error CS1504: { string.Format(CSharpResources.ERR_NoSourceFile, "a.csx", CSharpResources.CouldNotFindFile) } +(1,7): error CS1504: {string.Format(CSharpResources.ERR_NoSourceFile, "a.csx", CSharpResources.CouldNotFindFile)} «Gray» > SourcePaths.Add(@""{dir.Path}"") > #load ""a.csx"" @@ -693,7 +693,7 @@ public void SourceSearchPaths_Change1() ", runner.Console.Out.ToString()); AssertEx.AssertEqualToleratingWhitespaceDifferences( - $@"(1,7): error CS1504: { string.Format(CSharpResources.ERR_NoSourceFile, "a.csx", CSharpResources.CouldNotFindFile) }", + $@"(1,7): error CS1504: {string.Format(CSharpResources.ERR_NoSourceFile, "a.csx", CSharpResources.CouldNotFindFile)}", runner.Console.Error.ToString()); } @@ -719,7 +719,7 @@ public void ReferenceSearchPaths_Change1() SearchPaths {{ }} > #r ""C.dll"" «Red» -(1,1): error CS0006: { string.Format(CSharpResources.ERR_NoMetadataFile, "C.dll") } +(1,1): error CS0006: {string.Format(CSharpResources.ERR_NoMetadataFile, "C.dll")} «Gray» > ReferencePaths.Add(@""{dir.Path}"") > #r ""C.dll"" @@ -729,7 +729,7 @@ public void ReferenceSearchPaths_Change1() ", runner.Console.Out.ToString()); AssertEx.AssertEqualToleratingWhitespaceDifferences( - $@"(1,1): error CS0006: { string.Format(CSharpResources.ERR_NoMetadataFile, "C.dll") }", + $@"(1,1): error CS0006: {string.Format(CSharpResources.ERR_NoMetadataFile, "C.dll")}", runner.Console.Error.ToString()); } @@ -805,7 +805,7 @@ 1 1 AssertEx.AssertEqualToleratingWhitespaceDifferences($@" «Red» -{init.Path}(2,3): error CS1002: { CSharpResources.ERR_SemicolonExpected } +{init.Path}(2,3): error CS1002: {CSharpResources.ERR_SemicolonExpected} «Gray» > new C() C {{ }} @@ -813,7 +813,7 @@ 1 1 ", runner.Console.Out.ToString()); AssertEx.AssertEqualToleratingWhitespaceDifferences( - $@"{init.Path}(2,3): error CS1002: { CSharpResources.ERR_SemicolonExpected }", + $@"{init.Path}(2,3): error CS1002: {CSharpResources.ERR_SemicolonExpected}", runner.Console.Error.ToString()); } @@ -828,7 +828,7 @@ public void HelpCommand() Assert.Equal( $@"{LogoAndHelpPrompt} > #help -{ ScriptingResources.HelpText } +{ScriptingResources.HelpText} > ", runner.Console.Out.ToString()); } @@ -919,7 +919,7 @@ public class Lib2 > #r ""{file2.Path}"" > var l2 = new Lib2(); «Red» -{ string.Format(ScriptingResources.AssemblyAlreadyLoaded, libBaseName, "0.0.0.0", fileBase1.Path, fileBase2.Path) } +{string.Format(ScriptingResources.AssemblyAlreadyLoaded, libBaseName, "0.0.0.0", fileBase1.Path, fileBase2.Path)} «Gray» > ", runner.Console.Out.ToString()); } @@ -940,7 +940,7 @@ public void PreservingDeclarationsOnException() > int i = 100; > int j = 20; throw new System.Exception(""Bang!""); int k = 3; «Yellow» -(1,58): warning CS0162: { CSharpResources.WRN_UnreachableCode } +(1,58): warning CS0162: {CSharpResources.WRN_UnreachableCode} «Red» System.Exception: Bang! «Gray» @@ -949,7 +949,7 @@ public void PreservingDeclarationsOnException() > ", runner.Console.Out.ToString()); AssertEx.AssertEqualToleratingWhitespaceDifferences( -$@"(1,58): warning CS0162: { CSharpResources.WRN_UnreachableCode } +$@"(1,58): warning CS0162: {CSharpResources.WRN_UnreachableCode} System.Exception: Bang!", runner.Console.Error.ToString()); } @@ -984,7 +984,7 @@ public void InferredTupleNames() runner.RunInteractive(); AssertEx.AssertEqualToleratingWhitespaceDifferences( -$@"{ string.Format(CSharpScriptingResources.LogoLine1, s_compilerVersion) } +$@"{string.Format(CSharpScriptingResources.LogoLine1, s_compilerVersion)} {CSharpScriptingResources.LogoLine2} {ScriptingResources.HelpPrompt} > var a = 1; diff --git a/src/Scripting/CSharpTest/InteractiveSessionTests.cs b/src/Scripting/CSharpTest/InteractiveSessionTests.cs index a547dcd50bdbc..d0aacdbb5a85a 100644 --- a/src/Scripting/CSharpTest/InteractiveSessionTests.cs +++ b/src/Scripting/CSharpTest/InteractiveSessionTests.cs @@ -1175,6 +1175,30 @@ public async Task CSharp9PatternForms() Assert.Equal(true, state.ReturnValue); } + [Fact, WorkItem(63144, "https://github.com/dotnet/roslyn/issues/63144")] + public void InteractiveSession_ImportScopes() + { + var script = CSharpScript.Create(@" +1 + 1", ScriptOptions.Default.WithImports("System")); + + var compilation = script.GetCompilation(); + var tree = compilation.SyntaxTrees.Single(); + var semanticModel = compilation.GetSemanticModel(tree); + var scopes = semanticModel.GetImportScopes(0); + Assert.Single(scopes); + + var scope = scopes.Single(); + Assert.Empty(scope.Aliases); + Assert.Empty(scope.ExternAliases); + Assert.Empty(scope.XmlNamespaces); + + Assert.Single(scope.Imports); + var import = scope.Imports.Single(); + + Assert.True(import.NamespaceOrType is INamespaceSymbol { Name: "System", ContainingNamespace.IsGlobalNamespace: true }); + Assert.Null(import.DeclaringSyntaxReference); + } + #endregion #region References diff --git a/src/Scripting/Core/Hosting/AssemblyLoader/MetadataShadowCopyProvider.cs b/src/Scripting/Core/Hosting/AssemblyLoader/MetadataShadowCopyProvider.cs index 0a1fd9c67f6a1..613ea5944040c 100644 --- a/src/Scripting/Core/Hosting/AssemblyLoader/MetadataShadowCopyProvider.cs +++ b/src/Scripting/Core/Hosting/AssemblyLoader/MetadataShadowCopyProvider.cs @@ -366,10 +366,7 @@ public void SuppressShadowCopy(string originalPath) lock (Guard) { - if (_lazySuppressedFiles == null) - { - _lazySuppressedFiles = new HashSet(StringComparer.OrdinalIgnoreCase); - } + _lazySuppressedFiles ??= new HashSet(StringComparer.OrdinalIgnoreCase); _lazySuppressedFiles.Add(originalPath); } @@ -404,10 +401,7 @@ private CacheEntry CreateMetadataShadowCopy(string originalP { try { - if (ShadowCopyDirectory == null) - { - ShadowCopyDirectory = CreateUniqueDirectory(_baseDirectory); - } + ShadowCopyDirectory ??= CreateUniqueDirectory(_baseDirectory); // Create directory for the assembly. // If the assembly has any modules they have to be copied to the same directory @@ -490,10 +484,7 @@ private AssemblyMetadata CreateAssemblyMetadata(FileStream manifestModuleCopyStr { if (fault) { - if (manifestModule != null) - { - manifestModule.Dispose(); - } + manifestModule?.Dispose(); if (moduleBuilder != null) { diff --git a/src/Scripting/Core/Hosting/ObjectFormatter/CommonObjectFormatter.Visitor.cs b/src/Scripting/Core/Hosting/ObjectFormatter/CommonObjectFormatter.Visitor.cs index 0e2d76d022210..9bd615a8d2ac6 100644 --- a/src/Scripting/Core/Hosting/ObjectFormatter/CommonObjectFormatter.Visitor.cs +++ b/src/Scripting/Core/Hosting/ObjectFormatter/CommonObjectFormatter.Visitor.cs @@ -36,10 +36,7 @@ private HashSet VisitedObjects { get { - if (_lazyVisitedObjects == null) - { - _lazyVisitedObjects = new HashSet(ReferenceEqualityComparer.Instance); - } + _lazyVisitedObjects ??= new HashSet(ReferenceEqualityComparer.Instance); return _lazyVisitedObjects; } @@ -604,10 +601,7 @@ private void FormatDictionaryMembers(Builder result, IDictionary dict, bool inli } finally { - if (disposable != null) - { - disposable.Dispose(); - } + disposable?.Dispose(); } } catch (Exception e) diff --git a/src/Scripting/Core/ScriptBuilder.cs b/src/Scripting/Core/ScriptBuilder.cs index 908836a5f2ba3..ee1d4ebe04a2b 100644 --- a/src/Scripting/Core/ScriptBuilder.cs +++ b/src/Scripting/Core/ScriptBuilder.cs @@ -90,10 +90,7 @@ internal Func> CreateExecutor(ScriptCompiler compiler, Comp // emit can fail due to compilation errors or because there is nothing to emit: ThrowIfAnyCompilationErrors(diagnostics, compiler.DiagnosticFormatter); - if (executor == null) - { - executor = (s) => Task.FromResult(default(T)); - } + executor ??= (s) => Task.FromResult(default(T)); return executor; } diff --git a/src/Setup/DevDivVsix/CompilersPackage/arm64/Microsoft.CodeAnalysis.Compilers.Setup.arm64.csproj b/src/Setup/DevDivVsix/CompilersPackage/arm64/Microsoft.CodeAnalysis.Compilers.Setup.arm64.csproj index fa7029460c8d1..59af4ded76160 100644 --- a/src/Setup/DevDivVsix/CompilersPackage/arm64/Microsoft.CodeAnalysis.Compilers.Setup.arm64.csproj +++ b/src/Setup/DevDivVsix/CompilersPackage/arm64/Microsoft.CodeAnalysis.Compilers.Setup.arm64.csproj @@ -17,5 +17,5 @@ - + diff --git a/src/Setup/DevDivVsix/CompilersPackage/x64/Microsoft.CodeAnalysis.Compilers.Setup.x64.csproj b/src/Setup/DevDivVsix/CompilersPackage/x64/Microsoft.CodeAnalysis.Compilers.Setup.x64.csproj index c9409375b55cc..24c3a2e916905 100644 --- a/src/Setup/DevDivVsix/CompilersPackage/x64/Microsoft.CodeAnalysis.Compilers.Setup.x64.csproj +++ b/src/Setup/DevDivVsix/CompilersPackage/x64/Microsoft.CodeAnalysis.Compilers.Setup.x64.csproj @@ -17,5 +17,5 @@ - + diff --git a/src/Setup/DevDivVsix/CompilersPackage/x86/Microsoft.CodeAnalysis.Compilers.Setup.x86.csproj b/src/Setup/DevDivVsix/CompilersPackage/x86/Microsoft.CodeAnalysis.Compilers.Setup.x86.csproj index 9b270030d9788..99d0c70b305c5 100644 --- a/src/Setup/DevDivVsix/CompilersPackage/x86/Microsoft.CodeAnalysis.Compilers.Setup.x86.csproj +++ b/src/Setup/DevDivVsix/CompilersPackage/x86/Microsoft.CodeAnalysis.Compilers.Setup.x86.csproj @@ -17,5 +17,5 @@ - + diff --git a/src/Test/PdbUtilities/Reader/PdbValidation.cs b/src/Test/PdbUtilities/Reader/PdbValidation.cs index 4d86ef5f9ec7c..e23bf22e4d807 100644 --- a/src/Test/PdbUtilities/Reader/PdbValidation.cs +++ b/src/Test/PdbUtilities/Reader/PdbValidation.cs @@ -159,7 +159,7 @@ public static void VerifyPdb( [CallerLineNumber] int expectedValueSourceLine = 0, [CallerFilePath] string expectedValueSourcePath = null) { - VerifyPdb(compilation, "", expectedPdb, embeddedTexts, debugEntryPoint, format, options, expectedValueSourceLine, expectedValueSourcePath); + VerifyPdb(compilation, qualifiedMethodName: null, expectedPdb, embeddedTexts, debugEntryPoint, format, options, expectedValueSourceLine, expectedValueSourcePath); } public static void VerifyPdb( @@ -267,6 +267,29 @@ void Verify(bool isPortable, bool testOtherFormat) } } + public static void VerifyPdb( + Stream peStream, + Stream pdbStream, + string expectedPdb, + PdbValidationOptions options = PdbValidationOptions.Default, + [CallerLineNumber] int expectedValueSourceLine = 0, + [CallerFilePath] string expectedValueSourcePath = null) + { + pdbStream.Position = 0; + var isPortable = pdbStream.ReadByte() == 'B' && pdbStream.ReadByte() == 'S' && pdbStream.ReadByte() == 'J' && pdbStream.ReadByte() == 'B'; + + VerifyPdbMatchesExpectedXml( + peStream, + pdbStream, + qualifiedMethodName: null, + options.ToPdbToXmlOptions(), + expectedPdb.ToString(), + expectedValueSourceLine, + expectedValueSourcePath, + expectedIsXmlLiteral: false, + isPortable); + } + private static void VerifyPdbMatchesExpectedXml( Stream peStream, Stream pdbStream, diff --git a/src/Test/PdbUtilities/Roslyn.Test.PdbUtilities.csproj b/src/Test/PdbUtilities/Roslyn.Test.PdbUtilities.csproj index 664ba3d770d70..2533d26f9d625 100644 --- a/src/Test/PdbUtilities/Roslyn.Test.PdbUtilities.csproj +++ b/src/Test/PdbUtilities/Roslyn.Test.PdbUtilities.csproj @@ -12,6 +12,7 @@ + diff --git a/src/Test/Perf/Utilities/TestUtilities.cs b/src/Test/Perf/Utilities/TestUtilities.cs index 57b9ab96d5527..b94140906c468 100644 --- a/src/Test/Perf/Utilities/TestUtilities.cs +++ b/src/Test/Perf/Utilities/TestUtilities.cs @@ -121,10 +121,7 @@ public static ProcessResult ShellOut( string workingDirectory = null, CancellationToken cancellationToken = default(CancellationToken)) { - if (workingDirectory == null) - { - workingDirectory = AppDomain.CurrentDomain.BaseDirectory; - } + workingDirectory ??= AppDomain.CurrentDomain.BaseDirectory; var tcs = new TaskCompletionSource(); var startInfo = new ProcessStartInfo(file, args); diff --git a/src/Tools/AnalyzerRunner/DiagnosticAnalyzerRunner.cs b/src/Tools/AnalyzerRunner/DiagnosticAnalyzerRunner.cs index 0cf95652037f4..4125357e2f28a 100644 --- a/src/Tools/AnalyzerRunner/DiagnosticAnalyzerRunner.cs +++ b/src/Tools/AnalyzerRunner/DiagnosticAnalyzerRunner.cs @@ -182,7 +182,7 @@ private static async Task TestDocumentPerformanceAs } var compilation = await project.GetCompilationAsync(cancellationToken).ConfigureAwait(false); - var ideAnalyzerOptions = IdeAnalyzerOptions.GetDefault(project.LanguageServices); + var ideAnalyzerOptions = IdeAnalyzerOptions.GetDefault(project.Services); var stopwatch = PerformanceTracker.StartNew(); for (int i = 0; i < analyzerOptionsInternal.TestDocumentIterations; i++) @@ -393,7 +393,7 @@ private static async Task GetProjectAnalysisResultAsync( { var compilation = await project.GetCompilationAsync(cancellationToken).ConfigureAwait(false); var newCompilation = compilation.RemoveAllSyntaxTrees().AddSyntaxTrees(compilation.SyntaxTrees); - var ideAnalyzerOptions = IdeAnalyzerOptions.GetDefault(project.LanguageServices); + var ideAnalyzerOptions = IdeAnalyzerOptions.GetDefault(project.Services); var workspaceAnalyzerOptions = new WorkspaceAnalyzerOptions(project.AnalyzerOptions, project.Solution, ideAnalyzerOptions); var compilationWithAnalyzers = newCompilation.WithAnalyzers(analyzers, new CompilationWithAnalyzersOptions(workspaceAnalyzerOptions, null, analyzerOptionsInternal.RunConcurrent, logAnalyzerExecutionTime: true, reportSuppressedDiagnostics: analyzerOptionsInternal.ReportSuppressedDiagnostics)); diff --git a/src/Tools/AnalyzerRunner/IncrementalAnalyzerRunner.cs b/src/Tools/AnalyzerRunner/IncrementalAnalyzerRunner.cs index 150ed75d47fec..c8c50b5bc0c90 100644 --- a/src/Tools/AnalyzerRunner/IncrementalAnalyzerRunner.cs +++ b/src/Tools/AnalyzerRunner/IncrementalAnalyzerRunner.cs @@ -12,8 +12,6 @@ using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.FindSymbols.SymbolTree; using Microsoft.CodeAnalysis.Host; -using Microsoft.CodeAnalysis.Host.Mef; -using Microsoft.CodeAnalysis.IncrementalCaches; using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.SolutionCrawler; using Microsoft.CodeAnalysis.Storage; @@ -42,7 +40,7 @@ public async Task RunAsync(CancellationToken cancellationToken) var usePersistentStorage = _options.UsePersistentStorage; - var exportProvider = (IMefHostExportProvider)_workspace.Services.HostServices; + var exportProvider = _workspace.Services.SolutionServices.ExportProvider; var globalOptions = exportProvider.GetExports().Single().Value; globalOptions.SetGlobalOption(new OptionKey(SolutionCrawlerOptionsStorage.BackgroundAnalysisScopeOption, LanguageNames.CSharp), _options.AnalysisScope); @@ -56,7 +54,7 @@ public async Task RunAsync(CancellationToken cancellationToken) if (usePersistentStorage) { - var persistentStorageService = _workspace.Services.GetPersistentStorageService(); + var persistentStorageService = _workspace.Services.SolutionServices.GetPersistentStorageService(); await using var persistentStorage = await persistentStorageService.GetStorageAsync(SolutionKey.ToSolutionKey(_workspace.CurrentSolution), cancellationToken).ConfigureAwait(false); if (persistentStorage is NoOpPersistentStorage) { @@ -77,8 +75,8 @@ public async Task RunAsync(CancellationToken cancellationToken) switch (incrementalAnalyzerName) { case nameof(SymbolTreeInfoIncrementalAnalyzerProvider): - var symbolTreeInfoCacheService = _workspace.Services.GetRequiredService(); - var symbolTreeInfo = await symbolTreeInfoCacheService.TryGetSourceSymbolTreeInfoAsync(_workspace.CurrentSolution.Projects.First(), cancellationToken).ConfigureAwait(false); + var symbolTreeInfoCacheService = _workspace.Services.GetRequiredService(); + var symbolTreeInfo = await symbolTreeInfoCacheService.TryGetPotentiallyStaleSourceSymbolTreeInfoAsync(_workspace.CurrentSolution.Projects.First(), cancellationToken).ConfigureAwait(false); if (symbolTreeInfo is null) { throw new InvalidOperationException("Benchmark failed to calculate symbol tree info."); diff --git a/src/Tools/BuildActionTelemetryTable/Program.cs b/src/Tools/BuildActionTelemetryTable/Program.cs index 6379da889d3df..a215499e3f8c8 100644 --- a/src/Tools/BuildActionTelemetryTable/Program.cs +++ b/src/Tools/BuildActionTelemetryTable/Program.cs @@ -30,7 +30,6 @@ public class Program "Microsoft.CodeAnalysis.CodeActions.CodeAction+SolutionChangeAction", "Microsoft.CodeAnalysis.CodeActions.CustomCodeActions+DocumentChangeAction", "Microsoft.CodeAnalysis.CodeActions.CustomCodeActions+SolutionChangeAction", - "Microsoft.CodeAnalysis.CodeStyle.AbstractCodeStyleProvider`2+CodeRefactoringProvider", "Microsoft.CodeAnalysis.CodeFixes.DocumentBasedFixAllProvider+PostProcessCodeAction", }.ToImmutableHashSet(); diff --git a/src/Tools/BuildBoss/StructuredLoggerCheckerUtil.cs b/src/Tools/BuildBoss/StructuredLoggerCheckerUtil.cs index 7ceecc61c4baa..75cd4941b9343 100644 --- a/src/Tools/BuildBoss/StructuredLoggerCheckerUtil.cs +++ b/src/Tools/BuildBoss/StructuredLoggerCheckerUtil.cs @@ -32,7 +32,9 @@ public bool Check(TextWriter textWriter) { var build = Serialization.Read(_logFilePath); var doubleWrites = DoubleWritesAnalyzer.GetDoubleWrites(build).ToArray(); - if (doubleWrites.Any()) + + // Issue https://github.com/dotnet/roslyn/issues/62372 + if (doubleWrites.Any(doubleWrite => Path.GetFileName(doubleWrite.Key) != "Microsoft.VisualStudio.Text.Internal.dll")) { foreach (var doubleWrite in doubleWrites) { diff --git a/src/Tools/BuildValidator/LocalReferenceResolver.cs b/src/Tools/BuildValidator/LocalReferenceResolver.cs index 3c93b7cb02796..4958110830330 100644 --- a/src/Tools/BuildValidator/LocalReferenceResolver.cs +++ b/src/Tools/BuildValidator/LocalReferenceResolver.cs @@ -61,10 +61,7 @@ public LocalReferenceResolver(Options options, ILoggerFactory loggerFactory) public static DirectoryInfo GetNugetCacheDirectory() { var nugetPackageDirectory = Environment.GetEnvironmentVariable("NUGET_PACKAGES"); - if (nugetPackageDirectory is null) - { - nugetPackageDirectory = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), ".nuget"); - } + nugetPackageDirectory ??= Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), ".nuget"); return new DirectoryInfo(nugetPackageDirectory); } diff --git a/src/Tools/ExternalAccess/AspNetCore/EmbeddedLanguages/AspNetCoreCSharpRouteSyntaxDetector.cs b/src/Tools/ExternalAccess/AspNetCore/EmbeddedLanguages/AspNetCoreCSharpRouteSyntaxDetector.cs new file mode 100644 index 0000000000000..748f6c59f7442 --- /dev/null +++ b/src/Tools/ExternalAccess/AspNetCore/EmbeddedLanguages/AspNetCoreCSharpRouteSyntaxDetector.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.Collections.Immutable; +using System.Diagnostics.CodeAnalysis; +using System.Text; +using System.Threading; +using Microsoft.CodeAnalysis.CSharp.EmbeddedLanguages.LanguageServices; +using Microsoft.CodeAnalysis.EmbeddedLanguages; + +namespace Microsoft.CodeAnalysis.ExternalAccess.AspNetCore.EmbeddedLanguages +{ + internal sealed class AspNetCoreCSharpRouteSyntaxDetector + { + public static readonly AspNetCoreCSharpRouteSyntaxDetector Instance = new(); + + private readonly EmbeddedLanguageDetector _detector = new( + CSharpEmbeddedLanguagesProvider.Info, + ImmutableArray.Create("Route")); + + private AspNetCoreCSharpRouteSyntaxDetector() + { + } + + public bool IsEmbeddedLanguageToken( + SyntaxToken token, + SemanticModel semanticModel, + CancellationToken cancellationToken, + [NotNullWhen(true)] out string? identifier, + out IEnumerable? options) + { + return _detector.IsEmbeddedLanguageToken(token, semanticModel, cancellationToken, out identifier, out options); + } + } +} diff --git a/src/Tools/ExternalAccess/AspNetCore/EmbeddedLanguages/AspNetCoreVirtualChar.cs b/src/Tools/ExternalAccess/AspNetCore/EmbeddedLanguages/AspNetCoreVirtualChar.cs index 713f86869d74f..d526b8c731c76 100644 --- a/src/Tools/ExternalAccess/AspNetCore/EmbeddedLanguages/AspNetCoreVirtualChar.cs +++ b/src/Tools/ExternalAccess/AspNetCore/EmbeddedLanguages/AspNetCoreVirtualChar.cs @@ -11,11 +11,11 @@ namespace Microsoft.CodeAnalysis.ExternalAccess.AspNetCore.EmbeddedLanguages { internal readonly struct AspNetCoreVirtualChar : IEquatable { - private readonly VirtualChar _virtualChar; + internal readonly VirtualChar VirtualChar; internal AspNetCoreVirtualChar(VirtualChar virtualChar) { - _virtualChar = virtualChar; + VirtualChar = virtualChar; } /// @@ -25,28 +25,28 @@ public int RuneValue { // Rune is an internal shim with netstandard2.0 and accessing it throws an internal access exception. // Expose integer value. Can be converted back to Rune by caller. - get => _virtualChar.Rune.Value; + get => VirtualChar.Rune.Value; } /// - public char SurrogateChar => _virtualChar.SurrogateChar; + public char SurrogateChar => VirtualChar.SurrogateChar; /// - public TextSpan Span => _virtualChar.Span; + public TextSpan Span => VirtualChar.Span; /// - public int Value => _virtualChar.Value; + public int Value => VirtualChar.Value; /// - public override string ToString() => _virtualChar.ToString(); + public override string ToString() => VirtualChar.ToString(); /// public override bool Equals(object? obj) => obj is AspNetCoreVirtualChar vc && Equals(vc); /// - public bool Equals(AspNetCoreVirtualChar other) => _virtualChar.Equals(other._virtualChar); + public bool Equals(AspNetCoreVirtualChar other) => VirtualChar.Equals(other.VirtualChar); /// - public override int GetHashCode() => _virtualChar.GetHashCode(); + public override int GetHashCode() => VirtualChar.GetHashCode(); } } diff --git a/src/Tools/ExternalAccess/AspNetCore/EmbeddedLanguages/AspNetCoreVirtualCharSequence.cs b/src/Tools/ExternalAccess/AspNetCore/EmbeddedLanguages/AspNetCoreVirtualCharSequence.cs index a9a48e14ef3d7..abad1b710a699 100644 --- a/src/Tools/ExternalAccess/AspNetCore/EmbeddedLanguages/AspNetCoreVirtualCharSequence.cs +++ b/src/Tools/ExternalAccess/AspNetCore/EmbeddedLanguages/AspNetCoreVirtualCharSequence.cs @@ -3,7 +3,10 @@ // 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 @@ -21,6 +24,9 @@ internal AspNetCoreVirtualCharSequence(VirtualCharSequence virtualCharSequence) /// public static readonly AspNetCoreVirtualCharSequence Empty = new(VirtualCharSequence.Empty); + /// + public bool IsDefault => _virtualCharSequence.IsDefault; + /// public int Length => _virtualCharSequence.Length; @@ -40,5 +46,43 @@ internal AspNetCoreVirtualCharSequence(VirtualCharSequence virtualCharSequence) public static AspNetCoreVirtualCharSequence FromBounds( AspNetCoreVirtualCharSequence chars1, AspNetCoreVirtualCharSequence chars2) => new(VirtualCharSequence.FromBounds(chars1._virtualCharSequence, chars2._virtualCharSequence)); + + /// + public int IndexOf(AspNetCoreVirtualChar @char) + => _virtualCharSequence.IndexOf(@char.VirtualChar); + + /// + public bool Contains(AspNetCoreVirtualChar @char) + => _virtualCharSequence.Contains(@char.VirtualChar); + + /// + public Enumerator GetEnumerator() + => new Enumerator(_virtualCharSequence.GetEnumerator()); + + /// + public struct Enumerator : IEnumerator + { + private VirtualCharSequence.Enumerator _enumerator; + + public Enumerator(VirtualCharSequence.Enumerator enumerator) + { + _enumerator = enumerator; + } + + public bool MoveNext() + => _enumerator.MoveNext(); + + public AspNetCoreVirtualChar Current + => new(_enumerator.Current); + + public void Reset() + => _enumerator.Reset(); + + object IEnumerator.Current + => this.Current; + + public void Dispose() + => _enumerator.Dispose(); + } } } diff --git a/src/Tools/ExternalAccess/AspNetCore/EmbeddedLanguages/BraceMatching/AspNetCoreBraceMatchingResult.cs b/src/Tools/ExternalAccess/AspNetCore/EmbeddedLanguages/BraceMatching/AspNetCoreBraceMatchingResult.cs index 05ff4ee8310a4..eb9e9bf4cc3ae 100644 --- a/src/Tools/ExternalAccess/AspNetCore/EmbeddedLanguages/BraceMatching/AspNetCoreBraceMatchingResult.cs +++ b/src/Tools/ExternalAccess/AspNetCore/EmbeddedLanguages/BraceMatching/AspNetCoreBraceMatchingResult.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +using Microsoft.CodeAnalysis.BraceMatching; using Microsoft.CodeAnalysis.Editor; using Microsoft.CodeAnalysis.Text; diff --git a/src/Tools/ExternalAccess/AspNetCore/EmbeddedLanguages/BraceMatching/IAspNetCoreEmbeddedLanguageBraceMatcher.cs b/src/Tools/ExternalAccess/AspNetCore/EmbeddedLanguages/BraceMatching/IAspNetCoreEmbeddedLanguageBraceMatcher.cs index aaec3f234017d..e5a1b76c93a19 100644 --- a/src/Tools/ExternalAccess/AspNetCore/EmbeddedLanguages/BraceMatching/IAspNetCoreEmbeddedLanguageBraceMatcher.cs +++ b/src/Tools/ExternalAccess/AspNetCore/EmbeddedLanguages/BraceMatching/IAspNetCoreEmbeddedLanguageBraceMatcher.cs @@ -4,6 +4,7 @@ using System.Threading; using Microsoft.CodeAnalysis.Editor; +using Microsoft.CodeAnalysis.BraceMatching; namespace Microsoft.CodeAnalysis.ExternalAccess.AspNetCore.EmbeddedLanguages { diff --git a/src/Tools/ExternalAccess/AspNetCore/Microsoft.CodeAnalysis.ExternalAccess.AspNetCore.csproj b/src/Tools/ExternalAccess/AspNetCore/Microsoft.CodeAnalysis.ExternalAccess.AspNetCore.csproj index 85e178f7798e6..1e229cccf03e6 100644 --- a/src/Tools/ExternalAccess/AspNetCore/Microsoft.CodeAnalysis.ExternalAccess.AspNetCore.csproj +++ b/src/Tools/ExternalAccess/AspNetCore/Microsoft.CodeAnalysis.ExternalAccess.AspNetCore.csproj @@ -12,6 +12,8 @@ A supporting package for ASP.NET Core: https://github.com/dotnet/aspnetcore + + false @@ -32,10 +34,8 @@ - - diff --git a/src/Tools/ExternalAccess/Debugger/GlassTestsHotReloadService.cs b/src/Tools/ExternalAccess/Debugger/GlassTestsHotReloadService.cs index bb6501186170f..224a63e83bbda 100644 --- a/src/Tools/ExternalAccess/Debugger/GlassTestsHotReloadService.cs +++ b/src/Tools/ExternalAccess/Debugger/GlassTestsHotReloadService.cs @@ -7,7 +7,6 @@ using System.Threading.Tasks; using Microsoft.CodeAnalysis.EditAndContinue; using Microsoft.CodeAnalysis.Host; -using Microsoft.VisualStudio.Debugger.Contracts.EditAndContinue; using Microsoft.VisualStudio.Debugger.Contracts.HotReload; using Roslyn.Utilities; @@ -82,23 +81,12 @@ public void EndDebuggingSession() _sessionId = default; } - public async ValueTask GetEditAndContinueUpdatesAsync(Solution solution, CancellationToken cancellationToken) - { - var result = await _encService.EmitSolutionUpdateAsync(GetSessionId(), solution, s_noActiveStatementSpanProvider, cancellationToken).ConfigureAwait(false); - - return result.ModuleUpdates.FromContract(); - } - public async ValueTask GetHotReloadUpdatesAsync(Solution solution, CancellationToken cancellationToken) + public async ValueTask GetUpdatesAsync(Solution solution, CancellationToken cancellationToken) { var result = await _encService.EmitSolutionUpdateAsync(GetSessionId(), solution, s_noActiveStatementSpanProvider, cancellationToken).ConfigureAwait(false); - - var updates = result.ModuleUpdates.Updates.SelectAsArray( - update => new ManagedHotReloadUpdate(update.Module, update.ILDelta, update.MetadataDelta, update.PdbDelta, update.UpdatedTypes)); - - var diagnostics = await EmitSolutionUpdateResults.GetHotReloadDiagnosticsAsync(solution, result.GetDiagnosticData(solution), result.RudeEdits, result.GetSyntaxErrorData(solution), cancellationToken).ConfigureAwait(false); - - return new ManagedHotReloadUpdates(updates, diagnostics.FromContract()); + var diagnostics = await EmitSolutionUpdateResults.GetHotReloadDiagnosticsAsync(solution, result.GetDiagnosticData(solution), result.RudeEdits, result.GetSyntaxErrorData(solution), result.ModuleUpdates.Status, cancellationToken).ConfigureAwait(false); + return new ManagedHotReloadUpdates(result.ModuleUpdates.Updates.FromContract(), diagnostics.FromContract()); } } } diff --git a/src/Tools/ExternalAccess/FSharp/Completion/FSharpCompletionProviderBase.cs b/src/Tools/ExternalAccess/FSharp/Completion/FSharpCompletionProviderBase.cs index 1220da8e2a3a1..ea1f447b7bf56 100644 --- a/src/Tools/ExternalAccess/FSharp/Completion/FSharpCompletionProviderBase.cs +++ b/src/Tools/ExternalAccess/FSharp/Completion/FSharpCompletionProviderBase.cs @@ -14,7 +14,7 @@ internal abstract class FSharpCompletionProviderBase : CompletionProvider public sealed override bool ShouldTriggerCompletion(SourceText text, int caretPosition, CompletionTrigger trigger, OptionSet options) => ShouldTriggerCompletionImpl(text, caretPosition, trigger); - internal sealed override bool ShouldTriggerCompletion(HostLanguageServices languageServices, SourceText text, int caretPosition, CompletionTrigger trigger, CompletionOptions options, OptionSet passthroughOptions) + internal sealed override bool ShouldTriggerCompletion(Host.LanguageServices languageServices, SourceText text, int caretPosition, CompletionTrigger trigger, CompletionOptions options, OptionSet passthroughOptions) => ShouldTriggerCompletionImpl(text, caretPosition, trigger); protected abstract bool ShouldTriggerCompletionImpl(SourceText text, int caretPosition, CompletionTrigger trigger); diff --git a/src/Tools/ExternalAccess/FSharp/Completion/FSharpCompletionServiceWithProviders.cs b/src/Tools/ExternalAccess/FSharp/Completion/FSharpCompletionServiceWithProviders.cs index ce1c509a1e086..bcf02edc465b3 100644 --- a/src/Tools/ExternalAccess/FSharp/Completion/FSharpCompletionServiceWithProviders.cs +++ b/src/Tools/ExternalAccess/FSharp/Completion/FSharpCompletionServiceWithProviders.cs @@ -9,7 +9,7 @@ namespace Microsoft.CodeAnalysis.ExternalAccess.FSharp.Completion internal abstract class FSharpCompletionServiceWithProviders : CompletionService { internal FSharpCompletionServiceWithProviders(Workspace workspace) - : base(workspace) + : base(workspace.Services.SolutionServices) { } diff --git a/src/Tools/ExternalAccess/FSharp/Editor/InlineRename/FSharpInlineRenameInfo.cs b/src/Tools/ExternalAccess/FSharp/Editor/InlineRename/FSharpInlineRenameInfo.cs index 64e1ca6da91d2..3127f9f685dfb 100644 --- a/src/Tools/ExternalAccess/FSharp/Editor/InlineRename/FSharpInlineRenameInfo.cs +++ b/src/Tools/ExternalAccess/FSharp/Editor/InlineRename/FSharpInlineRenameInfo.cs @@ -59,5 +59,8 @@ bool IInlineRenameInfo.TryOnAfterGlobalSymbolRenamed(Workspace workspace, IEnume bool IInlineRenameInfo.TryOnBeforeGlobalSymbolRenamed(Workspace workspace, IEnumerable changedDocumentIDs, string replacementText) => true; + + public InlineRenameFileRenameInfo GetFileRenameInfo() + => InlineRenameFileRenameInfo.NotAllowed; } } diff --git a/src/Tools/ExternalAccess/FSharp/Internal/Classification/FSharpClassificationService.cs b/src/Tools/ExternalAccess/FSharp/Internal/Classification/FSharpClassificationService.cs index 63fcfaad8e4e0..db19368560a9f 100644 --- a/src/Tools/ExternalAccess/FSharp/Internal/Classification/FSharpClassificationService.cs +++ b/src/Tools/ExternalAccess/FSharp/Internal/Classification/FSharpClassificationService.cs @@ -9,6 +9,7 @@ using System.Threading.Tasks; using Microsoft.CodeAnalysis.Classification; using Microsoft.CodeAnalysis.ExternalAccess.FSharp.Classification; +using Microsoft.CodeAnalysis.Host; using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Text; @@ -55,12 +56,12 @@ public ClassifiedSpan AdjustStaleClassification(SourceText text, ClassifiedSpan return _service.AdjustStaleClassification(text, classifiedSpan); } - public void AddSyntacticClassifications(Workspace workspace, SyntaxNode root, TextSpan textSpan, ArrayBuilder result, CancellationToken cancellationToken) + public void AddSyntacticClassifications(SolutionServices services, SyntaxNode root, TextSpan textSpan, ArrayBuilder result, CancellationToken cancellationToken) { // F# does not support syntax. } - public TextChangeRange? ComputeSyntacticChangeRange(Workspace workspace, SyntaxNode oldRoot, SyntaxNode newRoot, TimeSpan timeout, CancellationToken cancellationToken) + public TextChangeRange? ComputeSyntacticChangeRange(SolutionServices services, SyntaxNode oldRoot, SyntaxNode newRoot, TimeSpan timeout, CancellationToken cancellationToken) { // F# does not support syntax. return null; diff --git a/src/Tools/ExternalAccess/FSharp/Internal/CommentSelection/FSharpCommentSelectionService.cs b/src/Tools/ExternalAccess/FSharp/Internal/CommentSelection/FSharpCommentSelectionService.cs index 41ef91a2f850f..a22ab48dce0d8 100644 --- a/src/Tools/ExternalAccess/FSharp/Internal/CommentSelection/FSharpCommentSelectionService.cs +++ b/src/Tools/ExternalAccess/FSharp/Internal/CommentSelection/FSharpCommentSelectionService.cs @@ -26,19 +26,12 @@ public FSharpCommentSelectionService() { } - public Task FormatAsync(Document document, ImmutableArray changes, SyntaxFormattingOptions formattingOptions, CancellationToken cancellationToken) - { - return Task.FromResult(document); - } - - public Task GetInfoAsync(Document document, TextSpan textSpan, CancellationToken cancellationToken) - { - return Task.FromResult(new CommentSelectionInfo( + public CommentSelectionInfo GetInfo() + => new( supportsSingleLineComment: true, supportsBlockComment: true, singleLineCommentString: "//", blockCommentStartString: "(*", - blockCommentEndString: "*)")); - } + blockCommentEndString: "*)"); } } diff --git a/src/Tools/ExternalAccess/FSharp/Internal/Diagnostics/FSharpDocumentDiagnosticAnalyzer.cs b/src/Tools/ExternalAccess/FSharp/Internal/Diagnostics/FSharpDocumentDiagnosticAnalyzer.cs index b98ee9cbf31cd..54a698d91c142 100644 --- a/src/Tools/ExternalAccess/FSharp/Internal/Diagnostics/FSharpDocumentDiagnosticAnalyzer.cs +++ b/src/Tools/ExternalAccess/FSharp/Internal/Diagnostics/FSharpDocumentDiagnosticAnalyzer.cs @@ -72,7 +72,7 @@ public static ImmutableArray CreateSupportedDiagnostics() public override Task> AnalyzeSemanticsAsync(Document document, CancellationToken cancellationToken) { - var analyzer = document.Project.LanguageServices.GetService(); + var analyzer = document.Project.Services.GetService(); if (analyzer == null) { return Task.FromResult(ImmutableArray.Empty); @@ -83,7 +83,7 @@ public override Task> AnalyzeSemanticsAsync(Document public override Task> AnalyzeSyntaxAsync(Document document, CancellationToken cancellationToken) { - var analyzer = document.Project.LanguageServices.GetService(); + var analyzer = document.Project.Services.GetService(); if (analyzer == null) { return Task.FromResult(ImmutableArray.Empty); diff --git a/src/Tools/ExternalAccess/FSharp/Internal/Diagnostics/FSharpSimplifyNameDiagnosticAnalyzer.cs b/src/Tools/ExternalAccess/FSharp/Internal/Diagnostics/FSharpSimplifyNameDiagnosticAnalyzer.cs index 942da23de0a7e..8dcc162607ea6 100644 --- a/src/Tools/ExternalAccess/FSharp/Internal/Diagnostics/FSharpSimplifyNameDiagnosticAnalyzer.cs +++ b/src/Tools/ExternalAccess/FSharp/Internal/Diagnostics/FSharpSimplifyNameDiagnosticAnalyzer.cs @@ -56,7 +56,7 @@ internal class FSharpSimplifyNameDiagnosticAnalyzer : DocumentDiagnosticAnalyzer public override Task> AnalyzeSemanticsAsync(Document document, CancellationToken cancellationToken) { - var analyzer = document.Project.LanguageServices.GetService(); + var analyzer = document.Project.Services.GetService(); if (analyzer == null) { return Task.FromResult(ImmutableArray.Empty); diff --git a/src/Tools/ExternalAccess/FSharp/Internal/Diagnostics/FSharpUnusedDeclarationsAnalyzer.cs b/src/Tools/ExternalAccess/FSharp/Internal/Diagnostics/FSharpUnusedDeclarationsAnalyzer.cs index f782bc09e31ca..062e00ea993a9 100644 --- a/src/Tools/ExternalAccess/FSharp/Internal/Diagnostics/FSharpUnusedDeclarationsAnalyzer.cs +++ b/src/Tools/ExternalAccess/FSharp/Internal/Diagnostics/FSharpUnusedDeclarationsAnalyzer.cs @@ -58,7 +58,7 @@ internal class FSharpUnusedDeclarationsDiagnosticAnalyzer : DocumentDiagnosticAn public override Task> AnalyzeSemanticsAsync(Document document, CancellationToken cancellationToken) { - var analyzer = document.Project.LanguageServices.GetService(); + var analyzer = document.Project.Services.GetService(); if (analyzer == null) { return Task.FromResult(ImmutableArray.Empty); diff --git a/src/Tools/ExternalAccess/FSharp/Internal/Diagnostics/FSharpUnusedOpensDiagnosticAnalyzer.cs b/src/Tools/ExternalAccess/FSharp/Internal/Diagnostics/FSharpUnusedOpensDiagnosticAnalyzer.cs index 39c8f27def26e..fafffa5865059 100644 --- a/src/Tools/ExternalAccess/FSharp/Internal/Diagnostics/FSharpUnusedOpensDiagnosticAnalyzer.cs +++ b/src/Tools/ExternalAccess/FSharp/Internal/Diagnostics/FSharpUnusedOpensDiagnosticAnalyzer.cs @@ -51,7 +51,7 @@ internal class FSharpUnusedOpensDeclarationsDiagnosticAnalyzer : DocumentDiagnos public override Task> AnalyzeSemanticsAsync(Document document, CancellationToken cancellationToken) { - var analyzer = document.Project.LanguageServices.GetService(); + var analyzer = document.Project.Services.GetService(); if (analyzer == null) { return Task.FromResult(ImmutableArray.Empty); diff --git a/src/Tools/ExternalAccess/FSharp/Internal/Editor/FSharpBraceMatcher.cs b/src/Tools/ExternalAccess/FSharp/Internal/Editor/FSharpBraceMatcher.cs index 59badf84a22b4..105dede75bc62 100644 --- a/src/Tools/ExternalAccess/FSharp/Internal/Editor/FSharpBraceMatcher.cs +++ b/src/Tools/ExternalAccess/FSharp/Internal/Editor/FSharpBraceMatcher.cs @@ -5,16 +5,16 @@ #nullable disable using System; -using System.ComponentModel.Composition; +using System.Composition; using System.Threading; using System.Threading.Tasks; -using Microsoft.CodeAnalysis.Editor; +using Microsoft.CodeAnalysis.BraceMatching; using Microsoft.CodeAnalysis.ExternalAccess.FSharp.Editor; using Microsoft.CodeAnalysis.Host.Mef; namespace Microsoft.CodeAnalysis.ExternalAccess.FSharp.Internal.Editor { - [ExportBraceMatcher(LanguageNames.FSharp)] + [ExportBraceMatcher(LanguageNames.FSharp), Shared] internal class FSharpBraceMatcher : IBraceMatcher { private readonly IFSharpBraceMatcher _braceMatcher; diff --git a/src/Tools/ExternalAccess/FSharp/Internal/Editor/FSharpEditorInlineRenameService.cs b/src/Tools/ExternalAccess/FSharp/Internal/Editor/FSharpEditorInlineRenameService.cs index 43c3325d4fc9d..d2ed503b29202 100644 --- a/src/Tools/ExternalAccess/FSharp/Internal/Editor/FSharpEditorInlineRenameService.cs +++ b/src/Tools/ExternalAccess/FSharp/Internal/Editor/FSharpEditorInlineRenameService.cs @@ -177,6 +177,9 @@ public bool TryOnBeforeGlobalSymbolRenamed(Workspace workspace, IEnumerable InlineRenameFileRenameInfo.NotAllowed; } #nullable enable diff --git a/src/Tools/ExternalAccess/FSharp/Internal/Editor/FSharpNavigationBarItemService.cs b/src/Tools/ExternalAccess/FSharp/Internal/Editor/FSharpNavigationBarItemService.cs index 2896c7fac5789..e83cf9830f36d 100644 --- a/src/Tools/ExternalAccess/FSharp/Internal/Editor/FSharpNavigationBarItemService.cs +++ b/src/Tools/ExternalAccess/FSharp/Internal/Editor/FSharpNavigationBarItemService.cs @@ -40,11 +40,16 @@ public FSharpNavigationBarItemService( public Task> GetItemsAsync(Document document, ITextVersion textVersion, CancellationToken cancellationToken) { - return ((INavigationBarItemService)this).GetItemsAsync(document, forceFrozenPartialSemanticsForCrossProcessOperations: false, textVersion, cancellationToken); + return ((INavigationBarItemService)this).GetItemsAsync( + document, workspaceSupportsDocumentChanges: true, forceFrozenPartialSemanticsForCrossProcessOperations: false, textVersion, cancellationToken); } async Task> INavigationBarItemService.GetItemsAsync( - Document document, bool forceFrozenPartialSemanticsForCrossProcessOperations, ITextVersion textVersion, CancellationToken cancellationToken) + Document document, + bool workspaceSupportsDocumentChanges, + bool forceFrozenPartialSemanticsForCrossProcessOperations, + ITextVersion textVersion, + CancellationToken cancellationToken) { var items = await _service.GetItemsAsync(document, cancellationToken).ConfigureAwait(false); return items == null diff --git a/src/Tools/ExternalAccess/FSharp/Internal/Editor/FSharpSmartIndentProvider.cs b/src/Tools/ExternalAccess/FSharp/Internal/Editor/FSharpSmartIndentProvider.cs index 28eb38a433ca1..79ae7cda8ce05 100644 --- a/src/Tools/ExternalAccess/FSharp/Internal/Editor/FSharpSmartIndentProvider.cs +++ b/src/Tools/ExternalAccess/FSharp/Internal/Editor/FSharpSmartIndentProvider.cs @@ -90,7 +90,9 @@ public void Dispose() TabSize: _textView.Options.GetOptionValue(DefaultOptions.TabSizeOptionId), IndentStyle: (FormattingOptions.IndentStyle)indentStyle); +#pragma warning disable 0618 // Compat with existing EA api result = _provider._service.GetDesiredIndentation(document.Project.LanguageServices, text, document.Id, document.FilePath, line.LineNumber, fsharpOptions); +#pragma warning restore } else { diff --git a/src/Tools/ExternalAccess/FSharp/Microsoft.CodeAnalysis.ExternalAccess.FSharp.csproj b/src/Tools/ExternalAccess/FSharp/Microsoft.CodeAnalysis.ExternalAccess.FSharp.csproj index d0964c328354a..86e44781004e7 100644 --- a/src/Tools/ExternalAccess/FSharp/Microsoft.CodeAnalysis.ExternalAccess.FSharp.csproj +++ b/src/Tools/ExternalAccess/FSharp/Microsoft.CodeAnalysis.ExternalAccess.FSharp.csproj @@ -25,6 +25,7 @@ --> + diff --git a/src/Tools/ExternalAccess/FSharp/VS/IFSharpWorkspaceProjectContextFactory.cs b/src/Tools/ExternalAccess/FSharp/VS/IFSharpWorkspaceProjectContextFactory.cs new file mode 100644 index 0000000000000..765625b82b9bc --- /dev/null +++ b/src/Tools/ExternalAccess/FSharp/VS/IFSharpWorkspaceProjectContextFactory.cs @@ -0,0 +1,196 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation 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.Text; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.Editor.Shared.Utilities; +using Microsoft.CodeAnalysis.Host.Mef; +using Microsoft.VisualStudio.LanguageServer.Protocol; +using Microsoft.VisualStudio.LanguageServices.ProjectSystem; +using Microsoft.VisualStudio.Shell.Interop; + +namespace Microsoft.CodeAnalysis.ExternalAccess.FSharp +{ + internal interface IFSharpWorkspaceProjectContextFactory + { + IFSharpWorkspaceProjectContext CreateProjectContext(string filePath, string uniqueName); + } + + internal interface IFSharpWorkspaceProjectContext : IDisposable + { + string DisplayName { get; set; } + ProjectId Id { get; } + string FilePath { get; } + int ProjectReferenceCount { get; } + bool HasProjectReference(string filePath); + int MetadataReferenceCount { get; } + bool HasMetadataReference(string referencePath); + void SetProjectReferences(IEnumerable projRefs); + void SetMetadataReferences(IEnumerable referencePaths); + void AddMetadataReference(string referencePath); + void AddSourceFile(string path, SourceCodeKind kind); + } + + [Shared] + [Export(typeof(FSharpWorkspaceProjectContextFactory))] + [Export(typeof(IFSharpWorkspaceProjectContextFactory))] + internal sealed class FSharpWorkspaceProjectContextFactory : IFSharpWorkspaceProjectContextFactory + { + private readonly IWorkspaceProjectContextFactory _factory; + private readonly IThreadingContext _threadingContext; + + [ImportingConstructor] + [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] + public FSharpWorkspaceProjectContextFactory(IWorkspaceProjectContextFactory factory, IThreadingContext threadingContext) + { + _factory = factory; + _threadingContext = threadingContext; + } + + IFSharpWorkspaceProjectContext IFSharpWorkspaceProjectContextFactory.CreateProjectContext(string filePath, string uniqueName) + => CreateProjectContext(filePath, uniqueName); + + public FSharpWorkspaceProjectContext CreateProjectContext(string filePath, string uniqueName) + => CreateProjectContext( + projectUniqueName: uniqueName, + projectFilePath: filePath, + projectGuid: Guid.NewGuid(), + hierarchy: null, + binOutputPath: null); + + public FSharpWorkspaceProjectContext CreateProjectContext(string projectUniqueName, string projectFilePath, Guid projectGuid, object? hierarchy, string? binOutputPath) + => new(_threadingContext.JoinableTaskFactory.Run(() => _factory.CreateProjectContextAsync( + id: projectGuid, + uniqueName: projectUniqueName, + languageName: LanguageNames.FSharp, + data: new FSharpEvaluationData(projectFilePath, binOutputPath), + hostObject: hierarchy, + CancellationToken.None))); + + private sealed class FSharpEvaluationData : EvaluationData + { + private readonly string _projectFilePath; + private readonly string? _binOutputPath; + + public FSharpEvaluationData(string projectFilePath, string? binOutputPath) + { + _projectFilePath = projectFilePath; + _binOutputPath = binOutputPath; + } + + public override string GetPropertyValue(string name) + => name switch + { + BuildPropertyNames.MSBuildProjectFullPath => _projectFilePath, + BuildPropertyNames.TargetPath => _binOutputPath ?? "", + _ => "", + }; + } + } + + internal sealed class FSharpWorkspaceProjectContext : IFSharpWorkspaceProjectContext + { + private readonly IWorkspaceProjectContext _vsProjectContext; + + private ImmutableDictionary _projectReferences; + private ImmutableHashSet _metadataReferences; + + public FSharpWorkspaceProjectContext(IWorkspaceProjectContext vsProjectContext) + { + _vsProjectContext = vsProjectContext; + _projectReferences = ImmutableDictionary.Create(StringComparer.OrdinalIgnoreCase); + _metadataReferences = ImmutableHashSet.Create(StringComparer.OrdinalIgnoreCase); + } + + public void Dispose() + => _vsProjectContext.Dispose(); + + public IVsLanguageServiceBuildErrorReporter2? BuildErrorReporter + => _vsProjectContext as IVsLanguageServiceBuildErrorReporter2; + + public string DisplayName + { + get => _vsProjectContext.DisplayName; + set => _vsProjectContext.DisplayName = value; + } + + public string BinOutputPath + { + get => _vsProjectContext.BinOutputPath; + set => _vsProjectContext.BinOutputPath = value; + } + + public ProjectId Id + => _vsProjectContext.Id; + + public string FilePath + => _vsProjectContext.ProjectFilePath; + + public int ProjectReferenceCount + => _projectReferences.Count; + + public bool HasProjectReference(string filePath) + => _projectReferences.ContainsKey(filePath); + + public int MetadataReferenceCount + => _metadataReferences.Count; + + public bool HasMetadataReference(string referencePath) + => _metadataReferences.Contains(referencePath); + + public void SetProjectReferences(IEnumerable projRefs) + { + var builder = ImmutableDictionary.CreateBuilder(); + + foreach (var reference in _projectReferences.Values.Cast()) + { + _vsProjectContext.RemoveProjectReference(reference._vsProjectContext); + } + + foreach (var reference in projRefs.Cast()) + { + _vsProjectContext.AddProjectReference(reference._vsProjectContext, MetadataReferenceProperties.Assembly); + builder.Add(reference.FilePath, reference); + } + + _projectReferences = builder.ToImmutable(); + } + + public void SetMetadataReferences(IEnumerable referencePaths) + { + var builder = ImmutableHashSet.CreateBuilder(); + + foreach (var referencePath in _metadataReferences) + { + RemoveMetadataReference(referencePath); + } + + foreach (var referencePath in referencePaths) + { + AddMetadataReference(referencePath); + builder.Add(referencePath); + } + + _metadataReferences = builder.ToImmutable(); + } + + public void RemoveMetadataReference(string referencePath) + => _vsProjectContext.RemoveMetadataReference(referencePath); + + public void AddMetadataReference(string referencePath) + => _vsProjectContext.AddMetadataReference(referencePath, MetadataReferenceProperties.Assembly); + + public void AddSourceFile(string path, SourceCodeKind kind) + => _vsProjectContext.AddSourceFile(path, sourceCodeKind: kind); + + public void RemoveSourceFile(string path) + => _vsProjectContext.RemoveSourceFile(path); + } +} diff --git a/src/Tools/ExternalAccess/OmniSharp/Analyzers/OmniSharpWorkspaceAnalyzerOptionsFactory.cs b/src/Tools/ExternalAccess/OmniSharp/Analyzers/OmniSharpWorkspaceAnalyzerOptionsFactory.cs index 17b362ae43f8c..40e9e417e718a 100644 --- a/src/Tools/ExternalAccess/OmniSharp/Analyzers/OmniSharpWorkspaceAnalyzerOptionsFactory.cs +++ b/src/Tools/ExternalAccess/OmniSharp/Analyzers/OmniSharpWorkspaceAnalyzerOptionsFactory.cs @@ -9,6 +9,6 @@ namespace Microsoft.CodeAnalysis.ExternalAccess.OmniSharp.Analyzers internal static class OmniSharpWorkspaceAnalyzerOptionsFactory { public static AnalyzerOptions Create(Solution solution, AnalyzerOptions options) - => new WorkspaceAnalyzerOptions(options, solution, IdeAnalyzerOptions.GetDefault(solution.Workspace.Services.GetLanguageServices(LanguageNames.CSharp))); + => new WorkspaceAnalyzerOptions(options, solution, IdeAnalyzerOptions.GetDefault(solution.Services.GetLanguageServices(LanguageNames.CSharp))); } } diff --git a/src/Tools/ExternalAccess/OmniSharp/CodeActions/OmniSharpCodeActionOptions.cs b/src/Tools/ExternalAccess/OmniSharp/CodeActions/OmniSharpCodeActionOptions.cs index d9ba5b33a1fdf..3b7e2c9faabae 100644 --- a/src/Tools/ExternalAccess/OmniSharp/CodeActions/OmniSharpCodeActionOptions.cs +++ b/src/Tools/ExternalAccess/OmniSharp/CodeActions/OmniSharpCodeActionOptions.cs @@ -3,7 +3,10 @@ // See the LICENSE file in the project root for more information. using Microsoft.CodeAnalysis.CodeActions; +using Microsoft.CodeAnalysis.CodeCleanup; using Microsoft.CodeAnalysis.ExternalAccess.OmniSharp.ImplementType; +using Microsoft.CodeAnalysis.ExternalAccess.OmniSharp.Options; +using Microsoft.CodeAnalysis.Formatting; using Microsoft.CodeAnalysis.Host; using Microsoft.CodeAnalysis.ImplementType; using Microsoft.CodeAnalysis.SymbolSearch; @@ -11,16 +14,30 @@ namespace Microsoft.CodeAnalysis.ExternalAccess.OmniSharp.CodeActions { internal readonly record struct OmniSharpCodeActionOptions( - OmniSharpImplementTypeOptions ImplementTypeOptions) + OmniSharpImplementTypeOptions ImplementTypeOptions, + OmniSharpLineFormattingOptions LineFormattingOptions) { - internal CodeActionOptions GetCodeActionOptions(HostLanguageServices languageServices) - => CodeActionOptions.GetDefault(languageServices) with + internal CodeActionOptions GetCodeActionOptions(LanguageServices languageServices) + { + var defaultOptions = CodeActionOptions.GetDefault(languageServices); + return defaultOptions with { + CleanupOptions = defaultOptions.CleanupOptions with + { + FormattingOptions = defaultOptions.CleanupOptions.FormattingOptions.With(new LineFormattingOptions + { + IndentationSize = LineFormattingOptions.IndentationSize, + TabSize = LineFormattingOptions.TabSize, + UseTabs = LineFormattingOptions.UseTabs, + NewLine = LineFormattingOptions.NewLine, + }) + }, ImplementTypeOptions = new() { InsertionBehavior = (ImplementTypeInsertionBehavior)ImplementTypeOptions.InsertionBehavior, PropertyGenerationBehavior = (ImplementTypePropertyGenerationBehavior)ImplementTypeOptions.PropertyGenerationBehavior } }; + } } } diff --git a/src/Tools/ExternalAccess/OmniSharp/Completion/OmniSharpCompletionService.cs b/src/Tools/ExternalAccess/OmniSharp/Completion/OmniSharpCompletionService.cs index 1d2654a38e6be..8318c8fe3ffea 100644 --- a/src/Tools/ExternalAccess/OmniSharp/Completion/OmniSharpCompletionService.cs +++ b/src/Tools/ExternalAccess/OmniSharp/Completion/OmniSharpCompletionService.cs @@ -6,7 +6,7 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.Completion; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; namespace Microsoft.CodeAnalysis.ExternalAccess.OmniSharp.Completion { @@ -22,7 +22,7 @@ public static async ValueTask ShouldTriggerCompletionAsync( CancellationToken cancellationToken) { var text = await document.GetTextAsync(cancellationToken).ConfigureAwait(false); - return completionService.ShouldTriggerCompletion(document.Project, document.Project.LanguageServices, text, caretPosition, trigger, options.ToCompletionOptions(), document.Project.Solution.Options, roles); + return completionService.ShouldTriggerCompletion(document.Project, document.Project.Services, text, caretPosition, trigger, options.ToCompletionOptions(), document.Project.Solution.Options, roles); } public static Task GetCompletionsAsync( diff --git a/src/Tools/ExternalAccess/OmniSharp/DocumentationComments/OmniSharpDocumentationCommentOptionsWrapper.cs b/src/Tools/ExternalAccess/OmniSharp/DocumentationComments/OmniSharpDocumentationCommentOptionsWrapper.cs index 16bb5b7b49835..46da88e2699b7 100644 --- a/src/Tools/ExternalAccess/OmniSharp/DocumentationComments/OmniSharpDocumentationCommentOptionsWrapper.cs +++ b/src/Tools/ExternalAccess/OmniSharp/DocumentationComments/OmniSharpDocumentationCommentOptionsWrapper.cs @@ -6,6 +6,7 @@ using System.Threading.Tasks; using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.DocumentationComments; +using Microsoft.CodeAnalysis.ExternalAccess.OmniSharp.Options; using Microsoft.CodeAnalysis.Formatting; namespace Microsoft.CodeAnalysis.ExternalAccess.OmniSharp.DocumentationComments @@ -19,12 +20,16 @@ internal OmniSharpDocumentationCommentOptionsWrapper(DocumentationCommentOptions public OmniSharpDocumentationCommentOptionsWrapper( bool autoXmlDocCommentGeneration, - int tabSize, - bool useTabs, - string newLine) + OmniSharpLineFormattingOptions lineFormattingOptions) : this(new DocumentationCommentOptions() { - LineFormatting = new LineFormattingOptions() { UseTabs = useTabs, TabSize = tabSize, IndentationSize = tabSize, NewLine = newLine }, + LineFormatting = new LineFormattingOptions() + { + UseTabs = lineFormattingOptions.UseTabs, + TabSize = lineFormattingOptions.TabSize, + IndentationSize = lineFormattingOptions.IndentationSize, + NewLine = lineFormattingOptions.NewLine, + }, AutoXmlDocCommentGeneration = autoXmlDocCommentGeneration }) { diff --git a/src/Tools/ExternalAccess/OmniSharp/ExtractClass/IOmniSharpExtractClassOptionsService.cs b/src/Tools/ExternalAccess/OmniSharp/ExtractClass/IOmniSharpExtractClassOptionsService.cs index 54faf1aea3097..f4ea93f41ec35 100644 --- a/src/Tools/ExternalAccess/OmniSharp/ExtractClass/IOmniSharpExtractClassOptionsService.cs +++ b/src/Tools/ExternalAccess/OmniSharp/ExtractClass/IOmniSharpExtractClassOptionsService.cs @@ -9,7 +9,7 @@ namespace Microsoft.CodeAnalysis.ExternalAccess.OmniSharp.ExtractClass { internal interface IOmniSharpExtractClassOptionsService { - Task GetExtractClassOptionsAsync(Document document, INamedTypeSymbol originalType, ISymbol? selectedMember); + Task GetExtractClassOptionsAsync(Document document, INamedTypeSymbol originalType, ImmutableArray selectedMembers); } internal sealed class OmniSharpExtractClassOptions diff --git a/src/Tools/ExternalAccess/OmniSharp/Formatting/OmniSharpOrganizeImportsOptionsWrapper.cs b/src/Tools/ExternalAccess/OmniSharp/Formatting/OmniSharpOrganizeImportsOptionsWrapper.cs index 7b0a46d18d6d6..133890f9031ab 100644 --- a/src/Tools/ExternalAccess/OmniSharp/Formatting/OmniSharpOrganizeImportsOptionsWrapper.cs +++ b/src/Tools/ExternalAccess/OmniSharp/Formatting/OmniSharpOrganizeImportsOptionsWrapper.cs @@ -31,7 +31,7 @@ public OmniSharpOrganizeImportsOptionsWrapper( { } - public static async ValueTask FromDocumentAsync(Document document, CancellationToken cancellationToken) - => new(await document.GetOrganizeImportsOptionsAsync(fallbackOptions: null, cancellationToken).ConfigureAwait(false)); + public static async ValueTask FromDocumentAsync(Document document, OmniSharpOrganizeImportsOptionsWrapper fallbackOptions, CancellationToken cancellationToken) + => new(await document.GetOrganizeImportsOptionsAsync(fallbackOptions.UnderlyingObject, cancellationToken).ConfigureAwait(false)); } } diff --git a/src/Tools/ExternalAccess/OmniSharp/Formatting/OmniSharpSyntaxFormattingOptionsWrapper.cs b/src/Tools/ExternalAccess/OmniSharp/Formatting/OmniSharpSyntaxFormattingOptionsWrapper.cs index c9b6dbe28ab4d..6f1e7ebb16991 100644 --- a/src/Tools/ExternalAccess/OmniSharp/Formatting/OmniSharpSyntaxFormattingOptionsWrapper.cs +++ b/src/Tools/ExternalAccess/OmniSharp/Formatting/OmniSharpSyntaxFormattingOptionsWrapper.cs @@ -6,6 +6,7 @@ using System.Threading.Tasks; using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeCleanup; +using Microsoft.CodeAnalysis.ExternalAccess.OmniSharp.Options; using Microsoft.CodeAnalysis.Formatting; using Microsoft.CodeAnalysis.Simplification; @@ -20,9 +21,21 @@ internal OmniSharpSyntaxFormattingOptionsWrapper(CodeCleanupOptions cleanupOptio CleanupOptions = cleanupOptions; } - public static async ValueTask FromDocumentAsync(Document document, CancellationToken cancellationToken) + public static async ValueTask FromDocumentAsync(Document document, OmniSharpLineFormattingOptions fallbackLineFormattingOptions, CancellationToken cancellationToken) { - var cleanupOptions = await document.GetCodeCleanupOptionsAsync(CodeActionOptions.DefaultProvider, cancellationToken).ConfigureAwait(false); + var defaultOptions = CodeCleanupOptions.GetDefault(document.Project.Services); + var fallbackOptions = defaultOptions with + { + FormattingOptions = defaultOptions.FormattingOptions.With(new LineFormattingOptions + { + IndentationSize = fallbackLineFormattingOptions.IndentationSize, + TabSize = fallbackLineFormattingOptions.TabSize, + UseTabs = fallbackLineFormattingOptions.UseTabs, + NewLine = fallbackLineFormattingOptions.NewLine, + }) + }; + + var cleanupOptions = await document.GetCodeCleanupOptionsAsync(fallbackOptions, cancellationToken).ConfigureAwait(false); return new OmniSharpSyntaxFormattingOptionsWrapper(cleanupOptions); } } diff --git a/src/Tools/ExternalAccess/OmniSharp/InlineHints/OmniSharpInlineHintsOptions.cs b/src/Tools/ExternalAccess/OmniSharp/InlineHints/OmniSharpInlineHintsOptions.cs index 0a3eeea63d54b..9f7defb342070 100644 --- a/src/Tools/ExternalAccess/OmniSharp/InlineHints/OmniSharpInlineHintsOptions.cs +++ b/src/Tools/ExternalAccess/OmniSharp/InlineHints/OmniSharpInlineHintsOptions.cs @@ -3,7 +3,7 @@ // See the LICENSE file in the project root for more information. using Microsoft.CodeAnalysis.InlineHints; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; namespace Microsoft.CodeAnalysis.ExternalAccess.OmniSharp.InlineHints; diff --git a/src/Tools/ExternalAccess/OmniSharp/Internal/ExtractClass/OmniSharpExtractClassOptionsService.cs b/src/Tools/ExternalAccess/OmniSharp/Internal/ExtractClass/OmniSharpExtractClassOptionsService.cs index 6d4abad23938a..75d800865f797 100644 --- a/src/Tools/ExternalAccess/OmniSharp/Internal/ExtractClass/OmniSharpExtractClassOptionsService.cs +++ b/src/Tools/ExternalAccess/OmniSharp/Internal/ExtractClass/OmniSharpExtractClassOptionsService.cs @@ -3,7 +3,9 @@ // 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.ExternalAccess.OmniSharp.ExtractClass; @@ -25,9 +27,9 @@ public OmniSharpExtractClassOptionsService(IOmniSharpExtractClassOptionsService _omniSharpExtractClassOptionsService = omniSharpExtractClassOptionsService; } - public async Task GetExtractClassOptionsAsync(Document document, INamedTypeSymbol originalType, ISymbol? selectedMember, CancellationToken cancellationToken) + public async Task GetExtractClassOptionsAsync(Document document, INamedTypeSymbol originalType, ImmutableArray selectedMembers, CancellationToken cancellationToken) { - var result = await _omniSharpExtractClassOptionsService.GetExtractClassOptionsAsync(document, originalType, selectedMember).ConfigureAwait(false); + var result = await _omniSharpExtractClassOptionsService.GetExtractClassOptionsAsync(document, originalType, selectedMembers).ConfigureAwait(false); return result == null ? null : new ExtractClassOptions( diff --git a/src/Tools/ExternalAccess/OmniSharp/Internal/ExtractInterface/OmniSharpExtractInterfaceOptionsService.cs b/src/Tools/ExternalAccess/OmniSharp/Internal/ExtractInterface/OmniSharpExtractInterfaceOptionsService.cs index a548126865277..13fc5e88d8888 100644 --- a/src/Tools/ExternalAccess/OmniSharp/Internal/ExtractInterface/OmniSharpExtractInterfaceOptionsService.cs +++ b/src/Tools/ExternalAccess/OmniSharp/Internal/ExtractInterface/OmniSharpExtractInterfaceOptionsService.cs @@ -14,7 +14,7 @@ using Microsoft.CodeAnalysis.ExternalAccess.OmniSharp.ExtractInterface; using Microsoft.CodeAnalysis.ExtractInterface; using Microsoft.CodeAnalysis.Host.Mef; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Notification; using Microsoft.CodeAnalysis.Options; using Roslyn.Utilities; diff --git a/src/Tools/ExternalAccess/OmniSharp/MetadataAsSource/OmniSharpMetadataAsSourceService.cs b/src/Tools/ExternalAccess/OmniSharp/MetadataAsSource/OmniSharpMetadataAsSourceService.cs index 15413195b7401..4560ea2b0d23b 100644 --- a/src/Tools/ExternalAccess/OmniSharp/MetadataAsSource/OmniSharpMetadataAsSourceService.cs +++ b/src/Tools/ExternalAccess/OmniSharp/MetadataAsSource/OmniSharpMetadataAsSourceService.cs @@ -37,7 +37,7 @@ public static async Task AddSourceToAsync(Document document, Compilati var cleanupOptions = await document.GetCodeCleanupOptionsAsync(CodeActionOptions.DefaultProvider, cancellationToken).ConfigureAwait(false); var options = new CleanCodeGenerationOptions( - GenerationOptions: CodeGenerationOptions.GetDefault(document.Project.LanguageServices), + GenerationOptions: CodeGenerationOptions.GetDefault(document.Project.Services), CleanupOptions: cleanupOptions); return await service.AddSourceToAsync(document, symbolCompilation, symbol, options, cancellationToken).ConfigureAwait(false); @@ -59,7 +59,7 @@ public static Task AddSourceToAsync(Document document, Compilation sym var service = document.GetRequiredLanguageService(); var options = new CleanCodeGenerationOptions( - GenerationOptions: CodeGenerationOptions.GetDefault(document.Project.LanguageServices), + GenerationOptions: CodeGenerationOptions.GetDefault(document.Project.Services), CleanupOptions: formattingOptions.CleanupOptions); return service.AddSourceToAsync(document, symbolCompilation, symbol, options, cancellationToken); diff --git a/src/Tools/ExternalAccess/OmniSharp/NavigateTo/OmniSharpNavigateToSearchResult.cs b/src/Tools/ExternalAccess/OmniSharp/NavigateTo/OmniSharpNavigateToSearchResult.cs new file mode 100644 index 0000000000000..6f62810cec32c --- /dev/null +++ b/src/Tools/ExternalAccess/OmniSharp/NavigateTo/OmniSharpNavigateToSearchResult.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.Collections.Immutable; +using System.Text; +using Microsoft.CodeAnalysis.ExternalAccess.OmniSharp.Navigation; +using Microsoft.CodeAnalysis.Text; + +namespace Microsoft.CodeAnalysis.ExternalAccess.OmniSharp.NavigateTo; + +internal readonly record struct OmniSharpNavigateToSearchResult( + string AdditionalInformation, + string Kind, + OmniSharpNavigateToMatchKind MatchKind, + bool IsCaseSensitive, + string Name, + ImmutableArray NameMatchSpans, + string SecondarySort, + string Summary, + OmniSharpNavigableItem NavigableItem); + +internal enum OmniSharpNavigateToMatchKind +{ + Exact = 0, + Prefix = 1, + Substring = 2, + Regular = 3, + None = 4, + CamelCaseExact = 5, + CamelCasePrefix = 6, + CamelCaseNonContiguousPrefix = 7, + CamelCaseSubstring = 8, + CamelCaseNonContiguousSubstring = 9, + Fuzzy = 10 +} diff --git a/src/Tools/ExternalAccess/OmniSharp/NavigateTo/OmniSharpNavigateToSearchService.cs b/src/Tools/ExternalAccess/OmniSharp/NavigateTo/OmniSharpNavigateToSearchService.cs new file mode 100644 index 0000000000000..250ab70773e20 --- /dev/null +++ b/src/Tools/ExternalAccess/OmniSharp/NavigateTo/OmniSharpNavigateToSearchService.cs @@ -0,0 +1,72 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.ExternalAccess.OmniSharp.Navigation; +using Microsoft.CodeAnalysis.NavigateTo; +using Microsoft.CodeAnalysis.Shared.TestHooks; + +namespace Microsoft.CodeAnalysis.ExternalAccess.OmniSharp.NavigateTo; + +internal static class OmniSharpNavigateToSearcher +{ + public delegate Task OmniSharpNavigateToCallback(Project project, in OmniSharpNavigateToSearchResult result, CancellationToken cancellationToken); + + public static Task SearchAsync( + Solution solution, + OmniSharpNavigateToCallback callback, + string searchPattern, + IImmutableSet kinds, + CancellationToken cancellationToken) + { + var searcher = NavigateToSearcher.Create( + solution, + AsynchronousOperationListenerProvider.NullListener, + new OmniSharpNavigateToCallbackImpl(callback), + searchPattern, + kinds, + disposalToken: CancellationToken.None); + + return searcher.SearchAsync(searchCurrentDocument: false, cancellationToken); + } + + private sealed class OmniSharpNavigateToCallbackImpl : INavigateToSearchCallback + { + private readonly OmniSharpNavigateToCallback _callback; + + public OmniSharpNavigateToCallbackImpl(OmniSharpNavigateToCallback callback) + { + _callback = callback; + } + + public Task AddItemAsync(Project project, INavigateToSearchResult result, CancellationToken cancellationToken) + { + var omniSharpResult = new OmniSharpNavigateToSearchResult( + result.AdditionalInformation, + result.Kind, + (OmniSharpNavigateToMatchKind)result.MatchKind, + result.IsCaseSensitive, + result.Name, + result.NameMatchSpans, + result.SecondarySort, + result.Summary, + new(result.NavigableItem.DisplayTaggedParts, result.NavigableItem.Document, result.NavigableItem.SourceSpan)); + + return _callback(project, omniSharpResult, cancellationToken); + } + + public void Done(bool isFullyLoaded) + { + } + + public void ReportProgress(int current, int maximum) + { + } + } +} diff --git a/src/Tools/ExternalAccess/OmniSharp/Options/IOmniSharpLineFormattingOptionsProvider.cs b/src/Tools/ExternalAccess/OmniSharp/Options/IOmniSharpLineFormattingOptionsProvider.cs new file mode 100644 index 0000000000000..8b92e27116e95 --- /dev/null +++ b/src/Tools/ExternalAccess/OmniSharp/Options/IOmniSharpLineFormattingOptionsProvider.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; +using System.Collections.Generic; +using System.Text; + +namespace Microsoft.CodeAnalysis.ExternalAccess.OmniSharp.Options +{ + internal interface IOmniSharpLineFormattingOptionsProvider + { + OmniSharpLineFormattingOptions GetLineFormattingOptions(); + } +} diff --git a/src/Tools/ExternalAccess/OmniSharp/Options/OmniSharpLineFormattingOptions.cs b/src/Tools/ExternalAccess/OmniSharp/Options/OmniSharpLineFormattingOptions.cs new file mode 100644 index 0000000000000..659cf731b54ef --- /dev/null +++ b/src/Tools/ExternalAccess/OmniSharp/Options/OmniSharpLineFormattingOptions.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; + +namespace Microsoft.CodeAnalysis.ExternalAccess.OmniSharp.Options +{ + internal sealed record class OmniSharpLineFormattingOptions + { + public bool UseTabs { get; init; } = false; + public int TabSize { get; init; } = 4; + public int IndentationSize { get; init; } = 4; + public string NewLine { get; init; } = Environment.NewLine; + } +} diff --git a/src/Tools/ExternalAccess/OmniSharp/Options/OmnisharpLegacyGlobalOptionsWorkspaceService.cs b/src/Tools/ExternalAccess/OmniSharp/Options/OmnisharpLegacyGlobalOptionsWorkspaceService.cs index a61a523455495..38e1db259fde7 100644 --- a/src/Tools/ExternalAccess/OmniSharp/Options/OmnisharpLegacyGlobalOptionsWorkspaceService.cs +++ b/src/Tools/ExternalAccess/OmniSharp/Options/OmnisharpLegacyGlobalOptionsWorkspaceService.cs @@ -2,17 +2,16 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using System; using System.Composition; -using Microsoft.CodeAnalysis.Formatting; -using Microsoft.CodeAnalysis.CodeGeneration; -using Microsoft.CodeAnalysis.GenerateEqualsAndGetHashCodeFromMembers; -using Microsoft.CodeAnalysis.Host; -using Microsoft.CodeAnalysis.Host.Mef; -using Microsoft.CodeAnalysis.InlineHints; -using Microsoft.CodeAnalysis.Options; using System.Threading.Tasks; using System.Threading; +using System; +using Microsoft.CodeAnalysis.Host.Mef; +using Microsoft.CodeAnalysis.Options; +using Microsoft.CodeAnalysis.CodeGeneration; +using Microsoft.CodeAnalysis.Formatting; +using Microsoft.CodeAnalysis.Host; +using Microsoft.CodeAnalysis.CodeCleanup; namespace Microsoft.CodeAnalysis.ExternalAccess.OmniSharp.Options { @@ -26,9 +25,9 @@ internal sealed class OmnisharpLegacyGlobalOptionsWorkspaceService : ILegacyGlob [ImportingConstructor] [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] - public OmnisharpLegacyGlobalOptionsWorkspaceService() + public OmnisharpLegacyGlobalOptionsWorkspaceService(IOmniSharpLineFormattingOptionsProvider lineFormattingOptionsProvider) { - _provider = new OmniSharpCleanCodeGenerationOptionsProvider(); + _provider = new OmniSharpCleanCodeGenerationOptionsProvider(lineFormattingOptionsProvider); } public bool RazorUseTabs @@ -76,9 +75,30 @@ public void SetGenerateConstructorFromMembersOptionsAddNullChecks(string languag internal sealed class OmniSharpCleanCodeGenerationOptionsProvider : AbstractCleanCodeGenerationOptionsProvider { - public override ValueTask GetCleanCodeGenerationOptionsAsync(HostLanguageServices languageServices, CancellationToken cancellationToken) + private readonly IOmniSharpLineFormattingOptionsProvider _lineFormattingOptionsProvider; + + public OmniSharpCleanCodeGenerationOptionsProvider(IOmniSharpLineFormattingOptionsProvider lineFormattingOptionsProvider) + { + _lineFormattingOptionsProvider = lineFormattingOptionsProvider; + } + + public override ValueTask GetCleanCodeGenerationOptionsAsync(LanguageServices languageServices, CancellationToken cancellationToken) { - return new ValueTask(CleanCodeGenerationOptions.GetDefault(languageServices)); + var lineFormattingOptions = _lineFormattingOptionsProvider.GetLineFormattingOptions(); + var codeGenerationOptions = CleanCodeGenerationOptions.GetDefault(languageServices) with + { + CleanupOptions = CodeCleanupOptions.GetDefault(languageServices) with + { + FormattingOptions = SyntaxFormattingOptions.GetDefault(languageServices).With(new LineFormattingOptions + { + IndentationSize = lineFormattingOptions.IndentationSize, + TabSize = lineFormattingOptions.TabSize, + UseTabs = lineFormattingOptions.UseTabs, + NewLine = lineFormattingOptions.NewLine, + }) + } + }; + return new ValueTask(codeGenerationOptions); } } } diff --git a/src/Tools/ExternalAccess/OmniSharp/Rename/OmniSharpRenamer.cs b/src/Tools/ExternalAccess/OmniSharp/Rename/OmniSharpRenamer.cs index 0dfe4d8ed0082..2f40e4e84f515 100644 --- a/src/Tools/ExternalAccess/OmniSharp/Rename/OmniSharpRenamer.cs +++ b/src/Tools/ExternalAccess/OmniSharp/Rename/OmniSharpRenamer.cs @@ -9,12 +9,13 @@ using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeCleanup; using Microsoft.CodeAnalysis.Rename; +using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.ExternalAccess.OmniSharp { internal static class OmniSharpRenamer { - public readonly record struct RenameResult(Solution Solution, string? ErrorMessage); + public readonly record struct RenameResult(Solution? Solution, string? ErrorMessage); public static async Task RenameSymbolAsync( Solution solution, @@ -24,7 +25,8 @@ public static async Task RenameSymbolAsync( ImmutableHashSet? nonConflictSymbols, CancellationToken cancellationToken) { - var resolution = await Renamer.RenameSymbolAsync(solution, symbol, newName, options.ToRenameOptions(), CodeActionOptions.DefaultProvider, nonConflictSymbols, cancellationToken).ConfigureAwait(false); + var nonConflictSymbolsKeys = nonConflictSymbols is null ? default : nonConflictSymbols.SelectAsArray(s => s.GetSymbolKey(cancellationToken)); + var resolution = await Renamer.RenameSymbolAsync(solution, symbol, newName, options.ToRenameOptions(), CodeActionOptions.DefaultProvider, nonConflictSymbolsKeys, cancellationToken).ConfigureAwait(false); return new RenameResult(resolution.NewSolution, resolution.ErrorMessage); } } diff --git a/src/Tools/ExternalAccess/OmniSharpTest/EnumTests.cs b/src/Tools/ExternalAccess/OmniSharpTest/EnumTests.cs index a552f27c40fc6..e0293cbc8fef2 100644 --- a/src/Tools/ExternalAccess/OmniSharpTest/EnumTests.cs +++ b/src/Tools/ExternalAccess/OmniSharpTest/EnumTests.cs @@ -6,8 +6,11 @@ using System.Linq; using Microsoft.CodeAnalysis.ExternalAccess.OmniSharp.ExtractInterface; using Microsoft.CodeAnalysis.ExternalAccess.OmniSharp.ImplementType; +using Microsoft.CodeAnalysis.ExternalAccess.OmniSharp.NavigateTo; using Microsoft.CodeAnalysis.ExtractInterface; using Microsoft.CodeAnalysis.ImplementType; +using Microsoft.CodeAnalysis.NavigateTo; +using Roslyn.Test.Utilities; using Xunit; namespace Microsoft.CodeAnalysis.ExternalAccess.OmniSharp.UnitTests @@ -19,6 +22,7 @@ public class EnumTests typeof(OmniSharpExtractInterfaceOptionsResult.OmniSharpExtractLocation))] [InlineData(typeof(ImplementTypeInsertionBehavior), typeof(OmniSharpImplementTypeInsertionBehavior))] [InlineData(typeof(ImplementTypePropertyGenerationBehavior), typeof(OmniSharpImplementTypePropertyGenerationBehavior))] + [InlineData(typeof(NavigateToMatchKind), typeof(OmniSharpNavigateToMatchKind))] public void AssertEnumsInSync(Type internalType, Type externalType) { var internalValues = Enum.GetValues(internalType).Cast().ToArray(); @@ -26,8 +30,8 @@ public void AssertEnumsInSync(Type internalType, Type externalType) var externalValues = Enum.GetValues(externalType).Cast().ToArray(); var externalNames = Enum.GetNames(externalType); - Assert.Equal(internalValues, externalValues); - Assert.Equal(internalNames, externalNames); + AssertEx.Equal(internalValues, externalValues); + AssertEx.Equal(internalNames, externalNames); } } } diff --git a/src/Tools/ExternalAccess/Razor/RazorCSharpFormattingInteractionService.cs b/src/Tools/ExternalAccess/Razor/RazorCSharpFormattingInteractionService.cs index 567ce64e44f8d..d76f837720b5e 100644 --- a/src/Tools/ExternalAccess/Razor/RazorCSharpFormattingInteractionService.cs +++ b/src/Tools/ExternalAccess/Razor/RazorCSharpFormattingInteractionService.cs @@ -65,7 +65,7 @@ public static IList GetFormattedTextChanges( CancellationToken cancellationToken) { Contract.ThrowIfFalse(root.Language is LanguageNames.CSharp); - return Formatter.GetFormattedTextChanges(root, span, services, GetFormattingOptions(indentationOptions), cancellationToken); + return Formatter.GetFormattedTextChanges(root, span, services.SolutionServices, GetFormattingOptions(indentationOptions), cancellationToken); } public static SyntaxNode Format( @@ -75,7 +75,7 @@ public static SyntaxNode Format( CancellationToken cancellationToken) { Contract.ThrowIfFalse(root.Language is LanguageNames.CSharp); - return Formatter.Format(root, services, GetFormattingOptions(indentationOptions), cancellationToken: cancellationToken); + return Formatter.Format(root, services.SolutionServices, GetFormattingOptions(indentationOptions), cancellationToken: cancellationToken); } private static SyntaxFormattingOptions GetFormattingOptions(RazorIndentationOptions indentationOptions) diff --git a/src/Tools/ExternalAccess/Razor/RazorClassifierAccessor.cs b/src/Tools/ExternalAccess/Razor/RazorClassifierAccessor.cs index 9f62f2d73a878..ac1593affd1db 100644 --- a/src/Tools/ExternalAccess/Razor/RazorClassifierAccessor.cs +++ b/src/Tools/ExternalAccess/Razor/RazorClassifierAccessor.cs @@ -17,7 +17,7 @@ public static async Task> GetClassifiedSpansAsync(Do { var semanticModel = await document.GetRequiredSemanticModelAsync(cancellationToken).ConfigureAwait(false); return Classifier.GetClassifiedSpans( - document.Project.Solution.Workspace.Services, document.Project, semanticModel, textSpan, options.UnderlyingObject, cancellationToken); + document.Project.Solution.Services, document.Project, semanticModel, textSpan, options.UnderlyingObject, cancellationToken); } } } diff --git a/src/Tools/ExternalAccess/Razor/RazorSpanMappingServiceWrapper.cs b/src/Tools/ExternalAccess/Razor/RazorSpanMappingServiceWrapper.cs index e3bbd1be26c77..d186da23ac528 100644 --- a/src/Tools/ExternalAccess/Razor/RazorSpanMappingServiceWrapper.cs +++ b/src/Tools/ExternalAccess/Razor/RazorSpanMappingServiceWrapper.cs @@ -33,7 +33,7 @@ public RazorSpanMappingServiceWrapper(IRazorSpanMappingService razorSpanMappingS Document newDocument, CancellationToken cancellationToken) { - var diffService = newDocument.Project.Solution.Workspace.Services.GetRequiredService(); + 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. diff --git a/src/Tools/ExternalAccess/Razor/Remote/RazorRemoteHostClient.cs b/src/Tools/ExternalAccess/Razor/Remote/RazorRemoteHostClient.cs index 99853a4d022c7..11659c96ae159 100644 --- a/src/Tools/ExternalAccess/Razor/Remote/RazorRemoteHostClient.cs +++ b/src/Tools/ExternalAccess/Razor/Remote/RazorRemoteHostClient.cs @@ -25,7 +25,7 @@ internal RazorRemoteHostClient(ServiceHubRemoteHostClient client, RazorServiceDe public static async Task TryGetClientAsync(HostWorkspaceServices services, RazorServiceDescriptorsWrapper serviceDescriptors, RazorRemoteServiceCallbackDispatcherRegistry callbackDispatchers, CancellationToken cancellationToken = default) { - var client = await RemoteHostClient.TryGetClientAsync(services, cancellationToken).ConfigureAwait(false); + var client = await RemoteHostClient.TryGetClientAsync(services.SolutionServices, cancellationToken).ConfigureAwait(false); if (client is null) return null; diff --git a/src/Tools/IdeBenchmarks/FormatterBenchmarks.cs b/src/Tools/IdeBenchmarks/FormatterBenchmarks.cs index f17f1ae8eb94d..429db326a589d 100644 --- a/src/Tools/IdeBenchmarks/FormatterBenchmarks.cs +++ b/src/Tools/IdeBenchmarks/FormatterBenchmarks.cs @@ -46,8 +46,8 @@ public object FormatCSharp() using var workspace = TestWorkspace.CreateCSharp(text); var document = workspace.CurrentSolution.GetDocument(workspace.Documents.First().Id); var root = document.GetSyntaxRootSynchronously(CancellationToken.None); - var options = workspace.GlobalOptions.GetSyntaxFormattingOptions(document.Project.LanguageServices); - return Formatter.GetFormattedTextChanges(root, workspace.Services, options, CancellationToken.None); + var options = workspace.GlobalOptions.GetSyntaxFormattingOptions(document.Project.Services); + return Formatter.GetFormattedTextChanges(root, workspace.Services.SolutionServices, options, CancellationToken.None); } [Benchmark] @@ -59,8 +59,8 @@ public object FormatVisualBasic() using var workspace = TestWorkspace.CreateVisualBasic(text); var document = workspace.CurrentSolution.GetDocument(workspace.Documents.First().Id); var root = document.GetSyntaxRootSynchronously(CancellationToken.None); - var options = workspace.GlobalOptions.GetSyntaxFormattingOptions(document.Project.LanguageServices); - return Formatter.GetFormattedTextChanges(root, workspace.Services, options, CancellationToken.None); + var options = workspace.GlobalOptions.GetSyntaxFormattingOptions(document.Project.Services); + return Formatter.GetFormattedTextChanges(root, workspace.Services.SolutionServices, options, CancellationToken.None); } } } diff --git a/src/Tools/IdeBenchmarks/IdeBenchmarks.csproj b/src/Tools/IdeBenchmarks/IdeBenchmarks.csproj index 28df8f7392000..62f6c171e1609 100644 --- a/src/Tools/IdeBenchmarks/IdeBenchmarks.csproj +++ b/src/Tools/IdeBenchmarks/IdeBenchmarks.csproj @@ -15,6 +15,7 @@ + diff --git a/src/Tools/IdeBenchmarks/RegexClassifierBenchmarks.cs b/src/Tools/IdeBenchmarks/RegexClassifierBenchmarks.cs index c05367103a6ae..17884b1529fd4 100644 --- a/src/Tools/IdeBenchmarks/RegexClassifierBenchmarks.cs +++ b/src/Tools/IdeBenchmarks/RegexClassifierBenchmarks.cs @@ -81,7 +81,7 @@ protected static async Task> GetSemanticClassific var service = document.GetLanguageService(); var classifiers = service.GetDefaultSyntaxClassifiers(); - var extensionManager = document.Project.Solution.Workspace.Services.GetService(); + var extensionManager = document.Project.Solution.Services.GetService(); var results = ArrayBuilder.GetInstance(); diff --git a/src/Tools/IdeCoreBenchmarks/FindReferencesBenchmarks.cs b/src/Tools/IdeCoreBenchmarks/FindReferencesBenchmarks.cs index 206bc9480814d..5b522c51e1171 100644 --- a/src/Tools/IdeCoreBenchmarks/FindReferencesBenchmarks.cs +++ b/src/Tools/IdeCoreBenchmarks/FindReferencesBenchmarks.cs @@ -91,7 +91,7 @@ private async Task LoadSolutionAsync() // Force a storage instance to be created. This makes it simple to go examine it prior to any operations we // perform, including seeing how big the initial string table is. - var storageService = _workspace.Services.GetPersistentStorageService(); + var storageService = _workspace.Services.SolutionServices.GetPersistentStorageService(); if (storageService == null) throw new ArgumentException("Couldn't get storage service"); diff --git a/src/Tools/IdeCoreBenchmarks/IncrementalSourceGeneratorBenchmarks.cs b/src/Tools/IdeCoreBenchmarks/IncrementalSourceGeneratorBenchmarks.cs index d57d35a9d1a53..3626836aefdf7 100644 --- a/src/Tools/IdeCoreBenchmarks/IncrementalSourceGeneratorBenchmarks.cs +++ b/src/Tools/IdeCoreBenchmarks/IncrementalSourceGeneratorBenchmarks.cs @@ -173,16 +173,18 @@ public async Task RunGenerator() Thread.Sleep(5000); var totalIncrementalTime = TimeSpan.Zero; - for (var i = 0; i < 5000; i++) + for (var i = 0; i < 50000; i++) { - var changedText = sourceText.WithChanges(new TextChange(new TextSpan(0, 0), $"// added text{i}\r\n")); + var changedText = sourceText.WithChanges(new TextChange(sourceText.Lines[0].Span, $"// added text{i}")); var changedTree = syntaxTree.WithChangedText(changedText); - var changedCompilation = compilation.ReplaceSyntaxTree(syntaxTree, changedTree); + compilation = compilation.ReplaceSyntaxTree(syntaxTree, changedTree); + sourceText = changedText; + syntaxTree = changedTree; start = DateTime.Now; - driver = driver.RunGenerators(changedCompilation); + driver = driver.RunGenerators(compilation); var incrementalTime = DateTime.Now - start; - if (i % 100 == 0) + if (i % 5000 == 0) Console.WriteLine("Incremental time: " + incrementalTime); totalIncrementalTime += incrementalTime; } diff --git a/src/Tools/IdeCoreBenchmarks/NavigateToBenchmarks.cs b/src/Tools/IdeCoreBenchmarks/NavigateToBenchmarks.cs index 7c99bff49846f..3077118dec05b 100644 --- a/src/Tools/IdeCoreBenchmarks/NavigateToBenchmarks.cs +++ b/src/Tools/IdeCoreBenchmarks/NavigateToBenchmarks.cs @@ -96,7 +96,7 @@ private async Task LoadSolutionAsync() // Force a storage instance to be created. This makes it simple to go examine it prior to any operations we // perform, including seeing how big the initial string table is. - var storageService = _workspace.Services.GetPersistentStorageService(); + var storageService = _workspace.Services.SolutionServices.GetPersistentStorageService(); if (storageService == null) throw new ArgumentException("Couldn't get storage service"); @@ -125,12 +125,10 @@ public async Task RunSerialIndexing() foreach (var document in project.Documents) { // await WalkTree(document); - await SyntaxTreeIndex.PrecalculateAsync(document, default).ConfigureAwait(false); + await SyntaxTreeIndex.GetIndexAsync(document, default).ConfigureAwait(false); } } Console.WriteLine("Serial: " + (DateTime.Now - start)); - Console.WriteLine("Precalculated count: " + SyntaxTreeIndex.PrecalculatedCount); - Console.WriteLine("Computed count: " + SyntaxTreeIndex.ComputedCount); Console.ReadLine(); } @@ -161,7 +159,7 @@ public async Task RunProjectParallelIndexing() async () => { // await WalkTree(d); - await TopLevelSyntaxTreeIndex.PrecalculateAsync(d, default); + await TopLevelSyntaxTreeIndex.GetIndexAsync(d, default); })).ToList(); await Task.WhenAll(tasks); } @@ -177,7 +175,7 @@ public async Task RunFullParallelIndexing() Console.WriteLine("Starting indexing"); var start = DateTime.Now; var tasks = _workspace.CurrentSolution.Projects.SelectMany(p => p.Documents).Select(d => Task.Run( - () => SyntaxTreeIndex.PrecalculateAsync(d, default))).ToList(); + () => SyntaxTreeIndex.GetIndexAsync(d, default))).ToList(); await Task.WhenAll(tasks); Console.WriteLine("Solution parallel: " + (DateTime.Now - start)); } @@ -201,7 +199,7 @@ public async Task RunNavigateTo() private async Task SearchAsync(Project project, ImmutableArray priorityDocuments) { - var service = project.LanguageServices.GetService(); + var service = project.Services.GetService(); var results = new List(); await service.SearchProjectAsync( project, priorityDocuments, "Syntax", service.KindsProvided, diff --git a/src/Tools/PrepareTests/PrepareTests.csproj b/src/Tools/PrepareTests/PrepareTests.csproj index 6ccdf0f041470..b0c04b5e2db3b 100644 --- a/src/Tools/PrepareTests/PrepareTests.csproj +++ b/src/Tools/PrepareTests/PrepareTests.csproj @@ -10,5 +10,8 @@ + + + diff --git a/src/Tools/PrepareTests/Program.cs b/src/Tools/PrepareTests/Program.cs index f012d3b71c12e..b5b34559c79d7 100644 --- a/src/Tools/PrepareTests/Program.cs +++ b/src/Tools/PrepareTests/Program.cs @@ -5,6 +5,8 @@ using System; using Mono.Options; +namespace PrepareTests; + internal static class Program { internal const int ExitFailure = 1; @@ -15,12 +17,14 @@ public static int Main(string[] args) string? source = null; string? destination = null; bool isUnix = false; + string? dotnetPath = null; var options = new OptionSet() { { "source=", "Path to binaries", (string s) => source = s }, { "destination=", "Output path", (string s) => destination = s }, - { "unix", "If true, prepares tests for unix environment instead of Windows", o => isUnix = o is object } + { "unix", "If true, prepares tests for unix environment instead of Windows", o => isUnix = o is object }, + { "dotnetPath=", "Path to the dotnet CLI", (string s) => dotnetPath = s }, }; options.Parse(args); @@ -36,6 +40,14 @@ public static int Main(string[] args) return ExitFailure; } + if (dotnetPath is null) + { + Console.Error.WriteLine("--dotnetPath argument must be provided"); + return ExitFailure; + } + + TestDiscovery.RunDiscovery(source, dotnetPath, isUnix); + MinimizeUtil.Run(source, destination, isUnix); return ExitSuccess; } diff --git a/src/Tools/PrepareTests/TestDiscovery.cs b/src/Tools/PrepareTests/TestDiscovery.cs new file mode 100644 index 0000000000000..86f2eafb79b98 --- /dev/null +++ b/src/Tools/PrepareTests/TestDiscovery.cs @@ -0,0 +1,127 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation 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; +using System.Diagnostics.Contracts; +using System.IO; +using System.Linq; +using System.Text.Json; +using Microsoft.TestPlatform.VsTestConsole.TranslationLayer; +using Microsoft.VisualStudio.TestPlatform.ObjectModel; +using Microsoft.VisualStudio.TestPlatform.ObjectModel.Client; +using Microsoft.VisualStudio.TestPlatform.ObjectModel.Logging; + +namespace PrepareTests; +internal class TestDiscovery +{ + public static void RunDiscovery(string repoRootDirectory, string dotnetPath, bool isUnix) + { + var binDirectory = Path.Combine(repoRootDirectory, "artifacts", "bin"); + var assemblies = GetAssemblies(binDirectory, isUnix); + + Console.WriteLine($"Found {assemblies.Count} test assemblies"); + + var vsTestConsole = Directory.EnumerateFiles(Path.Combine(Path.GetDirectoryName(dotnetPath)!, "sdk"), "vstest.console.dll", SearchOption.AllDirectories).OrderBy(s => s).Last(); + + var vstestConsoleWrapper = new VsTestConsoleWrapper(vsTestConsole, new ConsoleParameters + { + LogFilePath = Path.Combine(repoRootDirectory, "logs", "test_discovery_logs.txt"), + TraceLevel = TraceLevel.Error, + }); + + var discoveryHandler = new DiscoveryHandler(); + + var stopwatch = new Stopwatch(); + stopwatch.Start(); + vstestConsoleWrapper.DiscoverTests(assemblies, @"0", discoveryHandler); + stopwatch.Stop(); + + var tests = discoveryHandler.GetTests(); + + Console.WriteLine($"Discovered {tests.Length} tests in {stopwatch.Elapsed}"); + + stopwatch.Restart(); + var testGroupedByAssembly = tests.GroupBy(test => test.Source); + foreach (var assemblyGroup in testGroupedByAssembly) + { + var directory = Path.GetDirectoryName(assemblyGroup.Key); + + // Tests with combinatorial data are output multiple times with the same fully qualified test name. + // We only need to include it once as run all combinations under the same filter. + var testToWrite = assemblyGroup.Select(test => test.FullyQualifiedName).Distinct().ToList(); + + using var fileStream = File.Create(Path.Combine(directory!, "testlist.json")); + JsonSerializer.Serialize(fileStream, testToWrite); + } + stopwatch.Stop(); + Console.WriteLine($"Serialized tests in {stopwatch.Elapsed}"); + } + + private class DiscoveryHandler : ITestDiscoveryEventsHandler + { + private readonly ConcurrentBag _tests = new(); + private bool _isComplete = false; + + public void HandleDiscoveredTests(IEnumerable? discoveredTestCases) + { + if (discoveredTestCases != null) + { + foreach (var test in discoveredTestCases) + { + _tests.Add(test); + } + } + } + + public void HandleDiscoveryComplete(long totalTests, IEnumerable? lastChunk, bool isAborted) + { + if (lastChunk != null) + { + foreach (var test in lastChunk) + { + _tests.Add(test); + } + } + + _isComplete = true; + } + + public void HandleLogMessage(TestMessageLevel level, string? message) + { + Console.WriteLine(message); + } + + public void HandleRawMessage(string rawMessage) + { + } + + public ImmutableArray GetTests() + { + Contract.Assert(_isComplete); + return _tests.ToImmutableArray(); + } + } + + private static List GetAssemblies(string binDirectory, bool isUnix) + { + var unitTestAssemblies = Directory.GetFiles(binDirectory, "*.UnitTests.dll", SearchOption.AllDirectories).Where(ShouldInclude); + return unitTestAssemblies.ToList(); + + bool ShouldInclude(string path) + { + if (isUnix) + { + // Our unix build will build net framework dlls for multi-targeted projects. + // These are not valid testing on unix and discovery will throw if we try. + return Path.GetFileName(Path.GetDirectoryName(path)) != "net472"; + } + + return true; + } + } +} diff --git a/src/Tools/Source/CompilerGeneratorTools/Source/CSharpSyntaxGenerator/CachingSourceGenerator.cs b/src/Tools/Source/CompilerGeneratorTools/Source/CSharpSyntaxGenerator/CachingSourceGenerator.cs deleted file mode 100644 index 6872819048150..0000000000000 --- a/src/Tools/Source/CompilerGeneratorTools/Source/CSharpSyntaxGenerator/CachingSourceGenerator.cs +++ /dev/null @@ -1,116 +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. - -// We only build the Source Generator in the netstandard target -#if NETSTANDARD - -using System; -using System.Collections.Immutable; -using System.Diagnostics; -using System.Linq; -using System.Runtime.CompilerServices; -using System.Threading; -using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.Text; - -namespace CSharpSyntaxGenerator -{ - public abstract class CachingSourceGenerator : ISourceGenerator - { - /// - /// ⚠ This value may be accessed by multiple threads. - /// - private static readonly WeakReference s_cachedResult = new(null); - - protected abstract bool TryGetRelevantInput(in GeneratorExecutionContext context, out AdditionalText? input, out SourceText? inputText); - - protected abstract bool TryGenerateSources( - AdditionalText input, - SourceText inputText, - out ImmutableArray<(string hintName, SourceText sourceText)> sources, - out ImmutableArray diagnostics, - CancellationToken cancellationToken); - - public void Initialize(GeneratorInitializationContext context) - { - } - - public void Execute(GeneratorExecutionContext context) - { - if (!TryGetRelevantInput(in context, out var input, out var inputText)) - { - return; - } - - // Get the current input checksum, which will either be used for verifying the current cache or updating it - // with the new results. - var currentChecksum = inputText.GetChecksum(); - - // Read the current cached result once to avoid race conditions - if (s_cachedResult.TryGetTarget(out var cachedResult) - && cachedResult.Checksum.SequenceEqual(currentChecksum)) - { - // Add the previously-cached sources, and leave the cache as it was - AddSources(in context, sources: cachedResult.Sources); - return; - } - - if (TryGenerateSources(input, inputText, out var sources, out var diagnostics, context.CancellationToken)) - { - AddSources(in context, sources); - - if (diagnostics.IsEmpty) - { - var result = new CachedSourceGeneratorResult(currentChecksum, sources); - - // Default Large Object Heap size threshold - // https://github.com/dotnet/runtime/blob/c9d69e38d0e54bea5d188593ef6c3b30139f3ab1/src/coreclr/src/gc/gc.h#L111 - const int Threshold = 85000; - - // Overwrite the cached result with the new result. This is an opportunistic cache, so as long as - // the write is atomic (which it is for SetTarget) synchronization is unnecessary. We allocate an - // array on the Large Object Heap (which is always part of Generation 2) and give it a reference to - // the cached object to ensure this weak reference is not reclaimed prior to a full GC pass. - var largeArray = new CachedSourceGeneratorResult[Threshold / Unsafe.SizeOf()]; - Debug.Assert(GC.GetGeneration(largeArray) >= 2); - largeArray[0] = result; - s_cachedResult.SetTarget(result); - GC.KeepAlive(largeArray); - } - else - { - // Invalidate the cache since we cannot currently cache diagnostics - s_cachedResult.SetTarget(null); - } - } - else - { - // Invalidate the cache since generation failed - s_cachedResult.SetTarget(null); - } - - // Always report the diagnostics (if any) - foreach (var diagnostic in diagnostics) - { - context.ReportDiagnostic(diagnostic); - } - } - - private static void AddSources( - in GeneratorExecutionContext context, - ImmutableArray<(string hintName, SourceText sourceText)> sources) - { - foreach (var (hintName, sourceText) in sources) - { - context.AddSource(hintName, sourceText); - } - } - - private sealed record CachedSourceGeneratorResult( - ImmutableArray Checksum, - ImmutableArray<(string hintName, SourceText sourceText)> Sources); - } -} - -#endif diff --git a/src/Tools/Source/CompilerGeneratorTools/Source/CSharpSyntaxGenerator/SourceGenerator.cs b/src/Tools/Source/CompilerGeneratorTools/Source/CSharpSyntaxGenerator/SourceGenerator.cs index 6ef5b01266f72..e4590e6a99e0d 100644 --- a/src/Tools/Source/CompilerGeneratorTools/Source/CSharpSyntaxGenerator/SourceGenerator.cs +++ b/src/Tools/Source/CompilerGeneratorTools/Source/CSharpSyntaxGenerator/SourceGenerator.cs @@ -11,7 +11,6 @@ using System.Collections.Immutable; using System.IO; using System.Linq; -using System.Runtime.CompilerServices; using System.Text; using System.Threading; using System.Xml; @@ -22,7 +21,7 @@ namespace CSharpSyntaxGenerator { [Generator] - public sealed class SourceGenerator : CachingSourceGenerator + public sealed class SourceGenerator : IIncrementalGenerator { private static readonly DiagnosticDescriptor s_MissingSyntaxXml = new DiagnosticDescriptor( "CSSG1001", @@ -48,61 +47,64 @@ public sealed class SourceGenerator : CachingSourceGenerator defaultSeverity: DiagnosticSeverity.Error, isEnabledByDefault: true); - protected override bool TryGetRelevantInput(in GeneratorExecutionContext context, out AdditionalText? input, out SourceText? inputText) + public void Initialize(IncrementalGeneratorInitializationContext context) { - input = context.AdditionalFiles.SingleOrDefault(a => Path.GetFileName(a.Path) == "Syntax.xml"); - if (input == null) - { - context.ReportDiagnostic(Diagnostic.Create(s_MissingSyntaxXml, location: null)); - inputText = null; - return false; - } + var syntaxXmlFiles = context.AdditionalTextsProvider.Where(at => Path.GetFileName(at.Path) == "Syntax.xml").Collect(); - inputText = input.GetText(); - if (inputText == null) + context.RegisterSourceOutput(syntaxXmlFiles, static (context, syntaxXmlFiles) => { - context.ReportDiagnostic(Diagnostic.Create(s_UnableToReadSyntaxXml, location: null)); - return false; - } + var input = syntaxXmlFiles.SingleOrDefault(); + + if (input == null) + { + context.ReportDiagnostic(Diagnostic.Create(s_MissingSyntaxXml, location: null)); + return; + } + + var inputText = input.GetText(); + if (inputText == null) + { + context.ReportDiagnostic(Diagnostic.Create(s_UnableToReadSyntaxXml, location: null)); + return; + } + + Tree tree; + + try + { + var reader = XmlReader.Create(new SourceTextReader(inputText), new XmlReaderSettings { DtdProcessing = DtdProcessing.Prohibit }); + var serializer = new XmlSerializer(typeof(Tree)); + tree = (Tree)serializer.Deserialize(reader); + } + catch (InvalidOperationException ex) when (ex.InnerException is XmlException) + { + var xmlException = (XmlException)ex.InnerException; + + var line = inputText.Lines[xmlException.LineNumber - 1]; // LineNumber is one-based. + int offset = xmlException.LinePosition - 1; // LinePosition is one-based + var position = line.Start + offset; + var span = new TextSpan(position, 0); + var lineSpan = inputText.Lines.GetLinePositionSpan(span); + + context.ReportDiagnostic( + Diagnostic.Create( + s_SyntaxXmlError, + location: Location.Create(input.Path, span, lineSpan), + xmlException.Message)); + + return; - return true; + } + + DoGeneration(tree, context, context.CancellationToken); + }); } - protected override bool TryGenerateSources( - AdditionalText input, - SourceText inputText, - out ImmutableArray<(string hintName, SourceText sourceText)> sources, - out ImmutableArray diagnostics, + private static void DoGeneration( + Tree tree, + SourceProductionContext context, CancellationToken cancellationToken) { - Tree tree; - var reader = XmlReader.Create(new SourceTextReader(inputText), new XmlReaderSettings { DtdProcessing = DtdProcessing.Prohibit }); - - try - { - var serializer = new XmlSerializer(typeof(Tree)); - tree = (Tree)serializer.Deserialize(reader); - } - catch (InvalidOperationException ex) when (ex.InnerException is XmlException) - { - var xmlException = (XmlException)ex.InnerException; - - var line = inputText.Lines[xmlException.LineNumber - 1]; // LineNumber is one-based. - int offset = xmlException.LinePosition - 1; // LinePosition is one-based - var position = line.Start + offset; - var span = new TextSpan(position, 0); - var lineSpan = inputText.Lines.GetLinePositionSpan(span); - - sources = default; - diagnostics = ImmutableArray.Create( - Diagnostic.Create( - s_SyntaxXmlError, - location: Location.Create(input.Path, span, lineSpan), - xmlException.Message)); - - return false; - } - TreeFlattening.FlattenChildren(tree); var sourcesBuilder = ImmutableArray.CreateBuilder<(string hintName, SourceText sourceText)>(); @@ -110,10 +112,6 @@ protected override bool TryGenerateSources( addResult(writer => SourceWriter.WriteInternal(writer, tree, cancellationToken), "Syntax.xml.Internal.Generated.cs"); addResult(writer => SourceWriter.WriteSyntax(writer, tree, cancellationToken), "Syntax.xml.Syntax.Generated.cs"); - sources = sourcesBuilder.ToImmutable(); - diagnostics = ImmutableArray.Empty; - return true; - void addResult(Action writeFunction, string hintName) { // Write out the contents to a StringBuilder to avoid creating a single large string @@ -126,7 +124,7 @@ void addResult(Action writeFunction, string hintName) // And create a SourceText from the StringBuilder, once again avoiding allocating a single massive string var sourceText = SourceText.From(new StringBuilderReader(stringBuilder), stringBuilder.Length, encoding: Encoding.UTF8); - sourcesBuilder.Add((hintName, sourceText)); + context.AddSource(hintName, sourceText); } } diff --git a/src/Tools/Source/CompilerGeneratorTools/Source/VisualBasicSyntaxGenerator/GreenNodes/GreenNodeFactoryWriter.vb b/src/Tools/Source/CompilerGeneratorTools/Source/VisualBasicSyntaxGenerator/GreenNodes/GreenNodeFactoryWriter.vb index 73bf671515bbc..05b38ba086b8b 100644 --- a/src/Tools/Source/CompilerGeneratorTools/Source/VisualBasicSyntaxGenerator/GreenNodes/GreenNodeFactoryWriter.vb +++ b/src/Tools/Source/CompilerGeneratorTools/Source/VisualBasicSyntaxGenerator/GreenNodes/GreenNodeFactoryWriter.vb @@ -202,7 +202,7 @@ Friend Class GreenNodeFactoryWriter Dim kindsList = String.Join(", ", From kind In nodeStructure.NodeKinds Select kind.Name) - GenerateParameterXmlComment(_writer, "kind", String.Format("A representing the specific kind of {0}. One of {1}.", nodeStructure.Name, kindsList)) + GenerateParameterXmlComment(_writer, "kind", String.Format("A representing the specific kind of {0}. One of {1}.", nodeStructure.Name, kindsList)) End If If nodeStructure.IsTerminal Then diff --git a/src/Tools/Source/CompilerGeneratorTools/Source/VisualBasicSyntaxGenerator/RedNodes/RedNodeFactoryWriter.vb b/src/Tools/Source/CompilerGeneratorTools/Source/VisualBasicSyntaxGenerator/RedNodes/RedNodeFactoryWriter.vb index c4a8845345977..3b018f8bb39d1 100644 --- a/src/Tools/Source/CompilerGeneratorTools/Source/VisualBasicSyntaxGenerator/RedNodes/RedNodeFactoryWriter.vb +++ b/src/Tools/Source/CompilerGeneratorTools/Source/VisualBasicSyntaxGenerator/RedNodes/RedNodeFactoryWriter.vb @@ -342,7 +342,7 @@ Friend Class RedNodeFactoryWriter Dim kindsList = String.Join(", ", From kind In nodeStructure.NodeKinds Select kind.Name) - GenerateParameterXmlComment(_writer, "kind", String.Format("A representing the specific kind of {0}. One of {1}.", nodeStructure.Name, kindsList)) + GenerateParameterXmlComment(_writer, "kind", String.Format("A representing the specific kind of {0}. One of {1}.", nodeStructure.Name, kindsList)) End If If nodeStructure.IsTerminal Then @@ -668,7 +668,7 @@ Friend Class RedNodeFactoryWriter Dim kindsList = String.Join(", ", From kind In nodeStructure.NodeKinds Select kind.Name) - GenerateParameterXmlComment(_writer, "kind", String.Format("A representing the specific kind of {0}. One of {1}.", nodeStructure.Name, kindsList)) + GenerateParameterXmlComment(_writer, "kind", String.Format("A representing the specific kind of {0}. One of {1}.", nodeStructure.Name, kindsList)) End If If nodeStructure.IsTerminal Then diff --git a/src/Tools/Source/CompilerGeneratorTools/Source/VisualBasicSyntaxGenerator/Util/WriteUtils.vb b/src/Tools/Source/CompilerGeneratorTools/Source/VisualBasicSyntaxGenerator/Util/WriteUtils.vb index 378c4c831783f..8e7e02c0206f8 100644 --- a/src/Tools/Source/CompilerGeneratorTools/Source/VisualBasicSyntaxGenerator/Util/WriteUtils.vb +++ b/src/Tools/Source/CompilerGeneratorTools/Source/VisualBasicSyntaxGenerator/Util/WriteUtils.vb @@ -617,7 +617,7 @@ Public MustInherit Class WriteUtils text = XmlEscape(text) Else ' Ensure the text does not require escaping. - Dim filtered = text.Replace("", "").Replace("&", "").Replace("<", "").Replace(">", "") + Dim filtered = text.Replace("", "").Replace("&", "").Replace("<", "").Replace(">", "") Debug.Assert(filtered = XmlEscape(filtered)) End If diff --git a/src/Tools/Source/RunTests/AssemblyInfo.cs b/src/Tools/Source/RunTests/AssemblyInfo.cs new file mode 100644 index 0000000000000..1a1c898c01cb3 --- /dev/null +++ b/src/Tools/Source/RunTests/AssemblyInfo.cs @@ -0,0 +1,30 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Collections.Immutable; +using System.IO; + +namespace RunTests; + +public readonly record struct AssemblyInfo(string AssemblyPath) : IComparable +{ + public string AssemblyName => Path.GetFileName(AssemblyPath); + + public int CompareTo(AssemblyInfo other) + { + // Ensure we have a consistent ordering by ordering by assembly path. + return string.Compare(this.AssemblyPath, other.AssemblyPath, StringComparison.Ordinal); + } +} + +public readonly record struct TypeInfo(string Name, string FullyQualifiedName, ImmutableArray Tests) +{ + public override string ToString() => $"[Type]{FullyQualifiedName}"; +} + +public readonly record struct TestMethodInfo(string Name, string FullyQualifiedName, TimeSpan ExecutionTime) +{ + public override string ToString() => $"[Method]{FullyQualifiedName}"; +} diff --git a/src/Tools/Source/RunTests/AssemblyScheduler.cs b/src/Tools/Source/RunTests/AssemblyScheduler.cs index d724f7c1b17cb..5a1fa5c5206a1 100644 --- a/src/Tools/Source/RunTests/AssemblyScheduler.cs +++ b/src/Tools/Source/RunTests/AssemblyScheduler.cs @@ -2,359 +2,361 @@ // The .NET Foundation 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.Reflection.Metadata; using System.Reflection.PortableExecutable; -using System.Text; +using System.Text.Json; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.Test.Utilities; namespace RunTests { - internal readonly struct AssemblyInfo + internal record struct WorkItemInfo(ImmutableSortedDictionary> Filters, int PartitionIndex) { - internal PartitionInfo PartitionInfo { get; } - internal string TargetFramework { get; } - internal string Architecture { get; } - - internal string AssemblyPath => PartitionInfo.AssemblyPath; - internal string AssemblyName => Path.GetFileName(PartitionInfo.AssemblyPath); - internal string DisplayName => PartitionInfo.DisplayName; - - internal AssemblyInfo(PartitionInfo partitionInfo, string targetFramework, string architecture) - { - PartitionInfo = partitionInfo; - TargetFramework = targetFramework; - Architecture = architecture; - } + internal string DisplayName => $"{string.Join("_", Filters.Keys.Select(a => Path.GetFileNameWithoutExtension(a.AssemblyName)))}_{PartitionIndex}"; } - internal readonly struct PartitionInfo + internal sealed class AssemblyScheduler { - internal int? AssemblyPartitionId { get; } - internal string AssemblyPath { get; } - internal string DisplayName { get; } + /// + /// We attempt to partition our tests into work items that execute in under 2 minutes 30s. This is a derived limit based on a goal of running all tests + /// in under 5 minutes. However because of overhead in setting up the test run, e.g. + /// 1. Test discovery. + /// 2. Downloading assets to the helix machine. + /// 3. Setting up the test host for each assembly. + /// + /// we need to actually build partitions that run in under 5 minutes, hence our limit here of 2m30s. + /// + private static readonly TimeSpan s_maxExecutionTime = TimeSpan.FromSeconds(150); /// - /// Specific set of types to test in the assembly. Will be empty when testing the entire assembly + /// If we were unable to find the test execution history, we fall back to partitioning by just method count. /// - internal readonly ImmutableArray TypeInfoList; + private static readonly int s_maxMethodCount = 500; - internal PartitionInfo( - int assemblyPartitionId, - string assemblyPath, - string displayName, - ImmutableArray typeInfoList) - { - AssemblyPartitionId = assemblyPartitionId; - AssemblyPath = assemblyPath; - DisplayName = displayName; - TypeInfoList = typeInfoList; - } + private readonly Options _options; - internal PartitionInfo(string assemblyPath) + internal AssemblyScheduler(Options options) { - AssemblyPartitionId = null; - AssemblyPath = assemblyPath; - DisplayName = Path.GetFileName(assemblyPath); - TypeInfoList = ImmutableArray.Empty; + _options = options; } - public override string ToString() => DisplayName; - } - - public readonly struct TypeInfo - { - internal readonly string FullName; - internal readonly int MethodCount; - - internal TypeInfo(string fullName, int methodCount) + public async Task> ScheduleAsync(ImmutableArray assemblies, CancellationToken cancellationToken) { - FullName = fullName; - MethodCount = methodCount; - } - } - - internal sealed class AssemblyScheduler - { - /// - /// This is a test class inserted into assemblies to guard against a .NET desktop bug. The tests - /// inside of it counteract the underlying issue. If this test is included in any assembly it - /// must be added to every partition to ensure the work around is present - /// - /// https://github.com/dotnet/corefx/issues/3793 - /// https://github.com/dotnet/roslyn/issues/8936 - /// - private const string EventListenerGuardFullName = "Microsoft.CodeAnalysis.UnitTests.EventListenerGuard"; + Logger.Log($"Scheduling {assemblies.Length} assemblies"); - private static class AssemblyInfoBuilder - { - internal static void Build(string assemblyPath, int methodLimit, List typeInfoList, out ImmutableArray partitionInfoList) + if (_options.Sequential || !_options.UseHelix) { - var list = new List(); - var hasEventListenerGuard = typeInfoList.Any(x => x.FullName == EventListenerGuardFullName); - var currentTypeInfoList = new List(); - var currentClassNameLengthSum = -1; - var currentId = 0; - - BeginPartition(); + Logger.Log("Building work items with one assembly each."); + // return individual work items per assembly that contain all the tests in that assembly. + return CreateWorkItemsForFullAssemblies(assemblies); + } - foreach (var typeInfo in typeInfoList) - { - currentTypeInfoList.Add(typeInfo); - currentClassNameLengthSum += typeInfo.FullName.Length; - CheckForPartitionLimit(done: false); - } + var orderedTypeInfos = assemblies.ToImmutableSortedDictionary(assembly => assembly, GetTypeInfoList); - CheckForPartitionLimit(done: true); + ConsoleUtil.WriteLine($"Found {orderedTypeInfos.Values.SelectMany(t => t).SelectMany(t => t.Tests).Count()} tests to run in {orderedTypeInfos.Keys.Count()} assemblies"); - partitionInfoList = ImmutableArray.CreateRange(list); + // Retrieve test runtimes from azure devops historical data. + var testHistory = await TestHistoryManager.GetTestHistoryAsync(_options, cancellationToken); + if (testHistory.IsEmpty) + { + // We didn't have any test history from azure devops, just partition by test count. + ConsoleUtil.WriteLine($"##[warning]Could not look up test history - partitioning based on test count instead"); + var workItemsByMethodCount = BuildWorkItems( + orderedTypeInfos, + isOverLimitFunc: (accumulatedMethodCount) => accumulatedMethodCount >= s_maxMethodCount, + addFunc: (currentTest, accumulatedMethodCount) => accumulatedMethodCount + 1); + + LogWorkItems(workItemsByMethodCount); + return workItemsByMethodCount; + } - void BeginPartition() + // Now for our current set of test methods we got from the assemblies we built, match them to tests from our test run history + // so that we can extract an estimate of the test execution time for each test. + orderedTypeInfos = UpdateTestsWithExecutionTimes(orderedTypeInfos, testHistory); + + // Create work items by partitioning tests by historical execution time with the goal of running under our time limit. + // While we do our best to run tests from the same assembly together (by building work items in assembly order) it is expected + // that some work items will run tests from multiple assemblies due to large variances in test execution time. + var workItems = BuildWorkItems( + orderedTypeInfos, + isOverLimitFunc: (accumulatedExecutionTime) => accumulatedExecutionTime >= s_maxExecutionTime, + addFunc: (currentTest, accumulatedExecutionTime) => currentTest.ExecutionTime + accumulatedExecutionTime); + LogWorkItems(workItems); + return workItems; + + static ImmutableArray CreateWorkItemsForFullAssemblies(ImmutableArray assemblies) + { + var workItems = new List(); + var partitionIndex = 0; + foreach (var assembly in assemblies) { - currentId++; - currentTypeInfoList.Clear(); - currentClassNameLengthSum = 0; - - // Ensure the EventListenerGuard is in every partition. - if (hasEventListenerGuard) - { - currentClassNameLengthSum += EventListenerGuardFullName.Length; - } + var currentWorkItem = ImmutableSortedDictionary>.Empty.Add(assembly, ImmutableArray.Empty); + workItems.Add(new WorkItemInfo(currentWorkItem, partitionIndex++)); } - void CheckForPartitionLimit(bool done) - { - if (done) - { - // The builder is done looking at types. If there are any TypeInfo that have not - // been added to a partition then do it now. - if (currentTypeInfoList.Count > 0) - { - FinishPartition(); - } - - return; - } - - // One item we have to consider here is the maximum command line length in - // Windows which is 32767 characters (XP is smaller but don't care). Once - // we get close then create a partition and move on. - if (currentTypeInfoList.Sum(x => x.MethodCount) >= methodLimit || - currentClassNameLengthSum > 25000) - { - FinishPartition(); - BeginPartition(); - } - - void FinishPartition() - { - var partitionInfo = new PartitionInfo( - currentId, - assemblyPath, - $"{Path.GetFileName(assemblyPath)}.{currentId}", - ImmutableArray.CreateRange(currentTypeInfoList)); - list.Add(partitionInfo); - } - } + return workItems.ToImmutableArray(); } } - /// - /// Default number of methods to include per partition. - /// - internal const int DefaultMethodLimit = 2000; - - /// - /// Number of methods to include per Helix work item. - /// - internal const int HelixMethodLimit = 500; + private static ImmutableSortedDictionary> UpdateTestsWithExecutionTimes( + ImmutableSortedDictionary> assemblyTypes, + ImmutableDictionary testHistory) + { + // Determine the average execution time so that we can use it for tests that do not have any history. + var averageExecutionTime = TimeSpan.FromMilliseconds(testHistory.Values.Average(t => t.TotalMilliseconds)); - private readonly Options _options; - private readonly int _methodLimit; + // Store the tests we found locally that were missing remote historical data. + var unmatchedLocalTests = new HashSet(); - internal AssemblyScheduler(Options options) - { - _options = options; - _methodLimit = options.UseHelix ? AssemblyScheduler.HelixMethodLimit : AssemblyScheduler.DefaultMethodLimit; - } + // Store the tests we found in the remote historical data so we can report any we didn't find locally. + var matchedRemoteTests = new HashSet(); - public ImmutableArray Schedule(string assemblyPath, bool force = false) - { - if (_options.Sequential) - { - return ImmutableArray.Create(new PartitionInfo(assemblyPath)); - } + var updated = assemblyTypes.ToImmutableSortedDictionary( + kvp => kvp.Key, + kvp => kvp.Value.Select(WithTypeExecutionTime).ToImmutableArray()); - var typeInfoList = GetTypeInfoList(assemblyPath); - AssemblyInfoBuilder.Build(assemblyPath, _methodLimit, typeInfoList, out var partitionList); + LogResults(); + return updated; - // If the scheduling didn't actually produce multiple partition then send back an unpartitioned - // representation. - if (partitionList.Length == 1 && !force) + TypeInfo WithTypeExecutionTime(TypeInfo typeInfo) { - Logger.Log($"Assembly schedule produced a single partition {assemblyPath}"); - return ImmutableArray.Create(new PartitionInfo(assemblyPath)); + var tests = typeInfo.Tests.Select(WithTestExecutionTime).ToImmutableArray(); + return typeInfo with { Tests = tests }; } - Logger.Log($"Assembly Schedule: {Path.GetFileName(assemblyPath)}"); - foreach (var partition in partitionList) + TestMethodInfo WithTestExecutionTime(TestMethodInfo methodInfo) { - var methodCount = partition.TypeInfoList.Sum(x => x.MethodCount); - var delta = methodCount - _methodLimit; - Logger.Log($" Partition: {partition.AssemblyPartitionId} method count {methodCount} delta {delta}"); - foreach (var typeInfo in partition.TypeInfoList) + // Match by fully qualified test method name to azure devops historical data. + // Note for combinatorial tests, azure devops helpfully groups all sub-runs under a top level method (with combined test run times) with the same fully qualified method name + // that we get during test discovery. Since we only filter by the single method name (and not individual combinatorial runs) we do want the combined execution time. + if (testHistory.TryGetValue(methodInfo.FullyQualifiedName, out var executionTime)) { - Logger.Log($" {typeInfo.FullName} {typeInfo.MethodCount}"); + matchedRemoteTests.Add(methodInfo.FullyQualifiedName); + return methodInfo with { ExecutionTime = executionTime }; } - } - - return partitionList; - } - private static List GetTypeInfoList(string assemblyPath) - { - using (var stream = File.OpenRead(assemblyPath)) - using (var peReader = new PEReader(stream)) - { - var metadataReader = peReader.GetMetadataReader(); - return GetTypeInfoList(metadataReader); + // We didn't find the local type from our assembly in test run historical data. + // This usually occurs when tests have been added in between the last passing branch run and this PR. + unmatchedLocalTests.Add(methodInfo.FullyQualifiedName); + return methodInfo with { ExecutionTime = averageExecutionTime }; } - } - private static List GetTypeInfoList(MetadataReader reader) - { - var list = new List(); - foreach (var handle in reader.TypeDefinitions) + void LogResults() { - var type = reader.GetTypeDefinition(handle); - if (!IsValidIdentifier(reader, type.Name)) + foreach (var unmatchedLocalTest in unmatchedLocalTests) { - continue; + Logger.Log($"Could not find test execution history for test {unmatchedLocalTest}"); } - var methodCount = GetMethodCount(reader, type); - if (!ShouldIncludeType(reader, type, methodCount)) + var unmatchedRemoteTests = testHistory.Keys.Where(type => !matchedRemoteTests.Contains(type)); + foreach (var unmatchedRemoteTest in unmatchedRemoteTests) { - continue; + Logger.Log($"Found historical data for test {unmatchedRemoteTest} that was not present in local assemblies"); } - var fullName = GetFullName(reader, type); - list.Add(new TypeInfo(fullName, methodCount)); - } + var allTests = assemblyTypes.Values.SelectMany(v => v).SelectMany(v => v.Tests).Select(t => t.FullyQualifiedName).ToList(); - // Ensure we get classes back in a deterministic order. - list.Sort((x, y) => x.FullName.CompareTo(y.FullName)); - return list; + var totalExpectedRunTime = TimeSpan.FromMilliseconds(updated.Values.SelectMany(types => types).SelectMany(type => type.Tests).Sum(test => test.ExecutionTime.TotalMilliseconds)); + ConsoleUtil.WriteLine($"{unmatchedLocalTests.Count} tests were missing historical data. {unmatchedRemoteTests.Count()} tests were missing in local assemblies. Estimate of total execution time for tests is {totalExpectedRunTime}."); + } } - /// - /// Determine if this type should be one of the class values passed to xunit. This - /// code doesn't actually resolve base types or trace through inherrited Fact attributes - /// hence we have to error on the side of including types with no tests vs. excluding them. - /// - private static bool ShouldIncludeType(MetadataReader reader, TypeDefinition type, int testMethodCount) + private ImmutableArray BuildWorkItems( + ImmutableSortedDictionary> typeInfos, + Func isOverLimitFunc, + Func addFunc) where TWeight : struct { - // xunit only handles public, non-abstract classes - var isPublic = - TypeAttributes.Public == (type.Attributes & TypeAttributes.Public) || - TypeAttributes.NestedPublic == (type.Attributes & TypeAttributes.NestedPublic); - if (!isPublic || - TypeAttributes.Abstract == (type.Attributes & TypeAttributes.Abstract) || - TypeAttributes.Class != (type.Attributes & TypeAttributes.Class)) - { - return false; - } + var workItems = new List(); + + // Keep track of which work item we are creating - used to identify work items in names. + var workItemIndex = 0; + + // Keep track of the limit of the current work item we are adding to. + var accumulatedValue = default(TWeight); + + // Keep track of the types we're planning to add to the current work item. + var currentFilters = new SortedDictionary>(); - // Compiler generated types / methods have the shape of the heuristic that we are looking - // at here. Filter them out as well. - if (!IsValidIdentifier(reader, type.Name)) + // First find any assemblies we need to run in single assembly work items (due to state sharing concerns). + var singlePartitionAssemblies = typeInfos.Where(kvp => ShouldPartitionInSingleWorkItem(kvp.Key.AssemblyPath)); + typeInfos = typeInfos.RemoveRange(singlePartitionAssemblies.Select(kvp => kvp.Key)); + foreach (var (assembly, types) in singlePartitionAssemblies) { - return false; + Logger.Log($"Building single assembly work item {workItemIndex} for {assembly.AssemblyPath}"); + types.SelectMany(t => t.Tests).ToList().ForEach(test => AddFilter(assembly, test)); + + // End the work item so we don't include anything after this assembly. + AddCurrentWorkItem(); } - if (testMethodCount > 0) + // Iterate through each assembly and type and build up the work items to run. + // We add types from assemblies one by one until we hit our limit, + // at which point we create a work item with the current types and start a new one. + foreach (var (assembly, types) in typeInfos) { - return true; + foreach (var type in types) + { + foreach (var test in type.Tests) + { + // Get a new value representing the value from the test plus the accumulated value in the work item. + var newAccumulatedValue = addFunc(test, accumulatedValue); + + // If the new accumulated value is greater than the limit + if (isOverLimitFunc(newAccumulatedValue)) + { + // Adding this type would put us over the time limit for this partition. + // Add the current work item to our list and start a new one. + AddCurrentWorkItem(); + } + + // Update the current group in the work item with this new type. + AddFilter(assembly, test); + } + } } - // The case we still have to consider at this point is a class with 0 defined methods, - // inheritting from a class with > 0 defined test methods. That is a completely valid - // xunit scenario. For now we're just going to exclude types that inherit from object - // or other built-in base types because they clearly don't fit that category. - return !InheritsFromFrameworkBaseType(reader, type); - } + // Add any remaining tests to the work item. + AddCurrentWorkItem(); + return workItems.ToImmutableArray(); - private static int GetMethodCount(MetadataReader reader, TypeDefinition type) - { - var count = 0; - foreach (var handle in type.GetMethods()) + void AddCurrentWorkItem() { - var methodDefinition = reader.GetMethodDefinition(handle); - if (methodDefinition.GetCustomAttributes().Count == 0 || - !IsValidIdentifier(reader, methodDefinition.Name)) + if (currentFilters.Any()) { - continue; + workItems.Add(new WorkItemInfo(currentFilters.ToImmutableSortedDictionary(kvp => kvp.Key, kvp => kvp.Value.ToImmutableArray()), workItemIndex)); + workItemIndex++; } - count++; + currentFilters.Clear(); + accumulatedValue = default; } - return count; + void AddFilter(AssemblyInfo assembly, TestMethodInfo test) + { + if (currentFilters.TryGetValue(assembly, out var assemblyFilters)) + { + assemblyFilters.Add(test); + } + else + { + var filterList = new List + { + test + }; + currentFilters.Add(assembly, filterList); + } + + accumulatedValue = addFunc(test, accumulatedValue); + } } - private static bool IsValidIdentifier(MetadataReader reader, StringHandle handle) + + private static void LogWorkItems(ImmutableArray workItems) { - var name = reader.GetString(handle); - for (int i = 0; i < name.Length; i++) + ConsoleUtil.WriteLine($"Built {workItems.Length} work items"); + Logger.Log("==== Work Item List ===="); + foreach (var workItem in workItems) { - switch (name[i]) + var totalExecutionTime = TimeSpan.FromMilliseconds(workItem.Filters.Values.SelectMany(f => f).Sum(f => f.ExecutionTime.TotalMilliseconds)); + Logger.Log($"- Work Item {workItem.PartitionIndex} (Execution time {totalExecutionTime})"); + if (totalExecutionTime > s_maxExecutionTime) { - case '<': - case '>': - case '$': - return false; + // Log a warning to the console with work item details when we were not able to partition in under our limit. + // This can happen when a single specific test exceeds our execution time limit. + ConsoleUtil.WriteLine($"##[warning]Work item {workItem.PartitionIndex} estimated execution {totalExecutionTime} time exceeds max execution time {s_maxExecutionTime}."); + LogFilters(workItem, ConsoleUtil.WriteLine); + } + else + { + LogFilters(workItem, Logger.Log); } } - return true; + static void LogFilters(WorkItemInfo workItem, Action logger) + { + foreach (var assembly in workItem.Filters) + { + var assemblyRuntime = TimeSpan.FromMilliseconds(assembly.Value.Sum(f => f.ExecutionTime.TotalMilliseconds)); + logger($" - {assembly.Key.AssemblyName} with execution time {assemblyRuntime}"); + var testFilters = assembly.Value; + if (testFilters.Length > 0) + { + logger($" - {testFilters.Length} tests: {string.Join(",", testFilters.Select(t => t.FullyQualifiedName))}"); + } + } + } } - private static bool InheritsFromFrameworkBaseType(MetadataReader reader, TypeDefinition type) + private static ImmutableArray GetTypeInfoList(AssemblyInfo assemblyInfo) { - if (type.BaseType.Kind != HandleKind.TypeReference) + var assemblyDirectory = Path.GetDirectoryName(assemblyInfo.AssemblyPath); + var testListPath = Path.Combine(assemblyDirectory!, "testlist.json"); + if (!File.Exists(testListPath)) { - return false; + throw new ArgumentException($"{testListPath} does not exist"); } - var typeRef = reader.GetTypeReference((TypeReferenceHandle)type.BaseType); - return - reader.GetString(typeRef.Namespace) == "System" && - reader.GetString(typeRef.Name) is "Object" or "ValueType" or "Enum"; - } + var deserialized = JsonSerializer.Deserialize>(File.ReadAllText(testListPath)); + if (deserialized == null) + { + throw new InvalidOperationException($"Could not deserialize {testListPath}"); + } - private static string GetFullName(MetadataReader reader, TypeDefinition type) - { - var typeName = reader.GetString(type.Name); + var tests = deserialized.GroupBy(GetTypeName) + .Select(group => new TypeInfo(GetName(group.Key), group.Key, group.Select(test => new TestMethodInfo(GetName(test), test, TimeSpan.Zero)).ToImmutableArray())) + .ToImmutableArray(); + return tests; - if (TypeAttributes.NestedPublic == (type.Attributes & TypeAttributes.NestedPublic)) + static string GetTypeName(string fullyQualifiedTestName) { - // Need to take into account the containing type. - var declaringType = reader.GetTypeDefinition(type.GetDeclaringType()); - var declaringTypeFullName = GetFullName(reader, declaringType); - return $"{declaringTypeFullName}+{typeName}"; + var periodBeforeMethod = fullyQualifiedTestName.LastIndexOf("."); + return fullyQualifiedTestName[..periodBeforeMethod]; } - var namespaceName = reader.GetString(type.Namespace); - if (string.IsNullOrEmpty(namespaceName)) + static string GetName(string fullyQualifiedName) { - return typeName; + var lastPeriod = fullyQualifiedName.LastIndexOf("."); + return fullyQualifiedName[(lastPeriod + 1)..]; + } + } + + /// + /// Looks for the assembly marker attribute + /// that signifies tests in the assembly must be run separately. + /// + private static bool ShouldPartitionInSingleWorkItem(string assemblyPath) + { + using (var stream = File.OpenRead(assemblyPath)) + using (var peReader = new PEReader(stream)) + { + var metadataReader = peReader.GetMetadataReader(); + var attributes = metadataReader.GetAssemblyDefinition().GetCustomAttributes(); + foreach (var attributeHandle in attributes) + { + var attribute = metadataReader.GetCustomAttribute(attributeHandle); + if (attribute.Constructor.Kind is HandleKind.MemberReference) + { + var ctor = metadataReader.GetMemberReference((MemberReferenceHandle)attribute.Constructor); + if (ctor.Parent.Kind is HandleKind.TypeReference) + { + var typeNameHandle = metadataReader.GetTypeReference((TypeReferenceHandle)ctor.Parent).Name; + var typeName = metadataReader.GetString(typeNameHandle); + if (typeName == nameof(RunTestsInSinglePartitionAttribute)) + { + return true; + } + } + } + } } - return $"{namespaceName}.{typeName}"; + return false; } } } diff --git a/src/Tools/Source/RunTests/ITestExecutor.cs b/src/Tools/Source/RunTests/ITestExecutor.cs index 91e669b6c0bf6..8860870bd9cc4 100644 --- a/src/Tools/Source/RunTests/ITestExecutor.cs +++ b/src/Tools/Source/RunTests/ITestExecutor.cs @@ -4,24 +4,21 @@ using System; using System.Collections.Immutable; -using System.IO; namespace RunTests { internal readonly struct TestExecutionOptions { internal string DotnetFilePath { get; } - internal ProcDumpInfo? ProcDumpInfo { get; } internal string TestResultsDirectory { get; } internal string? TestFilter { get; } internal bool IncludeHtml { get; } internal bool Retry { get; } internal bool CollectDumps { get; } - internal TestExecutionOptions(string dotnetFilePath, ProcDumpInfo? procDumpInfo, string testResultsDirectory, string? testFilter, bool includeHtml, bool retry, bool collectDumps) + internal TestExecutionOptions(string dotnetFilePath, string testResultsDirectory, string? testFilter, bool includeHtml, bool retry, bool collectDumps) { DotnetFilePath = dotnetFilePath; - ProcDumpInfo = procDumpInfo; TestResultsDirectory = testResultsDirectory; TestFilter = testFilter; IncludeHtml = includeHtml; @@ -69,7 +66,7 @@ internal TestResultInfo(int exitCode, string? resultsFilePath, string? htmlResul internal readonly struct TestResult { internal TestResultInfo TestResultInfo { get; } - internal AssemblyInfo AssemblyInfo { get; } + internal WorkItemInfo WorkItemInfo { get; } internal string CommandLine { get; } internal string? Diagnostics { get; } @@ -78,9 +75,7 @@ internal readonly struct TestResult /// internal ImmutableArray ProcessResults { get; } - internal string AssemblyPath => AssemblyInfo.AssemblyPath; - internal string AssemblyName => Path.GetFileName(AssemblyPath); - internal string DisplayName => AssemblyInfo.DisplayName; + internal string DisplayName => WorkItemInfo.DisplayName; internal bool Succeeded => ExitCode == 0; internal int ExitCode => TestResultInfo.ExitCode; internal TimeSpan Elapsed => TestResultInfo.Elapsed; @@ -88,9 +83,9 @@ internal readonly struct TestResult internal string ErrorOutput => TestResultInfo.ErrorOutput; internal string? ResultsDisplayFilePath => TestResultInfo.HtmlResultsFilePath ?? TestResultInfo.ResultsFilePath; - internal TestResult(AssemblyInfo assemblyInfo, TestResultInfo testResultInfo, string commandLine, ImmutableArray processResults = default, string? diagnostics = null) + internal TestResult(WorkItemInfo workItemInfo, TestResultInfo testResultInfo, string commandLine, ImmutableArray processResults = default, string? diagnostics = null) { - AssemblyInfo = assemblyInfo; + WorkItemInfo = workItemInfo; TestResultInfo = testResultInfo; CommandLine = commandLine; ProcessResults = processResults.IsDefault ? ImmutableArray.Empty : processResults; diff --git a/src/Tools/Source/RunTests/Options.cs b/src/Tools/Source/RunTests/Options.cs index 23e1855ed40e3..7720a4d3bed33 100644 --- a/src/Tools/Source/RunTests/Options.cs +++ b/src/Tools/Source/RunTests/Options.cs @@ -6,6 +6,7 @@ using System.CodeDom.Compiler; using System.Collections.Generic; using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.IO; using System.Linq; using System.Runtime.InteropServices; @@ -103,6 +104,12 @@ internal class Options public string Architecture { get; set; } + public string? AccessToken { get; set; } + + public string? PhaseName { get; set; } + + public string? TargetBranchName { get; set; } + public Options( string dotnetFilePath, string artifactsDirectory, @@ -140,6 +147,9 @@ public Options( var collectDumps = false; string? procDumpFilePath = null; string? artifactsPath = null; + string? accessToken = null; + string? phaseName = null; + string? targetBranchName = null; var optionSet = new OptionSet() { { "dotnet=", "Path to dotnet", (string s) => dotnetFilePath = s }, @@ -161,6 +171,9 @@ public Options( { "procdumppath=", "Path to procdump", (string s) => procDumpFilePath = s }, { "collectdumps", "Whether or not to gather dumps on timeouts and crashes", o => collectDumps = o is object }, { "retry", "Retry failed test a few times", o => retry = o is object }, + { "accessToken=", "Pipeline access token with permissions to view test history", (string s) => accessToken = s }, + { "phaseName=", "Pipeline phase name associated with this test run", (string s) => phaseName = s }, + { "targetBranchName=", "Target branch of this pipeline run", (string s) => targetBranchName = s }, }; List assemblyList; @@ -237,6 +250,9 @@ public Options( TestFilter = testFilter, Timeout = timeout is { } t ? TimeSpan.FromMinutes(t) : null, Retry = retry, + AccessToken = accessToken, + PhaseName = phaseName, + TargetBranchName = targetBranchName, }; static string? TryGetArtifactsPath() diff --git a/src/Tools/Source/RunTests/ProcDumpUtil.cs b/src/Tools/Source/RunTests/ProcDumpUtil.cs index efcb7b1b77b79..6fe289137063a 100644 --- a/src/Tools/Source/RunTests/ProcDumpUtil.cs +++ b/src/Tools/Source/RunTests/ProcDumpUtil.cs @@ -12,44 +12,6 @@ namespace RunTests { - internal readonly struct ProcDumpInfo - { - private const string KeyProcDumpFilePath = "ProcDumpFilePath"; - private const string KeyProcDumpDirectory = "ProcDumpOutputPath"; - - internal string ProcDumpFilePath { get; } - internal string DumpDirectory { get; } - - internal ProcDumpInfo(string procDumpFilePath, string dumpDirectory) - { - Debug.Assert(Path.IsPathRooted(procDumpFilePath)); - Debug.Assert(Path.IsPathRooted(dumpDirectory)); - ProcDumpFilePath = procDumpFilePath; - DumpDirectory = dumpDirectory; - } - - internal void WriteEnvironmentVariables(Dictionary environment) - { - environment[KeyProcDumpFilePath] = ProcDumpFilePath; - environment[KeyProcDumpDirectory] = DumpDirectory; - } - - internal static ProcDumpInfo? ReadFromEnvironment() - { - bool validate([NotNullWhen(true)] string? s) => !string.IsNullOrEmpty(s) && Path.IsPathRooted(s); - - var procDumpFilePath = Environment.GetEnvironmentVariable(KeyProcDumpFilePath); - var dumpDirectory = Environment.GetEnvironmentVariable(KeyProcDumpDirectory); - - if (!validate(procDumpFilePath) || !validate(dumpDirectory)) - { - return null; - } - - return new ProcDumpInfo(procDumpFilePath, dumpDirectory); - } - } - internal static class DumpUtil { #pragma warning disable CA1416 // Validate platform compatibility @@ -81,35 +43,4 @@ internal static bool IsAdministrator() } #pragma warning restore CA1416 // Validate platform compatibility } - - internal static class ProcDumpUtil - { - internal static Process AttachProcDump(ProcDumpInfo procDumpInfo, int processId) - { - return AttachProcDump(procDumpInfo.ProcDumpFilePath, processId, procDumpInfo.DumpDirectory); - } - - internal static string GetProcDumpCommandLine(int processId, string dumpDirectory) - { - // /accepteula command line option to automatically accept the Sysinternals license agreement. - // -ma Write a 'Full' dump file. Includes All the Image, Mapped and Private memory. - // -e Write a dump when the process encounters an unhandled exception. Include the 1 to create dump on first chance exceptions. - // -f C00000FD.STACK_OVERFLOWC Dump when a stack overflow first chance exception is encountered. - const string procDumpSwitches = "/accepteula -ma -e -f C00000FD.STACK_OVERFLOW"; - dumpDirectory = dumpDirectory.TrimEnd('\\'); - return $" {procDumpSwitches} {processId} \"{dumpDirectory}\""; - } - - /// - /// Attaches a new procdump.exe against the specified process. - /// - /// The path to the procdump executable - /// process id - /// destination directory for dumps - internal static Process AttachProcDump(string procDumpFilePath, int processId, string dumpDirectory) - { - Directory.CreateDirectory(dumpDirectory); - return Process.Start(procDumpFilePath, GetProcDumpCommandLine(processId, dumpDirectory)); - } - } } diff --git a/src/Tools/Source/RunTests/ProcessRunner.cs b/src/Tools/Source/RunTests/ProcessRunner.cs index 2ac1b555703e9..5921452ca5387 100644 --- a/src/Tools/Source/RunTests/ProcessRunner.cs +++ b/src/Tools/Source/RunTests/ProcessRunner.cs @@ -88,57 +88,57 @@ public static ProcessInfo CreateProcess( process.StartInfo = processStartInfo; process.OutputDataReceived += (s, e) => + { + if (e.Data != null) { - if (e.Data != null) - { - onOutputDataReceived?.Invoke(e); - outputLines.Add(e.Data); - } - }; + onOutputDataReceived?.Invoke(e); + outputLines.Add(e.Data); + } + }; process.ErrorDataReceived += (s, e) => + { + if (e.Data != null) { - if (e.Data != null) - { - errorLines.Add(e.Data); - } - }; + errorLines.Add(e.Data); + } + }; process.Exited += (s, e) => + { + // We must call WaitForExit to make sure we've received all OutputDataReceived/ErrorDataReceived calls + // or else we'll be returning a list we're still modifying. For paranoia, we'll start a task here rather + // than enter right back into the Process type and start a wait which isn't guaranteed to be safe. + Task.Run(() => { - // We must call WaitForExit to make sure we've received all OutputDataReceived/ErrorDataReceived calls - // or else we'll be returning a list we're still modifying. For paranoia, we'll start a task here rather - // than enter right back into the Process type and start a wait which isn't guaranteed to be safe. - Task.Run(() => - { - process.WaitForExit(); - var result = new ProcessResult( - process, - process.ExitCode, - new ReadOnlyCollection(outputLines), - new ReadOnlyCollection(errorLines)); - tcs.TrySetResult(result); - }, cancellationToken); - }; + process.WaitForExit(); + var result = new ProcessResult( + process, + process.ExitCode, + new ReadOnlyCollection(outputLines), + new ReadOnlyCollection(errorLines)); + tcs.TrySetResult(result); + }, cancellationToken); + }; var registration = cancellationToken.Register(() => + { + if (tcs.TrySetCanceled()) { - if (tcs.TrySetCanceled()) + // If the underlying process is still running, we should kill it + if (!process.HasExited) { - // If the underlying process is still running, we should kill it - if (!process.HasExited) + try { - try - { - process.Kill(); - } - catch (InvalidOperationException) - { - // Ignore, since the process is already dead - } + process.Kill(); + } + catch (InvalidOperationException) + { + // Ignore, since the process is already dead } } - }); + } + }); process.Start(); onProcessStartHandler?.Invoke(process); diff --git a/src/Tools/Source/RunTests/ProcessTestExecutor.cs b/src/Tools/Source/RunTests/ProcessTestExecutor.cs index 193d707d14228..0fe279eaa2bf4 100644 --- a/src/Tools/Source/RunTests/ProcessTestExecutor.cs +++ b/src/Tools/Source/RunTests/ProcessTestExecutor.cs @@ -8,6 +8,7 @@ using System.Collections.Generic; using System.Collections.Immutable; using System.IO; +using System.Linq; using System.Text; using System.Threading; using System.Threading.Tasks; @@ -18,73 +19,31 @@ namespace RunTests { internal sealed class ProcessTestExecutor { - public TestExecutionOptions Options { get; } - - internal ProcessTestExecutor(TestExecutionOptions options) + public static string BuildRspFileContents(WorkItemInfo workItem, Options options) { - Options = options; - } + var fileContentsBuilder = new StringBuilder(); - public string GetCommandLineArguments(AssemblyInfo assemblyInfo, bool useSingleQuotes, bool isHelix) - { - // http://www.gnu.org/software/bash/manual/html_node/Single-Quotes.html - // Single quotes are needed in bash to avoid the need to escape characters such as backtick (`) which are found in metadata names. - // Batch scripts don't need to worry about escaping backticks, but they don't support single quoted strings, so we have to use double quotes. - // We also need double quotes when building an arguments string for Process.Start in .NET Core so that splitting/unquoting works as expected. - var sep = useSingleQuotes ? "'" : @""""; - - var builder = new StringBuilder(); - builder.Append($@"test"); - builder.Append($@" {sep}{assemblyInfo.AssemblyName}{sep}"); - var typeInfoList = assemblyInfo.PartitionInfo.TypeInfoList; - if (typeInfoList.Length > 0 || !string.IsNullOrWhiteSpace(Options.TestFilter)) + // Add each assembly we want to test on a new line. + var assemblyPaths = workItem.Filters.Keys.Select(assembly => assembly.AssemblyPath); + foreach (var path in assemblyPaths) { - builder.Append($@" --filter {sep}"); - var any = false; - foreach (var typeInfo in typeInfoList) - { - MaybeAddSeparator(); - // https://docs.microsoft.com/en-us/dotnet/core/testing/selective-unit-tests?pivots=mstest#syntax - // We want to avoid matching other test classes whose names are prefixed with this test class's name. - // For example, avoid running 'AttributeTests_WellKnownMember', when the request here is to run 'AttributeTests'. - // We append a '.', assuming that all test methods in the class *will* match it, but not methods in other classes. - builder.Append(typeInfo.FullName); - builder.Append('.'); - } - builder.Append(sep); - - if (Options.TestFilter is object) - { - MaybeAddSeparator(); - builder.Append(Options.TestFilter); - } - - void MaybeAddSeparator(char separator = '|') - { - if (any) - { - builder.Append(separator); - } - - any = true; - } + fileContentsBuilder.AppendLine($"\"{path}\""); } - builder.Append($@" --arch {assemblyInfo.Architecture}"); - builder.Append($@" --framework {assemblyInfo.TargetFramework}"); - builder.Append($@" --logger {sep}xunit;LogFilePath={GetResultsFilePath(assemblyInfo, "xml")}{sep}"); - - if (Options.IncludeHtml) + fileContentsBuilder.AppendLine($@"/Platform:{options.Architecture}"); + fileContentsBuilder.AppendLine($@"/Logger:xunit;LogFilePath={GetResultsFilePath(workItem, options, "xml")}"); + if (options.IncludeHtml) { - builder.AppendFormat($@" --logger {sep}html;LogFileName={GetResultsFilePath(assemblyInfo, "html")}{sep}"); + fileContentsBuilder.AppendLine($@"/Logger:html;LogFileName={GetResultsFilePath(workItem, options, "html")}"); } - if (!Options.CollectDumps) + var blameOption = "CollectHangDump"; + if (!options.CollectDumps) { // The 'CollectDumps' option uses operating system features to collect dumps when a process crashes. We // only enable the test executor blame feature in remaining cases, as the latter relies on ProcDump and // interferes with automatic crash dump collection on Windows. - builder.Append(" --blame-crash"); + blameOption = "CollectDump;CollectHangDump"; } // The 25 minute timeout in integration tests accounts for the fact that VSIX deployment and/or experimental hive reset and @@ -94,57 +53,103 @@ void MaybeAddSeparator(char separator = '|') // // Helix timeout is 15 minutes as helix jobs fully timeout in 30minutes. So in order to capture dumps we need the timeout // to be 2x shorter than the expected test run time (15min) in case only the last test hangs. - var timeout = isHelix ? "15minutes" : "25minutes"; + var timeout = options.UseHelix ? "15minutes" : "25minutes"; + fileContentsBuilder.AppendLine($"/Blame:{blameOption};TestTimeout=15minutes;DumpType=full"); + + // Build the filter string + var filterStringBuilder = new StringBuilder(); + var filters = workItem.Filters.Values.SelectMany(filter => filter).Where(filter => !string.IsNullOrEmpty(filter.FullyQualifiedName)).ToImmutableArray(); + + if (filters.Length > 0 || !string.IsNullOrWhiteSpace(options.TestFilter)) + { + filterStringBuilder.Append("/TestCaseFilter:\""); + var any = false; + foreach (var filter in filters) + { + MaybeAddSeparator(); + filterStringBuilder.Append($"FullyQualifiedName={filter.FullyQualifiedName}"); + } + + if (options.TestFilter is not null) + { + MaybeAddSeparator(); + filterStringBuilder.Append(options.TestFilter); + } - builder.Append($" --blame-hang-dump-type full --blame-hang-timeout {timeout}"); + filterStringBuilder.Append('"'); + + void MaybeAddSeparator(char separator = '|') + { + if (any) + { + filterStringBuilder.Append(separator); + } - return builder.ToString(); + any = true; + } + } + + fileContentsBuilder.AppendLine(filterStringBuilder.ToString()); + return fileContentsBuilder.ToString(); + } + + private static string GetVsTestConsolePath(string dotnetPath) + { + var dotnetDir = Path.GetDirectoryName(dotnetPath)!; + var sdkDir = Path.Combine(dotnetDir, "sdk"); + var vsTestConsolePath = Directory.EnumerateFiles(sdkDir, "vstest.console.dll", SearchOption.AllDirectories).Last(); + return vsTestConsolePath; } - private string GetResultsFilePath(AssemblyInfo assemblyInfo, string suffix = "xml") + private static string GetResultsFilePath(WorkItemInfo workItemInfo, Options options, string suffix = "xml") { - var fileName = $"{assemblyInfo.DisplayName}_{assemblyInfo.TargetFramework}_{assemblyInfo.Architecture}_test_results.{suffix}"; - return Path.Combine(Options.TestResultsDirectory, fileName); + var fileName = $"WorkItem_{workItemInfo.PartitionIndex}_{options.Architecture}_test_results.{suffix}"; + return Path.Combine(options.TestResultsDirectory, fileName); } - public async Task RunTestAsync(AssemblyInfo assemblyInfo, CancellationToken cancellationToken) + public async Task RunTestAsync(WorkItemInfo workItemInfo, Options options, CancellationToken cancellationToken) { - var result = await RunTestAsyncInternal(assemblyInfo, retry: false, cancellationToken); + var result = await RunTestAsyncInternal(workItemInfo, options, isRetry: false, cancellationToken); // For integration tests (TestVsi), we make one more attempt to re-run failed tests. - if (Options.Retry && !HasBuiltInRetry(assemblyInfo) && !Options.IncludeHtml && !result.Succeeded) + if (options.Retry && !HasBuiltInRetry(workItemInfo) && !options.IncludeHtml && !result.Succeeded) { - return await RunTestAsyncInternal(assemblyInfo, retry: true, cancellationToken); + return await RunTestAsyncInternal(workItemInfo, options, isRetry: true, cancellationToken); } return result; - static bool HasBuiltInRetry(AssemblyInfo assemblyInfo) + static bool HasBuiltInRetry(WorkItemInfo workItemInfo) { // vs-extension-testing handles test retry internally. - return assemblyInfo.AssemblyName == "Microsoft.VisualStudio.LanguageServices.New.IntegrationTests.dll"; + return workItemInfo.Filters.Keys.Any(key => key.AssemblyName == "Microsoft.VisualStudio.LanguageServices.New.IntegrationTests.dll"); } } - private async Task RunTestAsyncInternal(AssemblyInfo assemblyInfo, bool retry, CancellationToken cancellationToken) + private async Task RunTestAsyncInternal(WorkItemInfo workItemInfo, Options options, bool isRetry, CancellationToken cancellationToken) { try { - var commandLineArguments = GetCommandLineArguments(assemblyInfo, useSingleQuotes: false, isHelix: false); - var resultsFilePath = GetResultsFilePath(assemblyInfo); + var rspFileContents = BuildRspFileContents(workItemInfo, options); + var rspFilePath = Path.Combine(Directory.GetCurrentDirectory(), $"vstest_{workItemInfo.PartitionIndex}.rsp"); + File.WriteAllText(rspFilePath, rspFileContents); + + var vsTestConsolePath = GetVsTestConsolePath(options.DotnetFilePath); + + var commandLineArguments = $"exec \"{vsTestConsolePath}\" @\"{rspFilePath}\""; + + var resultsFilePath = GetResultsFilePath(workItemInfo, options); var resultsDir = Path.GetDirectoryName(resultsFilePath); - var htmlResultsFilePath = Options.IncludeHtml ? GetResultsFilePath(assemblyInfo, "html") : null; + var htmlResultsFilePath = options.IncludeHtml ? GetResultsFilePath(workItemInfo, options, "html") : null; var processResultList = new List(); - ProcessInfo? procDumpProcessInfo = null; // NOTE: xUnit doesn't always create the log directory Directory.CreateDirectory(resultsDir!); // Define environment variables for processes started via ProcessRunner. var environmentVariables = new Dictionary(); - Options.ProcDumpInfo?.WriteEnvironmentVariables(environmentVariables); - if (retry && File.Exists(resultsFilePath)) + if (isRetry && File.Exists(resultsFilePath)) { ConsoleUtil.WriteLine("Starting a retry. Tests which failed will run a second time to reduce flakiness."); try @@ -176,27 +181,20 @@ private async Task RunTestAsyncInternal(AssemblyInfo assemblyInfo, b var start = DateTime.UtcNow; var dotnetProcessInfo = ProcessRunner.CreateProcess( ProcessRunner.CreateProcessStartInfo( - Options.DotnetFilePath, + options.DotnetFilePath, commandLineArguments, - workingDirectory: Path.GetDirectoryName(assemblyInfo.AssemblyPath), displayWindow: false, captureOutput: true, environmentVariables: environmentVariables), lowPriority: false, cancellationToken: cancellationToken); - Logger.Log($"Create xunit process with id {dotnetProcessInfo.Id} for test {assemblyInfo.DisplayName}"); + Logger.Log($"Create xunit process with id {dotnetProcessInfo.Id} for test {workItemInfo.DisplayName}"); var xunitProcessResult = await dotnetProcessInfo.Result; var span = DateTime.UtcNow - start; - Logger.Log($"Exit xunit process with id {dotnetProcessInfo.Id} for test {assemblyInfo.DisplayName} with code {xunitProcessResult.ExitCode}"); + Logger.Log($"Exit xunit process with id {dotnetProcessInfo.Id} for test {workItemInfo.DisplayName} with code {xunitProcessResult.ExitCode}"); processResultList.Add(xunitProcessResult); - if (procDumpProcessInfo != null) - { - var procDumpProcessResult = await procDumpProcessInfo.Value.Result; - Logger.Log($"Exit procdump process with id {procDumpProcessInfo.Value.Id} for {dotnetProcessInfo.Id} for test {assemblyInfo.DisplayName} with code {procDumpProcessResult.ExitCode}"); - processResultList.Add(procDumpProcessResult); - } if (xunitProcessResult.ExitCode != 0) { @@ -223,7 +221,7 @@ private async Task RunTestAsyncInternal(AssemblyInfo assemblyInfo, b } } - Logger.Log($"Command line {assemblyInfo.DisplayName} completed in {span.TotalSeconds} seconds: {Options.DotnetFilePath} {commandLineArguments}"); + Logger.Log($"Command line {workItemInfo.DisplayName} completed in {span.TotalSeconds} seconds: {options.DotnetFilePath} {commandLineArguments}"); var standardOutput = string.Join(Environment.NewLine, xunitProcessResult.OutputLines) ?? ""; var errorOutput = string.Join(Environment.NewLine, xunitProcessResult.ErrorLines) ?? ""; @@ -236,14 +234,14 @@ private async Task RunTestAsyncInternal(AssemblyInfo assemblyInfo, b errorOutput: errorOutput); return new TestResult( - assemblyInfo, + workItemInfo, testResultInfo, commandLineArguments, processResults: ImmutableArray.CreateRange(processResultList)); } catch (Exception ex) { - throw new Exception($"Unable to run {assemblyInfo.AssemblyPath} with {Options.DotnetFilePath}. {ex}"); + throw new Exception($"Unable to run {workItemInfo.DisplayName} with {options.DotnetFilePath}. {ex}"); } } } diff --git a/src/Tools/Source/RunTests/Program.cs b/src/Tools/Source/RunTests/Program.cs index aaef3bd7eda5f..e3dce964d07be 100644 --- a/src/Tools/Source/RunTests/Program.cs +++ b/src/Tools/Source/RunTests/Program.cs @@ -6,13 +6,13 @@ using System; using System.Collections.Generic; +using System.Collections.Immutable; +using System.Diagnostics; using System.IO; using System.Linq; +using System.Text.RegularExpressions; using System.Threading; using System.Threading.Tasks; -using System.Collections.Immutable; -using System.Diagnostics; -using System.Text.RegularExpressions; namespace RunTests { @@ -126,23 +126,23 @@ private static async Task RunAsync(Options options, TimeSpan timeout, Cance private static async Task RunAsync(Options options, CancellationToken cancellationToken) { - var testExecutor = CreateTestExecutor(options); + var testExecutor = new ProcessTestExecutor(); var testRunner = new TestRunner(options, testExecutor); var start = DateTime.Now; - var assemblyInfoList = GetAssemblyList(options); - if (assemblyInfoList.Count == 0) + var workItems = await GetWorkItemsAsync(options, cancellationToken); + if (workItems.Length == 0) { + WriteLogFile(options); ConsoleUtil.WriteLine(ConsoleColor.Red, "No assemblies to test"); return ExitFailure; } - var assemblyCount = assemblyInfoList.GroupBy(x => x.AssemblyPath).Count(); ConsoleUtil.WriteLine($"Proc dump location: {options.ProcDumpFilePath}"); - ConsoleUtil.WriteLine($"Running {assemblyCount} test assemblies in {assemblyInfoList.Count} partitions"); + ConsoleUtil.WriteLine($"Running tests in {workItems.Length} partitions"); var result = options.UseHelix - ? await testRunner.RunAllOnHelixAsync(assemblyInfoList, cancellationToken).ConfigureAwait(true) - : await testRunner.RunAllAsync(assemblyInfoList, cancellationToken).ConfigureAwait(true); + ? await testRunner.RunAllOnHelixAsync(workItems, options, cancellationToken).ConfigureAwait(true) + : await testRunner.RunAllAsync(workItems, cancellationToken).ConfigureAwait(true); var elapsed = DateTime.Now - start; ConsoleUtil.WriteLine($"Test execution time: {elapsed}"); @@ -253,16 +253,16 @@ async Task DumpProcess(Process targetProcess, string procDumpExeFilePath, string } } - if (options.CollectDumps && GetProcDumpInfo(options) is { } procDumpInfo) + if (options.CollectDumps && !string.IsNullOrEmpty(options.ProcDumpFilePath)) { ConsoleUtil.WriteLine("Roslyn Error: test timeout exceeded, dumping remaining processes"); var counter = 0; foreach (var proc in ProcessUtil.GetProcessTree(Process.GetCurrentProcess()).OrderBy(x => x.ProcessName)) { - var dumpDir = procDumpInfo.DumpDirectory; + var dumpDir = options.LogFilesDirectory; var dumpFilePath = Path.Combine(dumpDir, $"{proc.ProcessName}-{counter}.dmp"); - await DumpProcess(proc, procDumpInfo.ProcDumpFilePath, dumpFilePath); + await DumpProcess(proc, options.ProcDumpFilePath, dumpFilePath); counter++; } } @@ -270,84 +270,84 @@ async Task DumpProcess(Process targetProcess, string procDumpExeFilePath, string WriteLogFile(options); } - private static ProcDumpInfo? GetProcDumpInfo(Options options) - { - if (!string.IsNullOrEmpty(options.ProcDumpFilePath)) - { - return new ProcDumpInfo(options.ProcDumpFilePath, options.LogFilesDirectory); - } - - return null; - } - - private static List GetAssemblyList(Options options) + private static async Task> GetWorkItemsAsync(Options options, CancellationToken cancellationToken) { var scheduler = new AssemblyScheduler(options); - var list = new List(); var assemblyPaths = GetAssemblyFilePaths(options); - - foreach (var assemblyPath in assemblyPaths.OrderByDescending(x => new FileInfo(x.FilePath).Length)) - { - list.AddRange(scheduler.Schedule(assemblyPath.FilePath).Select(x => new AssemblyInfo(x, assemblyPath.TargetFramework, options.Architecture))); - } - - return list; + var workItems = await scheduler.ScheduleAsync(assemblyPaths, cancellationToken); + return workItems; } - private static List<(string FilePath, string TargetFramework)> GetAssemblyFilePaths(Options options) + private static ImmutableArray GetAssemblyFilePaths(Options options) { - var list = new List<(string, string)>(); + var list = new List(); var binDirectory = Path.Combine(options.ArtifactsDirectory, "bin"); foreach (var project in Directory.EnumerateDirectories(binDirectory, "*", SearchOption.TopDirectoryOnly)) { var name = Path.GetFileName(project); - var include = false; - foreach (var pattern in options.IncludeFilter) - { - if (Regex.IsMatch(name, pattern.Trim('\'', '"'))) - { - include = true; - } - } - - if (!include) + if (!shouldInclude(name, options) || shouldExclude(name, options)) { continue; } - foreach (var pattern in options.ExcludeFilter) - { - if (Regex.IsMatch(name, pattern.Trim('\'', '"'))) - { - continue; - } - } - var fileName = $"{name}.dll"; + // Find the dlls matching the request configuration and target frameworks. foreach (var targetFramework in options.TargetFrameworks) { - var fileContainingDirectory = Path.Combine(project, options.Configuration, targetFramework); - var filePath = Path.Combine(fileContainingDirectory, fileName); + var targetFrameworkDirectory = Path.Combine(project, options.Configuration, targetFramework); + var filePath = Path.Combine(targetFrameworkDirectory, fileName); if (File.Exists(filePath)) { - list.Add((filePath, targetFramework)); + list.Add(new AssemblyInfo(filePath)); } - else if (Directory.Exists(fileContainingDirectory) && Directory.GetFiles(fileContainingDirectory, searchPattern: "*.UnitTests.dll") is { Length: > 0 } matches) + else if (Directory.Exists(targetFrameworkDirectory) && Directory.GetFiles(targetFrameworkDirectory, searchPattern: "*.UnitTests.dll") is { Length: > 0 } matches) { // If the unit test assembly name doesn't match the project folder name, but still matches our "unit test" name pattern, we want to run it. // If more than one such assembly is present in a project output folder, we assume something is wrong with the build configuration. // For example, one unit test project might be referencing another unit test project. if (matches.Length > 1) { - var message = $"Multiple unit test assemblies found in '{fileContainingDirectory}'. Please adjust the build to prevent this. Matches:{Environment.NewLine}{string.Join(Environment.NewLine, matches)}"; + var message = $"Multiple unit test assemblies found in '{targetFrameworkDirectory}'. Please adjust the build to prevent this. Matches:{Environment.NewLine}{string.Join(Environment.NewLine, matches)}"; throw new Exception(message); } - list.Add((matches[0], targetFramework)); + list.Add(new AssemblyInfo(matches[0])); } } } - return list; + if (list.Count == 0) + { + throw new InvalidOperationException($"Did not find any test assemblies"); + } + + list.Sort(); + return list.ToImmutableArray(); + + static bool shouldInclude(string name, Options options) + { + foreach (var pattern in options.IncludeFilter) + { + if (Regex.IsMatch(name, pattern.Trim('\'', '"'))) + { + return true; + } + } + + return false; + } + + static bool shouldExclude(string name, Options options) + { + foreach (var pattern in options.ExcludeFilter) + { + if (Regex.IsMatch(name, pattern.Trim('\'', '"'))) + { + return true; + } + } + + return false; + } } private static void DisplayResults(Display display, ImmutableArray testResults) @@ -378,19 +378,6 @@ private static void DisplayResults(Display display, ImmutableArray t } } - private static ProcessTestExecutor CreateTestExecutor(Options options) - { - var testExecutionOptions = new TestExecutionOptions( - dotnetFilePath: options.DotnetFilePath, - procDumpInfo: options.CollectDumps ? GetProcDumpInfo(options) : null, - testResultsDirectory: options.TestResultsDirectory, - testFilter: options.TestFilter, - includeHtml: options.IncludeHtml, - retry: options.Retry, - collectDumps: options.CollectDumps); - return new ProcessTestExecutor(testExecutionOptions); - } - /// /// Checks the total size of dump file and removes files exceeding a limit. /// diff --git a/src/Tools/Source/RunTests/RunTests.csproj b/src/Tools/Source/RunTests/RunTests.csproj index f2e74fa95453e..4127eba2b292a 100644 --- a/src/Tools/Source/RunTests/RunTests.csproj +++ b/src/Tools/Source/RunTests/RunTests.csproj @@ -16,5 +16,7 @@ + + \ No newline at end of file diff --git a/src/Tools/Source/RunTests/TestHistoryManager.cs b/src/Tools/Source/RunTests/TestHistoryManager.cs new file mode 100644 index 0000000000000..1f27cb39d5ac2 --- /dev/null +++ b/src/Tools/Source/RunTests/TestHistoryManager.cs @@ -0,0 +1,207 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.TeamFoundation.Build.WebApi; +using Microsoft.TeamFoundation.TestManagement.WebApi; +using Microsoft.VisualStudio.Services.TestResults.WebApi; +using Microsoft.VisualStudio.Services.WebApi; + +namespace RunTests; +internal class TestHistoryManager +{ + /// + /// Azure devops limits the number of tests returned per request to 10000. + /// + private const int MaxTestsReturnedPerRequest = 10_000; + + /// + /// The pipeline id for roslyn-ci, see https://dev.azure.com/dnceng/public/_build?definitionId=15 + /// + private const int RoslynCiBuildDefinitionId = 15; + + /// + /// The Azure devops project that the build pipeline is located in. + /// + private static readonly Uri s_projectUri = new(@"https://dev.azure.com/dnceng"); + + /// + /// Looks up the last passing test run for the current build and stage to estimate execution times for each test. + /// + public static async Task> GetTestHistoryAsync(Options options, CancellationToken cancellationToken) + { + // Access token that has permissions to lookup test history. This typically comes from the pipeline. + + var accessToken = options.AccessToken ?? GetEnvironmentVariable("SYSTEM_ACCESSTOKEN"); + + // The phase name is used to filter the tests on the last passing build to only those that apply to the currently running phase. + // Note here that 'phaseName' corresponds to the 'jobName' defined in our pipeline yaml file and the job name env var is not correct. + // See https://developercommunity.visualstudio.com/t/systemjobname-seems-to-be-incorrectly-assigned-and/1209736 + var phaseName = options.PhaseName ?? GetEnvironmentVariable("SYSTEM_PHASENAME"); + + // We use the target branch of the current build to lookup the last successful build for the same branch. + var targetBranch = options.TargetBranchName ?? GetEnvironmentVariable("SYSTEM_PULLREQUEST_TARGETBRANCH") ?? GetEnvironmentVariable("BUILD_SOURCEBRANCHNAME"); + if (string.IsNullOrEmpty(accessToken) || string.IsNullOrEmpty(phaseName) || string.IsNullOrEmpty(targetBranch)) + { + ConsoleUtil.WriteLine($"Missing required options to lookup test history, accessToken={accessToken}, phaseName={phaseName}, targetBranchName={targetBranch}"); + return ImmutableDictionary.Empty; + } + + var credentials = new Microsoft.VisualStudio.Services.Common.VssBasicCredential(string.Empty, accessToken); + + var connection = new VssConnection(s_projectUri, credentials); + + using var buildClient = connection.GetClient(); + + ConsoleUtil.WriteLine($"Getting last successful build for branch {targetBranch}"); + var adoBranch = $"refs/heads/{targetBranch}"; + var lastSuccessfulBuild = await GetLastSuccessfulBuildAsync(RoslynCiBuildDefinitionId, adoBranch, buildClient, cancellationToken); + if (lastSuccessfulBuild == null) + { + // If this is a new branch we may not have any historical data for it. + ConsoleUtil.WriteLine($"Unable to get the last successful build for definition {RoslynCiBuildDefinitionId} and branch {targetBranch}"); + return ImmutableDictionary.Empty; + } + + using var testClient = connection.GetClient(); + var runForThisStage = await GetRunForStageAsync(lastSuccessfulBuild, phaseName, testClient, cancellationToken); + if (runForThisStage == null) + { + // If this is a new stage, historical runs will not have any data for it. + ConsoleUtil.WriteLine($"Unable to get a run with name {phaseName} from build {lastSuccessfulBuild.Url}."); + return ImmutableDictionary.Empty; + } + + ConsoleUtil.WriteLine($"Looking up test execution data for build {lastSuccessfulBuild.Id} on branch {targetBranch} and stage {phaseName}"); + + var totalTests = runForThisStage.TotalTests; + + Dictionary testInfos = new(); + var duplicateCount = 0; + + // Get runtimes for all tests. + var timer = new Stopwatch(); + timer.Start(); + for (var i = 0; i < totalTests; i += MaxTestsReturnedPerRequest) + { + var testResults = await GetTestResultsAsync(runForThisStage, i, MaxTestsReturnedPerRequest, testClient, cancellationToken); + foreach (var testResult in testResults) + { + // Helix outputs results for the whole dll work item suffixed with WorkItemExecution which we should ignore. + if (testResult.AutomatedTestName.Contains("WorkItemExecution")) + { + Logger.Log($"Skipping overall result for work item {testResult.AutomatedTestName}"); + continue; + } + + var testName = CleanTestName(testResult.AutomatedTestName); + + if (!testInfos.TryAdd(testName, TimeSpan.FromMilliseconds(testResult.DurationInMs))) + { + // We can get duplicate tests if a test file is included in multiple assemblies (e.g. analyzer codestyle tests). + // This is fine, we'll just use capture one of the run times since it is the same test being run in both cases and unlikely to have different run times. + // + // Another case that can happen is if a test is incorrectly authored to have the same name and namespace as a test in another assembly. For example + // a test that applies to both VB and C#, but the tests in both the C# and VB assembly accidentally use the C# namespace. + // It may have a different run time, but ADO does not let us differentiate by assembly name, so we just have to pick one. + duplicateCount++; + } + } + } + + timer.Stop(); + + if (duplicateCount > 0) + { + Logger.Log($"Found {duplicateCount} duplicate tests in run {runForThisStage.Name}."); + } + + var totalTestRuntime = TimeSpan.FromMilliseconds(testInfos.Values.Sum(t => t.TotalMilliseconds)); + ConsoleUtil.WriteLine($"Retrieved {testInfos.Keys.Count} tests from AzureDevops in {timer.Elapsed}. Total runtime of all tests is {totalTestRuntime}"); + return testInfos.ToImmutableDictionary(); + } + + private static string? GetEnvironmentVariable(string envVarName) + { + var envVar = Environment.GetEnvironmentVariable(envVarName); + if (string.IsNullOrEmpty(envVar)) + { + ConsoleUtil.WriteLine($"Missing environment variable {envVarName}"); + } + + return envVar; + } + + private static string CleanTestName(string fullyQualifiedTestName) + { + // Some test names contain test arguments, so take everything before the first paren (since they are not valid in the fully qualified test name). + var beforeMethodArgs = fullyQualifiedTestName.Split('(')[0]; + return beforeMethodArgs; + } + + private static async Task GetLastSuccessfulBuildAsync(int definitionId, string branchName, BuildHttpClient buildClient, CancellationToken cancellationToken) + { + try + { + var builds = await buildClient.GetBuildsAsync2( + project: "public", + new int[] { definitionId }, + resultFilter: BuildResult.Succeeded, + queryOrder: BuildQueryOrder.FinishTimeDescending, + maxBuildsPerDefinition: 1, + reasonFilter: BuildReason.IndividualCI, + branchName: branchName, + cancellationToken: cancellationToken); + return builds?.FirstOrDefault(); + } + catch (Exception ex) + { + // We will fallback to test count partitioning if we fail to query ADO. + ConsoleUtil.WriteLine($"Caught exception querying ADO for passing build: {ex}"); + return null; + } + } + + private static async Task GetRunForStageAsync(Build build, string phaseName, TestResultsHttpClient testClient, CancellationToken cancellationToken) + { + try + { + // API requires us to pass a time range to query runs for. So just pass the times from the build. + var minTime = build.QueueTime!.Value; + var maxTime = build.FinishTime!.Value; + var runsInBuild = await testClient.QueryTestRunsAsync2("public", minTime, maxTime, buildIds: new int[] { build.Id }, cancellationToken: cancellationToken); + + var runForThisStage = runsInBuild.SingleOrDefault(r => r.Name.Contains(phaseName)); + return runForThisStage; + } + catch (Exception ex) + { + // We will fallback to test count partitioning if we fail to query ADO. + ConsoleUtil.WriteLine($"Caught exception querying ADO for test runs: {ex}"); + return null; + } + } + + private static async Task> GetTestResultsAsync(TestRun testRun, int skip, int top, TestResultsHttpClient testClient, CancellationToken cancellationToken) + { + try + { + var testResults = await testClient.GetTestResultsAsync("public", testRun.Id, skip: skip, top: top, cancellationToken: cancellationToken); + return testResults ?? new List(); + } + catch (Exception ex) + { + // We will fallback to test count partitioning if we fail to query ADO. + ConsoleUtil.WriteLine($"Caught exception querying ADO for test runs: {ex}"); + return new List(); + } + } +} diff --git a/src/Tools/Source/RunTests/TestRunner.cs b/src/Tools/Source/RunTests/TestRunner.cs index 8bf1a7dd09c97..4e1212bdbb4c3 100644 --- a/src/Tools/Source/RunTests/TestRunner.cs +++ b/src/Tools/Source/RunTests/TestRunner.cs @@ -5,7 +5,6 @@ using System; using System.Collections.Generic; using System.Collections.Immutable; -using System.Collections.ObjectModel; using System.Diagnostics; using System.IO; using System.Linq; @@ -43,7 +42,7 @@ internal TestRunner(Options options, ProcessTestExecutor testExecutor) _options = options; } - internal async Task RunAllOnHelixAsync(IEnumerable assemblyInfoList, CancellationToken cancellationToken) + internal async Task RunAllOnHelixAsync(ImmutableArray workItems, Options options, CancellationToken cancellationToken) { var sourceBranch = Environment.GetEnvironmentVariable("BUILD_SOURCEBRANCH"); if (sourceBranch is null) @@ -59,10 +58,10 @@ internal async Task RunAllOnHelixAsync(IEnumerable a throw new IOException($@"Malformed ArtifactsDirectory in options: ""{_options.ArtifactsDirectory}"""); } - var isAzureDevOpsRun = Environment.GetEnvironmentVariable("SYSTEM_ACCESSTOKEN") is not null; + var isAzureDevOpsRun = Environment.GetEnvironmentVariable("BUILD_BUILDID") is not null; if (!isAzureDevOpsRun) { - ConsoleUtil.WriteLine("SYSTEM_ACCESSTOKEN environment variable was not set, so test results will not be published."); + ConsoleUtil.WriteLine("BUILD_BUILDID environment variable was not set, will not publish test results for a local run."); // in a local run we assume the user runs using the root test.sh and that the test payload is nested in the artifacts directory. msbuildTestPayloadRoot = Path.Combine(msbuildTestPayloadRoot, "artifacts/testPayload"); } @@ -95,7 +94,7 @@ internal async Task RunAllOnHelixAsync(IEnumerable a Environment.SetEnvironmentVariable("BUILD_REASON", "pr"); var buildNumber = Environment.GetEnvironmentVariable("BUILD_BUILDNUMBER") ?? "0"; - var workItems = assemblyInfoList.Select(ai => makeHelixWorkItemProject(ai)); + var helixWorkItems = workItems.Select(workItem => MakeHelixWorkItemProject(workItem)); var globalJson = JsonConvert.DeserializeAnonymousType(File.ReadAllText(getGlobalJsonPath()), new { sdk = new { version = "" } }) ?? throw new InvalidOperationException("Failed to deserialize global.json."); @@ -116,7 +115,7 @@ internal async Task RunAllOnHelixAsync(IEnumerable a - " + correlationPayload + string.Join("", workItems) + @" + " + correlationPayload + string.Join("", helixWorkItems) + @" "; @@ -148,23 +147,46 @@ static string getGlobalJsonPath() throw new IOException($@"Could not find global.json by walking up from ""{AppContext.BaseDirectory}""."); } - string makeHelixWorkItemProject(AssemblyInfo assemblyInfo) + static void AddRehydrateTestFoldersCommand(StringBuilder commandBuilder, WorkItemInfo workItemInfo, bool isUnix) + { + // Rehydrate assemblies that we need to run as part of this work item. + foreach (var testAssembly in workItemInfo.Filters.Keys) + { + var directoryName = Path.GetDirectoryName(testAssembly.AssemblyPath); + if (isUnix) + { + // If we're on unix make sure we have permissions to run the rehydrate script. + commandBuilder.AppendLine($"chmod +x {directoryName}/rehydrate.sh"); + } + + commandBuilder.AppendLine(isUnix ? $"./{directoryName}/rehydrate.sh" : $@"call {directoryName}\rehydrate.cmd"); + commandBuilder.AppendLine(isUnix ? $"ls -l {directoryName}" : $"dir {directoryName}"); + } + } + + static string GetHelixRelativeAssemblyPath(string assemblyPath) + { + var tfmDir = Path.GetDirectoryName(assemblyPath)!; + var configurationDir = Path.GetDirectoryName(tfmDir)!; + var projectDir = Path.GetDirectoryName(configurationDir)!; + + var assemblyRelativePath = Path.Combine(Path.GetFileName(projectDir), Path.GetFileName(configurationDir), Path.GetFileName(tfmDir), Path.GetFileName(assemblyPath)); + return assemblyRelativePath; + } + + string MakeHelixWorkItemProject(WorkItemInfo workItemInfo) { // Currently, it's required for the client machine to use the same OS family as the target Helix queue. // We could relax this and allow for example Linux clients to kick off Windows jobs, but we'd have to // figure out solutions for issues such as creating file paths in the correct format for the target machine. var isUnix = !RuntimeInformation.IsOSPlatform(OSPlatform.Windows); - var commandLineArguments = _testExecutor.GetCommandLineArguments(assemblyInfo, useSingleQuotes: isUnix, isHelix: true); - commandLineArguments = SecurityElement.Escape(commandLineArguments); var setEnvironmentVariable = isUnix ? "export" : "set"; var command = new StringBuilder(); - command.AppendLine(isUnix ? "ls -l" : "dir"); - command.AppendLine(isUnix ? $"./rehydrate.sh" : $@"call .\rehydrate.cmd"); - command.AppendLine(isUnix ? "ls -l" : "dir"); command.AppendLine($"{setEnvironmentVariable} DOTNET_ROLL_FORWARD=LatestMajor"); command.AppendLine($"{setEnvironmentVariable} DOTNET_ROLL_FORWARD_TO_PRERELEASE=1"); + command.AppendLine(isUnix ? $"ls -l" : $"dir"); command.AppendLine("dotnet --info"); var knownEnvironmentVariables = new[] { "ROSLYN_TEST_IOPERATION", "ROSLYN_TEST_USEDASSEMBLIES" }; @@ -176,7 +198,46 @@ string makeHelixWorkItemProject(AssemblyInfo assemblyInfo) } } - command.AppendLine($"dotnet {commandLineArguments}"); + // Create a payload directory that contains all the assemblies in the work item in separate folders. + var payloadDirectory = Path.Combine(msbuildTestPayloadRoot, "artifacts", "bin"); + + // Update the assembly groups to test with the assembly paths in the context of the helix work item. + workItemInfo = workItemInfo with { Filters = workItemInfo.Filters.ToImmutableSortedDictionary(kvp => kvp.Key with { AssemblyPath = GetHelixRelativeAssemblyPath(kvp.Key.AssemblyPath) }, kvp => kvp.Value) }; + + AddRehydrateTestFoldersCommand(command, workItemInfo, isUnix); + + // Build an rsp file to send to dotnet test that contains all the assemblies and tests to run. + // This gets around command line length limitations and avoids weird escaping issues. + // See https://docs.microsoft.com/en-us/dotnet/standard/commandline/syntax#response-files + var rspFileContents = ProcessTestExecutor.BuildRspFileContents(workItemInfo, options); + var rspFileName = $"vstest_{workItemInfo.PartitionIndex}.rsp"; + File.WriteAllText(Path.Combine(payloadDirectory, rspFileName), rspFileContents); + + // Build the command to run the rsp file. + // dotnet test does not pass rsp files correctly the vs test console, so we have to manually invoke vs test console. + // See https://github.com/microsoft/vstest/issues/3513 + // The dotnet sdk includes the vstest.console.dll executable in the sdk folder in the installed version, so we look it up using the + // DOTNET_ROOT environment variable set by helix. + if (isUnix) + { + // $ is a special character in msbuild so we replace it with %24 in the helix project. + // https://docs.microsoft.com/en-us/visualstudio/msbuild/msbuild-special-characters?view=vs-2022 + command.AppendLine("vstestConsolePath=%24(find %24{DOTNET_ROOT} -name \"vstest.console.dll\")"); + command.AppendLine("echo %24{vstestConsolePath}"); + command.AppendLine($"dotnet exec \"%24{{vstestConsolePath}}\" @{rspFileName}"); + } + else + { + // Windows cmd doesn't have an easy way to set the output of a command to a variable. + // So send the output of the command to a file, then set the variable based on the file. + command.AppendLine("where /r %DOTNET_ROOT% vstest.console.dll > temp.txt"); + command.AppendLine("set /p vstestConsolePath= + {payloadDirectory} - {command} + {escapedCommand} {postCommands} @@ -214,13 +273,13 @@ string makeHelixWorkItemProject(AssemblyInfo assemblyInfo) } } - internal async Task RunAllAsync(IEnumerable assemblyInfoList, CancellationToken cancellationToken) + internal async Task RunAllAsync(ImmutableArray workItems, CancellationToken cancellationToken) { // Use 1.5 times the number of processors for unit tests, but only 1 processor for the open integration tests // since they perform actual UI operations (such as mouse clicks and sending keystrokes) and we don't want two // tests to conflict with one-another. var max = _options.Sequential ? 1 : (int)(Environment.ProcessorCount * 1.5); - var waiting = new Stack(assemblyInfoList); + var waiting = new Stack(workItems); var running = new List>(); var completed = new List(); var failures = 0; @@ -275,7 +334,7 @@ internal async Task RunAllAsync(IEnumerable assembly while (running.Count < max && waiting.Count > 0) { - var task = _testExecutor.RunTestAsync(waiting.Pop(), cancellationToken); + var task = _testExecutor.RunTestAsync(waiting.Pop(), _options, cancellationToken); running.Add(task); } @@ -343,7 +402,7 @@ private void PrintFailedTestResult(TestResult testResult) // Save out the error output for easy artifact inspecting var outputLogPath = Path.Combine(_options.LogFilesDirectory, $"xUnitFailure-{testResult.DisplayName}.log"); - ConsoleUtil.WriteLine($"Errors {testResult.AssemblyName}"); + ConsoleUtil.WriteLine($"Errors {testResult.DisplayName}"); ConsoleUtil.WriteLine(testResult.ErrorOutput); // TODO: Put this in the log and take it off the ConsoleUtil output to keep it simple? diff --git a/src/VisualStudio/CSharp/Impl/CSharpVSResources.resx b/src/VisualStudio/CSharp/Impl/CSharpVSResources.resx index 7f49e6d5786ac..9191602c7b664 100644 --- a/src/VisualStudio/CSharp/Impl/CSharpVSResources.resx +++ b/src/VisualStudio/CSharp/Impl/CSharpVSResources.resx @@ -655,4 +655,7 @@ Collapse usings on file open + + Show new snippet experience (experimental) + \ No newline at end of file diff --git a/src/VisualStudio/CSharp/Impl/CodeModel/CSharpCodeModelService.cs b/src/VisualStudio/CSharp/Impl/CodeModel/CSharpCodeModelService.cs index 3d667d025dd2d..604362b31f96c 100644 --- a/src/VisualStudio/CSharp/Impl/CodeModel/CSharpCodeModelService.cs +++ b/src/VisualStudio/CSharp/Impl/CodeModel/CSharpCodeModelService.cs @@ -39,16 +39,14 @@ internal partial class CSharpCodeModelService : AbstractCodeModelService { internal CSharpCodeModelService( HostLanguageServices languageServiceProvider, - IEditorOptionsFactoryService editorOptionsFactoryService, + EditorOptionsService editorOptionsService, IEnumerable refactorNotifyServices, - IGlobalOptionService globalOptions, IThreadingContext threadingContext) : base(languageServiceProvider, - editorOptionsFactoryService, + editorOptionsService, refactorNotifyServices, BlankLineInGeneratedMethodFormattingRule.Instance, EndRegionFormattingRule.Instance, - globalOptions, threadingContext) { } @@ -3562,17 +3560,11 @@ private static bool IsAutoImplementedProperty(PropertyDeclarationSyntax property switch (accessor.Kind()) { case SyntaxKind.GetAccessorDeclaration: - if (getAccessor == null) - { - getAccessor = accessor; - } + getAccessor ??= accessor; break; case SyntaxKind.SetAccessorDeclaration: - if (setAccessor == null) - { - setAccessor = accessor; - } + setAccessor ??= accessor; break; } diff --git a/src/VisualStudio/CSharp/Impl/CodeModel/CSharpCodeModelServiceFactory.cs b/src/VisualStudio/CSharp/Impl/CodeModel/CSharpCodeModelServiceFactory.cs index af3db5d41cfd8..18843e2c61ab8 100644 --- a/src/VisualStudio/CSharp/Impl/CodeModel/CSharpCodeModelServiceFactory.cs +++ b/src/VisualStudio/CSharp/Impl/CodeModel/CSharpCodeModelServiceFactory.cs @@ -19,26 +19,23 @@ namespace Microsoft.VisualStudio.LanguageServices.CSharp.CodeModel [ExportLanguageServiceFactory(typeof(ICodeModelService), LanguageNames.CSharp), Shared] internal partial class CSharpCodeModelServiceFactory : ILanguageServiceFactory { - private readonly IEditorOptionsFactoryService _editorOptionsFactoryService; + private readonly EditorOptionsService _editorOptionsService; private readonly IEnumerable _refactorNotifyServices; - private readonly IGlobalOptionService _globalOptions; private readonly IThreadingContext _threadingContext; [ImportingConstructor] [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] public CSharpCodeModelServiceFactory( - IEditorOptionsFactoryService editorOptionsFactoryService, + EditorOptionsService editorOptionsService, [ImportMany] IEnumerable refactorNotifyServices, - IGlobalOptionService globalOptions, IThreadingContext threadingContext) { - _editorOptionsFactoryService = editorOptionsFactoryService; + _editorOptionsService = editorOptionsService; _refactorNotifyServices = refactorNotifyServices; - _globalOptions = globalOptions; _threadingContext = threadingContext; } public ILanguageService CreateLanguageService(HostLanguageServices provider) - => new CSharpCodeModelService(provider, _editorOptionsFactoryService, _refactorNotifyServices, _globalOptions, _threadingContext); + => new CSharpCodeModelService(provider, _editorOptionsService, _refactorNotifyServices, _threadingContext); } } diff --git a/src/VisualStudio/CSharp/Impl/Interactive/CSharpInteractiveCommandHandler.cs b/src/VisualStudio/CSharp/Impl/Interactive/CSharpInteractiveCommandHandler.cs index f635bc344e563..3d74204805446 100644 --- a/src/VisualStudio/CSharp/Impl/Interactive/CSharpInteractiveCommandHandler.cs +++ b/src/VisualStudio/CSharp/Impl/Interactive/CSharpInteractiveCommandHandler.cs @@ -10,6 +10,7 @@ using Microsoft.CodeAnalysis.Editor.Host; using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.Interactive; +using Microsoft.CodeAnalysis.Options; using Microsoft.VisualStudio.InteractiveWindow; using Microsoft.VisualStudio.Text.Editor; using Microsoft.VisualStudio.Text.Operations; @@ -30,9 +31,9 @@ public CSharpInteractiveCommandHandler( CSharpVsInteractiveWindowProvider interactiveWindowProvider, ISendToInteractiveSubmissionProvider sendToInteractiveSubmissionProvider, IContentTypeRegistryService contentTypeRegistryService, - IEditorOptionsFactoryService editorOptionsFactoryService, + EditorOptionsService editorOptionsService, IEditorOperationsFactoryService editorOperationsFactoryService) - : base(contentTypeRegistryService, editorOptionsFactoryService, editorOperationsFactoryService) + : base(contentTypeRegistryService, editorOptionsService, editorOperationsFactoryService) { _interactiveWindowProvider = interactiveWindowProvider; _sendToInteractiveSubmissionProvider = sendToInteractiveSubmissionProvider; diff --git a/src/VisualStudio/CSharp/Impl/Interactive/CSharpVsInteractiveWindowProvider.cs b/src/VisualStudio/CSharp/Impl/Interactive/CSharpVsInteractiveWindowProvider.cs index 7cf17e208452c..c520c29fd0bd4 100644 --- a/src/VisualStudio/CSharp/Impl/Interactive/CSharpVsInteractiveWindowProvider.cs +++ b/src/VisualStudio/CSharp/Impl/Interactive/CSharpVsInteractiveWindowProvider.cs @@ -18,6 +18,7 @@ using Microsoft.VisualStudio.Shell; using Microsoft.VisualStudio.Text; using Microsoft.VisualStudio.Text.Classification; +using Microsoft.VisualStudio.Text.Editor; using Microsoft.VisualStudio.Utilities; using LanguageServiceGuids = Microsoft.VisualStudio.LanguageServices.Guids; @@ -28,8 +29,8 @@ internal sealed class CSharpVsInteractiveWindowProvider : VsInteractiveWindowPro { private readonly IThreadingContext _threadingContext; private readonly IAsynchronousOperationListener _listener; - private readonly IGlobalOptionService _globalOptions; private readonly ITextDocumentFactoryService _textDocumentFactoryService; + private readonly EditorOptionsService _editorOptionsService; [ImportingConstructor] [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] @@ -42,15 +43,15 @@ public CSharpVsInteractiveWindowProvider( IContentTypeRegistryService contentTypeRegistry, IInteractiveWindowCommandsFactory commandsFactory, [ImportMany] IInteractiveWindowCommand[] commands, - IGlobalOptionService globalOptions, ITextDocumentFactoryService textDocumentFactoryService, + EditorOptionsService editorOptionsService, VisualStudioWorkspace workspace) : base(serviceProvider, interactiveWindowFactory, classifierAggregator, contentTypeRegistry, commandsFactory, commands, workspace) { _threadingContext = threadingContext; _listener = listenerProvider.GetListener(FeatureAttribute.InteractiveEvaluator); - _globalOptions = globalOptions; _textDocumentFactoryService = textDocumentFactoryService; + _editorOptionsService = editorOptionsService; } protected override Guid LanguageServiceGuid => LanguageServiceGuids.CSharpLanguageServiceId; @@ -69,7 +70,6 @@ protected override CSharpInteractiveEvaluator CreateInteractiveEvaluator( VisualStudioWorkspace workspace) { return new CSharpInteractiveEvaluator( - _globalOptions, _threadingContext, _listener, contentTypeRegistry.GetContentType(ContentTypeNames.CSharpContentType), @@ -78,6 +78,7 @@ protected override CSharpInteractiveEvaluator CreateInteractiveEvaluator( CommandsFactory, Commands, _textDocumentFactoryService, + _editorOptionsService, CSharpInteractiveEvaluatorLanguageInfoProvider.Instance, Environment.GetFolderPath(Environment.SpecialFolder.UserProfile)); } diff --git a/src/VisualStudio/CSharp/Impl/LanguageService/CSharpHelpContextService.cs b/src/VisualStudio/CSharp/Impl/LanguageService/CSharpHelpContextService.cs index 531d58467fc90..02b1cbf3c7054 100644 --- a/src/VisualStudio/CSharp/Impl/LanguageService/CSharpHelpContextService.cs +++ b/src/VisualStudio/CSharp/Impl/LanguageService/CSharpHelpContextService.cs @@ -14,10 +14,10 @@ using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Extensions; using Microsoft.CodeAnalysis.CSharp.Extensions.ContextQuery; -using Microsoft.CodeAnalysis.CSharp.LanguageServices; +using Microsoft.CodeAnalysis.CSharp.LanguageService; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Host.Mef; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Text; using Microsoft.VisualStudio.LanguageServices.Implementation.F1Help; @@ -170,7 +170,7 @@ private bool TryGetTextForSymbol( } else { - symbol = semanticModel.GetSemanticInfo(token, document.Project.Solution.Workspace.Services, cancellationToken) + symbol = semanticModel.GetSemanticInfo(token, document.Project.Solution.Services, cancellationToken) .GetAnySymbol(includeType: true); if (symbol == null) diff --git a/src/VisualStudio/CSharp/Impl/Options/AdvancedOptionPageControl.xaml b/src/VisualStudio/CSharp/Impl/Options/AdvancedOptionPageControl.xaml index 3dde53e4cdb62..3dc78e581e5ac 100644 --- a/src/VisualStudio/CSharp/Impl/Options/AdvancedOptionPageControl.xaml +++ b/src/VisualStudio/CSharp/Impl/Options/AdvancedOptionPageControl.xaml @@ -7,15 +7,21 @@ xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:options="clr-namespace:Microsoft.VisualStudio.LanguageServices.Implementation.Options;assembly=Microsoft.VisualStudio.LanguageServices.Implementation" xmlns:local="clr-namespace:Microsoft.VisualStudio.LanguageServices.CSharp.Options" + xmlns:system="clr-namespace:System;assembly=mscorlib" mc:Ignorable="d" d:DesignHeight="500" d:DesignWidth="500"> + + True + False + + - diff --git a/src/VisualStudio/CSharp/Impl/Options/IntelliSenseOptionPageControl.xaml.cs b/src/VisualStudio/CSharp/Impl/Options/IntelliSenseOptionPageControl.xaml.cs index 3f668ff9d7f82..5193c137465eb 100644 --- a/src/VisualStudio/CSharp/Impl/Options/IntelliSenseOptionPageControl.xaml.cs +++ b/src/VisualStudio/CSharp/Impl/Options/IntelliSenseOptionPageControl.xaml.cs @@ -26,6 +26,7 @@ public IntelliSenseOptionPageControl(OptionStore optionStore) : base(optionStore BindToOption(Show_completion_list_after_a_character_is_typed, CompletionOptionsStorage.TriggerOnTypingLetters, LanguageNames.CSharp); Show_completion_list_after_a_character_is_deleted.IsChecked = this.OptionStore.GetOption(CompletionOptionsStorage.TriggerOnDeletion, LanguageNames.CSharp) == true; Show_completion_list_after_a_character_is_deleted.IsEnabled = Show_completion_list_after_a_character_is_typed.IsChecked == true; + AddSearchHandler(Show_completion_list_after_a_character_is_deleted); BindToOption(Never_include_snippets, CompletionOptionsStorage.SnippetsBehavior, SnippetsRule.NeverInclude, LanguageNames.CSharp); BindToOption(Always_include_snippets, CompletionOptionsStorage.SnippetsBehavior, SnippetsRule.AlwaysInclude, LanguageNames.CSharp); @@ -39,8 +40,13 @@ public IntelliSenseOptionPageControl(OptionStore optionStore) : base(optionStore BindToOption(Automatically_show_completion_list_in_argument_lists, CompletionOptionsStorage.TriggerInArgumentLists, LanguageNames.CSharp); Show_items_from_unimported_namespaces.IsChecked = this.OptionStore.GetOption(CompletionOptionsStorage.ShowItemsFromUnimportedNamespaces, LanguageNames.CSharp); + AddSearchHandler(Show_items_from_unimported_namespaces); + Tab_twice_to_insert_arguments.IsChecked = this.OptionStore.GetOption(CompletionViewOptions.EnableArgumentCompletionSnippets, LanguageNames.CSharp); + AddSearchHandler(Tab_twice_to_insert_arguments); + Show_new_snippet_experience.IsChecked = this.OptionStore.GetOption(CompletionOptionsStorage.ShowNewSnippetExperience, LanguageNames.CSharp); + AddSearchHandler(Show_new_snippet_experience); } private void Show_completion_list_after_a_character_is_typed_Checked(object sender, RoutedEventArgs e) @@ -70,5 +76,11 @@ private void Tab_twice_to_insert_arguments_CheckedChanged(object sender, RoutedE Tab_twice_to_insert_arguments.IsThreeState = false; this.OptionStore.SetOption(CompletionViewOptions.EnableArgumentCompletionSnippets, LanguageNames.CSharp, value: Tab_twice_to_insert_arguments.IsChecked); } + + private void Show_new_snippet_experience_CheckedChanged(object sender, RoutedEventArgs e) + { + Show_new_snippet_experience.IsThreeState = false; + this.OptionStore.SetOption(CompletionOptionsStorage.ShowNewSnippetExperience, LanguageNames.CSharp, value: Show_new_snippet_experience.IsChecked); + } } } diff --git a/src/VisualStudio/CSharp/Impl/Options/IntelliSenseOptionPageStrings.cs b/src/VisualStudio/CSharp/Impl/Options/IntelliSenseOptionPageStrings.cs index ce23a96563905..732d14be7798a 100644 --- a/src/VisualStudio/CSharp/Impl/Options/IntelliSenseOptionPageStrings.cs +++ b/src/VisualStudio/CSharp/Impl/Options/IntelliSenseOptionPageStrings.cs @@ -77,5 +77,8 @@ public static string Option_ShowSnippets public static string Automatically_show_completion_list_in_argument_lists => CSharpVSResources.Automatically_show_completion_list_in_argument_lists; + + public static string Option_Show_new_snippet_experience_experimental => + CSharpVSResources.Show_new_snippet_experience_experimental; } } diff --git a/src/VisualStudio/CSharp/Impl/ProjectSystemShim/CSharpProjectShim.OptionsProcessor.cs b/src/VisualStudio/CSharp/Impl/ProjectSystemShim/CSharpProjectShim.OptionsProcessor.cs index c9b8e4cf63c83..e01e86223d2a5 100644 --- a/src/VisualStudio/CSharp/Impl/ProjectSystemShim/CSharpProjectShim.OptionsProcessor.cs +++ b/src/VisualStudio/CSharp/Impl/ProjectSystemShim/CSharpProjectShim.OptionsProcessor.cs @@ -25,7 +25,7 @@ private class OptionsProcessor : VisualStudioProjectOptionsProcessor private string? _mainTypeName; private OutputKind _outputKind; - public OptionsProcessor(VisualStudioProject visualStudioProject, HostWorkspaceServices workspaceServices) + public OptionsProcessor(VisualStudioProject visualStudioProject, SolutionServices workspaceServices) : base(visualStudioProject, workspaceServices) { _visualStudioProject = visualStudioProject; diff --git a/src/VisualStudio/CSharp/Impl/ProjectSystemShim/CSharpProjectShim.cs b/src/VisualStudio/CSharp/Impl/ProjectSystemShim/CSharpProjectShim.cs index 6d49a0e2d4d81..f8c001cb6a312 100644 --- a/src/VisualStudio/CSharp/Impl/ProjectSystemShim/CSharpProjectShim.cs +++ b/src/VisualStudio/CSharp/Impl/ProjectSystemShim/CSharpProjectShim.cs @@ -67,7 +67,7 @@ public CSharpProjectShim( var componentModel = (IComponentModel)serviceProvider.GetService(typeof(SComponentModel)); this.ProjectCodeModel = componentModel.GetService().CreateProjectCodeModel(VisualStudioProject.Id, this); - this.VisualStudioProjectOptionsProcessor = new OptionsProcessor(this.VisualStudioProject, Workspace.Services); + this.VisualStudioProjectOptionsProcessor = new OptionsProcessor(this.VisualStudioProject, Workspace.Services.SolutionServices); // Ensure the default options are set up ResetAllOptions(); diff --git a/src/VisualStudio/CSharp/Impl/Snippets/SnippetCommandHandler.cs b/src/VisualStudio/CSharp/Impl/Snippets/SnippetCommandHandler.cs index 769da32ea385b..5cc0ee43260a2 100644 --- a/src/VisualStudio/CSharp/Impl/Snippets/SnippetCommandHandler.cs +++ b/src/VisualStudio/CSharp/Impl/Snippets/SnippetCommandHandler.cs @@ -15,6 +15,7 @@ using Microsoft.CodeAnalysis.CSharp.Extensions; using Microsoft.CodeAnalysis.Editor.CSharp.CompleteStatement; using Microsoft.CodeAnalysis.Editor.Implementation.IntelliSense.SignatureHelp; +using Microsoft.CodeAnalysis.Editor.Shared.Extensions; using Microsoft.CodeAnalysis.Editor.Shared.Utilities; using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.Options; @@ -55,8 +56,8 @@ public SnippetCommandHandler( IVsEditorAdaptersFactoryService editorAdaptersFactoryService, SVsServiceProvider serviceProvider, [ImportMany] IEnumerable> argumentProviders, - IGlobalOptionService globalOptions) - : base(threadingContext, signatureHelpControllerProvider, editorCommandHandlerServiceFactory, editorAdaptersFactoryService, globalOptions, serviceProvider) + EditorOptionsService editorOptionsService) + : base(threadingContext, signatureHelpControllerProvider, editorCommandHandlerServiceFactory, editorAdaptersFactoryService, editorOptionsService, serviceProvider) { _argumentProviders = argumentProviders.ToImmutableArray(); } @@ -82,12 +83,8 @@ public CommandState GetCommandState(SurroundWithCommandArgs args) return CommandState.Unspecified; } - if (!Workspace.TryGetWorkspace(args.SubjectBuffer.AsTextContainer(), out var workspace)) - { - return CommandState.Unspecified; - } - - if (!workspace.CanApplyChange(ApplyChangesKind.ChangeDocument)) + if (!args.SubjectBuffer.TryGetWorkspace(out var workspace) || + !workspace.CanApplyChange(ApplyChangesKind.ChangeDocument)) { return CommandState.Unspecified; } @@ -131,7 +128,7 @@ protected override AbstractSnippetExpansionClient GetSnippetExpansionClient(ITex EditorCommandHandlerServiceFactory, EditorAdaptersFactoryService, _argumentProviders, - GlobalOptions); + EditorOptionsService); textView.Properties.AddProperty(typeof(AbstractSnippetExpansionClient), expansionClient); } diff --git a/src/VisualStudio/CSharp/Impl/Snippets/SnippetExpansionClient.cs b/src/VisualStudio/CSharp/Impl/Snippets/SnippetExpansionClient.cs index 8146215f9b9b3..a2b2be8eddeed 100644 --- a/src/VisualStudio/CSharp/Impl/Snippets/SnippetExpansionClient.cs +++ b/src/VisualStudio/CSharp/Impl/Snippets/SnippetExpansionClient.cs @@ -45,7 +45,7 @@ public SnippetExpansionClient( IEditorCommandHandlerServiceFactory editorCommandHandlerServiceFactory, IVsEditorAdaptersFactoryService editorAdaptersFactoryService, ImmutableArray> argumentProviders, - IGlobalOptionService globalOptions) + EditorOptionsService editorOptionsService) : base( threadingContext, languageServiceGuid, @@ -55,7 +55,7 @@ public SnippetExpansionClient( editorCommandHandlerServiceFactory, editorAdaptersFactoryService, argumentProviders, - globalOptions) + editorOptionsService) { } diff --git a/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.cs.xlf b/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.cs.xlf index fe694a4b041ad..8564d5aaff1b2 100644 --- a/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.cs.xlf +++ b/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.cs.xlf @@ -182,6 +182,11 @@ Zobrazit položky z neimportovaných oborů názvů + + Show new snippet experience (experimental) + Show new snippet experience (experimental) + + Show remarks in Quick Info Zobrazit poznámky v Rychlých informacích diff --git a/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.de.xlf b/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.de.xlf index a095750831d79..dc5bffdcb447d 100644 --- a/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.de.xlf +++ b/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.de.xlf @@ -182,6 +182,11 @@ Elemente aus nicht importierten Namespaces anzeigen + + Show new snippet experience (experimental) + Show new snippet experience (experimental) + + Show remarks in Quick Info Hinweise in QuickInfo anzeigen diff --git a/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.es.xlf b/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.es.xlf index aee978d8059a2..1935c60d77383 100644 --- a/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.es.xlf +++ b/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.es.xlf @@ -182,6 +182,11 @@ Mostrar elementos de espacios de nombres no importados + + Show new snippet experience (experimental) + Show new snippet experience (experimental) + + Show remarks in Quick Info Mostrar comentarios en Información rápida diff --git a/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.fr.xlf b/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.fr.xlf index cea73095c5d60..adaeba798e6e0 100644 --- a/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.fr.xlf +++ b/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.fr.xlf @@ -182,6 +182,11 @@ Afficher les éléments des espaces de noms qui ne sont pas importés + + Show new snippet experience (experimental) + Show new snippet experience (experimental) + + Show remarks in Quick Info Afficher les notes dans Info express diff --git a/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.it.xlf b/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.it.xlf index c802756fbff40..accb679fea18d 100644 --- a/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.it.xlf +++ b/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.it.xlf @@ -182,6 +182,11 @@ Mostra elementi da spazi dei nomi non importati + + Show new snippet experience (experimental) + Show new snippet experience (experimental) + + Show remarks in Quick Info Mostra i commenti in Informazioni rapide diff --git a/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.ja.xlf b/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.ja.xlf index 6b0f38b0a3794..a98692ec266c8 100644 --- a/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.ja.xlf +++ b/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.ja.xlf @@ -182,6 +182,11 @@ インポートされていない名前空間の項目を表示する + + Show new snippet experience (experimental) + Show new snippet experience (experimental) + + Show remarks in Quick Info クイック ヒントに注釈を表示する diff --git a/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.ko.xlf b/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.ko.xlf index 270f709dc6b60..583811fa05f21 100644 --- a/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.ko.xlf +++ b/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.ko.xlf @@ -182,6 +182,11 @@ 가져오지 않은 네임스페이스의 항목 표시 + + Show new snippet experience (experimental) + Show new snippet experience (experimental) + + Show remarks in Quick Info 요약 정보에 설명 표시 diff --git a/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.pl.xlf b/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.pl.xlf index 48e0d64ec7181..54d954de7e5bb 100644 --- a/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.pl.xlf +++ b/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.pl.xlf @@ -182,6 +182,11 @@ Pokaż elementy z nieimportowanych przestrzeni nazw + + Show new snippet experience (experimental) + Show new snippet experience (experimental) + + Show remarks in Quick Info Pokaż uwagi w szybkich podpowiedziach diff --git a/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.pt-BR.xlf b/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.pt-BR.xlf index 33e47664e5bb2..897409ec14d72 100644 --- a/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.pt-BR.xlf +++ b/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.pt-BR.xlf @@ -182,6 +182,11 @@ Mostrar os itens de namespaces não importados + + Show new snippet experience (experimental) + Show new snippet experience (experimental) + + Show remarks in Quick Info Mostrar os comentários nas Informações Rápidas diff --git a/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.ru.xlf b/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.ru.xlf index df03f92d120d8..45357b2001345 100644 --- a/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.ru.xlf +++ b/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.ru.xlf @@ -182,6 +182,11 @@ Отображать элементы из неимпортированных пространств имен + + Show new snippet experience (experimental) + Show new snippet experience (experimental) + + Show remarks in Quick Info Показать заметки в кратких сведениях diff --git a/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.tr.xlf b/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.tr.xlf index 7f5cc468adb37..9739714c45443 100644 --- a/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.tr.xlf +++ b/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.tr.xlf @@ -182,6 +182,11 @@ İçeri aktarılmayan ad alanlarındaki öğeleri göster + + Show new snippet experience (experimental) + Show new snippet experience (experimental) + + Show remarks in Quick Info Hızlı Bilgi notlarını 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 511b5693de270..2506d0fd268c2 100644 --- a/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.zh-Hans.xlf +++ b/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.zh-Hans.xlf @@ -182,6 +182,11 @@ 显示 unimported 命名空间中的项 + + Show new snippet experience (experimental) + Show new snippet experience (experimental) + + Show remarks in Quick Info 在快速信息中显示备注 diff --git a/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.zh-Hant.xlf b/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.zh-Hant.xlf index 9db4dbd0a5950..b74d870657b7e 100644 --- a/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.zh-Hant.xlf +++ b/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.zh-Hant.xlf @@ -182,6 +182,11 @@ 顯示來自未匯入命名空間的項目 + + Show new snippet experience (experimental) + Show new snippet experience (experimental) + + Show remarks in Quick Info 在快速諮詢中顯示備註 diff --git a/src/VisualStudio/CSharp/Test/CodeModel/FileCodeModelTestHelpers.cs b/src/VisualStudio/CSharp/Test/CodeModel/FileCodeModelTestHelpers.cs index c481819cb2de3..dbf59e3ee4bfc 100644 --- a/src/VisualStudio/CSharp/Test/CodeModel/FileCodeModelTestHelpers.cs +++ b/src/VisualStudio/CSharp/Test/CodeModel/FileCodeModelTestHelpers.cs @@ -49,7 +49,7 @@ public static (TestWorkspace workspace, EnvDTE.FileCodeModel fileCodeModel) Crea var state = new CodeModelState( threadingContext, serviceProvider, - project.LanguageServices, + project.Services, visualStudioWorkspaceMock, workspace.ExportProvider.GetExportedValue()); diff --git a/src/VisualStudio/CSharp/Test/DocumentOutline/DocumentOutlineTests.cs b/src/VisualStudio/CSharp/Test/DocumentOutline/DocumentOutlineTests.cs new file mode 100644 index 0000000000000..ff4c95206e2b7 --- /dev/null +++ b/src/VisualStudio/CSharp/Test/DocumentOutline/DocumentOutlineTests.cs @@ -0,0 +1,260 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation 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.Test.Utilities; +using Microsoft.VisualStudio.LanguageServer.Protocol; +using Microsoft.VisualStudio.LanguageServices.DocumentOutline; +using Roslyn.Test.Utilities; +using Xunit; + +namespace Roslyn.VisualStudio.CSharp.UnitTests.DocumentOutline +{ + public class DocumentOutlineTests : DocumentOutlineTestsBase + { + private const string TestCode = @" + private class MyClass + { + int _x; + + static void Method1(string[] args) {} + + private class MyClass2 {} + + static void Method2(string[] args) {} + } + + class App + { + void Method() {} + + void Z() {} + } + + interface foo + { + void z() {} + + private static int apple = 9, b = 4, c = 6; + + void r() {} + }" +; + + private async Task<(DocumentOutlineTestMocks mocks, DocumentSymbolDataModel model, ImmutableArray uiItems)> InitializeMocksAndDataModelAndUIItems(string testCode) + { + using var mocks = await CreateMocksAsync(testCode); + var response = await DocumentOutlineHelper.DocumentSymbolsRequestAsync(mocks.TextBuffer, mocks.LanguageServiceBroker, mocks.FilePath, CancellationToken.None); + AssertEx.NotNull(response.Value); + + var responseBody = response.Value.response?.ToObject(); + AssertEx.NotNull(responseBody); + + var snapshot = response.Value.snapshot; + AssertEx.NotNull(snapshot); + + var model = DocumentOutlineHelper.CreateDocumentSymbolDataModel(responseBody, snapshot); + var uiItems = DocumentOutlineHelper.GetDocumentSymbolUIItems(model.DocumentSymbolData, mocks.ThreadingContext); + return (mocks, model, uiItems); + } + + [WpfFact, Trait(Traits.Feature, Traits.Features.DocumentOutline)] + public async Task TestSortDocumentSymbolDataByName() + { + await CheckSorting(SortOption.Name); + } + + [WpfFact, Trait(Traits.Feature, Traits.Features.DocumentOutline)] + public async Task TestSortDocumentSymbolDataByType() + { + await CheckSorting(SortOption.Type); + } + + [WpfFact, Trait(Traits.Feature, Traits.Features.DocumentOutline)] + public async Task TestSortDocumentSymbolDataByLocation() + { + await CheckSorting(SortOption.Location); + } + + private async Task CheckSorting(SortOption sortOption) + { + var (_, model, _) = await InitializeMocksAndDataModelAndUIItems(TestCode); + var sortedSymbols = DocumentOutlineHelper.SortDocumentSymbolData(model.DocumentSymbolData, sortOption, CancellationToken.None); + CheckSortedSymbols(sortedSymbols); + + void CheckSortedSymbols(ImmutableArray sortedSymbols) + { + for (var i = 0; i < sortedSymbols.Length - 1; i++) + { + switch (sortOption) + { + case SortOption.Name: + Assert.True(StringComparer.OrdinalIgnoreCase.Compare(sortedSymbols[i].Name, sortedSymbols[i + 1].Name) <= 0); + break; + case SortOption.Location: + Assert.True(sortedSymbols[i].RangeSpan.Start < sortedSymbols[i + 1].RangeSpan.Start); + break; + case SortOption.Type: + if (sortedSymbols[i].SymbolKind != sortedSymbols[i + 1].SymbolKind) + Assert.True(sortedSymbols[i].SymbolKind < sortedSymbols[i + 1].SymbolKind); + else + Assert.True(StringComparer.OrdinalIgnoreCase.Compare(sortedSymbols[i].Name, sortedSymbols[i + 1].Name) <= 0); + break; + } + } + + foreach (var symbol in sortedSymbols) + CheckSortedSymbols(symbol.Children); + } + } + + [WpfFact, Trait(Traits.Feature, Traits.Features.DocumentOutline)] + public async Task TestSearchDocumentSymbolData() + { + var (_, model, _) = await InitializeMocksAndDataModelAndUIItems(TestCode); + + // Empty search (added for completeness, SearchDocumentSymbolData is not called on an empty search string) + var searchedSymbols = DocumentOutlineHelper.SearchDocumentSymbolData(model.DocumentSymbolData, string.Empty, CancellationToken.None); + Assert.Equal(0, searchedSymbols.Length); + + // Search for 1 parent only (no children should match) + searchedSymbols = DocumentOutlineHelper.SearchDocumentSymbolData(model.DocumentSymbolData, "foo", CancellationToken.None); + Assert.Equal(1, searchedSymbols.Length); + Assert.Equal(0, searchedSymbols.Single(symbol => symbol.Name.Equals("foo")).Children.Length); + + // Search for children only (across 2 parents) + searchedSymbols = DocumentOutlineHelper.SearchDocumentSymbolData(model.DocumentSymbolData, "Method", CancellationToken.None); + Assert.Equal(2, searchedSymbols.Length); + Assert.Equal(2, searchedSymbols.Single(symbol => symbol.Name.Equals("MyClass")).Children.Length); + Assert.Equal(1, searchedSymbols.Single(symbol => symbol.Name.Equals("App")).Children.Length); + + // Search for a parent and a child (of aanother parent) + searchedSymbols = DocumentOutlineHelper.SearchDocumentSymbolData(model.DocumentSymbolData, "app", CancellationToken.None); + Assert.Equal(2, searchedSymbols.Length); + Assert.Equal(0, searchedSymbols.Single(symbol => symbol.Name.Equals("App")).Children.Length); + Assert.Equal(1, searchedSymbols.Single(symbol => symbol.Name.Equals("foo")).Children.Length); + + // No search results found + searchedSymbols = DocumentOutlineHelper.SearchDocumentSymbolData(model.DocumentSymbolData, "xyz", CancellationToken.None); + Assert.Equal(0, searchedSymbols.Length); + } + + [WpfFact, Trait(Traits.Feature, Traits.Features.DocumentOutline)] + public async Task TestGetDocumentNodeToSelect() + { + var (mocks, model, uiItems) = await InitializeMocksAndDataModelAndUIItems(TestCode); + var currentTextSnapshotLines = mocks.TextBuffer.CurrentSnapshot.Lines; + + // Click between 2 parent nodes (no symbol is selected) + var caretPosition = currentTextSnapshotLines.ElementAt(11).End; + var nodeToSelect = DocumentOutlineHelper.GetDocumentNodeToSelect(uiItems, model.OriginalSnapshot, caretPosition); + Assert.Null(nodeToSelect); + + // Click within range of a parent symbol + caretPosition = currentTextSnapshotLines.ElementAt(1).End; + nodeToSelect = DocumentOutlineHelper.GetDocumentNodeToSelect(uiItems, model.OriginalSnapshot, caretPosition); + Assert.Equal("MyClass", nodeToSelect?.Name); + + // Click within range of a child symbol + caretPosition = currentTextSnapshotLines.ElementAt(5).End - 1; + nodeToSelect = DocumentOutlineHelper.GetDocumentNodeToSelect(uiItems, model.OriginalSnapshot, caretPosition); + Assert.Equal("Method1", nodeToSelect?.Name); + + // Click between 2 child symbols (caret is in range of parent) + caretPosition = currentTextSnapshotLines.ElementAt(15).End; + nodeToSelect = DocumentOutlineHelper.GetDocumentNodeToSelect(uiItems, model.OriginalSnapshot, caretPosition); + Assert.Equal("App", nodeToSelect?.Name); + } + + [WpfFact, Trait(Traits.Feature, Traits.Features.DocumentOutline)] + public async Task TestSetIsExpanded() + { + var (mocks, model, originalUIItems) = await InitializeMocksAndDataModelAndUIItems(TestCode); + var updatedUIItems = DocumentOutlineHelper.GetDocumentSymbolUIItems(model.DocumentSymbolData, mocks.ThreadingContext); + + // Check that all updatedUIItems nodes are collapsed (originalUIItems parameter is unused) + DocumentOutlineHelper.SetIsExpanded(updatedUIItems, originalUIItems, ExpansionOption.Collapse); + CheckNodeExpansion(updatedUIItems, false); + + // Check that all updatedUIItems nodes are expanded (originalUIItems parameter is unused) + DocumentOutlineHelper.SetIsExpanded(updatedUIItems, originalUIItems, ExpansionOption.Expand); + CheckNodeExpansion(updatedUIItems, true); + + // Collapse 3 nodes in originalUIItems + originalUIItems.Single(parent => parent.Name.Equals("App")).IsExpanded = false; + originalUIItems.Single(parent => parent.Name.Equals("MyClass")).Children.Single(child => child.Name.Equals("Method2")).IsExpanded = false; + originalUIItems.Single(parent => parent.Name.Equals("foo")).Children.Single(child => child.Name.Equals("r")).IsExpanded = false; + + // Apply same expansion as originalUIItems to updatedUIItems + DocumentOutlineHelper.SetIsExpanded(updatedUIItems, originalUIItems, ExpansionOption.CurrentExpansion); + + // Confirm that matching expanded/collapsed node states have been applied + CheckNodeExpansionMatches(updatedUIItems, originalUIItems); + + static void CheckNodeExpansion(ImmutableArray documentSymbolItems, bool isExpanded) + { + foreach (var symbol in documentSymbolItems) + { + Assert.True(symbol.IsExpanded == isExpanded); + CheckNodeExpansion(symbol.Children, isExpanded); + } + } + + static void CheckNodeExpansionMatches(ImmutableArray newUIItems, ImmutableArray originalUIItems) + { + for (var i = 0; i < newUIItems.Length; i++) + { + Assert.True(newUIItems[i].IsExpanded == originalUIItems[i].IsExpanded); + CheckNodeExpansionMatches(newUIItems[i].Children, originalUIItems[i].Children); + } + } + } + + [WpfFact, Trait(Traits.Feature, Traits.Features.DocumentOutline)] + public async Task TestExpandAncestors() + { + var (mocks, model, uiItems) = await InitializeMocksAndDataModelAndUIItems(TestCode); + + // Collapse all nodes first + DocumentOutlineHelper.SetIsExpanded(uiItems, uiItems, ExpansionOption.Collapse); + + // Call ExpandAncestors on a child node + var selectedNode = uiItems.Single(parent => parent.Name.Equals("MyClass")).Children.Single(child => child.Name.Equals("Method2")); + DocumentOutlineHelper.ExpandAncestors(uiItems, selectedNode.RangeSpan); + + // Confirm that only the child node and its ancestors are expanded + CheckAncestorNodeExpansion(uiItems); + + static void CheckAncestorNodeExpansion(ImmutableArray documentSymbolItems) + { + foreach (var symbol in documentSymbolItems) + { + Assert.True(symbol.Name.Equals("MyClass") || symbol.Name.Equals("Method2") ? symbol.IsExpanded : !symbol.IsExpanded); + CheckAncestorNodeExpansion(symbol.Children); + } + } + } + + [WpfFact, Trait(Traits.Feature, Traits.Features.DocumentOutline)] + public async Task TestUnselectAll() + { + var (_, _, uiItems) = await InitializeMocksAndDataModelAndUIItems(TestCode); + DocumentOutlineHelper.UnselectAll(uiItems); + CheckNodesUnselected(uiItems); + + static void CheckNodesUnselected(ImmutableArray documentSymbolItems) + { + foreach (var symbol in documentSymbolItems) + { + Assert.False(symbol.IsSelected); + CheckNodesUnselected(symbol.Children); + } + } + } + } +} diff --git a/src/VisualStudio/CSharp/Test/DocumentOutline/DocumentOutlineTestsBase.cs b/src/VisualStudio/CSharp/Test/DocumentOutline/DocumentOutlineTestsBase.cs new file mode 100644 index 0000000000000..060a18bcda786 --- /dev/null +++ b/src/VisualStudio/CSharp/Test/DocumentOutline/DocumentOutlineTestsBase.cs @@ -0,0 +1,141 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.Diagnostics; +using Microsoft.CodeAnalysis.Editor.Shared.Utilities; +using Microsoft.CodeAnalysis.Editor.Test; +using Microsoft.CodeAnalysis.Editor.UnitTests; +using Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces; +using Microsoft.CodeAnalysis.LanguageServer.Handler; +using Microsoft.CodeAnalysis.Shared.Extensions; +using Microsoft.CodeAnalysis.Shared.TestHooks; +using Microsoft.CodeAnalysis.Test.Utilities; +using Microsoft.CodeAnalysis.Text; +using Microsoft.VisualStudio.LanguageServer.Client; +using Microsoft.VisualStudio.LanguageServer.Protocol; +using Microsoft.VisualStudio.Text; +using Microsoft.VisualStudio.Threading; +using Moq; +using Newtonsoft.Json.Linq; +using Roslyn.Test.Utilities; +using static Roslyn.Test.Utilities.AbstractLanguageServerProtocolTests; +using LSP = Microsoft.VisualStudio.LanguageServer.Protocol; + +namespace Roslyn.VisualStudio.CSharp.UnitTests.DocumentOutline +{ + [UseExportProvider] + public abstract class DocumentOutlineTestsBase + { + protected class DocumentOutlineTestMocks : IDisposable + { + private readonly TestWorkspace _workspace; + private readonly IDisposable _disposable; + + internal DocumentOutlineTestMocks( + ILanguageServiceBroker2 languageServiceBroker, + IThreadingContext threadingContext, + TestWorkspace workspace, + IDisposable disposable) + { + LanguageServiceBroker = languageServiceBroker; + ThreadingContext = threadingContext; + _workspace = workspace; + _disposable = disposable; + TextBuffer = workspace.Documents.Single().GetTextBuffer(); + } + + internal ILanguageServiceBroker2 LanguageServiceBroker { get; } + + internal IThreadingContext ThreadingContext { get; } + + internal ITextBuffer TextBuffer { get; } + + internal string FilePath + => "C:\\" + _workspace.Documents.Single().FilePath!; + + public void Dispose() + => _disposable.Dispose(); + } + + private static readonly TestComposition s_composition = EditorTestCompositions.LanguageServerProtocol + .AddParts(typeof(TestDocumentTrackingService)) + .AddParts(typeof(TestWorkspaceRegistrationService)) + .AddParts(typeof(TestWorkspaceConfigurationService)) + .RemoveParts(typeof(MockWorkspaceEventListenerProvider)); + + protected async Task CreateMocksAsync(string code) + { + var workspace = TestWorkspace.CreateCSharp(code, composition: s_composition); + var threadingContext = workspace.GetService(); + + var clientCapabilities = new LSP.ClientCapabilities() + { + TextDocument = new LSP.TextDocumentClientCapabilities() + { + DocumentSymbol = new LSP.DocumentSymbolSetting() + { + HierarchicalDocumentSymbolSupport = true + } + } + }; + + var testLspServer = await CreateTestLspServerAsync(workspace, new InitializationOptions { ClientCapabilities = clientCapabilities }); + var languageServiceBrokerMock = new Mock(MockBehavior.Strict); +#pragma warning disable CS0618 // Type or member is obsolete + languageServiceBrokerMock + .Setup(l => l.RequestAsync(It.IsAny(), It.IsAny>(), It.IsAny(), It.IsAny(), It.IsAny>(), It.IsAny())) + .Returns, string, string, Func, CancellationToken>(RequestAsync); +#pragma warning restore CS0618 // Type or member is obsolete + + var mocks = new DocumentOutlineTestMocks(languageServiceBrokerMock.Object, threadingContext, workspace, testLspServer); + return mocks; + + async Task RequestAsync(ITextBuffer textBuffer, Func capabilitiesFilter, string languageServerName, string method, Func parameterFactory, CancellationToken cancellationToken) + { + var request = parameterFactory(textBuffer.CurrentSnapshot).ToObject(); + var response = await testLspServer.ExecuteRequestAsync(method, request!, cancellationToken); + return new ManualInvocationResponse(string.Empty, JToken.FromObject(response!)); + } + } + + private static async Task CreateTestLspServerAsync(TestWorkspace workspace, InitializationOptions initializationOptions) + { + var solution = workspace.CurrentSolution; + + foreach (var document in workspace.Documents) + { + if (document.IsSourceGenerated) + continue; + + solution = solution.WithDocumentFilePath(document.Id, "C:\\" + document.Name); + + var documentText = await solution.GetRequiredDocument(document.Id).GetTextAsync(CancellationToken.None); + solution = solution.WithDocumentText(document.Id, SourceText.From(documentText.ToString(), System.Text.Encoding.UTF8)); + } + + foreach (var project in workspace.Projects) + { + // Ensure all the projects have a valid file path. + solution = solution.WithProjectFilePath(project.Id, "C:\\" + project.Name); + } + + solution = solution.WithAnalyzerReferences(new[] { new TestAnalyzerReferenceByLanguage(DiagnosticExtensions.GetCompilerDiagnosticAnalyzersMap()) }); + workspace.ChangeSolution(solution); + + // Important: We must wait for workspace creation operations to finish. + // Otherwise we could have a race where workspace change events triggered by creation are changing the state + // created by the initial test steps. This can interfere with the expected test state. + var operations = workspace.ExportProvider.GetExportedValue(); + var workspaceWaiter = operations.GetWaiter(FeatureAttribute.Workspace); + await workspaceWaiter.ExpeditedWaitAsync(); + + return await TestLspServer.CreateAsync(workspace, initializationOptions); + } + } +} diff --git a/src/VisualStudio/CSharp/Test/EditorConfigSettings/DataProvider/DataProviderTests.cs b/src/VisualStudio/CSharp/Test/EditorConfigSettings/DataProvider/DataProviderTests.cs index 9cbaa662820a4..54dff6734303f 100644 --- a/src/VisualStudio/CSharp/Test/EditorConfigSettings/DataProvider/DataProviderTests.cs +++ b/src/VisualStudio/CSharp/Test/EditorConfigSettings/DataProvider/DataProviderTests.cs @@ -112,12 +112,15 @@ public void TestGettingCodeStyleSettingProviderWorkspaceServiceAsync() var model = new TestViewModel(); settingsProvider.RegisterViewModel(model); var dataSnapShot = settingsProvider.GetCurrentDataSnapshot(); - // We need to substract as a UI for arbitrary strings for: - // + + // We need to substract for string options that are not yet supported. // CodeStyleOptions2.OperatorPlacementWhenWrapping // CodeStyleOptions2.FileHeaderTemplate + // CodeStyleOptions2.RemoveUnnecessarySuppressionExclusions + // + // We also subtract for this not-yet supported option, tracked by https://github.com/dotnet/roslyn/issues/62937 // CodeStyleOptions2.ForEachExplicitCastInSource - var optionsCount = CodeStyleOptions2.AllOptions.Where(x => x.StorageLocations.Any(y => y is IEditorConfigStorageLocation2)).Count() - 3; + var optionsCount = CodeStyleOptions2.AllOptions.Where(x => x.StorageLocations.Any(y => y is IEditorConfigStorageLocation2)).Count() - 4; Assert.Equal(optionsCount, dataSnapShot.Length); } diff --git a/src/VisualStudio/CSharp/Test/Interactive/Commands/InteractiveWindowCommandHandlerTestState.cs b/src/VisualStudio/CSharp/Test/Interactive/Commands/InteractiveWindowCommandHandlerTestState.cs index 690622508aab3..aed09e95bd722 100644 --- a/src/VisualStudio/CSharp/Test/Interactive/Commands/InteractiveWindowCommandHandlerTestState.cs +++ b/src/VisualStudio/CSharp/Test/Interactive/Commands/InteractiveWindowCommandHandlerTestState.cs @@ -8,6 +8,7 @@ using Microsoft.CodeAnalysis.Editor.UnitTests; using Microsoft.CodeAnalysis.Editor.UnitTests.Utilities; using Microsoft.CodeAnalysis.Interactive; +using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Test.Utilities; using Microsoft.VisualStudio.Commanding; using Microsoft.VisualStudio.Composition; @@ -51,7 +52,7 @@ public InteractiveWindowCommandHandlerTestState(XElement workspaceElement) TestHost.Window, GetExportedValue(), GetExportedValue(), - GetExportedValue(), + GetExportedValue(), GetExportedValue()); } diff --git a/src/VisualStudio/CSharp/Test/Interactive/Commands/ResetInteractiveTests.cs b/src/VisualStudio/CSharp/Test/Interactive/Commands/ResetInteractiveTests.cs index d518fac2ddfb9..eabf3d0f69453 100644 --- a/src/VisualStudio/CSharp/Test/Interactive/Commands/ResetInteractiveTests.cs +++ b/src/VisualStudio/CSharp/Test/Interactive/Commands/ResetInteractiveTests.cs @@ -21,6 +21,7 @@ using Microsoft.CodeAnalysis.Editor.UnitTests; using Microsoft.VisualStudio.InteractiveWindow; using Microsoft.VisualStudio.Utilities; +using Microsoft.CodeAnalysis.Options; namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.Interactive.Commands { @@ -82,13 +83,13 @@ private async Task AssertResetInteractiveAsync( testHost.Evaluator.OnExecute += executeSubmission; var uiThreadOperationExecutor = workspace.GetService(); - var editorOptionsFactoryService = workspace.GetService(); - var editorOptions = editorOptionsFactoryService.GetOptions(testHost.Window.CurrentLanguageBuffer); + var editorOptionsService = workspace.GetService(); + var editorOptions = editorOptionsService.Factory.GetOptions(testHost.Window.CurrentLanguageBuffer); var newLineCharacter = editorOptions.GetNewLineCharacter(); var resetInteractive = new TestResetInteractive( uiThreadOperationExecutor, - editorOptionsFactoryService, + editorOptionsService, CreateReplReferenceCommand, CreateImport, buildSucceeds: buildSucceeds) diff --git a/src/VisualStudio/CSharp/Test/Interactive/Commands/TestInteractiveCommandHandler.cs b/src/VisualStudio/CSharp/Test/Interactive/Commands/TestInteractiveCommandHandler.cs index 2b737fea9282b..d55cdd9b3e844 100644 --- a/src/VisualStudio/CSharp/Test/Interactive/Commands/TestInteractiveCommandHandler.cs +++ b/src/VisualStudio/CSharp/Test/Interactive/Commands/TestInteractiveCommandHandler.cs @@ -6,6 +6,7 @@ using Microsoft.CodeAnalysis.Editor.Host; using Microsoft.CodeAnalysis.Interactive; +using Microsoft.CodeAnalysis.Options; using Microsoft.VisualStudio.InteractiveWindow; using Microsoft.VisualStudio.Text.Editor; using Microsoft.VisualStudio.Text.Operations; @@ -23,9 +24,9 @@ public TestInteractiveCommandHandler( IInteractiveWindow interactiveWindow, ISendToInteractiveSubmissionProvider sendToInteractiveSubmissionProvider, IContentTypeRegistryService contentTypeRegistryService, - IEditorOptionsFactoryService editorOptionsFactoryService, + EditorOptionsService editorOptionsService, IEditorOperationsFactoryService editorOperationsFactoryService) - : base(contentTypeRegistryService, editorOptionsFactoryService, editorOperationsFactoryService) + : base(contentTypeRegistryService, editorOptionsService, editorOperationsFactoryService) { _interactiveWindow = interactiveWindow; _sendToInteractiveSubmissionProvider = sendToInteractiveSubmissionProvider; diff --git a/src/VisualStudio/CSharp/Test/Interactive/Commands/TestResetInteractive.cs b/src/VisualStudio/CSharp/Test/Interactive/Commands/TestResetInteractive.cs index e167bc7c92725..a45a32d5ad88b 100644 --- a/src/VisualStudio/CSharp/Test/Interactive/Commands/TestResetInteractive.cs +++ b/src/VisualStudio/CSharp/Test/Interactive/Commands/TestResetInteractive.cs @@ -17,6 +17,7 @@ using Microsoft.VisualStudio.Utilities; using Microsoft.VisualStudio.Language.Intellisense.Utilities; using Microsoft.CodeAnalysis.Interactive; +using Microsoft.CodeAnalysis.Options; namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.Interactive.Commands { @@ -46,11 +47,11 @@ internal class TestResetInteractive : ResetInteractive public TestResetInteractive( IUIThreadOperationExecutor uiThreadOperationExecutor, - IEditorOptionsFactoryService editorOptionsFactoryService, + EditorOptionsService editorOptionsService, Func createReference, Func createImport, bool buildSucceeds) - : base(editorOptionsFactoryService, createReference, createImport) + : base(editorOptionsService, createReference, createImport) { _uiThreadOperationExecutor = uiThreadOperationExecutor; _buildSucceeds = buildSucceeds; 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 fb9434791454d..f665c0e02b574 100644 --- a/src/VisualStudio/CSharp/Test/Microsoft.VisualStudio.LanguageServices.CSharp.UnitTests.csproj +++ b/src/VisualStudio/CSharp/Test/Microsoft.VisualStudio.LanguageServices.CSharp.UnitTests.csproj @@ -56,6 +56,18 @@ + + + + + true + diff --git a/src/VisualStudio/CSharp/Test/PersistentStorage/AbstractPersistentStorageTests.cs b/src/VisualStudio/CSharp/Test/PersistentStorage/AbstractPersistentStorageTests.cs index 66aeb589ccf7a..60e1ed8d19548 100644 --- a/src/VisualStudio/CSharp/Test/PersistentStorage/AbstractPersistentStorageTests.cs +++ b/src/VisualStudio/CSharp/Test/PersistentStorage/AbstractPersistentStorageTests.cs @@ -493,7 +493,7 @@ public async Task TestOpenWithSolutionKeyReadWithDocumentKey(Size size, [Combina await storage.WriteStreamAsync(document, streamName1, EncodeString(GetData1(size)), checksum: s_checksum1); } - await using (var storage = await GetStorageFromKeyAsync(solution.Workspace, SolutionKey.ToSolutionKey(solution))) + await using (var storage = await GetStorageFromKeyAsync(solution.Workspace.Services, SolutionKey.ToSolutionKey(solution))) { Assert.True(await storage.ChecksumMatchesAsync(DocumentKey.ToDocumentKey(document), streamName1, s_checksum1)); Assert.Equal(GetData1(size), ReadStringToEnd(await storage.ReadStreamAsync(DocumentKey.ToDocumentKey(document), streamName1))); @@ -514,7 +514,7 @@ public async Task TestOpenWithSolutionKeyReadWithDocument(Size size, [Combinator await storage.WriteStreamAsync(document, streamName1, EncodeString(GetData1(size)), checksum: s_checksum1); } - await using (var storage = await GetStorageFromKeyAsync(solution.Workspace, SolutionKey.ToSolutionKey(solution))) + await using (var storage = await GetStorageFromKeyAsync(solution.Workspace.Services, SolutionKey.ToSolutionKey(solution))) { Assert.True(await storage.ChecksumMatchesAsync(document, streamName1, s_checksum1)); Assert.Equal(GetData1(size), ReadStringToEnd(await storage.ReadStreamAsync(document, streamName1))); @@ -625,7 +625,7 @@ public async Task TestOpenWithSolutionKeyReadWithDocumentKeyAndDocument1(Size si await storage.WriteStreamAsync(document, streamName1, EncodeString(GetData1(size)), checksum: s_checksum1); } - await using (var storage = await GetStorageFromKeyAsync(solution.Workspace, SolutionKey.ToSolutionKey(solution))) + await using (var storage = await GetStorageFromKeyAsync(solution.Workspace.Services, SolutionKey.ToSolutionKey(solution))) { Assert.True(await storage.ChecksumMatchesAsync(DocumentKey.ToDocumentKey(document), streamName1, s_checksum1)); Assert.Equal(GetData1(size), ReadStringToEnd(await storage.ReadStreamAsync(DocumentKey.ToDocumentKey(document), streamName1))); @@ -649,7 +649,7 @@ public async Task TestOpenWithSolutionKeyReadWithDocumentKeyAndDocument2(Size si await storage.WriteStreamAsync(document, streamName1, EncodeString(GetData1(size)), checksum: s_checksum1); } - await using (var storage = await GetStorageFromKeyAsync(solution.Workspace, SolutionKey.ToSolutionKey(solution))) + await using (var storage = await GetStorageFromKeyAsync(solution.Workspace.Services, SolutionKey.ToSolutionKey(solution))) { Assert.True(await storage.ChecksumMatchesAsync(document, streamName1, s_checksum1)); Assert.Equal(GetData1(size), ReadStringToEnd(await storage.ReadStreamAsync(document, streamName1))); @@ -668,12 +668,12 @@ public async Task TestOpenWithSolutionKeyReadWithDocumentKey_WriteWithSolutionKe var streamName1 = "stream"; - await using (var storage = await GetStorageFromKeyAsync(solution.Workspace, SolutionKey.ToSolutionKey(solution))) + await using (var storage = await GetStorageFromKeyAsync(solution.Workspace.Services, SolutionKey.ToSolutionKey(solution))) { await storage.WriteStreamAsync(document, streamName1, EncodeString(GetData1(size)), checksum: s_checksum1); } - await using (var storage = await GetStorageFromKeyAsync(solution.Workspace, SolutionKey.ToSolutionKey(solution))) + await using (var storage = await GetStorageFromKeyAsync(solution.Workspace.Services, SolutionKey.ToSolutionKey(solution))) { Assert.True(await storage.ChecksumMatchesAsync(DocumentKey.ToDocumentKey(document), streamName1, s_checksum1)); Assert.Equal(GetData1(size), ReadStringToEnd(await storage.ReadStreamAsync(DocumentKey.ToDocumentKey(document), streamName1))); @@ -689,12 +689,12 @@ public async Task TestOpenWithSolutionKeyReadWithDocument_WriteWithSolutionKey(S var streamName1 = "stream"; - await using (var storage = await GetStorageFromKeyAsync(solution.Workspace, SolutionKey.ToSolutionKey(solution))) + await using (var storage = await GetStorageFromKeyAsync(solution.Workspace.Services, SolutionKey.ToSolutionKey(solution))) { await storage.WriteStreamAsync(document, streamName1, EncodeString(GetData1(size)), checksum: s_checksum1); } - await using (var storage = await GetStorageFromKeyAsync(solution.Workspace, SolutionKey.ToSolutionKey(solution))) + await using (var storage = await GetStorageFromKeyAsync(solution.Workspace.Services, SolutionKey.ToSolutionKey(solution))) { Assert.True(await storage.ChecksumMatchesAsync(document, streamName1, s_checksum1)); Assert.Equal(GetData1(size), ReadStringToEnd(await storage.ReadStreamAsync(document, streamName1))); @@ -710,7 +710,7 @@ public async Task TestOpenWithSolutionReadWithDocumentKey_WriteWithSolutionKey(S var streamName1 = "stream"; - await using (var storage = await GetStorageFromKeyAsync(solution.Workspace, SolutionKey.ToSolutionKey(solution))) + await using (var storage = await GetStorageFromKeyAsync(solution.Workspace.Services, SolutionKey.ToSolutionKey(solution))) { await storage.WriteStreamAsync(document, streamName1, EncodeString(GetData1(size)), checksum: s_checksum1); } @@ -731,7 +731,7 @@ public async Task TestOpenWithSolutionReadWithDocument_WriteWithSolutionKey(Size var streamName1 = "stream"; - await using (var storage = await GetStorageFromKeyAsync(solution.Workspace, SolutionKey.ToSolutionKey(solution))) + await using (var storage = await GetStorageFromKeyAsync(solution.Workspace.Services, SolutionKey.ToSolutionKey(solution))) { await storage.WriteStreamAsync(document, streamName1, EncodeString(GetData1(size)), checksum: s_checksum1); } @@ -752,7 +752,7 @@ public async Task TestOpenWithSolutionReadWithDocumentKeyAndDocument1_WriteWithS var streamName1 = "stream"; - await using (var storage = await GetStorageFromKeyAsync(solution.Workspace, SolutionKey.ToSolutionKey(solution))) + await using (var storage = await GetStorageFromKeyAsync(solution.Workspace.Services, SolutionKey.ToSolutionKey(solution))) { await storage.WriteStreamAsync(document, streamName1, EncodeString(GetData1(size)), checksum: s_checksum1); } @@ -776,7 +776,7 @@ public async Task TestOpenWithSolutionReadWithDocumentKeyAndDocument2_WriteWithS var streamName1 = "stream"; - await using (var storage = await GetStorageFromKeyAsync(solution.Workspace, SolutionKey.ToSolutionKey(solution))) + await using (var storage = await GetStorageFromKeyAsync(solution.Workspace.Services, SolutionKey.ToSolutionKey(solution))) { await storage.WriteStreamAsync(document, streamName1, EncodeString(GetData1(size)), checksum: s_checksum1); } @@ -800,12 +800,12 @@ public async Task TestOpenWithSolutionKeyReadWithDocumentKeyAndDocument1_WriteWi var streamName1 = "stream"; - await using (var storage = await GetStorageFromKeyAsync(solution.Workspace, SolutionKey.ToSolutionKey(solution))) + await using (var storage = await GetStorageFromKeyAsync(solution.Workspace.Services, SolutionKey.ToSolutionKey(solution))) { await storage.WriteStreamAsync(document, streamName1, EncodeString(GetData1(size)), checksum: s_checksum1); } - await using (var storage = await GetStorageFromKeyAsync(solution.Workspace, SolutionKey.ToSolutionKey(solution))) + await using (var storage = await GetStorageFromKeyAsync(solution.Workspace.Services, SolutionKey.ToSolutionKey(solution))) { Assert.True(await storage.ChecksumMatchesAsync(DocumentKey.ToDocumentKey(document), streamName1, s_checksum1)); Assert.Equal(GetData1(size), ReadStringToEnd(await storage.ReadStreamAsync(DocumentKey.ToDocumentKey(document), streamName1))); @@ -824,12 +824,12 @@ public async Task TestOpenWithSolutionKeyReadWithDocumentKeyAndDocument2_WriteWi var streamName1 = "stream"; - await using (var storage = await GetStorageFromKeyAsync(solution.Workspace, SolutionKey.ToSolutionKey(solution))) + await using (var storage = await GetStorageFromKeyAsync(solution.Workspace.Services, SolutionKey.ToSolutionKey(solution))) { await storage.WriteStreamAsync(document, streamName1, EncodeString(GetData1(size)), checksum: s_checksum1); } - await using (var storage = await GetStorageFromKeyAsync(solution.Workspace, SolutionKey.ToSolutionKey(solution))) + await using (var storage = await GetStorageFromKeyAsync(solution.Workspace.Services, SolutionKey.ToSolutionKey(solution))) { Assert.True(await storage.ChecksumMatchesAsync(document, streamName1, s_checksum1)); Assert.Equal(GetData1(size), ReadStringToEnd(await storage.ReadStreamAsync(document, streamName1))); @@ -973,7 +973,7 @@ internal async Task GetStorageAsync( _storageService?.GetTestAccessor().Shutdown(); var configuration = new MockPersistentStorageConfiguration(solution.Id, persistentFolder.Path, throwOnFailure); - _storageService = GetStorageService((IMefHostExportProvider)solution.Workspace.Services.HostServices, configuration, faultInjector, _persistentFolder.Path); + _storageService = GetStorageService(solution.Workspace.Services.SolutionServices.ExportProvider, configuration, faultInjector, _persistentFolder.Path); var storage = await _storageService.GetStorageAsync(SolutionKey.ToSolutionKey(solution), CancellationToken.None); // If we're injecting faults, we expect things to be strange @@ -986,13 +986,13 @@ internal async Task GetStorageAsync( } internal async Task GetStorageFromKeyAsync( - Workspace workspace, SolutionKey solutionKey, IPersistentStorageFaultInjector? faultInjector = null) + HostWorkspaceServices services, SolutionKey solutionKey, IPersistentStorageFaultInjector? faultInjector = null) { // If we handed out one for a previous test, we need to shut that down first _storageService?.GetTestAccessor().Shutdown(); var configuration = new MockPersistentStorageConfiguration(solutionKey.Id, _persistentFolder.Path, throwOnFailure: true); - _storageService = GetStorageService((IMefHostExportProvider)workspace.Services.HostServices, configuration, faultInjector, _persistentFolder.Path); + _storageService = GetStorageService(services.SolutionServices.ExportProvider, configuration, faultInjector, _persistentFolder.Path); var storage = await _storageService.GetStorageAsync(solutionKey, CancellationToken.None); // If we're injecting faults, we expect things to be strange diff --git a/src/VisualStudio/CSharp/Test/ProjectSystemShim/CPS/AdditionalPropertiesTests.cs b/src/VisualStudio/CSharp/Test/ProjectSystemShim/CPS/AdditionalPropertiesTests.cs index 972bad5c7d916..265d3f2532625 100644 --- a/src/VisualStudio/CSharp/Test/ProjectSystemShim/CPS/AdditionalPropertiesTests.cs +++ b/src/VisualStudio/CSharp/Test/ProjectSystemShim/CPS/AdditionalPropertiesTests.cs @@ -31,7 +31,7 @@ public async Task SetProperty_RootNamespace_CPS() Assert.Null(DefaultNamespaceOfSingleProject(environment)); var rootNamespace = "Foo.Bar"; - project.SetProperty(AdditionalPropertyNames.RootNamespace, rootNamespace); + project.SetProperty(BuildPropertyNames.RootNamespace, rootNamespace); Assert.Equal(rootNamespace, DefaultNamespaceOfSingleProject(environment)); } @@ -58,7 +58,7 @@ public async Task SetProperty_MaxSupportedLangVersion_CPS(LanguageVersion? maxSu var project = environment.Workspace.CurrentSolution.Projects.Single(); var oldParseOptions = (CSharpParseOptions)project.ParseOptions; - cpsProject.SetProperty(AdditionalPropertyNames.MaxSupportedLangVersion, maxSupportedLangVersion?.ToDisplayString()); + cpsProject.SetProperty(BuildPropertyNames.MaxSupportedLangVersion, maxSupportedLangVersion?.ToDisplayString()); var canApply = environment.Workspace.CanApplyParseOptionChange( oldParseOptions, @@ -131,8 +131,8 @@ async Task TestCPSProject() using var environment = new TestEnvironment(); using var cpsProject = await CSharpHelpers.CreateCSharpCPSProjectAsync(environment, "Test"); - cpsProject.SetProperty(AdditionalPropertyNames.RunAnalyzers, runAnalyzers); - cpsProject.SetProperty(AdditionalPropertyNames.RunAnalyzersDuringLiveAnalysis, runAnalyzersDuringLiveAnalysis); + cpsProject.SetProperty(BuildPropertyNames.RunAnalyzers, runAnalyzers); + cpsProject.SetProperty(BuildPropertyNames.RunAnalyzersDuringLiveAnalysis, runAnalyzersDuringLiveAnalysis); Assert.Equal(expectedRunAnalyzers, environment.Workspace.CurrentSolution.Projects.Single().State.RunAnalyzers); } @@ -146,11 +146,11 @@ void TestLegacyProject() Assert.True(ErrorHandler.Succeeded( storage.SetPropertyValue( - AdditionalPropertyNames.RunAnalyzers, null, (uint)_PersistStorageType.PST_PROJECT_FILE, runAnalyzers))); + BuildPropertyNames.RunAnalyzers, null, (uint)_PersistStorageType.PST_PROJECT_FILE, runAnalyzers))); Assert.True(ErrorHandler.Succeeded( storage.SetPropertyValue( - AdditionalPropertyNames.RunAnalyzersDuringLiveAnalysis, null, (uint)_PersistStorageType.PST_PROJECT_FILE, runAnalyzersDuringLiveAnalysis))); + BuildPropertyNames.RunAnalyzersDuringLiveAnalysis, null, (uint)_PersistStorageType.PST_PROJECT_FILE, runAnalyzersDuringLiveAnalysis))); _ = CSharpHelpers.CreateCSharpProject(environment, "Test", hierarchy); diff --git a/src/VisualStudio/CSharp/Test/ProjectSystemShim/CPS/CSharpCompilerOptionsTests.cs b/src/VisualStudio/CSharp/Test/ProjectSystemShim/CPS/CSharpCompilerOptionsTests.cs index 5343f23a54cd9..d876846afef1c 100644 --- a/src/VisualStudio/CSharp/Test/ProjectSystemShim/CPS/CSharpCompilerOptionsTests.cs +++ b/src/VisualStudio/CSharp/Test/ProjectSystemShim/CPS/CSharpCompilerOptionsTests.cs @@ -100,34 +100,13 @@ public async Task ProjectOutputBinPathChange_CPS() Assert.Equal(expectedNewBinPath, project.BinOutputPath); } - [WpfFact, WorkItem(14520, "https://github.com/dotnet/roslyn/issues/14520")] - [Trait(Traits.Feature, Traits.Features.ProjectSystemShims)] - public async Task InvalidProjectOutputBinPaths_CPS1() - { - using var environment = new TestEnvironment(); - using var project1 = await CSharpHelpers.CreateCSharpCPSProjectAsync(environment, "Test", binOutputPath: null); - // Null output path is allowed. - Assert.Null(project1.BinOutputPath); - } - - [WpfFact, WorkItem(14520, "https://github.com/dotnet/roslyn/issues/14520")] - [Trait(Traits.Feature, Traits.Features.ProjectSystemShims)] - public async Task InvalidProjectOutputBinPaths_CPS2() - { - using var environment = new TestEnvironment(); - using var project2 = await CSharpHelpers.CreateCSharpCPSProjectAsync(environment, "Test2", binOutputPath: String.Empty); - // Empty output path is not allowed, it gets reset to null. - Assert.Null(project2.BinOutputPath); - } - - [WpfFact, WorkItem(14520, "https://github.com/dotnet/roslyn/issues/14520")] + [WpfFact] [Trait(Traits.Feature, Traits.Features.ProjectSystemShims)] - public async Task InvalidProjectOutputBinPaths_CPS3() + public async Task InvalidProjectOutputBinPaths_CPS() { using var environment = new TestEnvironment(); - using var project3 = await CSharpHelpers.CreateCSharpCPSProjectAsync(environment, "Test3", binOutputPath: "Test.dll"); - // Non-rooted output path is not allowed, it gets reset to a temp rooted path. - Assert.Equal(Path.Combine(Path.GetTempPath(), "Test.dll"), project3.BinOutputPath); + await Assert.ThrowsAsync(() => CSharpHelpers.CreateCSharpCPSProjectAsync(environment, "Test2", binOutputPath: "")); + await Assert.ThrowsAsync(() => CSharpHelpers.CreateCSharpCPSProjectAsync(environment, "Test3", binOutputPath: "Test.dll")); } [WpfFact] diff --git a/src/VisualStudio/CSharp/Test/ProjectSystemShim/CPS/CSharpReferencesTests.cs b/src/VisualStudio/CSharp/Test/ProjectSystemShim/CPS/CSharpReferencesTests.cs index f59968b620a29..314923c54a098 100644 --- a/src/VisualStudio/CSharp/Test/ProjectSystemShim/CPS/CSharpReferencesTests.cs +++ b/src/VisualStudio/CSharp/Test/ProjectSystemShim/CPS/CSharpReferencesTests.cs @@ -115,10 +115,9 @@ public async Task RemoveProjectConvertsProjectReferencesBack() [Trait(Traits.Feature, Traits.Features.ProjectSystemShims)] public async Task AddingMetadataReferenceToProjectThatCannotCompileInTheIdeKeepsMetadataReference() { - using var environment = new TestEnvironment(typeof(NoCompilationLanguageServiceFactory)); + using var environment = new TestEnvironment(typeof(NoCompilationLanguageService)); var project1 = await CreateCSharpCPSProjectAsync(environment, "project1", commandLineArguments: @"/out:c:\project1.dll"); - var project2 = await CreateNonCompilableProjectAsync(environment, "project2", @"C:\project2.fsproj"); - project2.BinOutputPath = "c:\\project2.dll"; + var project2 = await CreateNonCompilableProjectAsync(environment, "project2", @"C:\project2.fsproj", targetPath: @"c:\project2.dll"); project1.AddMetadataReference(project2.BinOutputPath, MetadataReferenceProperties.Assembly); diff --git a/src/VisualStudio/CSharp/Test/ProjectSystemShim/CSharpHelpers.cs b/src/VisualStudio/CSharp/Test/ProjectSystemShim/CSharpHelpers.cs index 6bfdd9c096465..ea251ae58e5d7 100644 --- a/src/VisualStudio/CSharp/Test/ProjectSystemShim/CSharpHelpers.cs +++ b/src/VisualStudio/CSharp/Test/ProjectSystemShim/CSharpHelpers.cs @@ -22,6 +22,7 @@ using Microsoft.VisualStudio.LanguageServices.ProjectSystem; using Microsoft.VisualStudio.LanguageServices.UnitTests.ProjectSystemShim.Framework; using Microsoft.VisualStudio.Shell.Interop; +using Roslyn.Test.Utilities; using Xunit; namespace Roslyn.VisualStudio.CSharp.UnitTests.ProjectSystemShim @@ -79,14 +80,15 @@ public static async Task CreateCSharpCPSProjectAsync(TestEnvironment { var hierarchy = environment.CreateHierarchy(projectName, binOutputPath, projectRefPath: null, "CSharp"); var cpsProjectFactory = environment.ExportProvider.GetExportedValue(); + + var data = new TestEvaluationData(projectFilePath, binOutputPath, assemblyName: ""); + var cpsProject = (CPSProject)await cpsProjectFactory.CreateProjectContextAsync( - LanguageNames.CSharp, - projectName, - projectFilePath, projectGuid, + projectName, + LanguageNames.CSharp, + data, hierarchy, - binOutputPath, - assemblyName: null, CancellationToken.None); cpsProject.SetOptions(ImmutableArray.Create(commandLineArguments)); @@ -94,19 +96,19 @@ public static async Task CreateCSharpCPSProjectAsync(TestEnvironment return cpsProject; } - public static async Task CreateNonCompilableProjectAsync(TestEnvironment environment, string projectName, string projectFilePath) + public static async Task CreateNonCompilableProjectAsync(TestEnvironment environment, string projectName, string projectFilePath, string targetPath) { - var hierarchy = environment.CreateHierarchy(projectName, projectBinPath: null, projectRefPath: null, ""); + var hierarchy = environment.CreateHierarchy(projectName, projectBinPath: null, projectRefPath: null, projectCapabilities: ""); var cpsProjectFactory = environment.ExportProvider.GetExportedValue(); + var data = new TestEvaluationData(projectFilePath, targetPath, assemblyName: ""); + return (CPSProject)await cpsProjectFactory.CreateProjectContextAsync( - NoCompilationConstants.LanguageName, - projectName, - projectFilePath, Guid.NewGuid(), + projectName, + NoCompilationConstants.LanguageName, + data, hierarchy, - binOutputPath: null, - assemblyName: null, CancellationToken.None); } diff --git a/src/VisualStudio/CSharp/Test/ProjectSystemShim/LegacyProject/AnalyzersTests.cs b/src/VisualStudio/CSharp/Test/ProjectSystemShim/LegacyProject/AnalyzersTests.cs index 9a7692575583c..59f56a6b2f7b7 100644 --- a/src/VisualStudio/CSharp/Test/ProjectSystemShim/LegacyProject/AnalyzersTests.cs +++ b/src/VisualStudio/CSharp/Test/ProjectSystemShim/LegacyProject/AnalyzersTests.cs @@ -244,7 +244,7 @@ public async Task RuleSet_FileChangingOnDiskRefreshes(bool useCpsProject) using var environment = new TestEnvironment(); if (useCpsProject) { - await CSharpHelpers.CreateCSharpCPSProjectAsync(environment, "Test", binOutputPath: null, $"/ruleset:\"{ruleSetFile.Path}\""); + await CSharpHelpers.CreateCSharpCPSProjectAsync(environment, "Test", binOutputPath: @"C:\test.dll", $"/ruleset:\"{ruleSetFile.Path}\""); } else { diff --git a/src/VisualStudio/CSharp/Test/ProjectSystemShim/TestEvaluationData.cs b/src/VisualStudio/CSharp/Test/ProjectSystemShim/TestEvaluationData.cs new file mode 100644 index 0000000000000..5687836e372f3 --- /dev/null +++ b/src/VisualStudio/CSharp/Test/ProjectSystemShim/TestEvaluationData.cs @@ -0,0 +1,33 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Collections.Generic; +using Microsoft.VisualStudio.LanguageServices.ProjectSystem; +using Roslyn.Utilities; + +namespace Roslyn.VisualStudio.CSharp.UnitTests.ProjectSystemShim; + +internal sealed class TestEvaluationData : EvaluationData +{ + public string ProjectFilePath { get; } + public string TargetPath { get; } + public string AssemblyName { get; } + + public TestEvaluationData(string projectFilePath, string targetPath, string assemblyName) + { + ProjectFilePath = projectFilePath; + TargetPath = targetPath; + AssemblyName = assemblyName; + } + + public override string GetPropertyValue(string name) + => name switch + { + "MSBuildProjectFullPath" => ProjectFilePath, + "TargetPath" => TargetPath, + "AssemblyName" => AssemblyName, + _ => throw ExceptionUtilities.UnexpectedValue(name) + }; +} diff --git a/src/VisualStudio/CodeLens/ReferenceCodeLensProvider.cs b/src/VisualStudio/CodeLens/ReferenceCodeLensProvider.cs index f5b4079c4c2e4..e9bfa7068d082 100644 --- a/src/VisualStudio/CodeLens/ReferenceCodeLensProvider.cs +++ b/src/VisualStudio/CodeLens/ReferenceCodeLensProvider.cs @@ -130,10 +130,7 @@ private void AddDataPoint(DataPoint dataPoint) var versionedPoints = _dataPoints.GetOrAdd(dataPoint.Descriptor.ProjectGuid, _ => (version: VersionStamp.Default.ToString(), dataPoints: new HashSet())); versionedPoints.dataPoints.Add(dataPoint); - if (_pollingTask is null) - { - _pollingTask = Task.Run(PollForUpdatesAsync).ReportNonFatalErrorAsync(); - } + _pollingTask ??= Task.Run(PollForUpdatesAsync).ReportNonFatalErrorAsync(); } } diff --git a/src/VisualStudio/Core/Def/CallHierarchy/CallHierarchyCommandHandler.cs b/src/VisualStudio/Core/Def/CallHierarchy/CallHierarchyCommandHandler.cs index 9ce2b16fdd23e..973c83044e341 100644 --- a/src/VisualStudio/Core/Def/CallHierarchy/CallHierarchyCommandHandler.cs +++ b/src/VisualStudio/Core/Def/CallHierarchy/CallHierarchyCommandHandler.cs @@ -59,17 +59,17 @@ public bool ExecuteCommand(ViewCallHierarchyCommandArgs args, CommandExecutionCo return true; } - var workspace = document.Project.Solution.Workspace; var semanticModel = document.GetSemanticModelAsync(cancellationToken).WaitAndGetResult(cancellationToken); var caretPosition = args.TextView.Caret.Position.BufferPosition.Position; - var symbolUnderCaret = SymbolFinder.FindSymbolAtPositionAsync(semanticModel, caretPosition, workspace, cancellationToken) + var symbolUnderCaret = SymbolFinder.FindSymbolAtPositionAsync( + semanticModel, caretPosition, document.Project.Solution.Services, cancellationToken) .WaitAndGetResult(cancellationToken); if (symbolUnderCaret != null) { // Map symbols so that Call Hierarchy works from metadata-as-source - var mappingService = document.Project.Solution.Workspace.Services.GetService(); + var mappingService = document.Project.Solution.Services.GetService(); var mapping = mappingService.MapSymbolAsync(document, symbolUnderCaret, cancellationToken).WaitAndGetResult(cancellationToken); if (mapping.Symbol != null) @@ -89,7 +89,7 @@ public bool ExecuteCommand(ViewCallHierarchyCommandArgs args, CommandExecutionCo // wait context. That means the command system won't attempt to show its own wait dialog // and also will take it into consideration when measuring command handling duration. waitScope.Context.TakeOwnership(); - var notificationService = document.Project.Solution.Workspace.Services.GetService(); + var notificationService = document.Project.Solution.Services.GetService(); notificationService.SendNotification(EditorFeaturesResources.Cursor_must_be_on_a_member_name, severity: NotificationSeverity.Information); } diff --git a/src/VisualStudio/Core/Def/CallHierarchy/Finders/AbstractCallFinder.cs b/src/VisualStudio/Core/Def/CallHierarchy/Finders/AbstractCallFinder.cs index f8f0386c5ff79..011586a69bbd5 100644 --- a/src/VisualStudio/Core/Def/CallHierarchy/Finders/AbstractCallFinder.cs +++ b/src/VisualStudio/Core/Def/CallHierarchy/Finders/AbstractCallFinder.cs @@ -117,7 +117,7 @@ private static IImmutableSet IncludeDocuments(CallHierarchySearchScope { if (scope is CallHierarchySearchScope.CurrentDocument or CallHierarchySearchScope.CurrentProject) { - var documentTrackingService = project.Solution.Workspace.Services.GetRequiredService(); + var documentTrackingService = project.Solution.Services.GetRequiredService(); var activeDocument = documentTrackingService.TryGetActiveDocument(); if (activeDocument != null) { diff --git a/src/VisualStudio/Core/Def/ChangeSignature/AddParameterDialogViewModel.cs b/src/VisualStudio/Core/Def/ChangeSignature/AddParameterDialogViewModel.cs index adfe2d7dec0cb..ed05ed72a491c 100644 --- a/src/VisualStudio/Core/Def/ChangeSignature/AddParameterDialogViewModel.cs +++ b/src/VisualStudio/Core/Def/ChangeSignature/AddParameterDialogViewModel.cs @@ -6,7 +6,7 @@ using System.Threading; using System.Windows; using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Notification; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.VisualStudio.LanguageServices.Implementation.Utilities; @@ -25,7 +25,7 @@ internal class AddParameterDialogViewModel : AbstractNotifyPropertyChanged public AddParameterDialogViewModel(Document document, int positionForTypeBinding) { - _notificationService = document.Project.Solution.Workspace.Services.GetService(); + _notificationService = document.Project.Solution.Services.GetService(); _semanticModel = document.GetRequiredSemanticModelAsync(CancellationToken.None).AsTask().WaitAndGetResult_CanCallOnBackground(CancellationToken.None); TypeIsEmptyImage = Visibility.Visible; diff --git a/src/VisualStudio/Core/Def/ChangeSignature/ChangeSignatureDialog.xaml.cs b/src/VisualStudio/Core/Def/ChangeSignature/ChangeSignatureDialog.xaml.cs index 4341b7a7c2458..d23a7cb8f6497 100644 --- a/src/VisualStudio/Core/Def/ChangeSignature/ChangeSignatureDialog.xaml.cs +++ b/src/VisualStudio/Core/Def/ChangeSignature/ChangeSignatureDialog.xaml.cs @@ -223,10 +223,7 @@ private void SetFocusToSelectedRow(bool focusRow) private static void FocusRow(DataGridRow row) { var cell = row.FindDescendant(); - if (cell != null) - { - cell.Focus(); - } + cell?.Focus(); } private void MoveSelectionUp_Click(object sender, EventArgs e) diff --git a/src/VisualStudio/Core/Def/ChangeSignature/ChangeSignatureDialogViewModel.cs b/src/VisualStudio/Core/Def/ChangeSignature/ChangeSignatureDialogViewModel.cs index 4b8ebc6bbf7db..297d5929cf1c9 100644 --- a/src/VisualStudio/Core/Def/ChangeSignature/ChangeSignatureDialogViewModel.cs +++ b/src/VisualStudio/Core/Def/ChangeSignature/ChangeSignatureDialogViewModel.cs @@ -61,7 +61,7 @@ internal ChangeSignatureDialogViewModel( _classificationFormatMap = classificationFormatMap; _classificationTypeMap = classificationTypeMap; - _notificationService = document.Project.Solution.Workspace.Services.GetRequiredService(); + _notificationService = document.Project.Solution.Services.GetRequiredService(); // This index is displayed to users. That is why we start it from 1. var initialDisplayIndex = 1; diff --git a/src/VisualStudio/Core/Def/CodeCleanup/AbstractCodeCleanUpFixer.cs b/src/VisualStudio/Core/Def/CodeCleanup/AbstractCodeCleanUpFixer.cs index dbd9eacf9bc56..735e4f07d821c 100644 --- a/src/VisualStudio/Core/Def/CodeCleanup/AbstractCodeCleanUpFixer.cs +++ b/src/VisualStudio/Core/Def/CodeCleanup/AbstractCodeCleanUpFixer.cs @@ -136,7 +136,7 @@ private async Task FixHierarchyContentAsync(IVsHierarchyCodeCleanupScope h } var document = solution.GetRequiredDocument(documentId); - var options = _globalOptions.GetCodeActionOptions(document.Project.LanguageServices); + var options = _globalOptions.GetCodeActionOptions(document.Project.Services); return await FixDocumentAsync(document, options, context).ConfigureAwait(true); } } @@ -146,7 +146,7 @@ private async Task FixHierarchyContentAsync(IVsHierarchyCodeCleanupScope h private Task FixSolutionAsync(Solution solution, ICodeCleanUpExecutionContext context) { - return FixAsync(solution.Workspace, ApplyFixAsync, context); + return FixAsync(_workspace, ApplyFixAsync, context); // Local function Task ApplyFixAsync(ProgressTracker progressTracker, CancellationToken cancellationToken) @@ -157,7 +157,7 @@ Task ApplyFixAsync(ProgressTracker progressTracker, CancellationToken private Task FixProjectAsync(Project project, ICodeCleanUpExecutionContext context) { - return FixAsync(project.Solution.Workspace, ApplyFixAsync, context); + return FixAsync(_workspace, ApplyFixAsync, context); // Local function async Task ApplyFixAsync(ProgressTracker progressTracker, CancellationToken cancellationToken) @@ -205,7 +205,7 @@ async Task ApplyFixAsync(ProgressTracker progressTracker, Cancellation var document = buffer.CurrentSnapshot.GetOpenDocumentInCurrentContextWithChanges(); Contract.ThrowIfNull(document); - var options = _globalOptions.GetCodeActionOptions(document.Project.LanguageServices); + var options = _globalOptions.GetCodeActionOptions(document.Project.Services); var newDoc = await FixDocumentAsync(document, context.EnabledFixIds, progressTracker, options, cancellationToken).ConfigureAwait(true); return newDoc.Project.Solution; } @@ -292,7 +292,7 @@ private async Task FixProjectAsync( progressTracker.AddItems(project.DocumentIds.Count); } - var ideOptions = _globalOptions.GetCodeActionOptions(project.LanguageServices); + var ideOptions = _globalOptions.GetCodeActionOptions(project.Services); foreach (var documentId in project.DocumentIds) { @@ -314,7 +314,7 @@ private async Task FixProjectAsync( } private static bool CanCleanupProject(Project project) - => project.LanguageServices.GetService() != null; + => project.Services.GetService() != null; private static async Task FixDocumentAsync( Document document, diff --git a/src/VisualStudio/Core/Def/CodeLens/RemoteCodeLensReferencesService.cs b/src/VisualStudio/Core/Def/CodeLens/RemoteCodeLensReferencesService.cs index 61b9851efeb38..617d399d738fc 100644 --- a/src/VisualStudio/Core/Def/CodeLens/RemoteCodeLensReferencesService.cs +++ b/src/VisualStudio/Core/Def/CodeLens/RemoteCodeLensReferencesService.cs @@ -50,7 +50,7 @@ public ValueTask GetProjectCodeLensVersionAsync(Solution solution, return null; } - var client = await RemoteHostClient.TryGetClientAsync(solution.Workspace, cancellationToken).ConfigureAwait(false); + var client = await RemoteHostClient.TryGetClientAsync(solution.Services, cancellationToken).ConfigureAwait(false); if (client != null) { var result = await client.TryInvokeAsync( @@ -96,7 +96,7 @@ public ValueTask GetProjectCodeLensVersionAsync(Solution solution, return null; } - var client = await RemoteHostClient.TryGetClientAsync(solution.Workspace, cancellationToken).ConfigureAwait(false); + var client = await RemoteHostClient.TryGetClientAsync(solution.Services, cancellationToken).ConfigureAwait(false); if (client != null) { var result = await client.TryInvokeAsync?>( @@ -121,7 +121,7 @@ public ValueTask GetProjectCodeLensVersionAsync(Solution solution, return null; } - var client = await RemoteHostClient.TryGetClientAsync(solution.Workspace, cancellationToken).ConfigureAwait(false); + var client = await RemoteHostClient.TryGetClientAsync(solution.Services, cancellationToken).ConfigureAwait(false); if (client != null) { var result = await client.TryInvokeAsync( @@ -259,7 +259,7 @@ private static string GetLineTextOrEmpty(TextLineCollection lines, int index) return ImmutableArray.Empty; } - var client = await RemoteHostClient.TryGetClientAsync(solution.Workspace, cancellationToken).ConfigureAwait(false); + var client = await RemoteHostClient.TryGetClientAsync(solution.Services, cancellationToken).ConfigureAwait(false); if (client != null) { var result = await client.TryInvokeAsync?>( diff --git a/src/VisualStudio/Core/Def/CommonControls/MemberSelection.xaml b/src/VisualStudio/Core/Def/CommonControls/MemberSelection.xaml index c8789e10167fb..50efb6bda4e56 100644 --- a/src/VisualStudio/Core/Def/CommonControls/MemberSelection.xaml +++ b/src/VisualStudio/Core/Def/CommonControls/MemberSelection.xaml @@ -7,10 +7,18 @@ 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" 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" d:DesignHeight="450" d:DesignWidth="800"> - 2, 4, 4, 2 - + + + + + 2, 4, 4, 2 + + + @@ -39,7 +47,6 @@ Focusable="True" MinWidth="334" Height="Auto" - Background="White" AutomationProperties.Name="{Binding SelectMemberListViewAutomationText}" ItemsSource="{Binding Members, UpdateSourceTrigger=PropertyChanged, NotifyOnSourceUpdated=True, Mode=TwoWay}"> @@ -58,7 +65,8 @@ - + + - + - - - - + + + + + + - + - + - - + + + + @@ -149,6 +163,7 @@ x:Uid="SelecDependentsButton" Padding="{StaticResource ResourceKey=ButtonControlsPadding}" Content="{Binding ElementName=MemberSelectionControl, Path=SelectDependents}" + Visibility="{Binding ShowCheckDependentsButton, Converter={StaticResource BooleanToVisibilityConverter}}" Click="SelectDependentsButton_Click" Margin="2, 2, 0, 7" Width="Auto" @@ -157,6 +172,7 @@ x:Name="SelectPublicButton" x:Uid="SelectPublicButton" Content="{Binding ElementName=MemberSelectionControl, Path=SelectPublic}" + Visibility="{Binding ShowPublicButton, Converter={StaticResource BooleanToVisibilityConverter}}" Margin="2, 0, 0, 0" Click="SelectPublic_Click" Padding="{StaticResource ResourceKey=ButtonControlsPadding}" diff --git a/src/VisualStudio/Core/Def/CommonControls/MemberSelection.xaml.cs b/src/VisualStudio/Core/Def/CommonControls/MemberSelection.xaml.cs index 5d1b0b36f8ef4..3816cf3af20aa 100644 --- a/src/VisualStudio/Core/Def/CommonControls/MemberSelection.xaml.cs +++ b/src/VisualStudio/Core/Def/CommonControls/MemberSelection.xaml.cs @@ -28,7 +28,24 @@ public MemberSelection(MemberSelectionViewModel viewModel) ViewModel = viewModel; DataContext = ViewModel; + ViewModel.PropertyChanged += ViewModel_PropertyChanged; + InitializeComponent(); + + UpdateAbstractColumnVisibility(); + } + + private void ViewModel_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e) + { + if (e.PropertyName == nameof(MemberSelectionViewModel.ShowMakeAbstract)) + { + UpdateAbstractColumnVisibility(); + } + } + + private void UpdateAbstractColumnVisibility() + { + AbstractColumn.Visibility = ViewModel.ShowMakeAbstract ? Visibility.Visible : Visibility.Collapsed; } private void SelectDependentsButton_Click(object sender, RoutedEventArgs e) diff --git a/src/VisualStudio/Core/Def/CommonControls/MemberSelectionViewModel.cs b/src/VisualStudio/Core/Def/CommonControls/MemberSelectionViewModel.cs index 7246929295ed1..eab590cb6ec37 100644 --- a/src/VisualStudio/Core/Def/CommonControls/MemberSelectionViewModel.cs +++ b/src/VisualStudio/Core/Def/CommonControls/MemberSelectionViewModel.cs @@ -12,8 +12,8 @@ using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Editor.Host; using Microsoft.CodeAnalysis.Shared.Extensions; -using Microsoft.VisualStudio.LanguageServices.Implementation.PullMemberUp.MainDialog; using Microsoft.VisualStudio.LanguageServices.Implementation.Utilities; +using Microsoft.VisualStudio.LanguageServices.Utilities; using Microsoft.VisualStudio.Utilities; using Roslyn.Utilities; @@ -23,27 +23,35 @@ internal class MemberSelectionViewModel : AbstractNotifyPropertyChanged { private readonly IUIThreadOperationExecutor _uiThreadOperationExecutor; private readonly ImmutableDictionary>> _symbolToDependentsMap; - private readonly ImmutableDictionary _symbolToMemberViewMap; + private readonly ImmutableDictionary _symbolToMemberViewMap; public MemberSelectionViewModel( IUIThreadOperationExecutor uiThreadOperationExecutor, - ImmutableArray members, + ImmutableArray members, ImmutableDictionary>> dependentsMap, - TypeKind destinationTypeKind = TypeKind.Class) + TypeKind destinationTypeKind = TypeKind.Class, + bool showDependentsButton = true, + bool showPublicButton = true) { _uiThreadOperationExecutor = uiThreadOperationExecutor; // Use public property to hook property change events up - Members = members; + Members = members.OrderBy(s => s.SymbolName).ToImmutableArray(); _symbolToDependentsMap = dependentsMap; _symbolToMemberViewMap = members.ToImmutableDictionary(memberViewModel => memberViewModel.Symbol); UpdateMembersBasedOnDestinationKind(destinationTypeKind); + + ShowCheckDependentsButton = showDependentsButton; + ShowPublicButton = showPublicButton; } - public ImmutableArray CheckedMembers => Members.WhereAsArray(m => m.IsChecked && m.IsCheckable); + public bool ShowCheckDependentsButton { get; } + public bool ShowPublicButton { get; } + public bool ShowMakeAbstract => _members.Any(m => m.IsMakeAbstractCheckable); + public ImmutableArray CheckedMembers => Members.WhereAsArray(m => m.IsChecked && m.IsCheckable); - private ImmutableArray _members; - public ImmutableArray Members + private ImmutableArray _members; + public ImmutableArray Members { get => _members; set @@ -65,17 +73,24 @@ public ImmutableArray Members { member.PropertyChanged += MemberPropertyChangedHandler; } + + NotifyPropertyChanged(nameof(ShowMakeAbstract)); } } } private void MemberPropertyChangedHandler(object sender, PropertyChangedEventArgs e) { - if (e.PropertyName == nameof(PullMemberUpSymbolViewModel.IsChecked)) + if (e.PropertyName == nameof(MemberSymbolViewModel.IsChecked)) { // Hook the CheckedMembers property change to each individual member checked status change NotifyPropertyChanged(nameof(CheckedMembers)); } + + if (e.PropertyName == nameof(MemberSymbolViewModel.IsMakeAbstractCheckable)) + { + NotifyPropertyChanged(nameof(ShowMakeAbstract)); + } } public void SelectPublic() @@ -89,6 +104,8 @@ internal void DeselectAll() public void SelectDependents() { + Contract.ThrowIfFalse(ShowCheckDependentsButton); + var checkedMembers = Members .WhereAsArray(member => member.IsChecked && member.IsCheckable); @@ -142,7 +159,7 @@ public void UpdateMembersBasedOnDestinationKind(TypeKind destinationType) } } - private static void SelectMembers(ImmutableArray members, bool isChecked = true) + private static void SelectMembers(ImmutableArray members, bool isChecked = true) { foreach (var member in members.Where(viewModel => viewModel.IsCheckable)) { diff --git a/src/VisualStudio/Core/Def/CommonControls/NewTypeDestinationSelection.xaml b/src/VisualStudio/Core/Def/CommonControls/NewTypeDestinationSelection.xaml index a619cd3732694..5edd73d3569d1 100644 --- a/src/VisualStudio/Core/Def/CommonControls/NewTypeDestinationSelection.xaml +++ b/src/VisualStudio/Core/Def/CommonControls/NewTypeDestinationSelection.xaml @@ -7,19 +7,28 @@ xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:local="clr-namespace:Microsoft.VisualStudio.LanguageServices.Implementation.CommonControls" xmlns:u="clr-namespace:Microsoft.VisualStudio.LanguageServices.Implementation.Utilities" + xmlns:vs="clr-namespace:Microsoft.VisualStudio.PlatformUI;assembly=Microsoft.VisualStudio.Shell.15.0" mc:Ignorable="d" - d:DesignHeight="450" d:DesignWidth="800"> + d:DesignHeight="450" d:DesignWidth="800" + xmlns:vsshell="clr-namespace:Microsoft.VisualStudio.Shell;assembly=Microsoft.VisualStudio.Shell.15.0" + Background="{DynamicResource {x:Static vs:ThemedDialogColors.WindowPanelBrushKey}}"> - - - 0, 5, 0, 2 - 9,2,9,2 - 9,2,9,2 - 2 - 2, 0, 2, 0 + + 0, 5, 0, 2 + 9,2,9,2 + 9,2,9,2 + 2 + 2, 0, 2, 0 +